houdini 1.5.3 → 2.0.0-next.0
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/build/cmd-cjs/index.js +29435 -22707
- package/build/cmd-esm/index.js +27980 -21253
- package/build/codegen/generators/artifacts/index.d.ts +8 -0
- package/build/codegen/generators/runtime/index.d.ts +2 -7
- package/build/codegen/generators/runtime/pluginRuntime.d.ts +8 -1
- package/build/codegen/index.d.ts +3 -2
- package/build/codegen/transforms/fragmentVariables.d.ts +1 -1
- package/build/codegen/transforms/list.d.ts +2 -2
- package/build/codegen/transforms/paginate.d.ts +2 -34
- package/build/codegen/utils/flattenSelections.d.ts +1 -1
- package/build/codegen-cjs/index.js +24805 -19718
- package/build/codegen-esm/index.js +24979 -19892
- package/build/lib/fs.d.ts +3 -2
- package/build/lib/index.d.ts +1 -0
- package/build/lib/router/conventions.d.ts +1 -1
- package/build/lib/router/manifest.d.ts +1 -1
- package/build/lib/typescript.d.ts +1 -1
- package/build/lib/watchAndRun.d.ts +61 -0
- package/build/lib-cjs/index.js +27118 -21197
- package/build/lib-esm/index.js +25693 -19775
- package/build/runtime-cjs/cache/cache.js +22 -1
- package/build/runtime-cjs/cache/gc.js +1 -0
- package/build/runtime-cjs/cache/index.js +0 -2
- package/build/runtime-cjs/cache/lists.js +9 -0
- package/build/runtime-cjs/cache/staleManager.js +26 -1
- package/build/runtime-cjs/cache/storage.js +4 -0
- package/build/runtime-cjs/cache/subscription.js +1 -0
- package/build/runtime-cjs/client/documentStore.js +28 -2
- package/build/runtime-cjs/client/index.js +17 -1
- package/build/runtime-cjs/client/plugins/cache.js +8 -2
- package/build/runtime-cjs/client/plugins/fetch.js +14 -6
- package/build/runtime-cjs/client/plugins/fetchParams.js +2 -0
- package/build/runtime-cjs/client/plugins/fragment.js +1 -0
- package/build/runtime-cjs/client/plugins/index.js +9 -1
- package/build/runtime-cjs/client/plugins/injectedPlugins.js +0 -2
- package/build/runtime-cjs/client/plugins/mutation.js +6 -0
- package/build/runtime-cjs/client/plugins/optimisticKeys.js +10 -3
- package/build/runtime-cjs/client/plugins/query.js +4 -0
- package/build/runtime-cjs/client/utils/index.js +4 -0
- package/build/runtime-cjs/imports/config.js +0 -2
- package/build/runtime-cjs/imports/pluginConfig.js +0 -2
- package/build/runtime-cjs/index.js +12 -6
- package/build/runtime-cjs/lib/config.js +4 -0
- package/build/runtime-cjs/lib/deepEquals.js +2 -4
- package/build/runtime-cjs/lib/index.js +13 -0
- package/build/runtime-cjs/lib/pagination.js +2 -1
- package/build/runtime-cjs/lib/types.js +11 -1
- package/build/runtime-cjs/public/cache.js +11 -0
- package/build/runtime-cjs/public/record.js +5 -0
- package/build/runtime-cjs/router/jwt.js +15 -28
- package/build/runtime-cjs/router/match.js +2 -4
- package/build/runtime-cjs/router/server.js +6 -1
- package/build/runtime-cjs/router/session.js +1 -1
- package/build/runtime-esm/cache/cache.js +22 -1
- package/build/runtime-esm/cache/gc.js +1 -0
- package/build/runtime-esm/cache/lists.js +9 -0
- package/build/runtime-esm/cache/staleManager.js +26 -1
- package/build/runtime-esm/cache/storage.js +4 -0
- package/build/runtime-esm/cache/subscription.js +1 -0
- package/build/runtime-esm/client/documentStore.js +28 -2
- package/build/runtime-esm/client/index.js +13 -1
- package/build/runtime-esm/client/plugins/cache.js +4 -2
- package/build/runtime-esm/client/plugins/fetch.js +14 -6
- package/build/runtime-esm/client/plugins/fetchParams.js +2 -0
- package/build/runtime-esm/client/plugins/fragment.js +1 -0
- package/build/runtime-esm/client/plugins/mutation.js +6 -0
- package/build/runtime-esm/client/plugins/optimisticKeys.js +6 -3
- package/build/runtime-esm/client/plugins/query.js +4 -0
- package/build/runtime-esm/lib/deepEquals.js +2 -4
- package/build/runtime-esm/lib/pagination.js +2 -1
- package/build/runtime-esm/lib/types.js +9 -0
- package/build/runtime-esm/public/cache.js +11 -0
- package/build/runtime-esm/public/record.js +5 -0
- package/build/runtime-esm/router/jwt.js +15 -28
- package/build/runtime-esm/router/match.js +2 -4
- package/build/runtime-esm/router/server.js +6 -1
- package/build/runtime-esm/router/session.js +1 -1
- package/build/test-cjs/index.js +26344 -21258
- package/build/test-esm/index.js +24972 -19886
- package/build/vite/hmr.d.ts +5 -0
- package/build/vite/imports.d.ts +2 -2
- package/build/vite/schema.d.ts +0 -3
- package/build/vite-cjs/index.js +34848 -32101
- package/build/vite-esm/index.js +31526 -28780
- package/package.json +13 -14
|
@@ -38,6 +38,9 @@ var import_storage = require("./storage");
|
|
|
38
38
|
var import_stuff = require("./stuff");
|
|
39
39
|
var import_subscription = require("./subscription");
|
|
40
40
|
class Cache {
|
|
41
|
+
// the internal implementation for a lot of the cache's methods are moved into
|
|
42
|
+
// a second class to avoid users from relying on unstable APIs. typescript's private
|
|
43
|
+
// label accomplishes this but would not prevent someone using vanilla js
|
|
41
44
|
_internal_unstable;
|
|
42
45
|
constructor({
|
|
43
46
|
disabled,
|
|
@@ -60,6 +63,8 @@ class Cache {
|
|
|
60
63
|
this.setConfig((0, import_config.defaultConfigValues)(config));
|
|
61
64
|
}
|
|
62
65
|
}
|
|
66
|
+
// walk down the selection and save the values that we encounter.
|
|
67
|
+
// any changes will notify subscribers. writing to an optimistic layer will resolve it
|
|
63
68
|
write({
|
|
64
69
|
layer: layerID,
|
|
65
70
|
notifySubscribers = [],
|
|
@@ -70,6 +75,7 @@ class Cache {
|
|
|
70
75
|
this.#notifySubscribers(subscribers.concat(notifySubscribers));
|
|
71
76
|
return subscribers;
|
|
72
77
|
}
|
|
78
|
+
// reconstruct an object with the fields/relations specified by a selection
|
|
73
79
|
read(...args) {
|
|
74
80
|
const { data, partial, stale, hasData } = this._internal_unstable.getSelection(...args);
|
|
75
81
|
if (!hasData) {
|
|
@@ -81,6 +87,7 @@ class Cache {
|
|
|
81
87
|
stale
|
|
82
88
|
};
|
|
83
89
|
}
|
|
90
|
+
// register the provided callbacks with the fields specified by the selection
|
|
84
91
|
subscribe(spec, variables = {}) {
|
|
85
92
|
if (this._internal_unstable.disabled) {
|
|
86
93
|
return;
|
|
@@ -92,6 +99,7 @@ class Cache {
|
|
|
92
99
|
variables
|
|
93
100
|
});
|
|
94
101
|
}
|
|
102
|
+
// stop listening to a particular subscription
|
|
95
103
|
unsubscribe(spec, variables = {}) {
|
|
96
104
|
return this._internal_unstable.subscriptions.remove(
|
|
97
105
|
spec.parentID || import_stuff.rootID,
|
|
@@ -100,6 +108,7 @@ class Cache {
|
|
|
100
108
|
variables
|
|
101
109
|
);
|
|
102
110
|
}
|
|
111
|
+
// return the list handler to mutate a named list in the cache
|
|
103
112
|
list(name, parentID, allLists, skipMatches) {
|
|
104
113
|
const handler = this._internal_unstable.lists.get(name, parentID, allLists, skipMatches);
|
|
105
114
|
if (!handler) {
|
|
@@ -109,10 +118,12 @@ class Cache {
|
|
|
109
118
|
}
|
|
110
119
|
return handler;
|
|
111
120
|
}
|
|
121
|
+
// when an optimistic key resolves, we might momentarily know the same record by different IDs
|
|
112
122
|
registerKeyMap(source, mapped) {
|
|
113
123
|
this._internal_unstable.storage.registerIDMapping(source, mapped);
|
|
114
124
|
this._internal_unstable.subscriptions.copySubscribers(source, mapped);
|
|
115
125
|
}
|
|
126
|
+
// remove the record from the cache's store and unsubscribe from it
|
|
116
127
|
delete(id, layer) {
|
|
117
128
|
const recordIDs = [this._internal_unstable.storage.idMaps[id], id].filter(
|
|
118
129
|
Boolean
|
|
@@ -123,6 +134,7 @@ class Cache {
|
|
|
123
134
|
this._internal_unstable.storage.delete(recordID, layer);
|
|
124
135
|
}
|
|
125
136
|
}
|
|
137
|
+
// set the cache's config
|
|
126
138
|
setConfig(config) {
|
|
127
139
|
this._internal_unstable.setConfig(config);
|
|
128
140
|
}
|
|
@@ -204,6 +216,7 @@ class Cache {
|
|
|
204
216
|
}
|
|
205
217
|
this.#notifySubscribers(toNotify);
|
|
206
218
|
}
|
|
219
|
+
// reset the whole cache
|
|
207
220
|
reset() {
|
|
208
221
|
const subSpecs = this._internal_unstable.subscriptions.reset();
|
|
209
222
|
this._internal_unstable.staleManager.reset();
|
|
@@ -233,6 +246,7 @@ class Cache {
|
|
|
233
246
|
}
|
|
234
247
|
}
|
|
235
248
|
class CacheInternal {
|
|
249
|
+
// for server-side requests we need to be able to flag the cache as disabled so we dont write to it
|
|
236
250
|
disabled = false;
|
|
237
251
|
_config;
|
|
238
252
|
storage;
|
|
@@ -397,7 +411,8 @@ class CacheInternal {
|
|
|
397
411
|
forceNotify
|
|
398
412
|
});
|
|
399
413
|
}
|
|
400
|
-
} else if (Array.isArray(value) &&
|
|
414
|
+
} else if (Array.isArray(value) && // make typescript happy
|
|
415
|
+
(typeof previousValue === "undefined" || previousValue === null || Array.isArray(previousValue))) {
|
|
401
416
|
let oldIDs = [...previousValue || []];
|
|
402
417
|
const emptyEdges = !updates ? [] : oldIDs.map((id) => {
|
|
403
418
|
if (!id) {
|
|
@@ -593,6 +608,7 @@ class CacheInternal {
|
|
|
593
608
|
}
|
|
594
609
|
return toNotify;
|
|
595
610
|
}
|
|
611
|
+
// reconstruct an object defined by its selection
|
|
596
612
|
getSelection({
|
|
597
613
|
selection,
|
|
598
614
|
parent = import_stuff.rootID,
|
|
@@ -781,6 +797,8 @@ class CacheInternal {
|
|
|
781
797
|
}
|
|
782
798
|
return {
|
|
783
799
|
data: cascadeNull ? null : target,
|
|
800
|
+
// our value is considered true if there is some data but not everything
|
|
801
|
+
// has a full value
|
|
784
802
|
partial: !generateLoading && hasData && partial,
|
|
785
803
|
stale: hasData && stale,
|
|
786
804
|
hasData
|
|
@@ -796,12 +814,15 @@ class CacheInternal {
|
|
|
796
814
|
}
|
|
797
815
|
return type + ":" + id;
|
|
798
816
|
}
|
|
817
|
+
// the list of fields that we need in order to compute an objects id
|
|
799
818
|
idFields(type) {
|
|
800
819
|
return (0, import_config.keyFieldsForType)(this.config, type);
|
|
801
820
|
}
|
|
802
821
|
computeID(type, data) {
|
|
803
822
|
return (0, import_config.computeID)(this.config, type, data);
|
|
804
823
|
}
|
|
824
|
+
// figure out if this is an embedded object or a linked one by looking for all of the fields marked as
|
|
825
|
+
// required to compute the entity's id
|
|
805
826
|
isEmbedded(linkedType, value) {
|
|
806
827
|
const idFields = this.idFields(linkedType);
|
|
807
828
|
return idFields.length === 0 || idFields.filter((field) => typeof value[field] === "undefined").length > 0;
|
|
@@ -24,6 +24,7 @@ module.exports = __toCommonJS(gc_exports);
|
|
|
24
24
|
class GarbageCollector {
|
|
25
25
|
cache;
|
|
26
26
|
lifetimes = /* @__PURE__ */ new Map();
|
|
27
|
+
// the number of ticks of the garbage collector that a piece of data will
|
|
27
28
|
get cacheBufferSize() {
|
|
28
29
|
return this.cache._internal_unstable.config.cacheBufferSize ?? 10;
|
|
29
30
|
}
|
|
@@ -32,6 +32,7 @@ class ListManager {
|
|
|
32
32
|
this.rootID = rootID2;
|
|
33
33
|
this.cache = cache;
|
|
34
34
|
}
|
|
35
|
+
// associate list names with the handler that wraps the list
|
|
35
36
|
lists = /* @__PURE__ */ new Map();
|
|
36
37
|
listsByField = /* @__PURE__ */ new Map();
|
|
37
38
|
get(listName, id, allLists, skipMatches) {
|
|
@@ -170,6 +171,8 @@ class List {
|
|
|
170
171
|
get fieldRef() {
|
|
171
172
|
return `${this.recordID}.${this.key}`;
|
|
172
173
|
}
|
|
174
|
+
// looks for the collection of all of the lists in the cache that satisfies a when
|
|
175
|
+
// condition
|
|
173
176
|
when(when) {
|
|
174
177
|
return this.manager.lists.get(this.name).get(this.recordID).when(when);
|
|
175
178
|
}
|
|
@@ -326,6 +329,8 @@ class List {
|
|
|
326
329
|
const subscribers = this.cache._internal_unstable.subscriptions.get(this.recordID, this.key);
|
|
327
330
|
this.cache._internal_unstable.subscriptions.remove(
|
|
328
331
|
targetID,
|
|
332
|
+
// if we are unsubscribing from a connection, the fields we care about
|
|
333
|
+
// are tucked away under edges
|
|
329
334
|
this.connection ? this.selection.fields.edges.selection : this.selection,
|
|
330
335
|
subscribers.map((sub) => sub[0]),
|
|
331
336
|
variables
|
|
@@ -384,6 +389,8 @@ class List {
|
|
|
384
389
|
this.addToList(selection, data, variables, where, layer);
|
|
385
390
|
}
|
|
386
391
|
}
|
|
392
|
+
// iterating over the list handler should be the same as iterating over
|
|
393
|
+
// the underlying linked list
|
|
387
394
|
*[Symbol.iterator]() {
|
|
388
395
|
let entries = [];
|
|
389
396
|
let value = this.cache._internal_unstable.storage.get(this.recordID, this.key).value;
|
|
@@ -442,6 +449,8 @@ class ListCollection {
|
|
|
442
449
|
deleteListWithKey(key) {
|
|
443
450
|
return this.lists = this.lists.filter((list) => list.key !== key);
|
|
444
451
|
}
|
|
452
|
+
// iterating over the collection should be the same as iterating over
|
|
453
|
+
// the underlying list
|
|
445
454
|
*[Symbol.iterator]() {
|
|
446
455
|
for (let list of this.lists) {
|
|
447
456
|
for (const entry of list) {
|
|
@@ -24,6 +24,15 @@ module.exports = __toCommonJS(staleManager_exports);
|
|
|
24
24
|
var import_lib = require("../lib");
|
|
25
25
|
class StaleManager {
|
|
26
26
|
cache;
|
|
27
|
+
// id { "User:1" "_ROOT_"
|
|
28
|
+
// field { "id" "viewer"
|
|
29
|
+
// number | undefined | null
|
|
30
|
+
// }
|
|
31
|
+
// }
|
|
32
|
+
// number => data ok (not stale!)
|
|
33
|
+
// undefined => no data (not stale!)
|
|
34
|
+
// null => data stale (stale)
|
|
35
|
+
// nulls mean that the value is stale, and the number is the time that the value was set
|
|
27
36
|
fieldsTime = /* @__PURE__ */ new Map();
|
|
28
37
|
constructor(cache) {
|
|
29
38
|
this.cache = cache;
|
|
@@ -33,13 +42,28 @@ class StaleManager {
|
|
|
33
42
|
this.fieldsTime.set(id, /* @__PURE__ */ new Map());
|
|
34
43
|
}
|
|
35
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* get the FieldTime info
|
|
47
|
+
* @param id User:1
|
|
48
|
+
* @param field firstName
|
|
49
|
+
*/
|
|
36
50
|
getFieldTime(id, field) {
|
|
37
51
|
return this.fieldsTime.get(id)?.get(field);
|
|
38
52
|
}
|
|
53
|
+
/**
|
|
54
|
+
* set the date to a field
|
|
55
|
+
* @param id User:1
|
|
56
|
+
* @param field firstName
|
|
57
|
+
*/
|
|
39
58
|
setFieldTimeToNow(id, field) {
|
|
40
59
|
this.#initMapId(id);
|
|
41
|
-
this.fieldsTime.get(id)?.set(field, new Date().valueOf());
|
|
60
|
+
this.fieldsTime.get(id)?.set(field, (/* @__PURE__ */ new Date()).valueOf());
|
|
42
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* set null to a field (stale)
|
|
64
|
+
* @param id User:1
|
|
65
|
+
* @param field firstName
|
|
66
|
+
*/
|
|
43
67
|
markFieldStale(id, field) {
|
|
44
68
|
this.#initMapId(id);
|
|
45
69
|
this.fieldsTime.get(id)?.set(field, null);
|
|
@@ -80,6 +104,7 @@ class StaleManager {
|
|
|
80
104
|
}
|
|
81
105
|
}
|
|
82
106
|
}
|
|
107
|
+
// clean up the stale manager
|
|
83
108
|
delete(id, field) {
|
|
84
109
|
if (this.fieldsTime.has(id)) {
|
|
85
110
|
this.fieldsTime.get(id)?.delete(field);
|
|
@@ -43,6 +43,7 @@ class InMemoryStorage {
|
|
|
43
43
|
this.idMaps[from] = to;
|
|
44
44
|
this.idMaps[to] = from;
|
|
45
45
|
}
|
|
46
|
+
// create a layer and return its id
|
|
46
47
|
createLayer(optimistic = false) {
|
|
47
48
|
const layer = new Layer(this.idCount++);
|
|
48
49
|
layer.optimistic = optimistic;
|
|
@@ -210,6 +211,8 @@ class InMemoryStorage {
|
|
|
210
211
|
}
|
|
211
212
|
return this.data[this.data.length - 1];
|
|
212
213
|
}
|
|
214
|
+
// return a string representation of all of the data and necessary state to
|
|
215
|
+
// recreate the information stored
|
|
213
216
|
serialize() {
|
|
214
217
|
return JSON.stringify({
|
|
215
218
|
rank: this.rank,
|
|
@@ -343,6 +346,7 @@ class Layer {
|
|
|
343
346
|
[id]: {
|
|
344
347
|
...this.operations[id],
|
|
345
348
|
deleted: true,
|
|
349
|
+
// reapply any delete undos
|
|
346
350
|
undoDeletesInList: []
|
|
347
351
|
}
|
|
348
352
|
};
|
|
@@ -36,9 +36,14 @@ class DocumentStore extends import_store.Writable {
|
|
|
36
36
|
artifact;
|
|
37
37
|
#client;
|
|
38
38
|
#configFile;
|
|
39
|
+
// the list of instantiated plugins
|
|
39
40
|
#plugins;
|
|
41
|
+
// we need to track the last set of variables used so we can
|
|
42
|
+
// detect if they have changed
|
|
40
43
|
#lastVariables;
|
|
44
|
+
// we need the last context value we've seen in order to pass it during cleanup
|
|
41
45
|
#lastContext = null;
|
|
46
|
+
// a reference to the earliest resolving open promise that the store has sent
|
|
42
47
|
pendingPromise = null;
|
|
43
48
|
serverSideFallback;
|
|
44
49
|
controllerKey(variables) {
|
|
@@ -77,6 +82,7 @@ class DocumentStore extends import_store.Writable {
|
|
|
77
82
|
this.#lastVariables = null;
|
|
78
83
|
this.#configFile = (0, import_config.getCurrentConfig)();
|
|
79
84
|
this.#plugins = pipeline ?? [
|
|
85
|
+
// cache policy needs to always come first so that it can be the first network to fire
|
|
80
86
|
(0, import_plugins.cachePolicy)({
|
|
81
87
|
cache,
|
|
82
88
|
enabled: enableCache,
|
|
@@ -93,6 +99,7 @@ class DocumentStore extends import_store.Writable {
|
|
|
93
99
|
...plugins ?? []
|
|
94
100
|
];
|
|
95
101
|
}
|
|
102
|
+
// used by the client to send a new set of variables to the pipeline
|
|
96
103
|
async send({
|
|
97
104
|
metadata,
|
|
98
105
|
session,
|
|
@@ -159,6 +166,7 @@ class DocumentStore extends import_store.Writable {
|
|
|
159
166
|
reject,
|
|
160
167
|
then: (...args) => promise.then(...args)
|
|
161
168
|
},
|
|
169
|
+
// patch the context with new variables
|
|
162
170
|
context
|
|
163
171
|
};
|
|
164
172
|
if (this.pendingPromise === null) {
|
|
@@ -237,7 +245,14 @@ class DocumentStore extends import_store.Writable {
|
|
|
237
245
|
marshalVariables,
|
|
238
246
|
updateState: this.update.bind(this),
|
|
239
247
|
next: (newContext) => {
|
|
240
|
-
const nextIndex = ["forward", "error"].includes(direction) ?
|
|
248
|
+
const nextIndex = ["forward", "error"].includes(direction) ? (
|
|
249
|
+
// if we're going forward, add one
|
|
250
|
+
index + 1
|
|
251
|
+
) : (
|
|
252
|
+
// if we're moving backwards but called next, we
|
|
253
|
+
// we need to invoke the same hook
|
|
254
|
+
index
|
|
255
|
+
);
|
|
241
256
|
const nextStep = ["backwards", "error"].includes(direction) ? 0 : ctx.currentStep;
|
|
242
257
|
this.#step("forward", {
|
|
243
258
|
...ctx,
|
|
@@ -247,7 +262,14 @@ class DocumentStore extends import_store.Writable {
|
|
|
247
262
|
});
|
|
248
263
|
},
|
|
249
264
|
resolve: (newContext, value2) => {
|
|
250
|
-
const nextIndex = direction === "backwards" ?
|
|
265
|
+
const nextIndex = direction === "backwards" ? (
|
|
266
|
+
// if we're going backwards, subtract one
|
|
267
|
+
index - 1
|
|
268
|
+
) : (
|
|
269
|
+
// if we're moving forwards but then call resolve
|
|
270
|
+
// we need to visit the same hook
|
|
271
|
+
index
|
|
272
|
+
);
|
|
251
273
|
this.#step(
|
|
252
274
|
"backwards",
|
|
253
275
|
{
|
|
@@ -344,6 +366,7 @@ class DocumentStore extends import_store.Writable {
|
|
|
344
366
|
}
|
|
345
367
|
}
|
|
346
368
|
class ClientPluginContextWrapper {
|
|
369
|
+
// separate the last variables from what we pass to the user
|
|
347
370
|
#context;
|
|
348
371
|
#lastVariables;
|
|
349
372
|
constructor({
|
|
@@ -356,6 +379,8 @@ class ClientPluginContextWrapper {
|
|
|
356
379
|
get variables() {
|
|
357
380
|
return this.#context.variables;
|
|
358
381
|
}
|
|
382
|
+
// draft produces a wrapper over the context so users can mutate it without
|
|
383
|
+
// actually affecting the context values
|
|
359
384
|
draft() {
|
|
360
385
|
const ctx = {
|
|
361
386
|
...this.#context
|
|
@@ -423,6 +448,7 @@ class ClientPluginContextWrapper {
|
|
|
423
448
|
};
|
|
424
449
|
return ctx;
|
|
425
450
|
}
|
|
451
|
+
// apply applies the draft value in a new context
|
|
426
452
|
apply(values, newVariables) {
|
|
427
453
|
if (newVariables) {
|
|
428
454
|
values = this.applyVariables(this.#context, values);
|
|
@@ -18,6 +18,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
|
@@ -42,7 +46,9 @@ var import_injectedPlugins = __toESM(require("./plugins/injectedPlugins"), 1);
|
|
|
42
46
|
var import_documentStore2 = require("./documentStore");
|
|
43
47
|
var import_plugins2 = require("./plugins");
|
|
44
48
|
class HoudiniClient {
|
|
49
|
+
// the URL of the api
|
|
45
50
|
url;
|
|
51
|
+
// expose operations settings
|
|
46
52
|
throwOnError_operations;
|
|
47
53
|
cache = null;
|
|
48
54
|
throwOnError;
|
|
@@ -50,7 +56,9 @@ class HoudiniClient {
|
|
|
50
56
|
pipeline;
|
|
51
57
|
extraPlugins;
|
|
52
58
|
proxies = {};
|
|
59
|
+
// this is modified by page entries when they load in order to register the components source
|
|
53
60
|
componentCache = {};
|
|
61
|
+
// we need the ability to link the client up with an external cache
|
|
54
62
|
setCache(cache) {
|
|
55
63
|
this.cache = cache;
|
|
56
64
|
}
|
|
@@ -77,16 +85,24 @@ class HoudiniClient {
|
|
|
77
85
|
get plugins() {
|
|
78
86
|
return (0, import_flatten.flatten)(
|
|
79
87
|
[].concat(
|
|
88
|
+
// if they specified a throw behavior
|
|
80
89
|
this.throwOnError ? [(0, import_plugins.throwOnError)(this.throwOnError)] : [],
|
|
81
90
|
(0, import_plugins.fetchParams)(this.fetchParams),
|
|
82
|
-
|
|
91
|
+
// if the user wants to specify the entire pipeline, let them do so
|
|
92
|
+
this.pipeline ?? // the user doesn't have a specific pipeline so we should just add their desired plugins
|
|
93
|
+
// to the standard set
|
|
94
|
+
[
|
|
83
95
|
(0, import_plugins.optimisticKeys)(this.cache ?? import_cache.default),
|
|
96
|
+
// make sure that documents always work
|
|
84
97
|
(0, import_plugins.query)(this.cache ?? import_cache.default),
|
|
85
98
|
(0, import_plugins.mutation)(this.cache ?? import_cache.default),
|
|
86
99
|
(0, import_plugins.fragment)(this.cache ?? import_cache.default)
|
|
87
100
|
].concat(
|
|
101
|
+
// add the specified middlewares
|
|
88
102
|
this.extraPlugins ?? [],
|
|
103
|
+
// and any middlewares we got from plugins
|
|
89
104
|
import_injectedPlugins.default,
|
|
105
|
+
// if they provided a fetch function, use it as the body for the fetch middleware
|
|
90
106
|
(0, import_plugins.fetch)()
|
|
91
107
|
)
|
|
92
108
|
)
|
|
@@ -18,6 +18,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
|
@@ -49,7 +53,8 @@ const cachePolicy = ({
|
|
|
49
53
|
variables: marshalVariables(ctx),
|
|
50
54
|
fullCheck: true
|
|
51
55
|
});
|
|
52
|
-
const allowed = !value.partial || artifact
|
|
56
|
+
const allowed = !value.partial || // or the artifact allows for partial responses
|
|
57
|
+
artifact.kind === import_types.ArtifactKind.Query && artifact.partial;
|
|
53
58
|
if (policy === import_types.CachePolicy.CacheOnly) {
|
|
54
59
|
return resolve(ctx, {
|
|
55
60
|
fetching: false,
|
|
@@ -73,7 +78,8 @@ const cachePolicy = ({
|
|
|
73
78
|
stale: value.stale
|
|
74
79
|
});
|
|
75
80
|
}
|
|
76
|
-
if (useCache && !value.partial && !value.stale &&
|
|
81
|
+
if (useCache && !value.partial && !value.stale && // if the policy is CacheAndNetwork then we don't want to stop here regardless
|
|
82
|
+
ctx.policy !== "CacheAndNetwork") {
|
|
77
83
|
return;
|
|
78
84
|
}
|
|
79
85
|
}
|
|
@@ -50,6 +50,8 @@ const fetch = (target) => {
|
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
const result = await fetchFn({
|
|
53
|
+
// wrap the user's fetch function so we can identify SSR by checking
|
|
54
|
+
// the response.url
|
|
53
55
|
fetch: (url, args) => {
|
|
54
56
|
const newArgs = handleMultipart(fetchParams, args) ?? args;
|
|
55
57
|
return fetch2(url, {
|
|
@@ -142,8 +144,7 @@ function isExtractableFile(value) {
|
|
|
142
144
|
return typeof File !== "undefined" && value instanceof File || typeof Blob !== "undefined" && value instanceof Blob;
|
|
143
145
|
}
|
|
144
146
|
function extractFiles(value) {
|
|
145
|
-
if (!arguments.length)
|
|
146
|
-
throw new TypeError("Argument 1 `value` is required.");
|
|
147
|
+
if (!arguments.length) throw new TypeError("Argument 1 `value` is required.");
|
|
147
148
|
const clones = /* @__PURE__ */ new Map();
|
|
148
149
|
const files = /* @__PURE__ */ new Map();
|
|
149
150
|
function recurse(value2, path, recursed) {
|
|
@@ -158,8 +159,16 @@ function extractFiles(value) {
|
|
|
158
159
|
let clone = clones.get(value2);
|
|
159
160
|
const uncloned = !clone;
|
|
160
161
|
if (uncloned) {
|
|
161
|
-
clone = valueIsList ? [] :
|
|
162
|
-
|
|
162
|
+
clone = valueIsList ? [] : (
|
|
163
|
+
// Replicate if the plain object is an `Object` instance.
|
|
164
|
+
value2 instanceof /** @type {any} */
|
|
165
|
+
Object ? {} : /* @__PURE__ */ Object.create(null)
|
|
166
|
+
);
|
|
167
|
+
clones.set(
|
|
168
|
+
value2,
|
|
169
|
+
/** @type {Clone} */
|
|
170
|
+
clone
|
|
171
|
+
);
|
|
163
172
|
}
|
|
164
173
|
if (!recursed.has(value2)) {
|
|
165
174
|
const pathPrefix = path ? `${path}.` : "";
|
|
@@ -168,8 +177,7 @@ function extractFiles(value) {
|
|
|
168
177
|
let index = 0;
|
|
169
178
|
for (const item of value2) {
|
|
170
179
|
const itemClone = recurse(item, pathPrefix + index++, recursedDeeper);
|
|
171
|
-
if (uncloned)
|
|
172
|
-
clone.push(itemClone);
|
|
180
|
+
if (uncloned) clone.push(itemClone);
|
|
173
181
|
}
|
|
174
182
|
} else
|
|
175
183
|
for (const key in value2) {
|
|
@@ -26,11 +26,13 @@ const fetchParams = (fn = () => ({})) => () => ({
|
|
|
26
26
|
next({
|
|
27
27
|
...ctx,
|
|
28
28
|
fetchParams: fn({
|
|
29
|
+
// most of the stuff comes straight from the context
|
|
29
30
|
config: ctx.config,
|
|
30
31
|
policy: ctx.policy,
|
|
31
32
|
metadata: ctx.metadata,
|
|
32
33
|
session: ctx.session,
|
|
33
34
|
stuff: ctx.stuff,
|
|
35
|
+
// a few fields are renamed or modified
|
|
34
36
|
document: ctx.artifact,
|
|
35
37
|
variables: marshalVariables(ctx),
|
|
36
38
|
text: ctx.text,
|
|
@@ -28,6 +28,7 @@ const fragment = (cache) => (0, import_utils.documentPlugin)(import_types.Artifa
|
|
|
28
28
|
let subscriptionSpec = null;
|
|
29
29
|
let lastReference = null;
|
|
30
30
|
return {
|
|
31
|
+
// establish the cache subscription
|
|
31
32
|
start(ctx, { next, resolve, variablesChanged, marshalVariables }) {
|
|
32
33
|
if (!ctx.stuff.parentID) {
|
|
33
34
|
return next(ctx);
|
|
@@ -33,5 +33,13 @@ __reExport(plugins_exports, require("./fetchParams"), module.exports);
|
|
|
33
33
|
var import_optimisticKeys = require("./optimisticKeys");
|
|
34
34
|
// Annotate the CommonJS export names for ESM import in node:
|
|
35
35
|
0 && (module.exports = {
|
|
36
|
-
optimisticKeys
|
|
36
|
+
optimisticKeys,
|
|
37
|
+
...require("./fetch"),
|
|
38
|
+
...require("./cache"),
|
|
39
|
+
...require("./query"),
|
|
40
|
+
...require("./fragment"),
|
|
41
|
+
...require("./mutation"),
|
|
42
|
+
...require("./subscription"),
|
|
43
|
+
...require("./throwOnError"),
|
|
44
|
+
...require("./fetchParams")
|
|
37
45
|
});
|
|
@@ -33,6 +33,7 @@ const mutation = (cache) => (0, import_utils.documentPlugin)(import_types.Artifa
|
|
|
33
33
|
if (optimisticResponse) {
|
|
34
34
|
toNotify = cache.write({
|
|
35
35
|
selection: ctx.artifact.selection,
|
|
36
|
+
// make sure that any scalar values get processed into something we can cache
|
|
36
37
|
data: await (0, import_scalars.marshalSelection)({
|
|
37
38
|
selection: ctx.artifact.selection,
|
|
38
39
|
data: optimisticResponse
|
|
@@ -43,8 +44,13 @@ const mutation = (cache) => (0, import_utils.documentPlugin)(import_types.Artifa
|
|
|
43
44
|
}
|
|
44
45
|
ctx.cacheParams = {
|
|
45
46
|
...ctx.cacheParams,
|
|
47
|
+
// write to the mutation's layer
|
|
46
48
|
layer: layerOptimistic,
|
|
49
|
+
// notify any subscribers that we updated with the optimistic response
|
|
50
|
+
// in order to address situations where the optimistic update was wrong
|
|
47
51
|
notifySubscribers: toNotify,
|
|
52
|
+
// make sure that we notify subscribers for any values that we compare
|
|
53
|
+
// in order to address any race conditions when comparing the previous value
|
|
48
54
|
forceNotify: true
|
|
49
55
|
};
|
|
50
56
|
next(ctx);
|
|
@@ -18,6 +18,10 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
return to;
|
|
19
19
|
};
|
|
20
20
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
21
25
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
22
26
|
mod
|
|
23
27
|
));
|
|
@@ -52,6 +56,8 @@ const optimisticKeys = (cache, callbackCache = callbacks, keyCache = keys, objec
|
|
|
52
56
|
}
|
|
53
57
|
next(newCtx);
|
|
54
58
|
},
|
|
59
|
+
// if a request has variables that contain an optimistic key we need to block the
|
|
60
|
+
// request before it is sent to the server
|
|
55
61
|
beforeNetwork(ctx, { next }) {
|
|
56
62
|
if (Object.keys(keyCache).length === 0) {
|
|
57
63
|
return next(ctx);
|
|
@@ -101,6 +107,7 @@ const optimisticKeys = (cache, callbackCache = callbacks, keyCache = keys, objec
|
|
|
101
107
|
}
|
|
102
108
|
resolve(ctx);
|
|
103
109
|
},
|
|
110
|
+
// when the mutation ends, we no longer have any dependents that we have to track
|
|
104
111
|
end(ctx, { resolve }) {
|
|
105
112
|
if (typeof ctx.stuff.mutationID !== "undefined") {
|
|
106
113
|
delete keyCache[ctx.stuff.mutationID];
|
|
@@ -299,13 +306,13 @@ function replaceKeyWithVariable(variables, keys2) {
|
|
|
299
306
|
}
|
|
300
307
|
function generateKey(type) {
|
|
301
308
|
if (type === "Int") {
|
|
302
|
-
return new Date().getTime();
|
|
309
|
+
return (/* @__PURE__ */ new Date()).getTime();
|
|
303
310
|
}
|
|
304
311
|
if (type === "String") {
|
|
305
|
-
return new Date().getTime().toString();
|
|
312
|
+
return (/* @__PURE__ */ new Date()).getTime().toString();
|
|
306
313
|
}
|
|
307
314
|
if (type === "ID") {
|
|
308
|
-
return new Date().getTime().toString();
|
|
315
|
+
return (/* @__PURE__ */ new Date()).getTime().toString();
|
|
309
316
|
}
|
|
310
317
|
throw new Error(
|
|
311
318
|
`unsupported type for optimistic key: ${type}. Please provide a value in your mutation arguments.`
|
|
@@ -33,6 +33,8 @@ const query = (cache) => (0, import_utils.documentPlugin)(import_types.ArtifactK
|
|
|
33
33
|
};
|
|
34
34
|
ctx.variables = {
|
|
35
35
|
...lastVariables,
|
|
36
|
+
// we need to evaluate any runtime scalars but allow the user to overwrite them
|
|
37
|
+
// by explicitly passing variables
|
|
36
38
|
...Object.fromEntries(
|
|
37
39
|
Object.entries(ctx.artifact.input?.runtimeScalars ?? {}).map(
|
|
38
40
|
([field, type]) => {
|
|
@@ -48,6 +50,8 @@ const query = (cache) => (0, import_utils.documentPlugin)(import_types.ArtifactK
|
|
|
48
50
|
};
|
|
49
51
|
next(ctx);
|
|
50
52
|
},
|
|
53
|
+
// patch subscriptions on the way out so that we don't get a cache update
|
|
54
|
+
// before the promise resolves
|
|
51
55
|
end(ctx, { resolve, marshalVariables, variablesChanged }) {
|
|
52
56
|
if (variablesChanged(ctx) && !ctx.cacheParams?.disableSubscriptions) {
|
|
53
57
|
if (subscriptionSpec) {
|
|
@@ -16,3 +16,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
16
16
|
var utils_exports = {};
|
|
17
17
|
module.exports = __toCommonJS(utils_exports);
|
|
18
18
|
__reExport(utils_exports, require("./documentPlugins"), module.exports);
|
|
19
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
20
|
+
0 && (module.exports = {
|
|
21
|
+
...require("./documentPlugins")
|
|
22
|
+
});
|