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