Skip to content

Commit

Permalink
start documenting all exports
Browse files Browse the repository at this point in the history
  • Loading branch information
phryneas committed Mar 13, 2024
1 parent 37feeaa commit c0715a0
Show file tree
Hide file tree
Showing 20 changed files with 778 additions and 42 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ yalc.lock
.vscode/
.vercel
.next/
test-results/
test-results/
temp/
48 changes: 48 additions & 0 deletions packages/client-react-streaming/api-extractor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* Config file for API Extractor. For more info, please visit: https://api-extractor.com
*/
{
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "<projectFolder>/dist/combined.d.ts",
"bundledPackages": [],
"newlineKind": "lf",
"compiler": {
// "overrideTsconfig": {
// . . .
// }
"skipLibCheck": true
},
"apiReport": {
"enabled": false
},
"docModel": {
"enabled": true
},
"dtsRollup": {
"enabled": false
},
"tsdocMetadata": {
"enabled": false
},
"messages": {
"compilerMessageReporting": {
"default": {
"logLevel": "warning"
}
},
"extractorMessageReporting": {
"default": {
"logLevel": "warning"
},
"ae-forgotten-export": {
"addToApiReportFile": false,
"logLevel": "none"
}
},
"tsdocMessageReporting": {
"default": {
"logLevel": "warning"
}
}
}
}
16 changes: 16 additions & 0 deletions packages/client-react-streaming/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@
"browser": "./dist/index.browser.js",
"node": "./dist/index.ssr.js"
}
},
"#bundled/manual-transport": {
"require": {
"types": "./dist/manual-transport.ssr.d.cts",
"react-server": "./dist/empty.cjs",
"browser": "./dist/manual-transport.browser.cjs",
"node": "./dist/manual-transport.ssr.cjs"
},
"import": {
"types": "./dist/manual-transport.ssr.d.ts",
"react-server": "./dist/empty.js",
"browser": "./dist/manual-transport.browser.js",
"node": "./dist/manual-transport.ssr.js"
}
}
},
"exports": {
Expand Down Expand Up @@ -95,6 +109,7 @@
"devDependencies": {
"@apollo/client": "^3.9.6",
"@arethetypeswrong/cli": "0.13.6",
"@microsoft/api-extractor": "^7.42.3",
"@testing-library/react": "^14.2.1",
"@total-typescript/shoehorn": "0.1.1",
"@tsconfig/recommended": "1.0.3",
Expand All @@ -112,6 +127,7 @@
"graphql": "16.8.1",
"jsdom": "^24.0.0",
"react": "18.3.0-canary-60a927d04-20240113",
"react-error-boundary": "^4.0.13",
"rimraf": "5.0.5",
"superjson": "1.13.3",
"ts-node": "10.9.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,27 @@ export interface AccumulateMultipartResponsesConfig {
cutoffDelay: number;
}

/**
*
* This link can be used to "debounce" the initial response of a multipart request. Any incremental data received during the `cutoffDelay` time will be merged into the initial response.
*
* After `cutoffDelay`, the link will return the initial response, even if there is still incremental data pending, and close the network connection.
*
* If `cutoffDelay` is `0`, the link will immediately return data as soon as it is received, without waiting for incremental data, and immediately close the network connection.
*
* @example
* ```ts
* new AccumulateMultipartResponsesLink({
* // The maximum delay in milliseconds
* // from receiving the first response
* // until the accumulated data will be flushed
* // and the connection will be closed.
* cutoffDelay: 100,
* });
* ```
*
* @public
*/
export class AccumulateMultipartResponsesLink extends ApolloLink {
private maxDelay: number;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,29 @@ interface DataTransportAbstraction {
useStaticValueRef<T>(value: T): { current: T };
}

/**
* If you create a custom data transport, you need to wrap the child tree in a
* `DataTransportContext.Provider` and provide the `DataTransportAbstraction` to it.
*
* See for example
* https://github.com/apollographql/apollo-client-nextjs/blob/37feeaa9aea69b90a974eb9cd0fbd636b62d841a/integration-test/experimental-react/src/WrappedApolloProvider.tsx
*
* @public
*/
export const DataTransportContext =
/*#__PURE__*/ createContext<DataTransportAbstraction | null>(null);

/**
* Interface to be implemented by a custom data transport component,
* for usage with `WrapApolloProvider`.
*
* This component needs to provide a `DataTransportContext` to it's children.
*
* See for example
* https://github.com/apollographql/apollo-client-nextjs/blob/37feeaa9aea69b90a974eb9cd0fbd636b62d841a/integration-test/experimental-react/src/WrappedApolloProvider.tsx
*
* @public
*/
export type DataTransportProviderImplementation<
// eslint-disable-next-line @typescript-eslint/ban-types
ExtraProps = {},
Expand All @@ -41,6 +61,14 @@ export type DataTransportProviderImplementation<

export type TransportIdentifier = string & { __transportIdentifier: true };

/**
* Events that will be emitted by a wrapped ApolloClient instance during
* SSR on `DataTransportProviderImplementation.registerDispatchRequestStarted`,
* to be transported to the browser and replayed there using
* `DataTransportProviderImplementation.onQueryEvent`.
*
* @public
*/
export type QueryEvent =
| {
type: "started";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ApolloClient } from "./WrappedApolloClient.js";
import { ApolloProvider } from "@apollo/client/index.js";
import type { DataTransportProviderImplementation } from "./DataTransportAbstraction.js";
import { ApolloClientSingleton } from "./symbols.js";
import { bundle } from "../bundleInfo.js";

declare global {
interface Window {
Expand All @@ -13,21 +14,44 @@ declare global {
}

/**
* Creates an ApolloProvider for streaming SSR.
* @param TransportProvider The transport provider to be used.
* A version of `ApolloProvider` particularly suited for React's streaming SSR.
*/
export function WrapApolloProvider<ExtraProps>(
TransportProvider: DataTransportProviderImplementation<ExtraProps>
) {
const WrappedApolloProvider = ({
export interface WrappedApolloProvider<ExtraProps> {
({
makeClient,
children,
...extraProps
}: React.PropsWithChildren<
{
makeClient: () => ApolloClient<any>;
} & ExtraProps
>) => {
>): React.JSX.Element;
/**
* Information about the current package and it's export names, for use in error messages.
*/
info: {
pkg: string;
client: string;
cache: string;
};
}

/**
* Creates an ApolloProvider for streaming SSR.
*
* @param TransportProvider - The transport provider to be used.
* This could e.g. be a `ManualDataTransport` created by `buildManualDataTransport`,
* or a fully custom implementation of `DataTransportProviderImplementation`.
* @public
*/
export function WrapApolloProvider<ExtraProps>(
TransportProvider: DataTransportProviderImplementation<ExtraProps>
): WrappedApolloProvider<ExtraProps> {
const WrappedApolloProvider: WrappedApolloProvider<ExtraProps> = ({
makeClient,
children,
...extraProps
}) => {
const clientRef = useRef<ApolloClient<any>>();

if (process.env.REACT_ENV === "ssr") {
Expand All @@ -40,7 +64,7 @@ export function WrapApolloProvider<ExtraProps>(

if (!(clientRef.current instanceof ApolloClient)) {
throw new Error(
"When using Apollo Client streaming SSR, you must use the `ApolloClient` variant provided by the streaming package."
`When using \`ApolloClient\` in streaming SSR, you must use the \`${WrappedApolloProvider.info.client}\` export provided by \`"${WrappedApolloProvider.info.pkg}"\`.`
);
}

Expand All @@ -63,6 +87,6 @@ export function WrapApolloProvider<ExtraProps>(
</ApolloProvider>
);
};

WrappedApolloProvider.info = bundle;
return WrappedApolloProvider;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
QueryEvent,
TransportIdentifier,
} from "./DataTransportAbstraction.js";
import { bundle } from "../bundleInfo.js";

function getQueryManager<TCacheShape>(
client: OrigApolloClient<unknown>
Expand All @@ -40,20 +41,29 @@ type SimulatedQueryInfo = {

const wrappers = Symbol.for("apollo.hook.wrappers");
class ApolloClientBase<TCacheShape> extends OrigApolloClient<TCacheShape> {
/**
* Information about the current package and it's export names, for use in error messages.
*/
protected info = bundle;

constructor(options: ApolloClientOptions<TCacheShape>) {
super(options);

if (!(this.cache instanceof InMemoryCache)) {
throw new Error(
"When using Apollo Client streaming SSR, you must use the `InMemoryCache` variant provided by the streaming package."
`When using \`InMemoryCache\` in streaming SSR, you must use the \`${this.info.cache}\` export provided by \`"${this.info.pkg}"\`.`
);
}

getQueryManager(this)[wrappers] = hookWrappers;
}
}

class ApolloClientSSRImpl<TCacheShape> extends ApolloClientBase<TCacheShape> {
constructor(options: ApolloClientOptions<TCacheShape>) {
super(options);

getQueryManager(this)[wrappers] = hookWrappers;
}

watchQueryQueue = createBackpressuredCallback<{
event: Extract<QueryEvent, { type: "started" }>;
observable: Observable<Exclude<QueryEvent, { type: "started" }>>;
Expand Down Expand Up @@ -118,6 +128,12 @@ class ApolloClientSSRImpl<TCacheShape> extends ApolloClientBase<TCacheShape> {
export class ApolloClientBrowserImpl<
TCacheShape,
> extends ApolloClientBase<TCacheShape> {
constructor(options: ApolloClientOptions<TCacheShape>) {
super(options);

getQueryManager(this)[wrappers] = hookWrappers;
}

private simulatedStreamingQueries = new Map<
TransportIdentifier,
SimulatedQueryInfo
Expand Down Expand Up @@ -292,18 +308,34 @@ export class ApolloClientBrowserImpl<
};
}

export type ApolloClient<TCacheShape> = OrigApolloClient<TCacheShape> &
Partial<ApolloClientBrowserImpl<TCacheShape>> &
Partial<ApolloClientSSRImpl<TCacheShape>>;

export const ApolloClient: {
new <TCacheShape>(
options: ApolloClientOptions<TCacheShape>
): ApolloClient<TCacheShape>;
} = /*#__PURE__*/ (
process.env.REACT_ENV === "ssr"
const ApolloClientImplementation =
/*#__PURE__*/ process.env.REACT_ENV === "ssr"
? ApolloClientSSRImpl
: process.env.REACT_ENV === "browser"
? ApolloClientBrowserImpl
: OrigApolloClient
) as any;
: ApolloClientBase;

/**
* A version of `ApolloClient` to be used with streaming SSR.
*
* For more documentation, please see {@link https://www.apollographql.com/docs/react/api/core/ApolloClient | the Apollo Client API documentation}.
*
* @public
*/
export class ApolloClient<TCacheShape>
extends (ApolloClientImplementation as typeof ApolloClientBase)<TCacheShape>
implements
Partial<ApolloClientBrowserImpl<TCacheShape>>,
Partial<ApolloClientSSRImpl<TCacheShape>>
{
/** @internal */
declare onQueryStarted?: ApolloClientBrowserImpl<TCacheShape>["onQueryStarted"];
/** @internal */
declare onQueryProgress?: ApolloClientBrowserImpl<TCacheShape>["onQueryProgress"];
/** @internal */
declare rerunSimulatedQueries?: ApolloClientBrowserImpl<TCacheShape>["rerunSimulatedQueries"];
/** @internal */
declare rerunSimulatedQuery?: ApolloClientBrowserImpl<TCacheShape>["rerunSimulatedQuery"];
/** @internal */
declare watchQueryQueue?: ApolloClientSSRImpl<TCacheShape>["watchQueryQueue"];
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { InMemoryCache as OrigInMemoryCache } from "@apollo/client/index.js";
/**
/*
* We just subclass `InMemoryCache` here so that `WrappedApolloClient`
* can detect if it was initialized with an `InMemoryCache` instance that
* was also exported from this package.
Expand All @@ -8,4 +8,11 @@ import { InMemoryCache as OrigInMemoryCache } from "@apollo/client/index.js";
* So we want to enforce this import path from the start to prevent future
* subtle bugs if people update the package and don't read the patch notes.
*/
/**
* A version of `InMemoryCache` to be used with streaming SSR.
*
* For more documentation, please see {@link https://www.apollographql.com/docs/react/api/cache/InMemoryCache | the Apollo Client API documentation}.
*
* @public
*/
export class InMemoryCache extends OrigInMemoryCache {}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,7 @@ export type {
DataTransportProviderImplementation,
QueryEvent,
} from "./DataTransportAbstraction.js";
export { WrapApolloProvider } from "./WrapApolloProvider.js";
export {
WrapApolloProvider,
WrappedApolloProvider,
} from "./WrapApolloProvider.js";
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ApolloClientSingleton } from "./symbols.js";
* ```ts
* afterEach(resetApolloSingletons);
* ```
*
* @public
*/
export function resetApolloSingletons() {
delete window[ApolloClientSingleton];
Expand Down
Loading

0 comments on commit c0715a0

Please sign in to comment.