houdini 1.5.4 → 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 +29194 -22340
- package/build/cmd-esm/index.js +27597 -20744
- package/build/codegen/generators/artifacts/index.d.ts +8 -0
- 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 +26128 -21041
- package/build/codegen-esm/index.js +24463 -19376
- package/build/lib/fs.d.ts +3 -2
- package/build/lib/index.d.ts +1 -0
- package/build/lib/watchAndRun.d.ts +61 -0
- package/build/lib-cjs/index.js +26668 -20749
- package/build/lib-esm/index.js +25001 -19085
- 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 +26112 -21026
- package/build/test-esm/index.js +24447 -19361
- 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 +34670 -31925
- package/build/vite-esm/index.js +31149 -28405
- package/package.json +13 -14
|
@@ -13,9 +13,14 @@ class DocumentStore extends Writable {
|
|
|
13
13
|
artifact;
|
|
14
14
|
#client;
|
|
15
15
|
#configFile;
|
|
16
|
+
// the list of instantiated plugins
|
|
16
17
|
#plugins;
|
|
18
|
+
// we need to track the last set of variables used so we can
|
|
19
|
+
// detect if they have changed
|
|
17
20
|
#lastVariables;
|
|
21
|
+
// we need the last context value we've seen in order to pass it during cleanup
|
|
18
22
|
#lastContext = null;
|
|
23
|
+
// a reference to the earliest resolving open promise that the store has sent
|
|
19
24
|
pendingPromise = null;
|
|
20
25
|
serverSideFallback;
|
|
21
26
|
controllerKey(variables) {
|
|
@@ -54,6 +59,7 @@ class DocumentStore extends Writable {
|
|
|
54
59
|
this.#lastVariables = null;
|
|
55
60
|
this.#configFile = getCurrentConfig();
|
|
56
61
|
this.#plugins = pipeline ?? [
|
|
62
|
+
// cache policy needs to always come first so that it can be the first network to fire
|
|
57
63
|
cachePolicy({
|
|
58
64
|
cache,
|
|
59
65
|
enabled: enableCache,
|
|
@@ -70,6 +76,7 @@ class DocumentStore extends Writable {
|
|
|
70
76
|
...plugins ?? []
|
|
71
77
|
];
|
|
72
78
|
}
|
|
79
|
+
// used by the client to send a new set of variables to the pipeline
|
|
73
80
|
async send({
|
|
74
81
|
metadata,
|
|
75
82
|
session,
|
|
@@ -136,6 +143,7 @@ class DocumentStore extends Writable {
|
|
|
136
143
|
reject,
|
|
137
144
|
then: (...args) => promise.then(...args)
|
|
138
145
|
},
|
|
146
|
+
// patch the context with new variables
|
|
139
147
|
context
|
|
140
148
|
};
|
|
141
149
|
if (this.pendingPromise === null) {
|
|
@@ -214,7 +222,14 @@ class DocumentStore extends Writable {
|
|
|
214
222
|
marshalVariables,
|
|
215
223
|
updateState: this.update.bind(this),
|
|
216
224
|
next: (newContext) => {
|
|
217
|
-
const nextIndex = ["forward", "error"].includes(direction) ?
|
|
225
|
+
const nextIndex = ["forward", "error"].includes(direction) ? (
|
|
226
|
+
// if we're going forward, add one
|
|
227
|
+
index + 1
|
|
228
|
+
) : (
|
|
229
|
+
// if we're moving backwards but called next, we
|
|
230
|
+
// we need to invoke the same hook
|
|
231
|
+
index
|
|
232
|
+
);
|
|
218
233
|
const nextStep = ["backwards", "error"].includes(direction) ? 0 : ctx.currentStep;
|
|
219
234
|
this.#step("forward", {
|
|
220
235
|
...ctx,
|
|
@@ -224,7 +239,14 @@ class DocumentStore extends Writable {
|
|
|
224
239
|
});
|
|
225
240
|
},
|
|
226
241
|
resolve: (newContext, value2) => {
|
|
227
|
-
const nextIndex = direction === "backwards" ?
|
|
242
|
+
const nextIndex = direction === "backwards" ? (
|
|
243
|
+
// if we're going backwards, subtract one
|
|
244
|
+
index - 1
|
|
245
|
+
) : (
|
|
246
|
+
// if we're moving forwards but then call resolve
|
|
247
|
+
// we need to visit the same hook
|
|
248
|
+
index
|
|
249
|
+
);
|
|
228
250
|
this.#step(
|
|
229
251
|
"backwards",
|
|
230
252
|
{
|
|
@@ -321,6 +343,7 @@ class DocumentStore extends Writable {
|
|
|
321
343
|
}
|
|
322
344
|
}
|
|
323
345
|
class ClientPluginContextWrapper {
|
|
346
|
+
// separate the last variables from what we pass to the user
|
|
324
347
|
#context;
|
|
325
348
|
#lastVariables;
|
|
326
349
|
constructor({
|
|
@@ -333,6 +356,8 @@ class ClientPluginContextWrapper {
|
|
|
333
356
|
get variables() {
|
|
334
357
|
return this.#context.variables;
|
|
335
358
|
}
|
|
359
|
+
// draft produces a wrapper over the context so users can mutate it without
|
|
360
|
+
// actually affecting the context values
|
|
336
361
|
draft() {
|
|
337
362
|
const ctx = {
|
|
338
363
|
...this.#context
|
|
@@ -400,6 +425,7 @@ class ClientPluginContextWrapper {
|
|
|
400
425
|
};
|
|
401
426
|
return ctx;
|
|
402
427
|
}
|
|
428
|
+
// apply applies the draft value in a new context
|
|
403
429
|
apply(values, newVariables) {
|
|
404
430
|
if (newVariables) {
|
|
405
431
|
values = this.applyVariables(this.#context, values);
|
|
@@ -15,7 +15,9 @@ import pluginsFromPlugins from "./plugins/injectedPlugins";
|
|
|
15
15
|
import { DocumentStore as DocumentStore2 } from "./documentStore";
|
|
16
16
|
import { fetch, mutation, query, subscription } from "./plugins";
|
|
17
17
|
class HoudiniClient {
|
|
18
|
+
// the URL of the api
|
|
18
19
|
url;
|
|
20
|
+
// expose operations settings
|
|
19
21
|
throwOnError_operations;
|
|
20
22
|
cache = null;
|
|
21
23
|
throwOnError;
|
|
@@ -23,7 +25,9 @@ class HoudiniClient {
|
|
|
23
25
|
pipeline;
|
|
24
26
|
extraPlugins;
|
|
25
27
|
proxies = {};
|
|
28
|
+
// this is modified by page entries when they load in order to register the components source
|
|
26
29
|
componentCache = {};
|
|
30
|
+
// we need the ability to link the client up with an external cache
|
|
27
31
|
setCache(cache) {
|
|
28
32
|
this.cache = cache;
|
|
29
33
|
}
|
|
@@ -50,16 +54,24 @@ class HoudiniClient {
|
|
|
50
54
|
get plugins() {
|
|
51
55
|
return flatten(
|
|
52
56
|
[].concat(
|
|
57
|
+
// if they specified a throw behavior
|
|
53
58
|
this.throwOnError ? [throwOnErrorPlugin(this.throwOnError)] : [],
|
|
54
59
|
fetchParamsPlugin(this.fetchParams),
|
|
55
|
-
|
|
60
|
+
// if the user wants to specify the entire pipeline, let them do so
|
|
61
|
+
this.pipeline ?? // the user doesn't have a specific pipeline so we should just add their desired plugins
|
|
62
|
+
// to the standard set
|
|
63
|
+
[
|
|
56
64
|
optimisticKeys(this.cache ?? cacheRef),
|
|
65
|
+
// make sure that documents always work
|
|
57
66
|
queryPlugin(this.cache ?? cacheRef),
|
|
58
67
|
mutationPlugin(this.cache ?? cacheRef),
|
|
59
68
|
fragmentPlugin(this.cache ?? cacheRef)
|
|
60
69
|
].concat(
|
|
70
|
+
// add the specified middlewares
|
|
61
71
|
this.extraPlugins ?? [],
|
|
72
|
+
// and any middlewares we got from plugins
|
|
62
73
|
pluginsFromPlugins,
|
|
74
|
+
// if they provided a fetch function, use it as the body for the fetch middleware
|
|
63
75
|
fetchPlugin()
|
|
64
76
|
)
|
|
65
77
|
)
|
|
@@ -20,7 +20,8 @@ const cachePolicy = ({
|
|
|
20
20
|
variables: marshalVariables(ctx),
|
|
21
21
|
fullCheck: true
|
|
22
22
|
});
|
|
23
|
-
const allowed = !value.partial || artifact
|
|
23
|
+
const allowed = !value.partial || // or the artifact allows for partial responses
|
|
24
|
+
artifact.kind === ArtifactKind.Query && artifact.partial;
|
|
24
25
|
if (policy === CachePolicy.CacheOnly) {
|
|
25
26
|
return resolve(ctx, {
|
|
26
27
|
fetching: false,
|
|
@@ -44,7 +45,8 @@ const cachePolicy = ({
|
|
|
44
45
|
stale: value.stale
|
|
45
46
|
});
|
|
46
47
|
}
|
|
47
|
-
if (useCache && !value.partial && !value.stale &&
|
|
48
|
+
if (useCache && !value.partial && !value.stale && // if the policy is CacheAndNetwork then we don't want to stop here regardless
|
|
49
|
+
ctx.policy !== "CacheAndNetwork") {
|
|
48
50
|
return;
|
|
49
51
|
}
|
|
50
52
|
}
|
|
@@ -25,6 +25,8 @@ const fetch = (target) => {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
const result = await fetchFn({
|
|
28
|
+
// wrap the user's fetch function so we can identify SSR by checking
|
|
29
|
+
// the response.url
|
|
28
30
|
fetch: (url, args) => {
|
|
29
31
|
const newArgs = handleMultipart(fetchParams, args) ?? args;
|
|
30
32
|
return fetch2(url, {
|
|
@@ -117,8 +119,7 @@ function isExtractableFile(value) {
|
|
|
117
119
|
return typeof File !== "undefined" && value instanceof File || typeof Blob !== "undefined" && value instanceof Blob;
|
|
118
120
|
}
|
|
119
121
|
function extractFiles(value) {
|
|
120
|
-
if (!arguments.length)
|
|
121
|
-
throw new TypeError("Argument 1 `value` is required.");
|
|
122
|
+
if (!arguments.length) throw new TypeError("Argument 1 `value` is required.");
|
|
122
123
|
const clones = /* @__PURE__ */ new Map();
|
|
123
124
|
const files = /* @__PURE__ */ new Map();
|
|
124
125
|
function recurse(value2, path, recursed) {
|
|
@@ -133,8 +134,16 @@ function extractFiles(value) {
|
|
|
133
134
|
let clone = clones.get(value2);
|
|
134
135
|
const uncloned = !clone;
|
|
135
136
|
if (uncloned) {
|
|
136
|
-
clone = valueIsList ? [] :
|
|
137
|
-
|
|
137
|
+
clone = valueIsList ? [] : (
|
|
138
|
+
// Replicate if the plain object is an `Object` instance.
|
|
139
|
+
value2 instanceof /** @type {any} */
|
|
140
|
+
Object ? {} : /* @__PURE__ */ Object.create(null)
|
|
141
|
+
);
|
|
142
|
+
clones.set(
|
|
143
|
+
value2,
|
|
144
|
+
/** @type {Clone} */
|
|
145
|
+
clone
|
|
146
|
+
);
|
|
138
147
|
}
|
|
139
148
|
if (!recursed.has(value2)) {
|
|
140
149
|
const pathPrefix = path ? `${path}.` : "";
|
|
@@ -143,8 +152,7 @@ function extractFiles(value) {
|
|
|
143
152
|
let index = 0;
|
|
144
153
|
for (const item of value2) {
|
|
145
154
|
const itemClone = recurse(item, pathPrefix + index++, recursedDeeper);
|
|
146
|
-
if (uncloned)
|
|
147
|
-
clone.push(itemClone);
|
|
155
|
+
if (uncloned) clone.push(itemClone);
|
|
148
156
|
}
|
|
149
157
|
} else
|
|
150
158
|
for (const key in value2) {
|
|
@@ -3,11 +3,13 @@ const fetchParams = (fn = () => ({})) => () => ({
|
|
|
3
3
|
next({
|
|
4
4
|
...ctx,
|
|
5
5
|
fetchParams: fn({
|
|
6
|
+
// most of the stuff comes straight from the context
|
|
6
7
|
config: ctx.config,
|
|
7
8
|
policy: ctx.policy,
|
|
8
9
|
metadata: ctx.metadata,
|
|
9
10
|
session: ctx.session,
|
|
10
11
|
stuff: ctx.stuff,
|
|
12
|
+
// a few fields are renamed or modified
|
|
11
13
|
document: ctx.artifact,
|
|
12
14
|
variables: marshalVariables(ctx),
|
|
13
15
|
text: ctx.text,
|
|
@@ -5,6 +5,7 @@ const fragment = (cache) => documentPlugin(ArtifactKind.Fragment, function() {
|
|
|
5
5
|
let subscriptionSpec = null;
|
|
6
6
|
let lastReference = null;
|
|
7
7
|
return {
|
|
8
|
+
// establish the cache subscription
|
|
8
9
|
start(ctx, { next, resolve, variablesChanged, marshalVariables }) {
|
|
9
10
|
if (!ctx.stuff.parentID) {
|
|
10
11
|
return next(ctx);
|
|
@@ -10,6 +10,7 @@ const mutation = (cache) => documentPlugin(ArtifactKind.Mutation, () => {
|
|
|
10
10
|
if (optimisticResponse) {
|
|
11
11
|
toNotify = cache.write({
|
|
12
12
|
selection: ctx.artifact.selection,
|
|
13
|
+
// make sure that any scalar values get processed into something we can cache
|
|
13
14
|
data: await marshalSelection({
|
|
14
15
|
selection: ctx.artifact.selection,
|
|
15
16
|
data: optimisticResponse
|
|
@@ -20,8 +21,13 @@ const mutation = (cache) => documentPlugin(ArtifactKind.Mutation, () => {
|
|
|
20
21
|
}
|
|
21
22
|
ctx.cacheParams = {
|
|
22
23
|
...ctx.cacheParams,
|
|
24
|
+
// write to the mutation's layer
|
|
23
25
|
layer: layerOptimistic,
|
|
26
|
+
// notify any subscribers that we updated with the optimistic response
|
|
27
|
+
// in order to address situations where the optimistic update was wrong
|
|
24
28
|
notifySubscribers: toNotify,
|
|
29
|
+
// make sure that we notify subscribers for any values that we compare
|
|
30
|
+
// in order to address any race conditions when comparing the previous value
|
|
25
31
|
forceNotify: true
|
|
26
32
|
};
|
|
27
33
|
next(ctx);
|
|
@@ -23,6 +23,8 @@ const optimisticKeys = (cache, callbackCache = callbacks, keyCache = keys, objec
|
|
|
23
23
|
}
|
|
24
24
|
next(newCtx);
|
|
25
25
|
},
|
|
26
|
+
// if a request has variables that contain an optimistic key we need to block the
|
|
27
|
+
// request before it is sent to the server
|
|
26
28
|
beforeNetwork(ctx, { next }) {
|
|
27
29
|
if (Object.keys(keyCache).length === 0) {
|
|
28
30
|
return next(ctx);
|
|
@@ -72,6 +74,7 @@ const optimisticKeys = (cache, callbackCache = callbacks, keyCache = keys, objec
|
|
|
72
74
|
}
|
|
73
75
|
resolve(ctx);
|
|
74
76
|
},
|
|
77
|
+
// when the mutation ends, we no longer have any dependents that we have to track
|
|
75
78
|
end(ctx, { resolve }) {
|
|
76
79
|
if (typeof ctx.stuff.mutationID !== "undefined") {
|
|
77
80
|
delete keyCache[ctx.stuff.mutationID];
|
|
@@ -270,13 +273,13 @@ function replaceKeyWithVariable(variables, keys2) {
|
|
|
270
273
|
}
|
|
271
274
|
function generateKey(type) {
|
|
272
275
|
if (type === "Int") {
|
|
273
|
-
return new Date().getTime();
|
|
276
|
+
return (/* @__PURE__ */ new Date()).getTime();
|
|
274
277
|
}
|
|
275
278
|
if (type === "String") {
|
|
276
|
-
return new Date().getTime().toString();
|
|
279
|
+
return (/* @__PURE__ */ new Date()).getTime().toString();
|
|
277
280
|
}
|
|
278
281
|
if (type === "ID") {
|
|
279
|
-
return new Date().getTime().toString();
|
|
282
|
+
return (/* @__PURE__ */ new Date()).getTime().toString();
|
|
280
283
|
}
|
|
281
284
|
throw new Error(
|
|
282
285
|
`unsupported type for optimistic key: ${type}. Please provide a value in your mutation arguments.`
|
|
@@ -10,6 +10,8 @@ const query = (cache) => documentPlugin(ArtifactKind.Query, function() {
|
|
|
10
10
|
};
|
|
11
11
|
ctx.variables = {
|
|
12
12
|
...lastVariables,
|
|
13
|
+
// we need to evaluate any runtime scalars but allow the user to overwrite them
|
|
14
|
+
// by explicitly passing variables
|
|
13
15
|
...Object.fromEntries(
|
|
14
16
|
Object.entries(ctx.artifact.input?.runtimeScalars ?? {}).map(
|
|
15
17
|
([field, type]) => {
|
|
@@ -25,6 +27,8 @@ const query = (cache) => documentPlugin(ArtifactKind.Query, function() {
|
|
|
25
27
|
};
|
|
26
28
|
next(ctx);
|
|
27
29
|
},
|
|
30
|
+
// patch subscriptions on the way out so that we don't get a cache update
|
|
31
|
+
// before the promise resolves
|
|
28
32
|
end(ctx, { resolve, marshalVariables, variablesChanged }) {
|
|
29
33
|
if (variablesChanged(ctx) && !ctx.cacheParams?.disableSubscriptions) {
|
|
30
34
|
if (subscriptionSpec) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
function deepEquals(objA, objB, map = /* @__PURE__ */ new WeakMap()) {
|
|
2
|
-
if (Object.is(objA, objB))
|
|
3
|
-
return true;
|
|
2
|
+
if (Object.is(objA, objB)) return true;
|
|
4
3
|
if (objA instanceof Date && objB instanceof Date) {
|
|
5
4
|
return objA.getTime() === objB.getTime();
|
|
6
5
|
}
|
|
@@ -10,8 +9,7 @@ function deepEquals(objA, objB, map = /* @__PURE__ */ new WeakMap()) {
|
|
|
10
9
|
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) {
|
|
11
10
|
return false;
|
|
12
11
|
}
|
|
13
|
-
if (map.get(objA) === objB)
|
|
14
|
-
return true;
|
|
12
|
+
if (map.get(objA) === objB) return true;
|
|
15
13
|
map.set(objA, objB);
|
|
16
14
|
const keysA = Reflect.ownKeys(objA);
|
|
17
15
|
const keysB = Reflect.ownKeys(objB);
|
|
@@ -119,7 +119,8 @@ function cursorHandlers({
|
|
|
119
119
|
const queryVariables = {};
|
|
120
120
|
const count = countPage(artifact.refetch.path.concat("edges"), getState()) || artifact.refetch.pageSize;
|
|
121
121
|
if (count && count > artifact.refetch.pageSize) {
|
|
122
|
-
if (currentPageInfo.hasPreviousPage && currentPageInfo.hasNextPage &&
|
|
122
|
+
if (currentPageInfo.hasPreviousPage && currentPageInfo.hasNextPage && // only log if they haven't provided special parameters
|
|
123
|
+
!(variables?.["first"] && variables?.["after"] || variables?.["last"] && variables?.["before"])) {
|
|
123
124
|
console.warn(`\u26A0\uFE0F Encountered a fetch() in the middle of the connection.
|
|
124
125
|
Make sure to pass a cursor value by hand that includes the current set (ie the entry before startCursor)
|
|
125
126
|
`);
|
|
@@ -31,8 +31,17 @@ const RefetchUpdateMode = {
|
|
|
31
31
|
replace: "replace"
|
|
32
32
|
};
|
|
33
33
|
const DataSource = {
|
|
34
|
+
/**
|
|
35
|
+
* from the browser cache
|
|
36
|
+
*/
|
|
34
37
|
Cache: "cache",
|
|
38
|
+
/**
|
|
39
|
+
* from a browser side `fetch`
|
|
40
|
+
*/
|
|
35
41
|
Network: "network",
|
|
42
|
+
/**
|
|
43
|
+
* from a server side `fetch`
|
|
44
|
+
*/
|
|
36
45
|
Ssr: "ssr"
|
|
37
46
|
};
|
|
38
47
|
const fragmentKey = " $fragments";
|
|
@@ -6,6 +6,9 @@ class Cache {
|
|
|
6
6
|
constructor(cache) {
|
|
7
7
|
this._internal_unstable = cache;
|
|
8
8
|
}
|
|
9
|
+
// if the user is using the imperative API, we want the ability to break the API
|
|
10
|
+
// with any minor version. In order to do this, we require them to accept this contract
|
|
11
|
+
// through their config file
|
|
9
12
|
validateInstabilityWarning() {
|
|
10
13
|
if (!this.config.acceptImperativeInstability && !this.config.features?.imperativeCache) {
|
|
11
14
|
console.warn(`\u26A0\uFE0F The imperative cache API is considered unstable and will change in any minor version release
|
|
@@ -13,6 +16,7 @@ Please acknowledge this by enabling the imperative cache feature flage in your c
|
|
|
13
16
|
For more information: https://houdinigraphql.com/api/cache`);
|
|
14
17
|
}
|
|
15
18
|
}
|
|
19
|
+
// return the record proxy for the given type/id combo
|
|
16
20
|
get(type, data) {
|
|
17
21
|
this.validateInstabilityWarning();
|
|
18
22
|
let recordID = this._internal_unstable._internal_unstable.id(type, data);
|
|
@@ -56,6 +60,7 @@ For more information: https://houdinigraphql.com/api/cache`);
|
|
|
56
60
|
this.validateInstabilityWarning();
|
|
57
61
|
this._internal_unstable.write({
|
|
58
62
|
selection: query.artifact.selection,
|
|
63
|
+
// @ts-expect-error
|
|
59
64
|
data,
|
|
60
65
|
variables: marshalInputs({
|
|
61
66
|
config: this.config,
|
|
@@ -65,9 +70,15 @@ For more information: https://houdinigraphql.com/api/cache`);
|
|
|
65
70
|
});
|
|
66
71
|
return;
|
|
67
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Mark some elements of the cache stale.
|
|
75
|
+
*/
|
|
68
76
|
markStale(type, options) {
|
|
69
77
|
return this._internal_unstable.markTypeStale(type ? { ...options, type } : void 0);
|
|
70
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* Reset the entire cache by clearing all records and lists
|
|
81
|
+
*/
|
|
71
82
|
reset() {
|
|
72
83
|
return this._internal_unstable.reset();
|
|
73
84
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
function base64UrlParse(s) {
|
|
2
2
|
return new Uint8Array(
|
|
3
|
+
// @ts-ignore
|
|
3
4
|
Array.prototype.map.call(
|
|
4
5
|
atob(s.replace(/-/g, "+").replace(/_/g, "/").replace(/\s/g, "")),
|
|
5
6
|
(c) => c.charCodeAt(0)
|
|
@@ -52,20 +53,16 @@ function _decodePayload(raw) {
|
|
|
52
53
|
}
|
|
53
54
|
}
|
|
54
55
|
async function encode(payload, secret, options = { algorithm: "HS256", header: { typ: "JWT" } }) {
|
|
55
|
-
if (typeof options === "string")
|
|
56
|
-
options = { algorithm: options, header: { typ: "JWT" } };
|
|
56
|
+
if (typeof options === "string") options = { algorithm: options, header: { typ: "JWT" } };
|
|
57
57
|
options = { algorithm: "HS256", header: { typ: "JWT" }, ...options };
|
|
58
58
|
if (payload === null || typeof payload !== "object")
|
|
59
59
|
throw new Error("payload must be an object");
|
|
60
60
|
if (typeof secret !== "string" && typeof secret !== "object")
|
|
61
61
|
throw new Error("secret must be a string or a JWK object");
|
|
62
|
-
if (typeof options.algorithm !== "string")
|
|
63
|
-
throw new Error("options.algorithm must be a string");
|
|
62
|
+
if (typeof options.algorithm !== "string") throw new Error("options.algorithm must be a string");
|
|
64
63
|
const algorithm = algorithms[options.algorithm];
|
|
65
|
-
if (!algorithm)
|
|
66
|
-
|
|
67
|
-
if (!payload.iat)
|
|
68
|
-
payload.iat = Math.floor(Date.now() / 1e3);
|
|
64
|
+
if (!algorithm) throw new Error("algorithm not found");
|
|
65
|
+
if (!payload.iat) payload.iat = Math.floor(Date.now() / 1e3);
|
|
69
66
|
const payloadAsJSON = JSON.stringify(payload);
|
|
70
67
|
const partialToken = `${base64UrlStringify(
|
|
71
68
|
_utf8ToUint8Array(JSON.stringify({ ...options.header, alg: options.algorithm }))
|
|
@@ -80,42 +77,33 @@ async function encode(payload, secret, options = { algorithm: "HS256", header: {
|
|
|
80
77
|
keyData = _str2ab(
|
|
81
78
|
secret.replace(/-----BEGIN.*?-----/g, "").replace(/-----END.*?-----/g, "").replace(/\s/g, "")
|
|
82
79
|
);
|
|
83
|
-
} else
|
|
84
|
-
keyData = _utf8ToUint8Array(secret);
|
|
80
|
+
} else keyData = _utf8ToUint8Array(secret);
|
|
85
81
|
const key = await crypto.subtle.importKey(keyFormat, keyData, algorithm, false, ["sign"]);
|
|
86
82
|
const signature = await crypto.subtle.sign(algorithm, key, _utf8ToUint8Array(partialToken));
|
|
87
83
|
return `${partialToken}.${base64UrlStringify(new Uint8Array(signature))}`;
|
|
88
84
|
}
|
|
89
85
|
async function verify(token, secret, options = { algorithm: "HS256", throwError: false }) {
|
|
90
|
-
if (typeof options === "string")
|
|
91
|
-
options = { algorithm: options, throwError: false };
|
|
86
|
+
if (typeof options === "string") options = { algorithm: options, throwError: false };
|
|
92
87
|
options = { algorithm: "HS256", throwError: false, ...options };
|
|
93
|
-
if (typeof token !== "string")
|
|
94
|
-
throw new Error("token must be a string");
|
|
88
|
+
if (typeof token !== "string") throw new Error("token must be a string");
|
|
95
89
|
if (typeof secret !== "string" && typeof secret !== "object")
|
|
96
90
|
throw new Error("secret must be a string or a JWK object");
|
|
97
|
-
if (typeof options.algorithm !== "string")
|
|
98
|
-
throw new Error("options.algorithm must be a string");
|
|
91
|
+
if (typeof options.algorithm !== "string") throw new Error("options.algorithm must be a string");
|
|
99
92
|
const tokenParts = token.split(".");
|
|
100
|
-
if (tokenParts.length !== 3)
|
|
101
|
-
throw new Error("token must consist of 3 parts");
|
|
93
|
+
if (tokenParts.length !== 3) throw new Error("token must consist of 3 parts");
|
|
102
94
|
const algorithm = algorithms[options.algorithm];
|
|
103
|
-
if (!algorithm)
|
|
104
|
-
throw new Error("algorithm not found");
|
|
95
|
+
if (!algorithm) throw new Error("algorithm not found");
|
|
105
96
|
const { payload } = decode(token);
|
|
106
97
|
if (!payload) {
|
|
107
|
-
if (options.throwError)
|
|
108
|
-
throw "PARSE_ERROR";
|
|
98
|
+
if (options.throwError) throw "PARSE_ERROR";
|
|
109
99
|
return false;
|
|
110
100
|
}
|
|
111
101
|
if (payload.nbf && payload.nbf > Math.floor(Date.now() / 1e3)) {
|
|
112
|
-
if (options.throwError)
|
|
113
|
-
throw "NOT_YET_VALID";
|
|
102
|
+
if (options.throwError) throw "NOT_YET_VALID";
|
|
114
103
|
return false;
|
|
115
104
|
}
|
|
116
105
|
if (payload.exp && payload.exp <= Math.floor(Date.now() / 1e3)) {
|
|
117
|
-
if (options.throwError)
|
|
118
|
-
throw "EXPIRED";
|
|
106
|
+
if (options.throwError) throw "EXPIRED";
|
|
119
107
|
return false;
|
|
120
108
|
}
|
|
121
109
|
let keyFormat = "raw";
|
|
@@ -128,8 +116,7 @@ async function verify(token, secret, options = { algorithm: "HS256", throwError:
|
|
|
128
116
|
keyData = _str2ab(
|
|
129
117
|
secret.replace(/-----BEGIN.*?-----/g, "").replace(/-----END.*?-----/g, "").replace(/\s/g, "")
|
|
130
118
|
);
|
|
131
|
-
} else
|
|
132
|
-
keyData = _utf8ToUint8Array(secret);
|
|
119
|
+
} else keyData = _utf8ToUint8Array(secret);
|
|
133
120
|
const key = await crypto.subtle.importKey(keyFormat, keyData, algorithm, false, ["verify"]);
|
|
134
121
|
return await crypto.subtle.verify(
|
|
135
122
|
algorithm,
|
|
@@ -112,14 +112,12 @@ function exec(match, params) {
|
|
|
112
112
|
}
|
|
113
113
|
buffered = "";
|
|
114
114
|
if (value === void 0) {
|
|
115
|
-
if (param.rest)
|
|
116
|
-
result[param.name] = "";
|
|
115
|
+
if (param.rest) result[param.name] = "";
|
|
117
116
|
} else {
|
|
118
117
|
result[param.name] = decodeURIComponent(value);
|
|
119
118
|
}
|
|
120
119
|
}
|
|
121
|
-
if (buffered)
|
|
122
|
-
return;
|
|
120
|
+
if (buffered) return;
|
|
123
121
|
return result;
|
|
124
122
|
}
|
|
125
123
|
function escape(str) {
|
|
@@ -27,7 +27,12 @@ function _serverHandler({
|
|
|
27
27
|
if (schema) {
|
|
28
28
|
client.registerProxy(graphqlEndpoint, async ({ query, variables, session }) => {
|
|
29
29
|
const parsed = parse(query);
|
|
30
|
-
return await execute(
|
|
30
|
+
return await execute({
|
|
31
|
+
schema,
|
|
32
|
+
document: parsed,
|
|
33
|
+
contextValue: session,
|
|
34
|
+
variableValues: variables
|
|
35
|
+
});
|
|
31
36
|
});
|
|
32
37
|
}
|
|
33
38
|
return async (request) => {
|
|
@@ -35,7 +35,7 @@ async function redirect_auth(args) {
|
|
|
35
35
|
}
|
|
36
36
|
const session_cookie_name = "__houdini__";
|
|
37
37
|
async function set_session(req, response, value) {
|
|
38
|
-
const today = new Date();
|
|
38
|
+
const today = /* @__PURE__ */ new Date();
|
|
39
39
|
const expires = new Date(today.getTime() + 7 * 24 * 60 * 60 * 1e3);
|
|
40
40
|
const serialized = await encode(value, req.session_keys[0]);
|
|
41
41
|
response.headers.set(
|