graphql-persisted 0.0.1

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/README.md ADDED
@@ -0,0 +1,54 @@
1
+ ## graphql-persisted
2
+
3
+ Note: This package is experimental and not yet intended for any sort of production usage.
4
+ Still designing the APIs through real world use & experimentation, subject to breakage prior to 1.0
5
+
6
+ An opinionated GraphQL client, initially focused on:
7
+
8
+ - Goals:
9
+ - Server Persisted Queries
10
+ - Type-safety out of the box
11
+ - Minimizing GraphQL in the client (no client-side dependency on the "graphql" package)
12
+ - Performance, simplicity
13
+ - Non-Goals:
14
+ - Supporting multiple GraphQL endpoints in the same application
15
+
16
+ Built atop [graphql-normalize](https://github.com/tgriesser/graphql-normalize)
17
+
18
+ ### GraphQLQueryCache API:
19
+
20
+ ```ts
21
+ class GraphQLQueryCache {
22
+ //
23
+ }
24
+ ```
25
+
26
+ ### Queries:
27
+
28
+ ```ts
29
+ const { data } = usePersistedQuery('QueryName', { variables })
30
+ ```
31
+
32
+ ```ts
33
+ usePreloadedPersistedQuery('QueryName', { variables })
34
+ ```
35
+
36
+ ### Mutations:
37
+
38
+ ```ts
39
+ const { execute } = usePersistedMutation('MutationName')
40
+ ```
41
+
42
+ ### Subscriptions:
43
+
44
+ TODO
45
+
46
+ ### Fragments
47
+
48
+ ```ts
49
+ const unwrappedData = unwrapFragment('FragName', data)
50
+ ```
51
+
52
+ # License
53
+
54
+ MIT
@@ -0,0 +1,62 @@
1
+ import type { GraphQLCacheShape, GraphQLMutationResult, GraphQLOperationResult, GraphQLQueryCacheConfig, GraphQLQueryResult, InvalidateQueryArgs, MaybePromise, ExecutionOptions, ReadQueryArgs, SerializedVariables, SubscribeToQueryArgs, PreloadQueryOptions } from './types';
2
+ /**
3
+ * Manages the cached normalized state, and the execution of
4
+ * data accessed by different components
5
+ */
6
+ export declare class GraphQLQueryCache {
7
+ #private;
8
+ constructor(config: GraphQLQueryCacheConfig);
9
+ /**
10
+ * Invalidates a query by name or predicate fn
11
+ */
12
+ invalidateQuery(toInvalidate: InvalidateQueryArgs): void;
13
+ /**
14
+ * Invalidates a query by name or predicate fn
15
+ */
16
+ refetchQuery(toRefetch: InvalidateQueryArgs): void;
17
+ /**
18
+ * JSON.stringify(queryCache) produces the data we need
19
+ * to rehydrate the Client
20
+ */
21
+ toJSON(): GraphQLCacheShape;
22
+ /**
23
+ * Attempts to read a query from the cache, returning undefined
24
+ * if we are unable to for any reason. Used in initial hook execution
25
+ * where we don't want any side-effects, incase we're doing SSR
26
+ */
27
+ tryReadQuery<Q extends keyof GraphQLQuery.QueryRegistry>(args: ReadQueryArgs<Q>): GraphQLOperationResult<Q> | undefined;
28
+ /**
29
+ * Reads the query from the cache. Throws an error if we are unable
30
+ * to read the data, due to an incomplete result or lack of operation
31
+ * metadata
32
+ */
33
+ readQuery<Q extends keyof GraphQLQuery.QueryRegistry>(args: ReadQueryArgs<Q>): GraphQLOperationResult<Q>;
34
+ /**
35
+ * Reads the query from the cache if any of the following conditions are met:
36
+ * a) We already have the result of this query in the operation cache
37
+ * b) We have the necessary metadata, as well as all of the necessary fields info to complete
38
+ * this query from the field cache
39
+ */
40
+ readOrFetchQuery<Q extends keyof GraphQLQuery.QueryRegistry>(args: ReadQueryArgs<Q>): GraphQLOperationResult<Q> | Promise<GraphQLOperationResult<Q>>;
41
+ /**
42
+ * Loads the query if it's not already in the cache,
43
+ * useful when hydrating the cache outside of a component
44
+ */
45
+ preloadQuery<Q extends keyof GraphQLQuery.QueryRegistry>(queryName: Q, options: PreloadQueryOptions<Q>): MaybePromise<GraphQLOperationResult<Q>>;
46
+ fetchQuery<Q extends keyof GraphQLQuery.QueryRegistry>(args: ReadQueryArgs<Q>): Promise<GraphQLOperationResult<Q>>;
47
+ /**
48
+ * Executes a mutation, returning the result of that mutation
49
+ */
50
+ executeMutation<M extends keyof GraphQLQuery.MutationRegistry>(mutationName: M, variables: SerializedVariables | object, options?: ExecutionOptions): Promise<GraphQLMutationResult<M>>;
51
+ /**
52
+ * Executes a query, returning the result of that query
53
+ */
54
+ executeQuery<Q extends keyof GraphQLQuery.QueryRegistry>(queryName: Q, variables: SerializedVariables | GraphQLQuery.OperationVariables[Q]): Promise<GraphQLQueryResult<Q>>;
55
+ executeSubscription(): Promise<void>;
56
+ /**
57
+ * "Subscribes" to a query, meaning that when there are updates to fields in the
58
+ * field cache, we'll re-materialize the known value of the query. We'll also
59
+ * process based on configuration options, such as TTL, invalidateOnMutation
60
+ */
61
+ subscribeToQuery<Q extends keyof GraphQLQuery.QueryRegistry>(args: SubscribeToQueryArgs<Q>): () => void;
62
+ }
@@ -0,0 +1,456 @@
1
+ "use strict";
2
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
+ if (kind === "m") throw new TypeError("Private method is not writable");
4
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
+ };
8
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
+ };
13
+ var __importDefault = (this && this.__importDefault) || function (mod) {
14
+ return (mod && mod.__esModule) ? mod : { "default": mod };
15
+ };
16
+ var _GraphQLQueryCache_instances, _GraphQLQueryCache_fetcher, _GraphQLQueryCache_endpoint, _GraphQLQueryCache_persistedOperations, _GraphQLQueryCache_persistedDocuments, _GraphQLQueryCache_configMeta, _GraphQLQueryCache_subscribedQueries, _GraphQLQueryCache_inFlight, _GraphQLQueryCache_cacheStore, _GraphQLQueryCache_runtimeCache, _GraphQLQueryCache_queryInvalidation, _GraphQLQueryCache_mutationInvalidation, _GraphQLQueryCache_effectsIssued, _GraphQLQueryCache_getKey, _GraphQLQueryCache_executeOperation, _GraphQLQueryCache_getMeta, _GraphQLQueryCache_fetch, _GraphQLQueryCache_shouldRefetchQuery, _GraphQLQueryCache_gcOperations;
17
+ Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.GraphQLQueryCache = void 0;
19
+ const lodash_isequal_1 = __importDefault(require("lodash.isequal"));
20
+ const graphql_normalize_1 = require("graphql-normalize");
21
+ const immer_1 = require("immer");
22
+ const errors_1 = require("./errors");
23
+ const helpers_1 = require("./helpers");
24
+ /**
25
+ * Manages the cached normalized state, and the execution of
26
+ * data accessed by different components
27
+ */
28
+ class GraphQLQueryCache {
29
+ constructor(config) {
30
+ _GraphQLQueryCache_instances.add(this);
31
+ /**
32
+ * If an alterative fetch is provided, we will use that for operations
33
+ * Otherwise we'll use the native 'fetch'
34
+ */
35
+ _GraphQLQueryCache_fetcher.set(this, void 0);
36
+ /**
37
+ * GraphQL API endpoint
38
+ * @default /graphql
39
+ */
40
+ _GraphQLQueryCache_endpoint.set(this, void 0);
41
+ // A mapping of OperationName -> Operation Hash. The operation hash is sent to the
42
+ // server when we issue a query
43
+ _GraphQLQueryCache_persistedOperations.set(this, void 0);
44
+ // Mapping of persisted documents
45
+ _GraphQLQueryCache_persistedDocuments.set(this, void 0);
46
+ // A mapping of metadata between the config string and normalized metadata shape
47
+ _GraphQLQueryCache_configMeta.set(this, void 0);
48
+ // All queries we are "subscribed to", meaning that we React to any changes
49
+ // when there are updates to the cache.
50
+ _GraphQLQueryCache_subscribedQueries.set(this, {}
51
+ // All "in-flight" fetches, to deduplicate fetches that are already in-flight
52
+ // for an operation
53
+ );
54
+ // All "in-flight" fetches, to deduplicate fetches that are already in-flight
55
+ // for an operation
56
+ _GraphQLQueryCache_inFlight.set(this, {}
57
+ // Immutable object containing the normalized cache of all data
58
+ // as well as all operations we're tracking within the application
59
+ );
60
+ // Immutable object containing the normalized cache of all data
61
+ // as well as all operations we're tracking within the application
62
+ _GraphQLQueryCache_cacheStore.set(this, void 0);
63
+ // Keeps track of all the operations that have been issued in the application,
64
+ // as well as the metadata indicating the TTL / polling / invalidation / refetch
65
+ // logic necessary to keep things up to date
66
+ _GraphQLQueryCache_runtimeCache.set(this, {});
67
+ _GraphQLQueryCache_queryInvalidation.set(this, void 0);
68
+ _GraphQLQueryCache_mutationInvalidation.set(this, void 0);
69
+ /**
70
+ * A list of all "effects" that have run, used to keep track of
71
+ */
72
+ _GraphQLQueryCache_effectsIssued.set(this, []); // TODO: Include subscriptions
73
+ __classPrivateFieldSet(this, _GraphQLQueryCache_fetcher, config.fetcher || fetch, "f");
74
+ __classPrivateFieldSet(this, _GraphQLQueryCache_endpoint, config.endpoint || `${window.location.origin}/graphql`, "f");
75
+ __classPrivateFieldSet(this, _GraphQLQueryCache_persistedOperations, config.persistedOperations, "f");
76
+ __classPrivateFieldSet(this, _GraphQLQueryCache_persistedDocuments, config.persistedDocuments, "f");
77
+ __classPrivateFieldSet(this, _GraphQLQueryCache_configMeta, unwrapMeta(config.meta), "f");
78
+ __classPrivateFieldSet(this, _GraphQLQueryCache_queryInvalidation, config.queryInvalidation ?? {}, "f");
79
+ __classPrivateFieldSet(this, _GraphQLQueryCache_mutationInvalidation, config.mutationInvalidation ?? {}, "f");
80
+ __classPrivateFieldSet(this, _GraphQLQueryCache_cacheStore, (0, immer_1.produce)(config.hydratedCache ?? {
81
+ meta: {},
82
+ fields: {},
83
+ operations: {},
84
+ }, noop), "f");
85
+ }
86
+ /**
87
+ * Invalidates a query by name or predicate fn
88
+ */
89
+ invalidateQuery(toInvalidate) {
90
+ (0, immer_1.produce)(__classPrivateFieldGet(this, _GraphQLQueryCache_runtimeCache, "f"), () => {
91
+ //
92
+ });
93
+ }
94
+ /**
95
+ * Invalidates a query by name or predicate fn
96
+ */
97
+ refetchQuery(toRefetch) {
98
+ (0, immer_1.produce)(__classPrivateFieldGet(this, _GraphQLQueryCache_runtimeCache, "f"), () => {
99
+ //
100
+ });
101
+ }
102
+ /**
103
+ * JSON.stringify(queryCache) produces the data we need
104
+ * to rehydrate the Client
105
+ */
106
+ toJSON() {
107
+ const { fields, operations, meta } = __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f");
108
+ return {
109
+ fields,
110
+ operations: operations,
111
+ meta: meta,
112
+ };
113
+ }
114
+ // /**
115
+ // * Whether we've fetched the query in the cache yet
116
+ // */
117
+ // hasQuery<Q extends keyof GraphQLQuery.QueryRegistry>(
118
+ // queryName: Q,
119
+ // variable: SerializedVariables | GraphQLQuery.OperationVariables[Q]
120
+ // ) {
121
+ // // Object.values(this.#cacheStore.operations).find((o) => {
122
+ // // return o.operationType === 'query' && o
123
+ // // })
124
+ // }
125
+ /**
126
+ * Attempts to read a query from the cache, returning undefined
127
+ * if we are unable to for any reason. Used in initial hook execution
128
+ * where we don't want any side-effects, incase we're doing SSR
129
+ */
130
+ tryReadQuery(args) {
131
+ try {
132
+ return this.readQuery(args);
133
+ }
134
+ catch {
135
+ return undefined;
136
+ }
137
+ }
138
+ /**
139
+ * Reads the query from the cache. Throws an error if we are unable
140
+ * to read the data, due to an incomplete result or lack of operation
141
+ * metadata
142
+ */
143
+ readQuery(args) {
144
+ const { queryName, variables, options } = args;
145
+ const key = __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_getKey).call(this, queryName, variables);
146
+ const op = __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations[key];
147
+ if (op) {
148
+ return op;
149
+ }
150
+ // If we don't have metadata, we can't know how to read the query
151
+ // from the cache
152
+ const meta = __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_getMeta).call(this, queryName);
153
+ const { result } = (0, graphql_normalize_1.graphqlNormalize)({
154
+ action: 'read',
155
+ variableValues: typeof variables === 'string' ? JSON.parse(variables) : variables,
156
+ meta: meta,
157
+ cache: __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").fields,
158
+ isEqual: lodash_isequal_1.default,
159
+ });
160
+ return {
161
+ data: result,
162
+ };
163
+ }
164
+ /**
165
+ * Reads the query from the cache if any of the following conditions are met:
166
+ * a) We already have the result of this query in the operation cache
167
+ * b) We have the necessary metadata, as well as all of the necessary fields info to complete
168
+ * this query from the field cache
169
+ */
170
+ readOrFetchQuery(args) {
171
+ // If we don't have the metadata for the Query yet, we won't know how
172
+ // to read it from the cache. In this case we first need to fetch the query
173
+ // and check for the meta in the extensions to know how to normalize it
174
+ try {
175
+ const readResult = this.readQuery(args);
176
+ if (readResult) {
177
+ this.fetchQuery(args);
178
+ }
179
+ return readResult;
180
+ }
181
+ catch {
182
+ return this.fetchQuery(args);
183
+ }
184
+ }
185
+ /**
186
+ * Loads the query if it's not already in the cache,
187
+ * useful when hydrating the cache outside of a component
188
+ */
189
+ preloadQuery(queryName, options) {
190
+ const { blockIfStale = true } = options;
191
+ const variables = (0, helpers_1.variableString)(options.variables ?? {});
192
+ const sha256Hash = __classPrivateFieldGet(this, _GraphQLQueryCache_persistedOperations, "f")[queryName];
193
+ const key = `${sha256Hash}:${variables}`;
194
+ const operation = __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations[key];
195
+ // TODO: Give an option to eager return if we already have the operation but it's stale
196
+ if (!operation || operation.stale) {
197
+ const inFlight = this.fetchQuery({ queryName, variables: variables, options: {} });
198
+ return operation && blockIfStale === false ? operation : inFlight;
199
+ }
200
+ return operation;
201
+ }
202
+ fetchQuery(args) {
203
+ return __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_executeOperation).call(this, 'query', args.queryName, args.variables, args.options);
204
+ }
205
+ /**
206
+ * Executes a mutation, returning the result of that mutation
207
+ */
208
+ async executeMutation(mutationName, variables, options = {}) {
209
+ return __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_executeOperation).call(this, 'mutation', mutationName, variables, options);
210
+ }
211
+ /**
212
+ * Executes a query, returning the result of that query
213
+ */
214
+ async executeQuery(queryName, variables) {
215
+ return __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_executeOperation).call(this, 'query', queryName, variables);
216
+ }
217
+ async executeSubscription() {
218
+ throw new Error('Not yet supported');
219
+ }
220
+ /**
221
+ * "Subscribes" to a query, meaning that when there are updates to fields in the
222
+ * field cache, we'll re-materialize the known value of the query. We'll also
223
+ * process based on configuration options, such as TTL, invalidateOnMutation
224
+ */
225
+ subscribeToQuery(args) {
226
+ var _a;
227
+ const { queryName, queryResult, variables, onUpdate, options } = args;
228
+ const key = __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_getKey).call(this, queryName, variables);
229
+ const queries = ((_a = __classPrivateFieldGet(this, _GraphQLQueryCache_subscribedQueries, "f"))[key] ?? (_a[key] = []));
230
+ queries.push(args);
231
+ // Now that the component is subscribed, we can begin fetching,
232
+ // refetching, and otherwise managing the query
233
+ if (!queryResult) {
234
+ //
235
+ }
236
+ else if (options.ttl) {
237
+ //
238
+ }
239
+ // this.fetchQuery(args)
240
+ return () => {
241
+ queries.splice(queries.indexOf(args), 1);
242
+ };
243
+ }
244
+ }
245
+ exports.GraphQLQueryCache = GraphQLQueryCache;
246
+ _GraphQLQueryCache_fetcher = new WeakMap(), _GraphQLQueryCache_endpoint = new WeakMap(), _GraphQLQueryCache_persistedOperations = new WeakMap(), _GraphQLQueryCache_persistedDocuments = new WeakMap(), _GraphQLQueryCache_configMeta = new WeakMap(), _GraphQLQueryCache_subscribedQueries = new WeakMap(), _GraphQLQueryCache_inFlight = new WeakMap(), _GraphQLQueryCache_cacheStore = new WeakMap(), _GraphQLQueryCache_runtimeCache = new WeakMap(), _GraphQLQueryCache_queryInvalidation = new WeakMap(), _GraphQLQueryCache_mutationInvalidation = new WeakMap(), _GraphQLQueryCache_effectsIssued = new WeakMap(), _GraphQLQueryCache_instances = new WeakSet(), _GraphQLQueryCache_getKey = function _GraphQLQueryCache_getKey(operationName, variables) {
247
+ const sha256Hash = __classPrivateFieldGet(this, _GraphQLQueryCache_persistedOperations, "f")[operationName];
248
+ return `${sha256Hash}:${(0, helpers_1.variableString)(variables)}`;
249
+ }, _GraphQLQueryCache_executeOperation = async function _GraphQLQueryCache_executeOperation(operationType, operationName, variables) {
250
+ const sha256Hash = __classPrivateFieldGet(this, _GraphQLQueryCache_persistedOperations, "f")[operationName];
251
+ const key = __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_getKey).call(this, operationName, variables);
252
+ const operationVariables = (0, helpers_1.variableObject)(variables);
253
+ (0, errors_1.assertOperationHash)(sha256Hash, operationType, operationName);
254
+ const inFlight = __classPrivateFieldGet(this, _GraphQLQueryCache_inFlight, "f")[key];
255
+ if (operationType === 'query' && inFlight) {
256
+ return inFlight;
257
+ }
258
+ const operationInFlight = __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_fetch).call(this, {
259
+ query: '',
260
+ operationName,
261
+ variables: operationVariables,
262
+ extensions: {
263
+ persistedQuery: { version: 1, sha256Hash },
264
+ },
265
+ });
266
+ __classPrivateFieldGet(this, _GraphQLQueryCache_inFlight, "f")[key] = operationInFlight;
267
+ const operationResult = await operationInFlight.finally(() => {
268
+ delete __classPrivateFieldGet(this, _GraphQLQueryCache_inFlight, "f")[key];
269
+ });
270
+ if (operationResult.fetchError) {
271
+ return operationResult;
272
+ }
273
+ const meta = operationResult.extensions?.['graphqlNormalizeMeta'] ??
274
+ __classPrivateFieldGet(this, _GraphQLQueryCache_instances, "m", _GraphQLQueryCache_getMeta).call(this, operationName);
275
+ // Ensure we have metadata to be able to normalize the operation in our cache
276
+ if (!meta) {
277
+ throw new errors_1.MissingMetaError(operationName);
278
+ }
279
+ const lastCache = __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f");
280
+ __classPrivateFieldSet(this, _GraphQLQueryCache_cacheStore, (0, immer_1.produce)(__classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f"), (c) => {
281
+ const currentResult = c.operations[key];
282
+ const { added, modified, result } = (0, graphql_normalize_1.graphqlNormalize)({
283
+ action: 'write',
284
+ operationResult,
285
+ meta,
286
+ cache: c.fields,
287
+ variableValues: operationVariables,
288
+ currentResult,
289
+ isEqual: lodash_isequal_1.default,
290
+ });
291
+ //
292
+ if (operationType === 'query' && (added || modified)) {
293
+ c.operations[key] = {
294
+ stale: false,
295
+ meta,
296
+ operationName,
297
+ variableValues: operationVariables,
298
+ data: result,
299
+ errors: operationResult.errors,
300
+ extensions: operationResult.extensions,
301
+ operationType: operationType,
302
+ };
303
+ }
304
+ // If we've modified anything in the cache, we also need to update any
305
+ // mounted queries
306
+ if (modified) {
307
+ for (const [k, val] of Object.entries(c.operations)) {
308
+ if (k === key || val.operationType !== 'query') {
309
+ continue;
310
+ }
311
+ //
312
+ if (val.data) {
313
+ const { result } = (0, graphql_normalize_1.graphqlNormalize)({
314
+ action: 'read',
315
+ currentResult: val.data,
316
+ cache: c.fields,
317
+ meta: val.meta,
318
+ variableValues: val.variableValues,
319
+ });
320
+ if (result !== val) {
321
+ val.data = result;
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }), "f");
327
+ // If this was a mutation, we need to go through and determine if we need to mark
328
+ // any Queries as "stale", or eagerly refetch any of the queries
329
+ if (operationType === 'mutation') {
330
+ const toInvalidate = new Set();
331
+ const mutationName = operationName;
332
+ const mutationFn = __classPrivateFieldGet(this, _GraphQLQueryCache_mutationInvalidation, "f")?.[mutationName];
333
+ for (const [operationKey, operation] of Object.entries(__classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations)) {
334
+ if (operation.operationType !== 'query') {
335
+ continue;
336
+ }
337
+ const queryName = operation.operationName;
338
+ const queryVariables = operation.variableValues;
339
+ const queryFn = __classPrivateFieldGet(this, _GraphQLQueryCache_queryInvalidation, "f")[queryName];
340
+ if (queryFn?.(mutationName, operationVariables, queryVariables)) {
341
+ toInvalidate.add(operationKey);
342
+ }
343
+ if (mutationFn?.(queryName, queryVariables, operationVariables)) {
344
+ toInvalidate.add(operationKey);
345
+ }
346
+ }
347
+ if (toInvalidate.size) {
348
+ __classPrivateFieldSet(this, _GraphQLQueryCache_cacheStore, (0, immer_1.produce)(__classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f"), (o) => {
349
+ for (const key of toInvalidate) {
350
+ const op = o.operations[key];
351
+ if (op)
352
+ op.stale = true;
353
+ }
354
+ }), "f");
355
+ }
356
+ }
357
+ // If we've updated any operations, we need to update any subscribed components
358
+ if (lastCache.operations !== __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations) {
359
+ for (const [key, val] of Object.entries(__classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations)) {
360
+ if (__classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations[key] !== lastCache.operations[key]) {
361
+ if (__classPrivateFieldGet(this, _GraphQLQueryCache_subscribedQueries, "f")[key]) {
362
+ __classPrivateFieldGet(this, _GraphQLQueryCache_subscribedQueries, "f")[key]?.forEach((o) => o.onUpdate(val));
363
+ }
364
+ }
365
+ }
366
+ }
367
+ if (operationType === 'query') {
368
+ return __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").operations[key];
369
+ }
370
+ return operationResult;
371
+ }, _GraphQLQueryCache_getMeta = function _GraphQLQueryCache_getMeta(opName) {
372
+ const meta = __classPrivateFieldGet(this, _GraphQLQueryCache_cacheStore, "f").meta[opName] ?? __classPrivateFieldGet(this, _GraphQLQueryCache_configMeta, "f")?.[opName];
373
+ if (!meta) {
374
+ throw new errors_1.MissingMetaError(opName);
375
+ }
376
+ return meta;
377
+ }, _GraphQLQueryCache_fetch =
378
+ /**
379
+ * Handles "fetch", ensuring we catch network errors and handle non-200
380
+ * responses properly so we're able to forward these on in a normalized fashion
381
+ */
382
+ async function _GraphQLQueryCache_fetch(body) {
383
+ let result;
384
+ try {
385
+ result = await fetch(__classPrivateFieldGet(this, _GraphQLQueryCache_endpoint, "f"), {
386
+ method: 'POST',
387
+ body: JSON.stringify(body),
388
+ headers: {
389
+ 'content-type': 'application/json',
390
+ },
391
+ });
392
+ if (result.status === 200) {
393
+ const json = (await result.json());
394
+ return json;
395
+ }
396
+ else {
397
+ return {
398
+ fetchError: {
399
+ name: 'ResponseError',
400
+ message: await result.text(),
401
+ status: result.status,
402
+ statusText: result.statusText,
403
+ },
404
+ };
405
+ }
406
+ }
407
+ catch (e) {
408
+ const error = e instanceof Error ? e : new Error(String(e));
409
+ return {
410
+ fetchError: {
411
+ name: error.name,
412
+ message: error.message,
413
+ stack: error.stack,
414
+ status: result?.status,
415
+ statusText: result?.statusText,
416
+ },
417
+ };
418
+ }
419
+ }, _GraphQLQueryCache_shouldRefetchQuery = function _GraphQLQueryCache_shouldRefetchQuery() {
420
+ //
421
+ }, _GraphQLQueryCache_gcOperations = function _GraphQLQueryCache_gcOperations() {
422
+ //
423
+ };
424
+ function unwrapMeta(meta) {
425
+ if (!meta)
426
+ return meta;
427
+ const o = {};
428
+ for (const [key, val] of Object.entries(meta)) {
429
+ if (typeof val === 'string') {
430
+ o[key] = isBase64(val) ? JSON.parse(fromBase64(val)) : JSON.parse(val);
431
+ }
432
+ else {
433
+ o[key] = val;
434
+ }
435
+ }
436
+ return o;
437
+ }
438
+ function isBase64(str) {
439
+ if (typeof Buffer !== 'undefined') {
440
+ return Buffer.from(str, 'base64').toString('base64') === str;
441
+ }
442
+ try {
443
+ window.btoa(str);
444
+ return true;
445
+ }
446
+ catch {
447
+ return false;
448
+ }
449
+ }
450
+ function fromBase64(str) {
451
+ if (typeof Buffer !== 'undefined') {
452
+ return Buffer.from(str, 'base64').toString('utf8');
453
+ }
454
+ return window.atob(str);
455
+ }
456
+ function noop() { }
@@ -0,0 +1,21 @@
1
+ import React from 'react';
2
+ import type { GraphQLQueryCache } from './GraphQLQueryCache.js';
3
+ /**
4
+ * Provides an initialized `GraphQLQueryCache` for use by hooks throughout
5
+ * the rest of the application.
6
+ *
7
+ * @example
8
+ * <GraphQLQueryProvider cache={cache}>
9
+ * <App />
10
+ * </GraphQLQueryProvider>
11
+ */
12
+ export declare const GraphQLQueryProvider: React.FC<{
13
+ cache: GraphQLQueryCache;
14
+ children: React.ReactNode | React.ReactNode[];
15
+ }>;
16
+ /**
17
+ * Hook returning the initialized GraphQL Query Cache
18
+ *
19
+ * Throws if accessed outside of a `GraphQLQueryProvider`
20
+ */
21
+ export declare const useGraphQLQueryCache: () => GraphQLQueryCache;
package/cjs/context.js ADDED
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useGraphQLQueryCache = exports.GraphQLQueryProvider = void 0;
4
+ const jsx_runtime_1 = require("react/jsx-runtime");
5
+ const react_1 = require("react");
6
+ const GraphQLQueryContext = (0, react_1.createContext)(null);
7
+ /**
8
+ * Provides an initialized `GraphQLQueryCache` for use by hooks throughout
9
+ * the rest of the application.
10
+ *
11
+ * @example
12
+ * <GraphQLQueryProvider cache={cache}>
13
+ * <App />
14
+ * </GraphQLQueryProvider>
15
+ */
16
+ const GraphQLQueryProvider = ({ cache, children }) => {
17
+ return (0, jsx_runtime_1.jsx)(GraphQLQueryContext.Provider, { value: cache, children: children });
18
+ };
19
+ exports.GraphQLQueryProvider = GraphQLQueryProvider;
20
+ /**
21
+ * Hook returning the initialized GraphQL Query Cache
22
+ *
23
+ * Throws if accessed outside of a `GraphQLQueryProvider`
24
+ */
25
+ const useGraphQLQueryCache = () => {
26
+ const ctx = (0, react_1.useContext)(GraphQLQueryContext);
27
+ if (!ctx) {
28
+ throw new Error(`useGraphQLQueryCache must be nested inside a GraphQLQueryProvider`);
29
+ }
30
+ return ctx;
31
+ };
32
+ exports.useGraphQLQueryCache = useGraphQLQueryCache;
@@ -0,0 +1,19 @@
1
+ export declare class GraphQLQueryError extends Error {
2
+ }
3
+ /**
4
+ * Thrown in situations where we are expecting graphql-normalize metadata
5
+ * to be available, but it isn't yet available.
6
+ */
7
+ export declare class MissingMetaError extends Error {
8
+ constructor(queryName: string);
9
+ }
10
+ export declare class UnknownOperationError extends Error {
11
+ constructor(operationName: string, operationType: string);
12
+ }
13
+ export declare class MissingNormalizeMetaError extends Error {
14
+ constructor(operationName: string, operationType: string);
15
+ }
16
+ export declare class ExpectedPreloadedQueryError extends GraphQLQueryError {
17
+ constructor(queryName: string);
18
+ }
19
+ export declare function assertOperationHash(hash: string | undefined, operationType: 'query' | 'mutation' | 'subscription', operationName: string): void;