houdini 1.1.7 → 1.2.0-next.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 +1 -1
- package/build/cmd-cjs/index.js +1739 -1256
- package/build/cmd-esm/index.js +1739 -1256
- package/build/codegen/generators/artifacts/selection.d.ts +2 -1
- package/build/codegen/generators/typescript/inlineType.d.ts +5 -2
- package/build/codegen/generators/typescript/loadingState.d.ts +8 -0
- package/build/codegen-cjs/index.js +1701 -1241
- package/build/codegen-esm/index.js +1701 -1241
- package/build/lib/config.d.ts +5 -0
- package/build/lib/graphql.d.ts +5 -1
- package/build/lib/parse.d.ts +11 -1
- package/build/lib/types.d.ts +4 -1
- package/build/lib-cjs/index.js +611 -493
- package/build/lib-esm/index.js +608 -493
- package/build/runtime/cache/cache.d.ts +7 -8
- package/build/runtime/cache/stuff.d.ts +1 -4
- package/build/runtime/client/documentStore.d.ts +6 -3
- package/build/runtime/client/index.d.ts +9 -8
- package/build/runtime/client/plugins/cache.d.ts +1 -1
- package/build/runtime/client/plugins/fetch.d.ts +1 -0
- package/build/runtime/client/plugins/subscription.d.ts +1 -0
- package/build/runtime/client/plugins/throwOnError.d.ts +2 -1
- package/build/runtime/lib/pageInfo.d.ts +7 -0
- package/build/runtime/lib/pagination.d.ts +27 -0
- package/build/runtime/lib/selection.d.ts +1 -1
- package/build/runtime/lib/types.d.ts +79 -4
- package/build/runtime-cjs/cache/cache.d.ts +7 -8
- package/build/runtime-cjs/cache/cache.js +78 -36
- package/build/runtime-cjs/cache/stuff.d.ts +1 -4
- package/build/runtime-cjs/cache/stuff.js +2 -2
- package/build/runtime-cjs/cache/subscription.js +5 -5
- package/build/runtime-cjs/client/documentStore.d.ts +6 -3
- package/build/runtime-cjs/client/documentStore.js +20 -7
- package/build/runtime-cjs/client/index.d.ts +9 -8
- package/build/runtime-cjs/client/index.js +12 -4
- package/build/runtime-cjs/client/plugins/cache.d.ts +1 -1
- package/build/runtime-cjs/client/plugins/cache.js +12 -2
- package/build/runtime-cjs/client/plugins/fetch.d.ts +1 -0
- package/build/runtime-cjs/client/plugins/fetch.js +3 -2
- package/build/runtime-cjs/client/plugins/fragment.js +8 -1
- package/build/runtime-cjs/client/plugins/query.js +2 -1
- package/build/runtime-cjs/client/plugins/subscription.d.ts +1 -0
- package/build/runtime-cjs/client/plugins/subscription.js +1 -0
- package/build/runtime-cjs/client/plugins/throwOnError.d.ts +2 -1
- package/build/runtime-cjs/lib/config.js +2 -1
- package/build/runtime-cjs/lib/pageInfo.d.ts +7 -0
- package/build/runtime-cjs/lib/pageInfo.js +79 -0
- package/build/runtime-cjs/lib/pagination.d.ts +27 -0
- package/build/runtime-cjs/lib/pagination.js +219 -0
- package/build/runtime-cjs/lib/scalars.js +1 -1
- package/build/runtime-cjs/lib/selection.d.ts +1 -1
- package/build/runtime-cjs/lib/selection.js +28 -1
- package/build/runtime-cjs/lib/types.d.ts +79 -4
- package/build/runtime-cjs/lib/types.js +3 -0
- package/build/runtime-esm/cache/cache.d.ts +7 -8
- package/build/runtime-esm/cache/cache.js +79 -37
- package/build/runtime-esm/cache/stuff.d.ts +1 -4
- package/build/runtime-esm/cache/stuff.js +2 -2
- package/build/runtime-esm/cache/subscription.js +5 -5
- package/build/runtime-esm/client/documentStore.d.ts +6 -3
- package/build/runtime-esm/client/documentStore.js +20 -7
- package/build/runtime-esm/client/index.d.ts +9 -8
- package/build/runtime-esm/client/index.js +15 -7
- package/build/runtime-esm/client/plugins/cache.d.ts +1 -1
- package/build/runtime-esm/client/plugins/cache.js +12 -2
- package/build/runtime-esm/client/plugins/fetch.d.ts +1 -0
- package/build/runtime-esm/client/plugins/fetch.js +3 -2
- package/build/runtime-esm/client/plugins/fragment.js +8 -1
- package/build/runtime-esm/client/plugins/query.js +2 -1
- package/build/runtime-esm/client/plugins/subscription.d.ts +1 -0
- package/build/runtime-esm/client/plugins/subscription.js +1 -0
- package/build/runtime-esm/client/plugins/throwOnError.d.ts +2 -1
- package/build/runtime-esm/lib/config.js +2 -1
- package/build/runtime-esm/lib/pageInfo.d.ts +7 -0
- package/build/runtime-esm/lib/pageInfo.js +52 -0
- package/build/runtime-esm/lib/pagination.d.ts +27 -0
- package/build/runtime-esm/lib/pagination.js +194 -0
- package/build/runtime-esm/lib/scalars.js +1 -1
- package/build/runtime-esm/lib/selection.d.ts +1 -1
- package/build/runtime-esm/lib/selection.js +28 -1
- package/build/runtime-esm/lib/types.d.ts +79 -4
- package/build/runtime-esm/lib/types.js +2 -0
- package/build/test/index.d.ts +15 -0
- package/build/test-cjs/index.js +1706 -1223
- package/build/test-esm/index.js +1706 -1223
- package/build/vite-cjs/index.js +1757 -1274
- package/build/vite-esm/index.js +1757 -1274
- package/package.json +5 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { computeKey } from "../lib";
|
|
1
|
+
import { computeKey, PendingValue } from "../lib";
|
|
2
2
|
import { computeID, defaultConfigValues, keyFieldsForType, getCurrentConfig } from "../lib/config";
|
|
3
3
|
import { deepEquals } from "../lib/deepEquals";
|
|
4
4
|
import { flatten } from "../lib/flatten";
|
|
@@ -6,7 +6,6 @@ import { getFieldsForType } from "../lib/selection";
|
|
|
6
6
|
import { fragmentKey } from "../lib/types";
|
|
7
7
|
import { GarbageCollector } from "./gc";
|
|
8
8
|
import { ListManager } from "./lists";
|
|
9
|
-
import { SchemaManager } from "./schema";
|
|
10
9
|
import { StaleManager } from "./staleManager";
|
|
11
10
|
import { InMemoryStorage } from "./storage";
|
|
12
11
|
import { evaluateKey } from "./stuff";
|
|
@@ -21,7 +20,6 @@ class Cache {
|
|
|
21
20
|
lists: new ListManager(this, rootID),
|
|
22
21
|
lifetimes: new GarbageCollector(this),
|
|
23
22
|
staleManager: new StaleManager(this),
|
|
24
|
-
schema: new SchemaManager(this),
|
|
25
23
|
disabled: disabled ?? typeof globalThis.window === "undefined"
|
|
26
24
|
});
|
|
27
25
|
if (Object.keys(config).length > 0) {
|
|
@@ -132,7 +130,6 @@ class CacheInternal {
|
|
|
132
130
|
cache;
|
|
133
131
|
lifetimes;
|
|
134
132
|
staleManager;
|
|
135
|
-
schema;
|
|
136
133
|
constructor({
|
|
137
134
|
storage,
|
|
138
135
|
subscriptions,
|
|
@@ -140,7 +137,6 @@ class CacheInternal {
|
|
|
140
137
|
cache,
|
|
141
138
|
lifetimes,
|
|
142
139
|
staleManager,
|
|
143
|
-
schema,
|
|
144
140
|
disabled,
|
|
145
141
|
config
|
|
146
142
|
}) {
|
|
@@ -150,7 +146,6 @@ class CacheInternal {
|
|
|
150
146
|
this.cache = cache;
|
|
151
147
|
this.lifetimes = lifetimes;
|
|
152
148
|
this.staleManager = staleManager;
|
|
153
|
-
this.schema = schema;
|
|
154
149
|
this._config = config;
|
|
155
150
|
this._disabled = disabled;
|
|
156
151
|
try {
|
|
@@ -180,7 +175,11 @@ class CacheInternal {
|
|
|
180
175
|
if (this._disabled) {
|
|
181
176
|
return [];
|
|
182
177
|
}
|
|
183
|
-
let targetSelection = getFieldsForType(
|
|
178
|
+
let targetSelection = getFieldsForType(
|
|
179
|
+
selection,
|
|
180
|
+
data["__typename"],
|
|
181
|
+
false
|
|
182
|
+
);
|
|
184
183
|
for (const [field, value] of Object.entries(data)) {
|
|
185
184
|
if (!selection || !targetSelection[field]) {
|
|
186
185
|
continue;
|
|
@@ -191,17 +190,9 @@ class CacheInternal {
|
|
|
191
190
|
selection: fieldSelection,
|
|
192
191
|
operations,
|
|
193
192
|
abstract: isAbstract,
|
|
194
|
-
updates
|
|
195
|
-
nullable
|
|
193
|
+
updates
|
|
196
194
|
} = targetSelection[field];
|
|
197
195
|
const key = evaluateKey(keyRaw, variables);
|
|
198
|
-
this.schema.setFieldType({
|
|
199
|
-
parent,
|
|
200
|
-
key: keyRaw,
|
|
201
|
-
type: linkedType,
|
|
202
|
-
nullable,
|
|
203
|
-
link: !!fieldSelection
|
|
204
|
-
});
|
|
205
196
|
if (value && typeof value === "object" && "__typename" in value && value["__typename"]) {
|
|
206
197
|
linkedType = value["__typename"];
|
|
207
198
|
}
|
|
@@ -447,32 +438,49 @@ class CacheInternal {
|
|
|
447
438
|
variables,
|
|
448
439
|
stepsFromConnection = null,
|
|
449
440
|
ignoreMasking,
|
|
450
|
-
fullCheck = false
|
|
441
|
+
fullCheck = false,
|
|
442
|
+
loading: generateLoading
|
|
451
443
|
}) {
|
|
452
444
|
if (parent === null) {
|
|
453
445
|
return { data: null, partial: false, stale: false, hasData: true };
|
|
454
446
|
}
|
|
455
447
|
const target = {};
|
|
456
448
|
if (selection.fragments) {
|
|
457
|
-
target[fragmentKey] =
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
449
|
+
target[fragmentKey] = {
|
|
450
|
+
loading: Boolean(generateLoading),
|
|
451
|
+
values: Object.fromEntries(
|
|
452
|
+
Object.entries(selection.fragments).filter(([, value]) => !generateLoading || value.loading).map(([key, value]) => [
|
|
453
|
+
key,
|
|
454
|
+
{
|
|
455
|
+
parent,
|
|
456
|
+
variables: evaluateFragmentVariables(
|
|
457
|
+
value.arguments,
|
|
458
|
+
variables ?? {}
|
|
459
|
+
)
|
|
460
|
+
}
|
|
461
|
+
])
|
|
462
|
+
)
|
|
463
|
+
};
|
|
466
464
|
}
|
|
467
465
|
let hasData = !!selection.fragments;
|
|
468
466
|
let partial = false;
|
|
469
467
|
let cascadeNull = false;
|
|
470
468
|
let stale = false;
|
|
471
469
|
const typename = this.storage.get(parent, "__typename").value;
|
|
472
|
-
let targetSelection = getFieldsForType(selection, typename);
|
|
470
|
+
let targetSelection = getFieldsForType(selection, typename, !!generateLoading);
|
|
473
471
|
for (const [
|
|
474
472
|
attributeName,
|
|
475
|
-
{
|
|
473
|
+
{
|
|
474
|
+
type,
|
|
475
|
+
keyRaw,
|
|
476
|
+
selection: fieldSelection,
|
|
477
|
+
nullable,
|
|
478
|
+
list,
|
|
479
|
+
visible,
|
|
480
|
+
directives,
|
|
481
|
+
loading: fieldLoading,
|
|
482
|
+
abstractHasRequired
|
|
483
|
+
}
|
|
476
484
|
] of Object.entries(targetSelection)) {
|
|
477
485
|
if (!visible && !ignoreMasking && !fullCheck) {
|
|
478
486
|
continue;
|
|
@@ -495,11 +503,17 @@ class CacheInternal {
|
|
|
495
503
|
}
|
|
496
504
|
const fieldTarget = visible || ignoreMasking ? target : {};
|
|
497
505
|
const key = evaluateKey(keyRaw, variables);
|
|
498
|
-
|
|
506
|
+
if (generateLoading && !fieldLoading) {
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
let { value } = this.storage.get(parent, key);
|
|
499
510
|
const dt_field = this.staleManager.getFieldTime(parent, key);
|
|
500
511
|
if (dt_field === null) {
|
|
501
512
|
stale = true;
|
|
502
513
|
}
|
|
514
|
+
if (generateLoading) {
|
|
515
|
+
value = void 0;
|
|
516
|
+
}
|
|
503
517
|
let nextStep = stepsFromConnection;
|
|
504
518
|
if (nextStep !== null) {
|
|
505
519
|
if (nextStep >= 2) {
|
|
@@ -515,7 +529,10 @@ class CacheInternal {
|
|
|
515
529
|
if (typeof value === "undefined" && !embeddedCursor) {
|
|
516
530
|
partial = true;
|
|
517
531
|
}
|
|
518
|
-
if (
|
|
532
|
+
if (generateLoading && fieldLoading?.kind === "value") {
|
|
533
|
+
fieldTarget[attributeName] = PendingValue;
|
|
534
|
+
hasData = true;
|
|
535
|
+
} else if (!generateLoading && typeof value === "undefined" || value === null) {
|
|
519
536
|
fieldTarget[attributeName] = null;
|
|
520
537
|
if (typeof value !== "undefined") {
|
|
521
538
|
hasData = true;
|
|
@@ -535,7 +552,8 @@ class CacheInternal {
|
|
|
535
552
|
linkedList: value,
|
|
536
553
|
stepsFromConnection: nextStep,
|
|
537
554
|
ignoreMasking: !!ignoreMasking,
|
|
538
|
-
fullCheck
|
|
555
|
+
fullCheck,
|
|
556
|
+
loading: generateLoading
|
|
539
557
|
});
|
|
540
558
|
fieldTarget[attributeName] = listValue.data;
|
|
541
559
|
if (listValue.partial) {
|
|
@@ -554,7 +572,8 @@ class CacheInternal {
|
|
|
554
572
|
variables,
|
|
555
573
|
stepsFromConnection: nextStep,
|
|
556
574
|
ignoreMasking,
|
|
557
|
-
fullCheck
|
|
575
|
+
fullCheck,
|
|
576
|
+
loading: generateLoading
|
|
558
577
|
});
|
|
559
578
|
fieldTarget[attributeName] = objectFields.data;
|
|
560
579
|
if (objectFields.partial) {
|
|
@@ -567,13 +586,27 @@ class CacheInternal {
|
|
|
567
586
|
hasData = true;
|
|
568
587
|
}
|
|
569
588
|
}
|
|
589
|
+
if (generateLoading && fieldLoading?.list) {
|
|
590
|
+
fieldTarget[attributeName] = wrapInLists(
|
|
591
|
+
Array.from({ length: fieldLoading.list.count }).fill(
|
|
592
|
+
fieldTarget[attributeName]
|
|
593
|
+
),
|
|
594
|
+
fieldLoading.list.depth - 1
|
|
595
|
+
);
|
|
596
|
+
}
|
|
570
597
|
if (fieldTarget[attributeName] === null && !nullable && !embeddedCursor) {
|
|
571
|
-
|
|
598
|
+
if (abstractHasRequired) {
|
|
599
|
+
target[attributeName] = {
|
|
600
|
+
__typename: "@required field missing; don't match this"
|
|
601
|
+
};
|
|
602
|
+
} else {
|
|
603
|
+
cascadeNull = true;
|
|
604
|
+
}
|
|
572
605
|
}
|
|
573
606
|
}
|
|
574
607
|
return {
|
|
575
608
|
data: cascadeNull ? null : target,
|
|
576
|
-
partial: hasData && partial,
|
|
609
|
+
partial: !generateLoading && hasData && partial,
|
|
577
610
|
stale: hasData && stale,
|
|
578
611
|
hasData
|
|
579
612
|
};
|
|
@@ -600,7 +633,8 @@ class CacheInternal {
|
|
|
600
633
|
linkedList,
|
|
601
634
|
stepsFromConnection,
|
|
602
635
|
ignoreMasking,
|
|
603
|
-
fullCheck
|
|
636
|
+
fullCheck,
|
|
637
|
+
loading
|
|
604
638
|
}) {
|
|
605
639
|
const result = [];
|
|
606
640
|
let partialData = false;
|
|
@@ -614,7 +648,8 @@ class CacheInternal {
|
|
|
614
648
|
linkedList: entry,
|
|
615
649
|
stepsFromConnection,
|
|
616
650
|
ignoreMasking,
|
|
617
|
-
fullCheck
|
|
651
|
+
fullCheck,
|
|
652
|
+
loading
|
|
618
653
|
});
|
|
619
654
|
result.push(nestedValue.data);
|
|
620
655
|
if (nestedValue.partial) {
|
|
@@ -637,7 +672,8 @@ class CacheInternal {
|
|
|
637
672
|
variables,
|
|
638
673
|
stepsFromConnection,
|
|
639
674
|
ignoreMasking,
|
|
640
|
-
fullCheck
|
|
675
|
+
fullCheck,
|
|
676
|
+
loading
|
|
641
677
|
});
|
|
642
678
|
result.push(data);
|
|
643
679
|
if (partial) {
|
|
@@ -744,6 +780,12 @@ function evaluateFragmentVariables(variables, args) {
|
|
|
744
780
|
Object.entries(variables).map(([key, value]) => [key, fragmentVariableValue(value, args)])
|
|
745
781
|
);
|
|
746
782
|
}
|
|
783
|
+
function wrapInLists(target, count = 0) {
|
|
784
|
+
if (count === 0) {
|
|
785
|
+
return target;
|
|
786
|
+
}
|
|
787
|
+
return wrapInLists([target], count - 1);
|
|
788
|
+
}
|
|
747
789
|
function fragmentVariableValue(value, args) {
|
|
748
790
|
if (value.kind === "StringValue") {
|
|
749
791
|
return value.value;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
function evaluateKey(key, variables =
|
|
1
|
+
function evaluateKey(key, variables = null) {
|
|
2
2
|
let evaluated = "";
|
|
3
3
|
let varName = "";
|
|
4
4
|
let inString = false;
|
|
@@ -8,7 +8,7 @@ function evaluateKey(key, variables = {}) {
|
|
|
8
8
|
varName += char;
|
|
9
9
|
continue;
|
|
10
10
|
}
|
|
11
|
-
const value = variables[varName.slice(1)];
|
|
11
|
+
const value = variables?.[varName.slice(1)];
|
|
12
12
|
evaluated += typeof value !== "undefined" ? JSON.stringify(value) : "undefined";
|
|
13
13
|
varName = "";
|
|
14
14
|
}
|
|
@@ -17,7 +17,7 @@ class InMemorySubscriptions {
|
|
|
17
17
|
parentType
|
|
18
18
|
}) {
|
|
19
19
|
const __typename = this.cache._internal_unstable.storage.get(parent, "__typename").value;
|
|
20
|
-
let targetSelection = getFieldsForType(selection, __typename);
|
|
20
|
+
let targetSelection = getFieldsForType(selection, __typename, false);
|
|
21
21
|
for (const fieldSelection of Object.values(targetSelection || {})) {
|
|
22
22
|
const {
|
|
23
23
|
keyRaw,
|
|
@@ -34,7 +34,7 @@ class InMemorySubscriptions {
|
|
|
34
34
|
let targetSelection2;
|
|
35
35
|
if (innerSelection) {
|
|
36
36
|
const __typename2 = this.cache._internal_unstable.storage.get(parent, "__typename").value;
|
|
37
|
-
targetSelection2 = getFieldsForType(innerSelection, __typename2);
|
|
37
|
+
targetSelection2 = getFieldsForType(innerSelection, __typename2, false);
|
|
38
38
|
}
|
|
39
39
|
this.addFieldSubscription({
|
|
40
40
|
id: parent,
|
|
@@ -145,7 +145,7 @@ class InMemorySubscriptions {
|
|
|
145
145
|
filters
|
|
146
146
|
} = selection;
|
|
147
147
|
const key = evaluateKey(keyRaw, variables);
|
|
148
|
-
const fieldSelection = innerSelection ? getFieldsForType(innerSelection, parentType) : void 0;
|
|
148
|
+
const fieldSelection = innerSelection ? getFieldsForType(innerSelection, parentType, false) : void 0;
|
|
149
149
|
this.addFieldSubscription({
|
|
150
150
|
id: parent,
|
|
151
151
|
key,
|
|
@@ -175,7 +175,7 @@ class InMemorySubscriptions {
|
|
|
175
175
|
linkedRecord,
|
|
176
176
|
"__typename"
|
|
177
177
|
).value;
|
|
178
|
-
let targetSelection2 = getFieldsForType(childSelection, __typename);
|
|
178
|
+
let targetSelection2 = getFieldsForType(childSelection, __typename, false);
|
|
179
179
|
this.addMany({
|
|
180
180
|
parent: linkedRecord,
|
|
181
181
|
variables,
|
|
@@ -194,7 +194,7 @@ class InMemorySubscriptions {
|
|
|
194
194
|
visited.push(id);
|
|
195
195
|
const linkedIDs = [];
|
|
196
196
|
const __typename = this.cache._internal_unstable.storage.get(id, "__typename").value;
|
|
197
|
-
let targetSelection = getFieldsForType(selection, __typename);
|
|
197
|
+
let targetSelection = getFieldsForType(selection, __typename, false);
|
|
198
198
|
for (const fieldSelection of Object.values(targetSelection || {})) {
|
|
199
199
|
const key = evaluateKey(fieldSelection.keyRaw, variables);
|
|
200
200
|
this.removeSubscribers(id, key, targets);
|
|
@@ -2,9 +2,12 @@ import type { HoudiniClient } from '.';
|
|
|
2
2
|
import type { Layer } from '../cache/storage';
|
|
3
3
|
import type { ConfigFile } from '../lib/config';
|
|
4
4
|
import { Writable } from '../lib/store';
|
|
5
|
-
import type { DocumentArtifact, QueryResult, GraphQLObject, SubscriptionSpec, CachePolicies } from '../lib/types';
|
|
6
|
-
export declare class DocumentStore<_Data extends GraphQLObject, _Input extends
|
|
5
|
+
import type { DocumentArtifact, QueryResult, GraphQLObject, SubscriptionSpec, CachePolicies, GraphQLVariables } from '../lib/types';
|
|
6
|
+
export declare class DocumentStore<_Data extends GraphQLObject, _Input extends GraphQLVariables> extends Writable<QueryResult<_Data, _Input>> {
|
|
7
7
|
#private;
|
|
8
|
+
pendingPromise: {
|
|
9
|
+
then: (val: any) => void;
|
|
10
|
+
} | null;
|
|
8
11
|
constructor({ artifact, plugins, pipeline, client, cache, initialValue, fetching, }: {
|
|
9
12
|
artifact: DocumentArtifact;
|
|
10
13
|
plugins?: ClientHooks[];
|
|
@@ -17,7 +20,7 @@ export declare class DocumentStore<_Data extends GraphQLObject, _Input extends R
|
|
|
17
20
|
send({ metadata, session, fetch, variables, policy, stuff, cacheParams, setup, silenceEcho, }?: SendParams): Promise<QueryResult<_Data, _Input>>;
|
|
18
21
|
cleanup(): Promise<void>;
|
|
19
22
|
}
|
|
20
|
-
declare function marshalVariables<_Data extends GraphQLObject, _Input extends
|
|
23
|
+
declare function marshalVariables<_Data extends GraphQLObject, _Input extends GraphQLVariables>(ctx: ClientPluginContext): Record<string, any>;
|
|
21
24
|
export type ClientPlugin = () => ClientHooks | null | (ClientHooks | ClientPlugin | null)[];
|
|
22
25
|
export type ClientHooks = {
|
|
23
26
|
start?: ClientPluginEnterPhase;
|
|
@@ -15,6 +15,7 @@ class DocumentStore extends Writable {
|
|
|
15
15
|
#plugins;
|
|
16
16
|
#lastVariables;
|
|
17
17
|
#lastContext = null;
|
|
18
|
+
pendingPromise = null;
|
|
18
19
|
constructor({
|
|
19
20
|
artifact,
|
|
20
21
|
plugins,
|
|
@@ -47,7 +48,15 @@ class DocumentStore extends Writable {
|
|
|
47
48
|
this.#plugins = pipeline ?? [
|
|
48
49
|
cachePolicy({
|
|
49
50
|
enabled: cache,
|
|
50
|
-
setFetching: (fetching2
|
|
51
|
+
setFetching: (fetching2, data) => {
|
|
52
|
+
this.update((state) => {
|
|
53
|
+
const newState = { ...state, fetching: fetching2 };
|
|
54
|
+
if (fetching2 && data) {
|
|
55
|
+
newState.data = data;
|
|
56
|
+
}
|
|
57
|
+
return newState;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
51
60
|
})(),
|
|
52
61
|
...plugins ?? []
|
|
53
62
|
];
|
|
@@ -87,7 +96,7 @@ class DocumentStore extends Writable {
|
|
|
87
96
|
const draft = context.draft();
|
|
88
97
|
draft.variables = variables ?? null;
|
|
89
98
|
context = context.apply(draft, false);
|
|
90
|
-
|
|
99
|
+
const promise = new Promise((resolve, reject) => {
|
|
91
100
|
const state = {
|
|
92
101
|
setup,
|
|
93
102
|
currentStep: 0,
|
|
@@ -96,12 +105,17 @@ class DocumentStore extends Writable {
|
|
|
96
105
|
promise: {
|
|
97
106
|
resolved: false,
|
|
98
107
|
resolve,
|
|
99
|
-
reject
|
|
108
|
+
reject,
|
|
109
|
+
then: (...args) => promise.then(...args)
|
|
100
110
|
},
|
|
101
111
|
context
|
|
102
112
|
};
|
|
113
|
+
if (this.pendingPromise === null) {
|
|
114
|
+
this.pendingPromise = state.promise;
|
|
115
|
+
}
|
|
103
116
|
this.#step("forward", state);
|
|
104
117
|
});
|
|
118
|
+
return await promise;
|
|
105
119
|
}
|
|
106
120
|
async cleanup() {
|
|
107
121
|
for (const plugin of this.#plugins) {
|
|
@@ -220,16 +234,15 @@ class DocumentStore extends Writable {
|
|
|
220
234
|
value
|
|
221
235
|
);
|
|
222
236
|
}
|
|
237
|
+
if (!ctx.silenceEcho || value.data !== this.state.data) {
|
|
238
|
+
this.set(value);
|
|
239
|
+
}
|
|
223
240
|
if (!ctx.promise.resolved) {
|
|
224
241
|
ctx.promise.resolve(value);
|
|
225
242
|
ctx.promise.resolved = true;
|
|
226
243
|
}
|
|
227
244
|
this.#lastContext = ctx.context.draft();
|
|
228
245
|
this.#lastVariables = this.#lastContext.stuff.inputs.marshaled;
|
|
229
|
-
if (ctx.silenceEcho && value.data === this.state.data) {
|
|
230
|
-
return;
|
|
231
|
-
}
|
|
232
|
-
this.set(value);
|
|
233
246
|
}
|
|
234
247
|
}
|
|
235
248
|
class ClientPluginContextWrapper {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/// <reference path="../../../../../houdini.d.ts" />
|
|
2
|
-
import type { DocumentArtifact, GraphQLObject, NestedList } from '../lib/types';
|
|
3
|
-
import type {
|
|
2
|
+
import type { DocumentArtifact, GraphQLVariables, GraphQLObject, NestedList } from '../lib/types';
|
|
3
|
+
import type { ClientHooks, ClientPlugin } from './documentStore';
|
|
4
4
|
import { DocumentStore } from './documentStore';
|
|
5
|
-
import {
|
|
6
|
-
export { DocumentStore, type ClientPlugin } from './documentStore';
|
|
5
|
+
import type { FetchParamFn, ThrowOnErrorOperations, ThrowOnErrorParams } from './plugins';
|
|
6
|
+
export { DocumentStore, type ClientPlugin, type SendParams } from './documentStore';
|
|
7
7
|
export { fetch, mutation, query, subscription } from './plugins';
|
|
8
|
-
type
|
|
8
|
+
export type HoudiniClientConstructorArgs = {
|
|
9
9
|
url: string;
|
|
10
10
|
fetchParams?: FetchParamFn;
|
|
11
11
|
plugins?: NestedList<ClientPlugin>;
|
|
@@ -19,9 +19,10 @@ export type ObserveParams<_Data extends GraphQLObject, _Artifact extends Documen
|
|
|
19
19
|
fetching?: boolean;
|
|
20
20
|
};
|
|
21
21
|
export declare class HoudiniClient {
|
|
22
|
-
#private;
|
|
23
22
|
url: string;
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
readonly plugins: ClientPlugin[];
|
|
24
|
+
readonly throwOnError_operations: ThrowOnErrorOperations[];
|
|
25
|
+
constructor({ url, fetchParams, plugins, pipeline, throwOnError, }: HoudiniClientConstructorArgs);
|
|
26
|
+
observe<_Data extends GraphQLObject, _Input extends GraphQLVariables>({ artifact, cache, initialValue, fetching, }: ObserveParams<_Data>): DocumentStore<_Data, _Input>;
|
|
26
27
|
}
|
|
27
28
|
export declare function createPluginHooks(plugins: ClientPlugin[]): ClientHooks[];
|
|
@@ -2,25 +2,33 @@ import { flatten } from "../lib/flatten";
|
|
|
2
2
|
import { DocumentStore } from "./documentStore";
|
|
3
3
|
import {
|
|
4
4
|
fetch as fetchPlugin,
|
|
5
|
+
fetchParams as fetchParamsPlugin,
|
|
6
|
+
fragment as fragmentPlugin,
|
|
5
7
|
mutation as mutationPlugin,
|
|
6
8
|
query as queryPlugin,
|
|
7
|
-
|
|
8
|
-
throwOnError as throwOnErrorPlugin,
|
|
9
|
-
fetchParams as fetchParamsPlugin
|
|
9
|
+
throwOnError as throwOnErrorPlugin
|
|
10
10
|
} from "./plugins";
|
|
11
11
|
import pluginsFromPlugins from "./plugins/injectedPlugins";
|
|
12
12
|
import { DocumentStore as DocumentStore2 } from "./documentStore";
|
|
13
13
|
import { fetch, mutation, query, subscription } from "./plugins";
|
|
14
14
|
class HoudiniClient {
|
|
15
15
|
url;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
plugins;
|
|
17
|
+
throwOnError_operations;
|
|
18
|
+
constructor({
|
|
19
|
+
url,
|
|
20
|
+
fetchParams,
|
|
21
|
+
plugins,
|
|
22
|
+
pipeline,
|
|
23
|
+
throwOnError
|
|
24
|
+
}) {
|
|
18
25
|
if (plugins && pipeline) {
|
|
19
26
|
throw new Error(
|
|
20
27
|
"A client cannot be given a pipeline and a list of plugins at the same time."
|
|
21
28
|
);
|
|
22
29
|
}
|
|
23
|
-
this
|
|
30
|
+
this.throwOnError_operations = throwOnError?.operations ?? [];
|
|
31
|
+
this.plugins = flatten(
|
|
24
32
|
[].concat(
|
|
25
33
|
throwOnError ? [throwOnErrorPlugin(throwOnError)] : [],
|
|
26
34
|
fetchParamsPlugin(fetchParams),
|
|
@@ -46,7 +54,7 @@ class HoudiniClient {
|
|
|
46
54
|
return new DocumentStore({
|
|
47
55
|
client: this,
|
|
48
56
|
artifact,
|
|
49
|
-
plugins: createPluginHooks(this
|
|
57
|
+
plugins: createPluginHooks(this.plugins),
|
|
50
58
|
cache,
|
|
51
59
|
initialValue,
|
|
52
60
|
fetching
|
|
@@ -3,7 +3,7 @@ import { Cache } from '../../cache/cache';
|
|
|
3
3
|
import type { ClientPlugin } from '../documentStore';
|
|
4
4
|
export declare const cachePolicy: ({ enabled, setFetching, cache: localCache, serverSideFallback, }: {
|
|
5
5
|
enabled: boolean;
|
|
6
|
-
setFetching: (val: boolean) => void;
|
|
6
|
+
setFetching: (val: boolean, data?: any) => void;
|
|
7
7
|
cache?: Cache | undefined;
|
|
8
8
|
serverSideFallback?: boolean | undefined;
|
|
9
9
|
}) => ClientPlugin;
|
|
@@ -12,7 +12,7 @@ const cachePolicy = ({
|
|
|
12
12
|
network(ctx, { initialValue, next, resolve, marshalVariables }) {
|
|
13
13
|
const { policy, artifact } = ctx;
|
|
14
14
|
let useCache = false;
|
|
15
|
-
if (enabled && artifact.kind === ArtifactKind.Query && !ctx.cacheParams?.disableRead) {
|
|
15
|
+
if (enabled && (artifact.kind === ArtifactKind.Query || artifact.kind === ArtifactKind.Fragment) && !ctx.cacheParams?.disableRead) {
|
|
16
16
|
if (policy !== CachePolicy.NetworkOnly) {
|
|
17
17
|
const value = localCache.read({
|
|
18
18
|
selection: artifact.selection,
|
|
@@ -53,7 +53,17 @@ const cachePolicy = ({
|
|
|
53
53
|
localCache._internal_unstable.collectGarbage();
|
|
54
54
|
}, 0);
|
|
55
55
|
}
|
|
56
|
-
|
|
56
|
+
if (!ctx.stuff?.silenceLoading) {
|
|
57
|
+
let fetchingState = null;
|
|
58
|
+
if (!useCache && "enableLoadingState" in artifact && artifact.enableLoadingState) {
|
|
59
|
+
fetchingState = localCache.read({
|
|
60
|
+
selection: artifact.selection,
|
|
61
|
+
variables: marshalVariables(ctx),
|
|
62
|
+
loading: true
|
|
63
|
+
}).data;
|
|
64
|
+
}
|
|
65
|
+
setFetching(!useCache, fetchingState);
|
|
66
|
+
}
|
|
57
67
|
return next(ctx);
|
|
58
68
|
},
|
|
59
69
|
afterNetwork(ctx, { resolve, value, marshalVariables }) {
|
|
@@ -21,6 +21,7 @@ export type FetchContext = {
|
|
|
21
21
|
export type RequestHandlerArgs = FetchContext & FetchParams;
|
|
22
22
|
export type RequestHandler<_Data = any> = (args: RequestHandlerArgs) => Promise<RequestPayload<_Data>>;
|
|
23
23
|
export type FetchParams = {
|
|
24
|
+
name: string;
|
|
24
25
|
text: string;
|
|
25
26
|
hash: string;
|
|
26
27
|
variables: {
|
|
@@ -8,6 +8,7 @@ const fetch = (target) => {
|
|
|
8
8
|
}
|
|
9
9
|
const fetch2 = ctx.fetch ?? globalThis.fetch;
|
|
10
10
|
const fetchParams = {
|
|
11
|
+
name: ctx.artifact.name,
|
|
11
12
|
text: ctx.text,
|
|
12
13
|
hash: ctx.hash,
|
|
13
14
|
variables: marshalVariables(ctx)
|
|
@@ -48,10 +49,10 @@ const defaultFetch = (url, params) => {
|
|
|
48
49
|
"Could not find configured client url. Please specify one in your HoudiniClient constructor."
|
|
49
50
|
);
|
|
50
51
|
}
|
|
51
|
-
return async ({ fetch: fetch2, text, variables }) => {
|
|
52
|
+
return async ({ fetch: fetch2, name, text, variables }) => {
|
|
52
53
|
const result = await fetch2(url, {
|
|
53
54
|
method: "POST",
|
|
54
|
-
body: JSON.stringify({ query: text, variables }),
|
|
55
|
+
body: JSON.stringify({ operationName: name, query: text, variables }),
|
|
55
56
|
...params,
|
|
56
57
|
headers: {
|
|
57
58
|
Accept: "application/graphql+json, application/json",
|
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import cache from "../../cache";
|
|
2
|
+
import { deepEquals } from "../../lib/deepEquals";
|
|
2
3
|
import { ArtifactKind, DataSource } from "../../lib/types";
|
|
3
4
|
import { documentPlugin } from "../utils";
|
|
4
5
|
const fragment = documentPlugin(ArtifactKind.Fragment, function() {
|
|
5
6
|
let subscriptionSpec = null;
|
|
7
|
+
let lastReference = null;
|
|
6
8
|
return {
|
|
7
9
|
start(ctx, { next, resolve, variablesChanged, marshalVariables }) {
|
|
8
10
|
if (!ctx.stuff.parentID) {
|
|
9
11
|
return next(ctx);
|
|
10
12
|
}
|
|
11
|
-
|
|
13
|
+
const currentReference = {
|
|
14
|
+
parent: ctx.stuff.parentID,
|
|
15
|
+
variables: marshalVariables(ctx)
|
|
16
|
+
};
|
|
17
|
+
if (!ctx.cacheParams?.disableSubscriptions && (!deepEquals(lastReference, currentReference) || variablesChanged(ctx))) {
|
|
12
18
|
if (subscriptionSpec) {
|
|
13
19
|
cache.unsubscribe(subscriptionSpec, subscriptionSpec.variables?.() || {});
|
|
14
20
|
}
|
|
@@ -31,6 +37,7 @@ const fragment = documentPlugin(ArtifactKind.Fragment, function() {
|
|
|
31
37
|
}
|
|
32
38
|
};
|
|
33
39
|
cache.subscribe(subscriptionSpec, variables);
|
|
40
|
+
lastReference = currentReference;
|
|
34
41
|
}
|
|
35
42
|
next(ctx);
|
|
36
43
|
},
|
|
@@ -18,10 +18,11 @@ const query = documentPlugin(ArtifactKind.Query, function() {
|
|
|
18
18
|
cache.unsubscribe(subscriptionSpec, subscriptionSpec.variables?.() || {});
|
|
19
19
|
}
|
|
20
20
|
lastVariables = { ...marshalVariables(ctx) };
|
|
21
|
+
const variables = lastVariables;
|
|
21
22
|
subscriptionSpec = {
|
|
22
23
|
rootType: ctx.artifact.rootType,
|
|
23
24
|
selection: ctx.artifact.selection,
|
|
24
|
-
variables: () =>
|
|
25
|
+
variables: () => variables,
|
|
25
26
|
set: (newValue) => {
|
|
26
27
|
resolve(ctx, {
|
|
27
28
|
data: newValue,
|
|
@@ -3,6 +3,7 @@ export declare function subscription(factory: SubscriptionHandler): import("../d
|
|
|
3
3
|
export type SubscriptionHandler = (ctx: ClientPluginContext) => SubscriptionClient;
|
|
4
4
|
export type SubscriptionClient = {
|
|
5
5
|
subscribe: (payload: {
|
|
6
|
+
operationName: string;
|
|
6
7
|
query: string;
|
|
7
8
|
variables?: {};
|
|
8
9
|
}, handlers: {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { QueryResult } from '../../lib';
|
|
2
2
|
import type { ClientPlugin, ClientPluginContext } from '../documentStore';
|
|
3
|
+
export type ThrowOnErrorOperations = 'all' | 'query' | 'mutation' | 'subscription';
|
|
3
4
|
export type ThrowOnErrorParams = {
|
|
4
|
-
operations:
|
|
5
|
+
operations: ThrowOnErrorOperations[];
|
|
5
6
|
error?: (errors: NonNullable<QueryResult<any, any>['errors']>, ctx: ClientPluginContext) => unknown;
|
|
6
7
|
};
|
|
7
8
|
export declare const throwOnError: ({ operations, error }: ThrowOnErrorParams) => ClientPlugin;
|
|
@@ -24,7 +24,8 @@ function defaultConfigValues(file) {
|
|
|
24
24
|
};
|
|
25
25
|
}
|
|
26
26
|
function keyFieldsForType(configFile, type) {
|
|
27
|
-
|
|
27
|
+
const withDefault = defaultConfigValues(configFile);
|
|
28
|
+
return withDefault.types?.[type]?.keys || withDefault.defaultKeys;
|
|
28
29
|
}
|
|
29
30
|
function computeID(configFile, type, data) {
|
|
30
31
|
const fields = keyFieldsForType(configFile, type);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { GraphQLObject, PageInfo } from './types';
|
|
2
|
+
export declare function nullPageInfo(): PageInfo;
|
|
3
|
+
export declare function missingPageSizeError(fnName: string): {
|
|
4
|
+
message: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function extractPageInfo(data: any, path: string[]): PageInfo;
|
|
7
|
+
export declare function countPage<_Data extends GraphQLObject>(source: string[], value: _Data | null): number;
|