@remix-relay/react 2.4.4 → 2.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +39 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,12 +48,31 @@ var import_react_router = require("react-router");
|
|
|
48
48
|
// src/deferred-query-context.tsx
|
|
49
49
|
var import_react = require("react");
|
|
50
50
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
function createDeferredQueryStore() {
|
|
52
|
+
let value = void 0;
|
|
53
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
54
|
+
return {
|
|
55
|
+
get: () => value,
|
|
56
|
+
set: (newValue) => {
|
|
57
|
+
value = newValue;
|
|
58
|
+
listeners.forEach((l) => l());
|
|
59
|
+
},
|
|
60
|
+
subscribe: (listener) => {
|
|
61
|
+
listeners.add(listener);
|
|
62
|
+
return () => listeners.delete(listener);
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
var DeferredQueryStoreContext = (0, import_react.createContext)(
|
|
67
|
+
createDeferredQueryStore()
|
|
68
|
+
);
|
|
69
|
+
function useDeferredQuery() {
|
|
70
|
+
const store = (0, import_react.use)(DeferredQueryStoreContext);
|
|
71
|
+
return (0, import_react.useSyncExternalStore)(store.subscribe, store.get, () => void 0);
|
|
72
|
+
}
|
|
54
73
|
function RemixRelayProvider({ children }) {
|
|
55
|
-
const
|
|
56
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
74
|
+
const store = (0, import_react.useMemo)(() => createDeferredQueryStore(), []);
|
|
75
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(DeferredQueryStoreContext, { value: store, children });
|
|
57
76
|
}
|
|
58
77
|
|
|
59
78
|
// src/Deferred.tsx
|
|
@@ -68,7 +87,7 @@ function useIsMounted() {
|
|
|
68
87
|
}
|
|
69
88
|
function Deferred({ children, ...rest }) {
|
|
70
89
|
const mounted = useIsMounted();
|
|
71
|
-
const deferredQuery = (
|
|
90
|
+
const deferredQuery = useDeferredQuery();
|
|
72
91
|
if (!mounted || deferredQuery === void 0) {
|
|
73
92
|
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: rest.fallback });
|
|
74
93
|
}
|
|
@@ -148,11 +167,16 @@ function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
|
|
|
148
167
|
const preloadedQuery = "preloadedQuery" in loaderData ? loaderData.preloadedQuery : null;
|
|
149
168
|
const deferredQueries = "deferredQueries" in loaderData ? loaderData.deferredQueries : null;
|
|
150
169
|
const [deferredResult, setDeferredResult] = (0, import_react3.useState)(preloadedQuery);
|
|
151
|
-
const
|
|
152
|
-
(0, import_react3.
|
|
170
|
+
const store = (0, import_react3.use)(DeferredQueryStoreContext);
|
|
171
|
+
const transformedPromiseRef = (0, import_react3.useRef)(null);
|
|
172
|
+
const prevDeferredQueriesRef = (0, import_react3.useRef)(
|
|
173
|
+
/* @__PURE__ */ Symbol()
|
|
174
|
+
);
|
|
175
|
+
if (deferredQueries !== prevDeferredQueriesRef.current) {
|
|
176
|
+
prevDeferredQueriesRef.current = deferredQueries;
|
|
153
177
|
if (deferredQueries) {
|
|
154
|
-
|
|
155
|
-
|
|
178
|
+
transformedPromiseRef.current = deferredQueries.then(
|
|
179
|
+
async (deferredResults) => {
|
|
156
180
|
deferredResults.forEach((result) => {
|
|
157
181
|
(0, import_react_dom.flushSync)(() => {
|
|
158
182
|
setDeferredResult(
|
|
@@ -161,12 +185,14 @@ function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
|
|
|
161
185
|
});
|
|
162
186
|
});
|
|
163
187
|
return deferredResults;
|
|
164
|
-
}
|
|
188
|
+
}
|
|
165
189
|
);
|
|
190
|
+
store.set(transformedPromiseRef.current);
|
|
166
191
|
} else {
|
|
167
|
-
|
|
192
|
+
transformedPromiseRef.current = null;
|
|
193
|
+
store.set(null);
|
|
168
194
|
}
|
|
169
|
-
}
|
|
195
|
+
}
|
|
170
196
|
const environment = useRelayEnvironment();
|
|
171
197
|
(0, import_react3.useMemo)(() => {
|
|
172
198
|
if (deferredResult) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/Deferred.tsx","../src/deferred-query-context.tsx","../src/client-loader-query.ts","../src/get-cached-response.ts","../src/meta-query.ts","../src/useLoaderQuery.ts"],"sourcesContent":["export { Deferred } from \"./Deferred\";\nexport { clientLoaderQuery, getClientLoaderQuery } from \"./client-loader-query\";\nexport { RemixRelayProvider } from \"./deferred-query-context\";\nexport { getCachedResponse } from \"./get-cached-response\";\nexport { metaQuery } from \"./meta-query\";\nexport { useLoaderQuery, useRouteLoaderQuery } from \"./useLoaderQuery\";\n","import { Suspense, SuspenseProps, use, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { DeferredQueryContext } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = use(DeferredQueryContext);\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from \"react\";\nimport { createContext, useState } from \"react\";\n\nexport const DeferredQueryContext = createContext<\n Promise<unknown> | null | undefined\n>(undefined);\nexport const SetDeferredQueryContext = createContext<\n Dispatch<SetStateAction<Promise<unknown> | null | undefined>>\n>(() => {});\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const [deferredQueries, setDeferredQueries] = useState<\n Promise<unknown> | null | undefined\n >(undefined);\n\n return (\n <SetDeferredQueryContext value={setDeferredQueries}>\n <DeferredQueryContext value={deferredQueries}>\n {children}\n </DeferredQueryContext>\n </SetDeferredQueryContext>\n );\n}\n","import relay from \"react-relay\";\nimport type {\n Environment,\n GraphQLTaggedNode,\n OperationType,\n VariablesOf,\n} from \"relay-runtime\";\n\nconst { fetchQuery, loadQuery } = relay;\n\nexport function getClientLoaderQuery(environment: Environment) {\n return async <TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n ) => clientLoaderQuery(environment, query, variables);\n}\n\nexport async function clientLoaderQuery<TQuery extends OperationType>(\n environment: Environment,\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n) {\n const data = await fetchQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-or-network\",\n }).toPromise();\n\n const queryRef = loadQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-only\",\n });\n\n return { queryRef, data };\n}\n","import type {\n CacheConfig,\n GraphQLResponse,\n RequestParameters,\n Variables,\n} from \"relay-runtime\";\nimport { Observable, QueryResponseCache } from \"relay-runtime\";\n\nexport const responseCache: QueryResponseCache = new QueryResponseCache({\n size: 100,\n ttl: 5000,\n});\n\nexport function getCachedResponse(\n params: RequestParameters,\n variables: Variables,\n cacheConfig: CacheConfig,\n) {\n const isQuery = params.operationKind === \"query\";\n const cacheKey = params.id ?? params.cacheID;\n const forceFetch = cacheConfig && cacheConfig.force;\n\n if (responseCache === null || !isQuery || forceFetch) {\n return null;\n }\n\n const fromCache = responseCache.get(cacheKey, variables);\n\n const deferredFromCache: GraphQLResponse[] = [];\n\n for (let i = 0; ; i++) {\n const deferred = responseCache.get(`${cacheKey}-${i}`, variables);\n if (!deferred) break;\n deferredFromCache.push(deferred);\n }\n\n if (fromCache === null) {\n return null;\n }\n\n return Observable.create((sink) => {\n sink.next(fromCache);\n\n for (const deferred of deferredFromCache) {\n sink.next(deferred);\n }\n\n sink.complete();\n });\n}\n","import type { MetaFunction } from \"react-router\";\nimport type { OperationType } from \"relay-runtime\";\n\nexport function metaQuery<TQuery extends OperationType>(\n metaFunction: (\n args: Parameters<MetaFunction>[0] & {\n data: TQuery[\"response\"];\n },\n ) => ReturnType<MetaFunction>,\n): MetaFunction<\n () =>\n | { preloadedQuery: { response: { data: TQuery[\"response\"] } } }\n | { data: TQuery[\"response\"] }\n> {\n return ({ data, ...rest }) => {\n const metaData: TQuery[\"response\"] =\n data && \"data\" in data\n ? data.data\n : data && \"preloadedQuery\" in data\n ? (data.preloadedQuery.response as { data: TQuery[\"response\"] }).data\n : null;\n\n return metaFunction({\n data: metaData,\n ...rest,\n });\n };\n}\n","import { use, useEffect, useMemo, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type {\n GraphQLTaggedNode,\n PreloadFetchPolicy,\n PreloadedQuery,\n} from \"react-relay\";\nimport relay from \"react-relay\";\nimport type { useQueryLoaderHookType } from \"react-relay/relay-hooks/useQueryLoader\";\nimport { useLoaderData, useRouteLoaderData } from \"react-router\";\nimport type {\n ConcreteRequest,\n GraphQLResponse,\n OperationType,\n RequestParameters,\n VariablesOf,\n} from \"relay-runtime\";\nimport invariant from \"tiny-invariant\";\nimport { SetDeferredQueryContext } from \"./deferred-query-context\";\nimport { responseCache } from \"./get-cached-response\";\n\nconst { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay;\n\nexport type SerializablePreloadedQuery<TQuery extends OperationType> = {\n params: ConcreteRequest[\"params\"];\n variables: VariablesOf<TQuery>;\n response: GraphQLResponse;\n};\n\ntype LoaderData<TQuery extends OperationType> =\n | {\n preloadedQuery: SerializablePreloadedQuery<TQuery>;\n deferredQueries: Promise<SerializablePreloadedQuery<TQuery>[]>;\n }\n | { queryRef: PreloadedQuery<TQuery> };\n\nfunction useCommonLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy,\n loaderData: LoaderData<TQuery>,\n): [\n TQuery[\"response\"],\n useQueryLoaderHookType<TQuery>[1],\n useQueryLoaderHookType<TQuery>[2],\n] {\n const preloadedQuery =\n \"preloadedQuery\" in loaderData\n ? (loaderData.preloadedQuery as unknown as SerializablePreloadedQuery<TQuery>)\n : null;\n\n const deferredQueries =\n \"deferredQueries\" in loaderData\n ? (loaderData.deferredQueries as unknown as Promise<\n SerializablePreloadedQuery<TQuery>[]\n >)\n : null;\n\n const [deferredResult, setDeferredResult] = useState(preloadedQuery);\n\n const setDeferredQueries = use(SetDeferredQueryContext);\n\n useEffect(() => {\n if (deferredQueries) {\n setDeferredQueries(\n deferredQueries.then(async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n\n return deferredResults;\n }),\n );\n } else {\n setDeferredQueries(null);\n }\n }, [deferredQueries, preloadedQuery, setDeferredQueries, setDeferredResult]);\n\n const environment = useRelayEnvironment();\n\n useMemo(() => {\n if (deferredResult) {\n writePreloadedQueryToCache(deferredResult);\n }\n }, [deferredResult]);\n\n let ref: PreloadedQuery<TQuery> | null =\n \"queryRef\" in loaderData\n ? (loaderData.queryRef as unknown as PreloadedQuery<TQuery>)\n : deferredResult\n ? {\n environment,\n fetchKey: `${\n deferredResult.params.id ?? deferredResult.params.cacheID\n }${simpleHash(deferredResult.response)}`,\n fetchPolicy,\n isDisposed: false,\n name: deferredResult.params.name,\n kind: \"PreloadedQuery\",\n variables: deferredResult.variables,\n dispose: () => {},\n }\n : null;\n\n invariant(ref, \"Missing queryRef\");\n\n const [queryRef, loadQuery, disposeQuery] = useQueryLoader<TQuery>(query);\n\n if (queryRef) ref = queryRef;\n\n const reloadQuery: typeof loadQuery = (\n variables,\n options = { fetchPolicy: \"store-and-network\" },\n ) => loadQuery(variables, options);\n\n const data = usePreloadedQuery<TQuery>(query, ref);\n\n return [data, reloadQuery, disposeQuery];\n}\n\nexport function useLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> = useLoaderData();\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nexport function useRouteLoaderQuery<TQuery extends OperationType>(\n routeId: string,\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> | undefined =\n useRouteLoaderData(routeId);\n\n invariant(loaderData, `Missing loader data for routeId ${routeId}`);\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nfunction writePreloadedQueryToCache<TQuery extends OperationType>(\n preloadedQueryObject: SerializablePreloadedQuery<TQuery>,\n) {\n const params = preloadedQueryObject.params as RequestParameters & {\n cacheID?: string;\n };\n\n const cacheKey = params.cacheID ?? params.id;\n invariant(cacheKey, \"Missing cacheKey\");\n\n responseCache?.set(\n cacheKey,\n preloadedQueryObject.variables,\n preloadedQueryObject.response,\n );\n}\n\nfunction simpleHash(input: unknown): number {\n return JSON.stringify(input)\n .split(\"\")\n .reduce((a, b) => {\n a = (a << 5) - a + b.charCodeAt(0);\n return a & a;\n }, 0);\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","relay","import_react","import_react_relay","import_react_router","relay","invariant","loadQuery"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/Deferred.tsx","../src/deferred-query-context.tsx","../src/client-loader-query.ts","../src/get-cached-response.ts","../src/meta-query.ts","../src/useLoaderQuery.ts"],"sourcesContent":["export { Deferred } from \"./Deferred\";\nexport { clientLoaderQuery, getClientLoaderQuery } from \"./client-loader-query\";\nexport { RemixRelayProvider } from \"./deferred-query-context\";\nexport { getCachedResponse } from \"./get-cached-response\";\nexport { metaQuery } from \"./meta-query\";\nexport { useLoaderQuery, useRouteLoaderQuery } from \"./useLoaderQuery\";\n","import { Suspense, SuspenseProps, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { useDeferredQuery } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = useDeferredQuery();\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { PropsWithChildren } from \"react\";\nimport { createContext, use, useMemo, useSyncExternalStore } from \"react\";\n\ntype DeferredQueryValue = Promise<unknown> | null | undefined;\n\ntype DeferredQueryStore = {\n get: () => DeferredQueryValue;\n set: (value: DeferredQueryValue) => void;\n subscribe: (listener: () => void) => () => void;\n};\n\nfunction createDeferredQueryStore(): DeferredQueryStore {\n let value: DeferredQueryValue = undefined;\n const listeners = new Set<() => void>();\n\n return {\n get: () => value,\n set: (newValue) => {\n value = newValue;\n listeners.forEach((l) => l());\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nexport const DeferredQueryStoreContext = createContext<DeferredQueryStore>(\n createDeferredQueryStore(),\n);\n\nexport function useDeferredQuery(): DeferredQueryValue {\n const store = use(DeferredQueryStoreContext);\n return useSyncExternalStore(store.subscribe, store.get, () => undefined);\n}\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const store = useMemo(() => createDeferredQueryStore(), []);\n\n return (\n <DeferredQueryStoreContext value={store}>\n {children}\n </DeferredQueryStoreContext>\n );\n}\n","import relay from \"react-relay\";\nimport type {\n Environment,\n GraphQLTaggedNode,\n OperationType,\n VariablesOf,\n} from \"relay-runtime\";\n\nconst { fetchQuery, loadQuery } = relay;\n\nexport function getClientLoaderQuery(environment: Environment) {\n return async <TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n ) => clientLoaderQuery(environment, query, variables);\n}\n\nexport async function clientLoaderQuery<TQuery extends OperationType>(\n environment: Environment,\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n) {\n const data = await fetchQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-or-network\",\n }).toPromise();\n\n const queryRef = loadQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-only\",\n });\n\n return { queryRef, data };\n}\n","import type {\n CacheConfig,\n GraphQLResponse,\n RequestParameters,\n Variables,\n} from \"relay-runtime\";\nimport { Observable, QueryResponseCache } from \"relay-runtime\";\n\nexport const responseCache: QueryResponseCache = new QueryResponseCache({\n size: 100,\n ttl: 5000,\n});\n\nexport function getCachedResponse(\n params: RequestParameters,\n variables: Variables,\n cacheConfig: CacheConfig,\n) {\n const isQuery = params.operationKind === \"query\";\n const cacheKey = params.id ?? params.cacheID;\n const forceFetch = cacheConfig && cacheConfig.force;\n\n if (responseCache === null || !isQuery || forceFetch) {\n return null;\n }\n\n const fromCache = responseCache.get(cacheKey, variables);\n\n const deferredFromCache: GraphQLResponse[] = [];\n\n for (let i = 0; ; i++) {\n const deferred = responseCache.get(`${cacheKey}-${i}`, variables);\n if (!deferred) break;\n deferredFromCache.push(deferred);\n }\n\n if (fromCache === null) {\n return null;\n }\n\n return Observable.create((sink) => {\n sink.next(fromCache);\n\n for (const deferred of deferredFromCache) {\n sink.next(deferred);\n }\n\n sink.complete();\n });\n}\n","import type { MetaFunction } from \"react-router\";\nimport type { OperationType } from \"relay-runtime\";\n\nexport function metaQuery<TQuery extends OperationType>(\n metaFunction: (\n args: Parameters<MetaFunction>[0] & {\n data: TQuery[\"response\"];\n },\n ) => ReturnType<MetaFunction>,\n): MetaFunction<\n () =>\n | { preloadedQuery: { response: { data: TQuery[\"response\"] } } }\n | { data: TQuery[\"response\"] }\n> {\n return ({ data, ...rest }) => {\n const metaData: TQuery[\"response\"] =\n data && \"data\" in data\n ? data.data\n : data && \"preloadedQuery\" in data\n ? (data.preloadedQuery.response as { data: TQuery[\"response\"] }).data\n : null;\n\n return metaFunction({\n data: metaData,\n ...rest,\n });\n };\n}\n","import { use, useMemo, useRef, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type {\n GraphQLTaggedNode,\n PreloadFetchPolicy,\n PreloadedQuery,\n} from \"react-relay\";\nimport relay from \"react-relay\";\nimport type { useQueryLoaderHookType } from \"react-relay/relay-hooks/useQueryLoader\";\nimport { useLoaderData, useRouteLoaderData } from \"react-router\";\nimport type {\n ConcreteRequest,\n GraphQLResponse,\n OperationType,\n RequestParameters,\n VariablesOf,\n} from \"relay-runtime\";\nimport invariant from \"tiny-invariant\";\nimport { DeferredQueryStoreContext } from \"./deferred-query-context\";\nimport { responseCache } from \"./get-cached-response\";\n\nconst { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay;\n\nexport type SerializablePreloadedQuery<TQuery extends OperationType> = {\n params: ConcreteRequest[\"params\"];\n variables: VariablesOf<TQuery>;\n response: GraphQLResponse;\n};\n\ntype LoaderData<TQuery extends OperationType> =\n | {\n preloadedQuery: SerializablePreloadedQuery<TQuery>;\n deferredQueries: Promise<SerializablePreloadedQuery<TQuery>[]>;\n }\n | { queryRef: PreloadedQuery<TQuery> };\n\nfunction useCommonLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy,\n loaderData: LoaderData<TQuery>,\n): [\n TQuery[\"response\"],\n useQueryLoaderHookType<TQuery>[1],\n useQueryLoaderHookType<TQuery>[2],\n] {\n const preloadedQuery =\n \"preloadedQuery\" in loaderData\n ? (loaderData.preloadedQuery as unknown as SerializablePreloadedQuery<TQuery>)\n : null;\n\n const deferredQueries =\n \"deferredQueries\" in loaderData\n ? (loaderData.deferredQueries as unknown as Promise<\n SerializablePreloadedQuery<TQuery>[]\n >)\n : null;\n\n const [deferredResult, setDeferredResult] = useState(preloadedQuery);\n\n const store = use(DeferredQueryStoreContext);\n\n // Track transformed promise to avoid recreating on every render\n const transformedPromiseRef = useRef<Promise<unknown> | null>(null);\n const prevDeferredQueriesRef = useRef<typeof deferredQueries | symbol>(\n Symbol(),\n );\n\n // Set store synchronously during render (before Deferred reads it)\n if (deferredQueries !== prevDeferredQueriesRef.current) {\n prevDeferredQueriesRef.current = deferredQueries;\n if (deferredQueries) {\n transformedPromiseRef.current = deferredQueries.then(\n async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n return deferredResults;\n },\n );\n store.set(transformedPromiseRef.current);\n } else {\n transformedPromiseRef.current = null;\n store.set(null);\n }\n }\n\n const environment = useRelayEnvironment();\n\n useMemo(() => {\n if (deferredResult) {\n writePreloadedQueryToCache(deferredResult);\n }\n }, [deferredResult]);\n\n let ref: PreloadedQuery<TQuery> | null =\n \"queryRef\" in loaderData\n ? (loaderData.queryRef as unknown as PreloadedQuery<TQuery>)\n : deferredResult\n ? {\n environment,\n fetchKey: `${\n deferredResult.params.id ?? deferredResult.params.cacheID\n }${simpleHash(deferredResult.response)}`,\n fetchPolicy,\n isDisposed: false,\n name: deferredResult.params.name,\n kind: \"PreloadedQuery\",\n variables: deferredResult.variables,\n dispose: () => {},\n }\n : null;\n\n invariant(ref, \"Missing queryRef\");\n\n const [queryRef, loadQuery, disposeQuery] = useQueryLoader<TQuery>(query);\n\n if (queryRef) ref = queryRef;\n\n const reloadQuery: typeof loadQuery = (\n variables,\n options = { fetchPolicy: \"store-and-network\" },\n ) => loadQuery(variables, options);\n\n const data = usePreloadedQuery<TQuery>(query, ref);\n\n return [data, reloadQuery, disposeQuery];\n}\n\nexport function useLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> = useLoaderData();\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nexport function useRouteLoaderQuery<TQuery extends OperationType>(\n routeId: string,\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> | undefined =\n useRouteLoaderData(routeId);\n\n invariant(loaderData, `Missing loader data for routeId ${routeId}`);\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nfunction writePreloadedQueryToCache<TQuery extends OperationType>(\n preloadedQueryObject: SerializablePreloadedQuery<TQuery>,\n) {\n const params = preloadedQueryObject.params as RequestParameters & {\n cacheID?: string;\n };\n\n const cacheKey = params.cacheID ?? params.id;\n invariant(cacheKey, \"Missing cacheKey\");\n\n responseCache?.set(\n cacheKey,\n preloadedQueryObject.variables,\n preloadedQueryObject.response,\n );\n}\n\nfunction simpleHash(input: unknown): number {\n return JSON.stringify(input)\n .split(\"\")\n .reduce((a, b) => {\n a = (a << 5) - a + b.charCodeAt(0);\n return a & a;\n }, 0);\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","relay","import_react","import_react_relay","import_react_router","relay","invariant","loadQuery"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,22 +1,41 @@
|
|
|
1
1
|
// src/Deferred.tsx
|
|
2
|
-
import { Suspense,
|
|
2
|
+
import { Suspense, useSyncExternalStore as useSyncExternalStore2 } from "react";
|
|
3
3
|
import { Await } from "react-router";
|
|
4
4
|
|
|
5
5
|
// src/deferred-query-context.tsx
|
|
6
|
-
import { createContext,
|
|
6
|
+
import { createContext, use, useMemo, useSyncExternalStore } from "react";
|
|
7
7
|
import { jsx } from "react/jsx-runtime";
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
function createDeferredQueryStore() {
|
|
9
|
+
let value = void 0;
|
|
10
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
11
|
+
return {
|
|
12
|
+
get: () => value,
|
|
13
|
+
set: (newValue) => {
|
|
14
|
+
value = newValue;
|
|
15
|
+
listeners.forEach((l) => l());
|
|
16
|
+
},
|
|
17
|
+
subscribe: (listener) => {
|
|
18
|
+
listeners.add(listener);
|
|
19
|
+
return () => listeners.delete(listener);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
var DeferredQueryStoreContext = createContext(
|
|
24
|
+
createDeferredQueryStore()
|
|
25
|
+
);
|
|
26
|
+
function useDeferredQuery() {
|
|
27
|
+
const store = use(DeferredQueryStoreContext);
|
|
28
|
+
return useSyncExternalStore(store.subscribe, store.get, () => void 0);
|
|
29
|
+
}
|
|
11
30
|
function RemixRelayProvider({ children }) {
|
|
12
|
-
const
|
|
13
|
-
return /* @__PURE__ */ jsx(
|
|
31
|
+
const store = useMemo(() => createDeferredQueryStore(), []);
|
|
32
|
+
return /* @__PURE__ */ jsx(DeferredQueryStoreContext, { value: store, children });
|
|
14
33
|
}
|
|
15
34
|
|
|
16
35
|
// src/Deferred.tsx
|
|
17
36
|
import { Fragment, jsx as jsx2 } from "react/jsx-runtime";
|
|
18
37
|
function useIsMounted() {
|
|
19
|
-
return
|
|
38
|
+
return useSyncExternalStore2(
|
|
20
39
|
() => () => {
|
|
21
40
|
},
|
|
22
41
|
() => true,
|
|
@@ -25,7 +44,7 @@ function useIsMounted() {
|
|
|
25
44
|
}
|
|
26
45
|
function Deferred({ children, ...rest }) {
|
|
27
46
|
const mounted = useIsMounted();
|
|
28
|
-
const deferredQuery =
|
|
47
|
+
const deferredQuery = useDeferredQuery();
|
|
29
48
|
if (!mounted || deferredQuery === void 0) {
|
|
30
49
|
return /* @__PURE__ */ jsx2(Fragment, { children: rest.fallback });
|
|
31
50
|
}
|
|
@@ -95,7 +114,7 @@ function metaQuery(metaFunction) {
|
|
|
95
114
|
}
|
|
96
115
|
|
|
97
116
|
// src/useLoaderQuery.ts
|
|
98
|
-
import { use as use2,
|
|
117
|
+
import { use as use2, useMemo as useMemo2, useRef, useState } from "react";
|
|
99
118
|
import { flushSync } from "react-dom";
|
|
100
119
|
import relay2 from "react-relay";
|
|
101
120
|
import { useLoaderData, useRouteLoaderData } from "react-router";
|
|
@@ -104,12 +123,17 @@ var { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay2;
|
|
|
104
123
|
function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
|
|
105
124
|
const preloadedQuery = "preloadedQuery" in loaderData ? loaderData.preloadedQuery : null;
|
|
106
125
|
const deferredQueries = "deferredQueries" in loaderData ? loaderData.deferredQueries : null;
|
|
107
|
-
const [deferredResult, setDeferredResult] =
|
|
108
|
-
const
|
|
109
|
-
|
|
126
|
+
const [deferredResult, setDeferredResult] = useState(preloadedQuery);
|
|
127
|
+
const store = use2(DeferredQueryStoreContext);
|
|
128
|
+
const transformedPromiseRef = useRef(null);
|
|
129
|
+
const prevDeferredQueriesRef = useRef(
|
|
130
|
+
/* @__PURE__ */ Symbol()
|
|
131
|
+
);
|
|
132
|
+
if (deferredQueries !== prevDeferredQueriesRef.current) {
|
|
133
|
+
prevDeferredQueriesRef.current = deferredQueries;
|
|
110
134
|
if (deferredQueries) {
|
|
111
|
-
|
|
112
|
-
|
|
135
|
+
transformedPromiseRef.current = deferredQueries.then(
|
|
136
|
+
async (deferredResults) => {
|
|
113
137
|
deferredResults.forEach((result) => {
|
|
114
138
|
flushSync(() => {
|
|
115
139
|
setDeferredResult(
|
|
@@ -118,14 +142,16 @@ function useCommonLoaderQuery(query, fetchPolicy, loaderData) {
|
|
|
118
142
|
});
|
|
119
143
|
});
|
|
120
144
|
return deferredResults;
|
|
121
|
-
}
|
|
145
|
+
}
|
|
122
146
|
);
|
|
147
|
+
store.set(transformedPromiseRef.current);
|
|
123
148
|
} else {
|
|
124
|
-
|
|
149
|
+
transformedPromiseRef.current = null;
|
|
150
|
+
store.set(null);
|
|
125
151
|
}
|
|
126
|
-
}
|
|
152
|
+
}
|
|
127
153
|
const environment = useRelayEnvironment();
|
|
128
|
-
|
|
154
|
+
useMemo2(() => {
|
|
129
155
|
if (deferredResult) {
|
|
130
156
|
writePreloadedQueryToCache(deferredResult);
|
|
131
157
|
}
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Deferred.tsx","../src/deferred-query-context.tsx","../src/client-loader-query.ts","../src/get-cached-response.ts","../src/meta-query.ts","../src/useLoaderQuery.ts"],"sourcesContent":["import { Suspense, SuspenseProps, use, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { DeferredQueryContext } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = use(DeferredQueryContext);\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { Dispatch, PropsWithChildren, SetStateAction } from \"react\";\nimport { createContext, useState } from \"react\";\n\nexport const DeferredQueryContext = createContext<\n Promise<unknown> | null | undefined\n>(undefined);\nexport const SetDeferredQueryContext = createContext<\n Dispatch<SetStateAction<Promise<unknown> | null | undefined>>\n>(() => {});\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const [deferredQueries, setDeferredQueries] = useState<\n Promise<unknown> | null | undefined\n >(undefined);\n\n return (\n <SetDeferredQueryContext value={setDeferredQueries}>\n <DeferredQueryContext value={deferredQueries}>\n {children}\n </DeferredQueryContext>\n </SetDeferredQueryContext>\n );\n}\n","import relay from \"react-relay\";\nimport type {\n Environment,\n GraphQLTaggedNode,\n OperationType,\n VariablesOf,\n} from \"relay-runtime\";\n\nconst { fetchQuery, loadQuery } = relay;\n\nexport function getClientLoaderQuery(environment: Environment) {\n return async <TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n ) => clientLoaderQuery(environment, query, variables);\n}\n\nexport async function clientLoaderQuery<TQuery extends OperationType>(\n environment: Environment,\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n) {\n const data = await fetchQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-or-network\",\n }).toPromise();\n\n const queryRef = loadQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-only\",\n });\n\n return { queryRef, data };\n}\n","import type {\n CacheConfig,\n GraphQLResponse,\n RequestParameters,\n Variables,\n} from \"relay-runtime\";\nimport { Observable, QueryResponseCache } from \"relay-runtime\";\n\nexport const responseCache: QueryResponseCache = new QueryResponseCache({\n size: 100,\n ttl: 5000,\n});\n\nexport function getCachedResponse(\n params: RequestParameters,\n variables: Variables,\n cacheConfig: CacheConfig,\n) {\n const isQuery = params.operationKind === \"query\";\n const cacheKey = params.id ?? params.cacheID;\n const forceFetch = cacheConfig && cacheConfig.force;\n\n if (responseCache === null || !isQuery || forceFetch) {\n return null;\n }\n\n const fromCache = responseCache.get(cacheKey, variables);\n\n const deferredFromCache: GraphQLResponse[] = [];\n\n for (let i = 0; ; i++) {\n const deferred = responseCache.get(`${cacheKey}-${i}`, variables);\n if (!deferred) break;\n deferredFromCache.push(deferred);\n }\n\n if (fromCache === null) {\n return null;\n }\n\n return Observable.create((sink) => {\n sink.next(fromCache);\n\n for (const deferred of deferredFromCache) {\n sink.next(deferred);\n }\n\n sink.complete();\n });\n}\n","import type { MetaFunction } from \"react-router\";\nimport type { OperationType } from \"relay-runtime\";\n\nexport function metaQuery<TQuery extends OperationType>(\n metaFunction: (\n args: Parameters<MetaFunction>[0] & {\n data: TQuery[\"response\"];\n },\n ) => ReturnType<MetaFunction>,\n): MetaFunction<\n () =>\n | { preloadedQuery: { response: { data: TQuery[\"response\"] } } }\n | { data: TQuery[\"response\"] }\n> {\n return ({ data, ...rest }) => {\n const metaData: TQuery[\"response\"] =\n data && \"data\" in data\n ? data.data\n : data && \"preloadedQuery\" in data\n ? (data.preloadedQuery.response as { data: TQuery[\"response\"] }).data\n : null;\n\n return metaFunction({\n data: metaData,\n ...rest,\n });\n };\n}\n","import { use, useEffect, useMemo, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type {\n GraphQLTaggedNode,\n PreloadFetchPolicy,\n PreloadedQuery,\n} from \"react-relay\";\nimport relay from \"react-relay\";\nimport type { useQueryLoaderHookType } from \"react-relay/relay-hooks/useQueryLoader\";\nimport { useLoaderData, useRouteLoaderData } from \"react-router\";\nimport type {\n ConcreteRequest,\n GraphQLResponse,\n OperationType,\n RequestParameters,\n VariablesOf,\n} from \"relay-runtime\";\nimport invariant from \"tiny-invariant\";\nimport { SetDeferredQueryContext } from \"./deferred-query-context\";\nimport { responseCache } from \"./get-cached-response\";\n\nconst { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay;\n\nexport type SerializablePreloadedQuery<TQuery extends OperationType> = {\n params: ConcreteRequest[\"params\"];\n variables: VariablesOf<TQuery>;\n response: GraphQLResponse;\n};\n\ntype LoaderData<TQuery extends OperationType> =\n | {\n preloadedQuery: SerializablePreloadedQuery<TQuery>;\n deferredQueries: Promise<SerializablePreloadedQuery<TQuery>[]>;\n }\n | { queryRef: PreloadedQuery<TQuery> };\n\nfunction useCommonLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy,\n loaderData: LoaderData<TQuery>,\n): [\n TQuery[\"response\"],\n useQueryLoaderHookType<TQuery>[1],\n useQueryLoaderHookType<TQuery>[2],\n] {\n const preloadedQuery =\n \"preloadedQuery\" in loaderData\n ? (loaderData.preloadedQuery as unknown as SerializablePreloadedQuery<TQuery>)\n : null;\n\n const deferredQueries =\n \"deferredQueries\" in loaderData\n ? (loaderData.deferredQueries as unknown as Promise<\n SerializablePreloadedQuery<TQuery>[]\n >)\n : null;\n\n const [deferredResult, setDeferredResult] = useState(preloadedQuery);\n\n const setDeferredQueries = use(SetDeferredQueryContext);\n\n useEffect(() => {\n if (deferredQueries) {\n setDeferredQueries(\n deferredQueries.then(async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n\n return deferredResults;\n }),\n );\n } else {\n setDeferredQueries(null);\n }\n }, [deferredQueries, preloadedQuery, setDeferredQueries, setDeferredResult]);\n\n const environment = useRelayEnvironment();\n\n useMemo(() => {\n if (deferredResult) {\n writePreloadedQueryToCache(deferredResult);\n }\n }, [deferredResult]);\n\n let ref: PreloadedQuery<TQuery> | null =\n \"queryRef\" in loaderData\n ? (loaderData.queryRef as unknown as PreloadedQuery<TQuery>)\n : deferredResult\n ? {\n environment,\n fetchKey: `${\n deferredResult.params.id ?? deferredResult.params.cacheID\n }${simpleHash(deferredResult.response)}`,\n fetchPolicy,\n isDisposed: false,\n name: deferredResult.params.name,\n kind: \"PreloadedQuery\",\n variables: deferredResult.variables,\n dispose: () => {},\n }\n : null;\n\n invariant(ref, \"Missing queryRef\");\n\n const [queryRef, loadQuery, disposeQuery] = useQueryLoader<TQuery>(query);\n\n if (queryRef) ref = queryRef;\n\n const reloadQuery: typeof loadQuery = (\n variables,\n options = { fetchPolicy: \"store-and-network\" },\n ) => loadQuery(variables, options);\n\n const data = usePreloadedQuery<TQuery>(query, ref);\n\n return [data, reloadQuery, disposeQuery];\n}\n\nexport function useLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> = useLoaderData();\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nexport function useRouteLoaderQuery<TQuery extends OperationType>(\n routeId: string,\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> | undefined =\n useRouteLoaderData(routeId);\n\n invariant(loaderData, `Missing loader data for routeId ${routeId}`);\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nfunction writePreloadedQueryToCache<TQuery extends OperationType>(\n preloadedQueryObject: SerializablePreloadedQuery<TQuery>,\n) {\n const params = preloadedQueryObject.params as RequestParameters & {\n cacheID?: string;\n };\n\n const cacheKey = params.cacheID ?? params.id;\n invariant(cacheKey, \"Missing cacheKey\");\n\n responseCache?.set(\n cacheKey,\n preloadedQueryObject.variables,\n preloadedQueryObject.response,\n );\n}\n\nfunction simpleHash(input: unknown): number {\n return JSON.stringify(input)\n .split(\"\")\n .reduce((a, b) => {\n a = (a << 5) - a + b.charCodeAt(0);\n return a & a;\n }, 0);\n}\n"],"mappings":"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","names":["jsx","use","useState","relay","relay","useState","use","loadQuery"]}
|
|
1
|
+
{"version":3,"sources":["../src/Deferred.tsx","../src/deferred-query-context.tsx","../src/client-loader-query.ts","../src/get-cached-response.ts","../src/meta-query.ts","../src/useLoaderQuery.ts"],"sourcesContent":["import { Suspense, SuspenseProps, useSyncExternalStore } from \"react\";\nimport { Await } from \"react-router\";\nimport { useDeferredQuery } from \"./deferred-query-context\";\n\nfunction useIsMounted() {\n return useSyncExternalStore(\n () => () => {},\n () => true,\n () => false,\n );\n}\n\nexport function Deferred({ children, ...rest }: SuspenseProps) {\n const mounted = useIsMounted();\n const deferredQuery = useDeferredQuery();\n\n // SSR or context not yet initialized - show fallback\n if (!mounted || deferredQuery === undefined) {\n return <>{rest.fallback}</>;\n }\n\n // No deferred data in this query - render children directly\n if (deferredQuery === null) {\n return <>{children}</>;\n }\n\n // Has deferred data - use Await\n return (\n <Suspense {...rest}>\n <Await resolve={deferredQuery}>{children}</Await>\n </Suspense>\n );\n}\n","import type { PropsWithChildren } from \"react\";\nimport { createContext, use, useMemo, useSyncExternalStore } from \"react\";\n\ntype DeferredQueryValue = Promise<unknown> | null | undefined;\n\ntype DeferredQueryStore = {\n get: () => DeferredQueryValue;\n set: (value: DeferredQueryValue) => void;\n subscribe: (listener: () => void) => () => void;\n};\n\nfunction createDeferredQueryStore(): DeferredQueryStore {\n let value: DeferredQueryValue = undefined;\n const listeners = new Set<() => void>();\n\n return {\n get: () => value,\n set: (newValue) => {\n value = newValue;\n listeners.forEach((l) => l());\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n };\n}\n\nexport const DeferredQueryStoreContext = createContext<DeferredQueryStore>(\n createDeferredQueryStore(),\n);\n\nexport function useDeferredQuery(): DeferredQueryValue {\n const store = use(DeferredQueryStoreContext);\n return useSyncExternalStore(store.subscribe, store.get, () => undefined);\n}\n\nexport function RemixRelayProvider({ children }: PropsWithChildren) {\n const store = useMemo(() => createDeferredQueryStore(), []);\n\n return (\n <DeferredQueryStoreContext value={store}>\n {children}\n </DeferredQueryStoreContext>\n );\n}\n","import relay from \"react-relay\";\nimport type {\n Environment,\n GraphQLTaggedNode,\n OperationType,\n VariablesOf,\n} from \"relay-runtime\";\n\nconst { fetchQuery, loadQuery } = relay;\n\nexport function getClientLoaderQuery(environment: Environment) {\n return async <TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n ) => clientLoaderQuery(environment, query, variables);\n}\n\nexport async function clientLoaderQuery<TQuery extends OperationType>(\n environment: Environment,\n query: GraphQLTaggedNode,\n variables: VariablesOf<TQuery>,\n) {\n const data = await fetchQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-or-network\",\n }).toPromise();\n\n const queryRef = loadQuery<TQuery>(environment, query, variables, {\n fetchPolicy: \"store-only\",\n });\n\n return { queryRef, data };\n}\n","import type {\n CacheConfig,\n GraphQLResponse,\n RequestParameters,\n Variables,\n} from \"relay-runtime\";\nimport { Observable, QueryResponseCache } from \"relay-runtime\";\n\nexport const responseCache: QueryResponseCache = new QueryResponseCache({\n size: 100,\n ttl: 5000,\n});\n\nexport function getCachedResponse(\n params: RequestParameters,\n variables: Variables,\n cacheConfig: CacheConfig,\n) {\n const isQuery = params.operationKind === \"query\";\n const cacheKey = params.id ?? params.cacheID;\n const forceFetch = cacheConfig && cacheConfig.force;\n\n if (responseCache === null || !isQuery || forceFetch) {\n return null;\n }\n\n const fromCache = responseCache.get(cacheKey, variables);\n\n const deferredFromCache: GraphQLResponse[] = [];\n\n for (let i = 0; ; i++) {\n const deferred = responseCache.get(`${cacheKey}-${i}`, variables);\n if (!deferred) break;\n deferredFromCache.push(deferred);\n }\n\n if (fromCache === null) {\n return null;\n }\n\n return Observable.create((sink) => {\n sink.next(fromCache);\n\n for (const deferred of deferredFromCache) {\n sink.next(deferred);\n }\n\n sink.complete();\n });\n}\n","import type { MetaFunction } from \"react-router\";\nimport type { OperationType } from \"relay-runtime\";\n\nexport function metaQuery<TQuery extends OperationType>(\n metaFunction: (\n args: Parameters<MetaFunction>[0] & {\n data: TQuery[\"response\"];\n },\n ) => ReturnType<MetaFunction>,\n): MetaFunction<\n () =>\n | { preloadedQuery: { response: { data: TQuery[\"response\"] } } }\n | { data: TQuery[\"response\"] }\n> {\n return ({ data, ...rest }) => {\n const metaData: TQuery[\"response\"] =\n data && \"data\" in data\n ? data.data\n : data && \"preloadedQuery\" in data\n ? (data.preloadedQuery.response as { data: TQuery[\"response\"] }).data\n : null;\n\n return metaFunction({\n data: metaData,\n ...rest,\n });\n };\n}\n","import { use, useMemo, useRef, useState } from \"react\";\nimport { flushSync } from \"react-dom\";\nimport type {\n GraphQLTaggedNode,\n PreloadFetchPolicy,\n PreloadedQuery,\n} from \"react-relay\";\nimport relay from \"react-relay\";\nimport type { useQueryLoaderHookType } from \"react-relay/relay-hooks/useQueryLoader\";\nimport { useLoaderData, useRouteLoaderData } from \"react-router\";\nimport type {\n ConcreteRequest,\n GraphQLResponse,\n OperationType,\n RequestParameters,\n VariablesOf,\n} from \"relay-runtime\";\nimport invariant from \"tiny-invariant\";\nimport { DeferredQueryStoreContext } from \"./deferred-query-context\";\nimport { responseCache } from \"./get-cached-response\";\n\nconst { usePreloadedQuery, useQueryLoader, useRelayEnvironment } = relay;\n\nexport type SerializablePreloadedQuery<TQuery extends OperationType> = {\n params: ConcreteRequest[\"params\"];\n variables: VariablesOf<TQuery>;\n response: GraphQLResponse;\n};\n\ntype LoaderData<TQuery extends OperationType> =\n | {\n preloadedQuery: SerializablePreloadedQuery<TQuery>;\n deferredQueries: Promise<SerializablePreloadedQuery<TQuery>[]>;\n }\n | { queryRef: PreloadedQuery<TQuery> };\n\nfunction useCommonLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy,\n loaderData: LoaderData<TQuery>,\n): [\n TQuery[\"response\"],\n useQueryLoaderHookType<TQuery>[1],\n useQueryLoaderHookType<TQuery>[2],\n] {\n const preloadedQuery =\n \"preloadedQuery\" in loaderData\n ? (loaderData.preloadedQuery as unknown as SerializablePreloadedQuery<TQuery>)\n : null;\n\n const deferredQueries =\n \"deferredQueries\" in loaderData\n ? (loaderData.deferredQueries as unknown as Promise<\n SerializablePreloadedQuery<TQuery>[]\n >)\n : null;\n\n const [deferredResult, setDeferredResult] = useState(preloadedQuery);\n\n const store = use(DeferredQueryStoreContext);\n\n // Track transformed promise to avoid recreating on every render\n const transformedPromiseRef = useRef<Promise<unknown> | null>(null);\n const prevDeferredQueriesRef = useRef<typeof deferredQueries | symbol>(\n Symbol(),\n );\n\n // Set store synchronously during render (before Deferred reads it)\n if (deferredQueries !== prevDeferredQueriesRef.current) {\n prevDeferredQueriesRef.current = deferredQueries;\n if (deferredQueries) {\n transformedPromiseRef.current = deferredQueries.then(\n async (deferredResults) => {\n deferredResults.forEach((result) => {\n flushSync(() => {\n setDeferredResult(\n result as unknown as SerializablePreloadedQuery<TQuery>,\n );\n });\n });\n return deferredResults;\n },\n );\n store.set(transformedPromiseRef.current);\n } else {\n transformedPromiseRef.current = null;\n store.set(null);\n }\n }\n\n const environment = useRelayEnvironment();\n\n useMemo(() => {\n if (deferredResult) {\n writePreloadedQueryToCache(deferredResult);\n }\n }, [deferredResult]);\n\n let ref: PreloadedQuery<TQuery> | null =\n \"queryRef\" in loaderData\n ? (loaderData.queryRef as unknown as PreloadedQuery<TQuery>)\n : deferredResult\n ? {\n environment,\n fetchKey: `${\n deferredResult.params.id ?? deferredResult.params.cacheID\n }${simpleHash(deferredResult.response)}`,\n fetchPolicy,\n isDisposed: false,\n name: deferredResult.params.name,\n kind: \"PreloadedQuery\",\n variables: deferredResult.variables,\n dispose: () => {},\n }\n : null;\n\n invariant(ref, \"Missing queryRef\");\n\n const [queryRef, loadQuery, disposeQuery] = useQueryLoader<TQuery>(query);\n\n if (queryRef) ref = queryRef;\n\n const reloadQuery: typeof loadQuery = (\n variables,\n options = { fetchPolicy: \"store-and-network\" },\n ) => loadQuery(variables, options);\n\n const data = usePreloadedQuery<TQuery>(query, ref);\n\n return [data, reloadQuery, disposeQuery];\n}\n\nexport function useLoaderQuery<TQuery extends OperationType>(\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> = useLoaderData();\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nexport function useRouteLoaderQuery<TQuery extends OperationType>(\n routeId: string,\n query: GraphQLTaggedNode,\n fetchPolicy: PreloadFetchPolicy = \"network-only\",\n) {\n const loaderData: LoaderData<TQuery> | undefined =\n useRouteLoaderData(routeId);\n\n invariant(loaderData, `Missing loader data for routeId ${routeId}`);\n return useCommonLoaderQuery(query, fetchPolicy, loaderData);\n}\n\nfunction writePreloadedQueryToCache<TQuery extends OperationType>(\n preloadedQueryObject: SerializablePreloadedQuery<TQuery>,\n) {\n const params = preloadedQueryObject.params as RequestParameters & {\n cacheID?: string;\n };\n\n const cacheKey = params.cacheID ?? params.id;\n invariant(cacheKey, \"Missing cacheKey\");\n\n responseCache?.set(\n cacheKey,\n preloadedQueryObject.variables,\n preloadedQueryObject.response,\n );\n}\n\nfunction simpleHash(input: unknown): number {\n return JSON.stringify(input)\n .split(\"\")\n .reduce((a, b) => {\n a = (a << 5) - a + b.charCodeAt(0);\n return a & a;\n }, 0);\n}\n"],"mappings":"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","names":["useSyncExternalStore","jsx","useSyncExternalStore","use","useMemo","relay","relay","use","useMemo","loadQuery"]}
|