houdini 1.3.1 → 1.4.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/build/cmd-cjs/index.js +143 -28
- package/build/cmd-esm/index.js +143 -28
- package/build/codegen-cjs/index.js +123 -10
- package/build/codegen-esm/index.js +123 -10
- package/build/lib/config.d.ts +1 -0
- package/build/lib/router/types.d.ts +3 -1
- package/build/lib-cjs/index.js +92 -19
- package/build/lib-esm/index.js +91 -19
- package/build/runtime/cache/cache.d.ts +1 -1
- package/build/runtime/cache/lists.d.ts +3 -1
- package/build/runtime/lib/config.d.ts +10 -1
- package/build/runtime/lib/types.d.ts +14 -2
- package/build/runtime-cjs/cache/cache.d.ts +1 -1
- package/build/runtime-cjs/cache/cache.js +31 -5
- package/build/runtime-cjs/cache/lists.d.ts +3 -1
- package/build/runtime-cjs/cache/lists.js +15 -1
- package/build/runtime-cjs/client/documentStore.js +27 -7
- package/build/runtime-cjs/client/plugins/fetch.js +5 -0
- package/build/runtime-cjs/lib/config.d.ts +10 -1
- package/build/runtime-cjs/lib/types.d.ts +14 -2
- package/build/runtime-cjs/lib/types.js +7 -0
- package/build/runtime-cjs/router/match.js +1 -1
- package/build/runtime-esm/cache/cache.d.ts +1 -1
- package/build/runtime-esm/cache/cache.js +31 -5
- package/build/runtime-esm/cache/lists.d.ts +3 -1
- package/build/runtime-esm/cache/lists.js +15 -1
- package/build/runtime-esm/client/documentStore.js +28 -8
- package/build/runtime-esm/client/plugins/fetch.js +5 -0
- package/build/runtime-esm/lib/config.d.ts +10 -1
- package/build/runtime-esm/lib/types.d.ts +14 -2
- package/build/runtime-esm/lib/types.js +6 -0
- package/build/runtime-esm/router/match.js +1 -1
- package/build/test-cjs/index.js +129 -15
- package/build/test-esm/index.js +129 -15
- package/build/vite/ast.d.ts +8 -2
- package/build/vite-cjs/index.js +374 -255
- package/build/vite-esm/index.js +374 -255
- package/package.json +3 -3
package/build/lib-esm/index.js
CHANGED
|
@@ -61448,6 +61448,11 @@ var CachePolicy = {
|
|
|
61448
61448
|
CacheAndNetwork: "CacheAndNetwork",
|
|
61449
61449
|
NoCache: "NoCache"
|
|
61450
61450
|
};
|
|
61451
|
+
var DedupeMatchMode = {
|
|
61452
|
+
Variables: "Variables",
|
|
61453
|
+
Operation: "Operation",
|
|
61454
|
+
None: "None"
|
|
61455
|
+
};
|
|
61451
61456
|
var PaginateMode = {
|
|
61452
61457
|
Infinite: "Infinite",
|
|
61453
61458
|
SinglePage: "SinglePage"
|
|
@@ -63894,7 +63899,18 @@ var ListManager = class {
|
|
|
63894
63899
|
}
|
|
63895
63900
|
lists = /* @__PURE__ */ new Map();
|
|
63896
63901
|
listsByField = /* @__PURE__ */ new Map();
|
|
63897
|
-
get(listName, id, allLists) {
|
|
63902
|
+
get(listName, id, allLists, skipMatches) {
|
|
63903
|
+
const lists = this.getLists(listName, id, allLists);
|
|
63904
|
+
if (!lists) {
|
|
63905
|
+
return null;
|
|
63906
|
+
}
|
|
63907
|
+
if (skipMatches) {
|
|
63908
|
+
return new ListCollection(lists.lists.filter((list) => !skipMatches.has(list.fieldRef)));
|
|
63909
|
+
} else {
|
|
63910
|
+
return lists;
|
|
63911
|
+
}
|
|
63912
|
+
}
|
|
63913
|
+
getLists(listName, id, allLists) {
|
|
63898
63914
|
const matches = this.lists.get(listName);
|
|
63899
63915
|
if (!matches || matches.size === 0) {
|
|
63900
63916
|
return null;
|
|
@@ -64016,6 +64032,9 @@ var List = class {
|
|
|
64016
64032
|
this.manager = manager;
|
|
64017
64033
|
this.abstract = abstract;
|
|
64018
64034
|
}
|
|
64035
|
+
get fieldRef() {
|
|
64036
|
+
return `${this.recordID}.${this.key}`;
|
|
64037
|
+
}
|
|
64019
64038
|
when(when) {
|
|
64020
64039
|
return this.manager.lists.get(this.name).get(this.recordID).when(when);
|
|
64021
64040
|
}
|
|
@@ -65168,8 +65187,8 @@ var Cache = class {
|
|
|
65168
65187
|
variables
|
|
65169
65188
|
);
|
|
65170
65189
|
}
|
|
65171
|
-
list(name, parentID, allLists) {
|
|
65172
|
-
const handler = this._internal_unstable.lists.get(name, parentID, allLists);
|
|
65190
|
+
list(name, parentID, allLists, skipMatches) {
|
|
65191
|
+
const handler = this._internal_unstable.lists.get(name, parentID, allLists, skipMatches);
|
|
65173
65192
|
if (!handler) {
|
|
65174
65193
|
throw new Error(
|
|
65175
65194
|
`Cannot find list with name: ${name}${parentID ? " under parent " + parentID : ""}. Is it possible that the query is not mounted?`
|
|
@@ -65584,6 +65603,7 @@ var CacheInternal = class {
|
|
|
65584
65603
|
});
|
|
65585
65604
|
}
|
|
65586
65605
|
}
|
|
65606
|
+
const processedOperations = /* @__PURE__ */ new Set();
|
|
65587
65607
|
for (const operation of operations || []) {
|
|
65588
65608
|
let parentID;
|
|
65589
65609
|
if (operation.parentID) {
|
|
@@ -65603,7 +65623,12 @@ var CacheInternal = class {
|
|
|
65603
65623
|
const targets = Array.isArray(value) ? value : [value];
|
|
65604
65624
|
for (const target of targets) {
|
|
65605
65625
|
if (operation.action === "insert" && target instanceof Object && fieldSelection && operation.list) {
|
|
65606
|
-
this.cache.list(
|
|
65626
|
+
this.cache.list(
|
|
65627
|
+
operation.list,
|
|
65628
|
+
parentID,
|
|
65629
|
+
operation.target === "all",
|
|
65630
|
+
processedOperations
|
|
65631
|
+
).when(operation.when).addToList(
|
|
65607
65632
|
fieldSelection,
|
|
65608
65633
|
target,
|
|
65609
65634
|
variables,
|
|
@@ -65611,7 +65636,12 @@ var CacheInternal = class {
|
|
|
65611
65636
|
layer
|
|
65612
65637
|
);
|
|
65613
65638
|
} else if (operation.action === "toggle" && target instanceof Object && fieldSelection && operation.list) {
|
|
65614
|
-
this.cache.list(
|
|
65639
|
+
this.cache.list(
|
|
65640
|
+
operation.list,
|
|
65641
|
+
parentID,
|
|
65642
|
+
operation.target === "all",
|
|
65643
|
+
processedOperations
|
|
65644
|
+
).when(operation.when).toggleElement({
|
|
65615
65645
|
selection: fieldSelection,
|
|
65616
65646
|
data: target,
|
|
65617
65647
|
variables,
|
|
@@ -65619,7 +65649,12 @@ var CacheInternal = class {
|
|
|
65619
65649
|
layer
|
|
65620
65650
|
});
|
|
65621
65651
|
} else if (operation.action === "remove" && target instanceof Object && fieldSelection && operation.list) {
|
|
65622
|
-
this.cache.list(
|
|
65652
|
+
this.cache.list(
|
|
65653
|
+
operation.list,
|
|
65654
|
+
parentID,
|
|
65655
|
+
operation.target === "all",
|
|
65656
|
+
processedOperations
|
|
65657
|
+
).when(operation.when).remove(target, variables, layer);
|
|
65623
65658
|
} else if (operation.action === "delete" && operation.type && target) {
|
|
65624
65659
|
const targetID = this.id(operation.type, target);
|
|
65625
65660
|
if (!targetID) {
|
|
@@ -65631,6 +65666,16 @@ var CacheInternal = class {
|
|
|
65631
65666
|
this.cache.delete(targetID, layer);
|
|
65632
65667
|
}
|
|
65633
65668
|
}
|
|
65669
|
+
if (operation.list) {
|
|
65670
|
+
const matchingLists = this.cache.list(
|
|
65671
|
+
operation.list,
|
|
65672
|
+
parentID,
|
|
65673
|
+
operation.target === "all"
|
|
65674
|
+
);
|
|
65675
|
+
for (const list of matchingLists.lists) {
|
|
65676
|
+
processedOperations.add(list.fieldRef);
|
|
65677
|
+
}
|
|
65678
|
+
}
|
|
65634
65679
|
}
|
|
65635
65680
|
}
|
|
65636
65681
|
return toNotify;
|
|
@@ -66147,6 +66192,11 @@ var defaultFetch = (url, params) => {
|
|
|
66147
66192
|
...params?.headers
|
|
66148
66193
|
}
|
|
66149
66194
|
});
|
|
66195
|
+
if (!result.ok && !result.headers.get("content-type")?.startsWith("application/json") && !result.headers.get("content-type")?.startsWith("application/graphql+json")) {
|
|
66196
|
+
throw new Error(
|
|
66197
|
+
`Failed to fetch: server returned invalid response with error ${result.status}: ${result.statusText}`
|
|
66198
|
+
);
|
|
66199
|
+
}
|
|
66150
66200
|
return await result.json();
|
|
66151
66201
|
};
|
|
66152
66202
|
};
|
|
@@ -66967,7 +67017,8 @@ var DocumentStore = class extends Writable {
|
|
|
66967
67017
|
pendingPromise = null;
|
|
66968
67018
|
serverSideFallback;
|
|
66969
67019
|
controllerKey(variables) {
|
|
66970
|
-
|
|
67020
|
+
const usedVariables = "dedupe" in this.artifact && this.artifact.dedupe?.match !== DedupeMatchMode.Variables ? {} : variables;
|
|
67021
|
+
return `${this.artifact.name}@${stableStringify(usedVariables)}`;
|
|
66971
67022
|
}
|
|
66972
67023
|
constructor({
|
|
66973
67024
|
artifact,
|
|
@@ -67029,16 +67080,20 @@ var DocumentStore = class extends Writable {
|
|
|
67029
67080
|
silenceEcho = false,
|
|
67030
67081
|
abortController = new AbortController()
|
|
67031
67082
|
} = {}) {
|
|
67032
|
-
if ("dedupe" in this.artifact) {
|
|
67033
|
-
|
|
67034
|
-
|
|
67035
|
-
|
|
67036
|
-
inflightRequests[
|
|
67083
|
+
if ("dedupe" in this.artifact && this.artifact.dedupe && this.artifact.dedupe.match !== "None") {
|
|
67084
|
+
const dedupeKey = this.controllerKey(variables);
|
|
67085
|
+
if (inflightRequests[dedupeKey]) {
|
|
67086
|
+
if (this.artifact.dedupe.cancel === "first") {
|
|
67087
|
+
inflightRequests[dedupeKey].controller.abort();
|
|
67088
|
+
inflightRequests[dedupeKey].controller = abortController;
|
|
67037
67089
|
} else {
|
|
67038
67090
|
abortController.abort();
|
|
67039
67091
|
}
|
|
67040
67092
|
} else {
|
|
67041
|
-
inflightRequests[
|
|
67093
|
+
inflightRequests[dedupeKey] = {
|
|
67094
|
+
variables,
|
|
67095
|
+
controller: abortController
|
|
67096
|
+
};
|
|
67042
67097
|
}
|
|
67043
67098
|
}
|
|
67044
67099
|
let context = new ClientPluginContextWrapper({
|
|
@@ -67360,6 +67415,21 @@ function marshalVariables(ctx) {
|
|
|
67360
67415
|
function variablesChanged(ctx) {
|
|
67361
67416
|
return ctx.stuff.inputs?.changed;
|
|
67362
67417
|
}
|
|
67418
|
+
function stableStringify(obj) {
|
|
67419
|
+
return JSON.stringify(sortObject(obj));
|
|
67420
|
+
}
|
|
67421
|
+
function sortObject(obj) {
|
|
67422
|
+
if (obj === null || typeof obj !== "object") {
|
|
67423
|
+
return obj;
|
|
67424
|
+
}
|
|
67425
|
+
if (Array.isArray(obj)) {
|
|
67426
|
+
return obj.map(sortObject);
|
|
67427
|
+
}
|
|
67428
|
+
return Object.keys(obj).sort().reduce((result, key) => {
|
|
67429
|
+
result[key] = sortObject(obj[key]);
|
|
67430
|
+
return result;
|
|
67431
|
+
}, {});
|
|
67432
|
+
}
|
|
67363
67433
|
|
|
67364
67434
|
// src/runtime/client/plugins/injectedPlugins.ts
|
|
67365
67435
|
var plugins = [];
|
|
@@ -67796,8 +67866,9 @@ var Config = class {
|
|
|
67796
67866
|
localSchema;
|
|
67797
67867
|
projectRoot;
|
|
67798
67868
|
schema;
|
|
67869
|
+
runtimeDir;
|
|
67799
67870
|
schemaPath;
|
|
67800
|
-
persistedQueriesPath
|
|
67871
|
+
persistedQueriesPath;
|
|
67801
67872
|
exclude;
|
|
67802
67873
|
scalars;
|
|
67803
67874
|
module = "esm";
|
|
@@ -67838,6 +67909,7 @@ var Config = class {
|
|
|
67838
67909
|
let {
|
|
67839
67910
|
schema,
|
|
67840
67911
|
schemaPath = "./schema.graphql",
|
|
67912
|
+
runtimeDir = "$houdini",
|
|
67841
67913
|
exclude = [],
|
|
67842
67914
|
module = "esm",
|
|
67843
67915
|
scalars,
|
|
@@ -67876,6 +67948,7 @@ var Config = class {
|
|
|
67876
67948
|
this.projectRoot = dirname(
|
|
67877
67949
|
projectDir ? join2(process.cwd(), projectDir) : filepath
|
|
67878
67950
|
);
|
|
67951
|
+
this.runtimeDir = runtimeDir;
|
|
67879
67952
|
this.scalars = scalars;
|
|
67880
67953
|
this.cacheBufferSize = cacheBufferSize;
|
|
67881
67954
|
this.defaultCachePolicy = defaultCachePolicy;
|
|
@@ -67890,11 +67963,9 @@ var Config = class {
|
|
|
67890
67963
|
this.schemaPollInterval = watchSchema?.interval === void 0 ? 2e3 : watchSchema.interval;
|
|
67891
67964
|
this.schemaPollTimeout = watchSchema?.timeout ?? 3e4;
|
|
67892
67965
|
this.schemaPollHeaders = watchSchema?.headers ?? {};
|
|
67893
|
-
this.rootDir = join2(this.projectRoot,
|
|
67966
|
+
this.rootDir = join2(this.projectRoot, this.runtimeDir);
|
|
67967
|
+
this.persistedQueriesPath = persistedQueriesPath ?? join2(this.rootDir, "persisted_queries.json");
|
|
67894
67968
|
this.#fragmentVariableMaps = {};
|
|
67895
|
-
if (persistedQueriesPath) {
|
|
67896
|
-
this.persistedQueriesPath = persistedQueriesPath;
|
|
67897
|
-
}
|
|
67898
67969
|
if (defaultKeys) {
|
|
67899
67970
|
this.defaultKeys = defaultKeys;
|
|
67900
67971
|
}
|
|
@@ -69206,7 +69277,7 @@ function exec(match, params) {
|
|
|
69206
69277
|
if (param.rest)
|
|
69207
69278
|
result[param.name] = "";
|
|
69208
69279
|
} else {
|
|
69209
|
-
result[param.name] = value;
|
|
69280
|
+
result[param.name] = decodeURIComponent(value);
|
|
69210
69281
|
}
|
|
69211
69282
|
}
|
|
69212
69283
|
if (buffered)
|
|
@@ -69733,6 +69804,7 @@ export {
|
|
|
69733
69804
|
CompiledSubscriptionKind,
|
|
69734
69805
|
Config,
|
|
69735
69806
|
DataSource,
|
|
69807
|
+
DedupeMatchMode,
|
|
69736
69808
|
DocumentStore,
|
|
69737
69809
|
HoudiniClient,
|
|
69738
69810
|
HoudiniError,
|
|
@@ -35,7 +35,7 @@ export declare class Cache {
|
|
|
35
35
|
};
|
|
36
36
|
subscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
37
37
|
unsubscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
38
|
-
list(name: string, parentID?: string, allLists?: boolean): ListCollection;
|
|
38
|
+
list(name: string, parentID?: string, allLists?: boolean, skipMatches?: Set<string>): ListCollection;
|
|
39
39
|
registerKeyMap(source: string, mapped: string): void;
|
|
40
40
|
delete(id: string, layer?: Layer): void;
|
|
41
41
|
setConfig(config: ConfigFile): void;
|
|
@@ -7,7 +7,8 @@ export declare class ListManager {
|
|
|
7
7
|
constructor(cache: Cache, rootID: string);
|
|
8
8
|
lists: Map<string, Map<string, ListCollection>>;
|
|
9
9
|
private listsByField;
|
|
10
|
-
get(listName: string, id?: string, allLists?: boolean): ListCollection | null
|
|
10
|
+
get(listName: string, id?: string, allLists?: boolean, skipMatches?: Set<string>): ListCollection | null;
|
|
11
|
+
getLists(listName: string, id?: string, allLists?: boolean): ListCollection | null | undefined;
|
|
11
12
|
remove(listName: string, id: string): void;
|
|
12
13
|
add(list: {
|
|
13
14
|
name: string;
|
|
@@ -41,6 +42,7 @@ export declare class List {
|
|
|
41
42
|
constructor({ name, recordID, recordType, key, listType, selection, when, filters, connection, manager, abstract, }: Parameters<ListManager['add']>[0] & {
|
|
42
43
|
manager: ListManager;
|
|
43
44
|
});
|
|
45
|
+
get fieldRef(): string;
|
|
44
46
|
when(when?: ListWhen): ListCollection;
|
|
45
47
|
append({ selection, data, variables, layer, }: {
|
|
46
48
|
selection: SubscriptionSelection;
|
|
@@ -73,6 +73,10 @@ export type ConfigFile = {
|
|
|
73
73
|
* Specifies whether the default paginate mode is Infinite or SinglePage. (default: `Infinite`)
|
|
74
74
|
*/
|
|
75
75
|
defaultPaginateMode?: PaginateModes;
|
|
76
|
+
/**
|
|
77
|
+
* Prevents the runtime from deduplicating pagination requests
|
|
78
|
+
*/
|
|
79
|
+
supressPaginationDeduplication?: boolean;
|
|
76
80
|
/**
|
|
77
81
|
* A list of fields to use when computing a record’s id. The default value is ['id']. For more information: https://www.houdinigraphql.com/guides/caching-data#custom-ids
|
|
78
82
|
*/
|
|
@@ -95,7 +99,7 @@ export type ConfigFile = {
|
|
|
95
99
|
*/
|
|
96
100
|
watchSchema?: WatchSchemaConfig;
|
|
97
101
|
/**
|
|
98
|
-
* Specifies the the persisted queries path and file. (default:
|
|
102
|
+
* Specifies the the persisted queries path and file. (default: `<rootDir>/persisted_queries.json`)
|
|
99
103
|
*/
|
|
100
104
|
persistedQueriesPath?: string;
|
|
101
105
|
/**
|
|
@@ -107,6 +111,11 @@ export type ConfigFile = {
|
|
|
107
111
|
* @default process.cwd()
|
|
108
112
|
*/
|
|
109
113
|
projectDir?: string;
|
|
114
|
+
/**
|
|
115
|
+
* The relative path from your project directory pointing to your output directory.
|
|
116
|
+
* @default `$houdini`
|
|
117
|
+
*/
|
|
118
|
+
runtimeDir?: string;
|
|
110
119
|
/**
|
|
111
120
|
* For now, the cache's imperative API is considered unstable. In order to suppress the warning,
|
|
112
121
|
* you must enable this flag.
|
|
@@ -7,6 +7,12 @@ export declare const CachePolicy: {
|
|
|
7
7
|
readonly NoCache: "NoCache";
|
|
8
8
|
};
|
|
9
9
|
export type CachePolicies = ValuesOf<typeof CachePolicy>;
|
|
10
|
+
export declare const DedupeMatchMode: {
|
|
11
|
+
readonly Variables: "Variables";
|
|
12
|
+
readonly Operation: "Operation";
|
|
13
|
+
readonly None: "None";
|
|
14
|
+
};
|
|
15
|
+
export type DedupeMatchModes = ValuesOf<typeof DedupeMatchMode>;
|
|
10
16
|
export declare const PaginateMode: {
|
|
11
17
|
readonly Infinite: "Infinite";
|
|
12
18
|
readonly SinglePage: "SinglePage";
|
|
@@ -60,11 +66,17 @@ export type QueryArtifact = BaseCompiledDocument<'HoudiniQuery'> & {
|
|
|
60
66
|
policy?: CachePolicies;
|
|
61
67
|
partial?: boolean;
|
|
62
68
|
enableLoadingState?: 'global' | 'local';
|
|
63
|
-
dedupe?:
|
|
69
|
+
dedupe?: {
|
|
70
|
+
cancel: 'first' | 'last';
|
|
71
|
+
match: DedupeMatchModes;
|
|
72
|
+
};
|
|
64
73
|
};
|
|
65
74
|
export type MutationArtifact = BaseCompiledDocument<'HoudiniMutation'> & {
|
|
66
75
|
optimisticKeys?: boolean;
|
|
67
|
-
dedupe?:
|
|
76
|
+
dedupe?: {
|
|
77
|
+
cancel: 'first' | 'last';
|
|
78
|
+
match: DedupeMatchModes;
|
|
79
|
+
};
|
|
68
80
|
};
|
|
69
81
|
export type FragmentArtifact = BaseCompiledDocument<'HoudiniFragment'> & {
|
|
70
82
|
enableLoadingState?: 'global' | 'local';
|
|
@@ -35,7 +35,7 @@ export declare class Cache {
|
|
|
35
35
|
};
|
|
36
36
|
subscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
37
37
|
unsubscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
38
|
-
list(name: string, parentID?: string, allLists?: boolean): ListCollection;
|
|
38
|
+
list(name: string, parentID?: string, allLists?: boolean, skipMatches?: Set<string>): ListCollection;
|
|
39
39
|
registerKeyMap(source: string, mapped: string): void;
|
|
40
40
|
delete(id: string, layer?: Layer): void;
|
|
41
41
|
setConfig(config: ConfigFile): void;
|
|
@@ -100,8 +100,8 @@ class Cache {
|
|
|
100
100
|
variables
|
|
101
101
|
);
|
|
102
102
|
}
|
|
103
|
-
list(name, parentID, allLists) {
|
|
104
|
-
const handler = this._internal_unstable.lists.get(name, parentID, allLists);
|
|
103
|
+
list(name, parentID, allLists, skipMatches) {
|
|
104
|
+
const handler = this._internal_unstable.lists.get(name, parentID, allLists, skipMatches);
|
|
105
105
|
if (!handler) {
|
|
106
106
|
throw new Error(
|
|
107
107
|
`Cannot find list with name: ${name}${parentID ? " under parent " + parentID : ""}. Is it possible that the query is not mounted?`
|
|
@@ -516,6 +516,7 @@ class CacheInternal {
|
|
|
516
516
|
});
|
|
517
517
|
}
|
|
518
518
|
}
|
|
519
|
+
const processedOperations = /* @__PURE__ */ new Set();
|
|
519
520
|
for (const operation of operations || []) {
|
|
520
521
|
let parentID;
|
|
521
522
|
if (operation.parentID) {
|
|
@@ -535,7 +536,12 @@ class CacheInternal {
|
|
|
535
536
|
const targets = Array.isArray(value) ? value : [value];
|
|
536
537
|
for (const target of targets) {
|
|
537
538
|
if (operation.action === "insert" && target instanceof Object && fieldSelection && operation.list) {
|
|
538
|
-
this.cache.list(
|
|
539
|
+
this.cache.list(
|
|
540
|
+
operation.list,
|
|
541
|
+
parentID,
|
|
542
|
+
operation.target === "all",
|
|
543
|
+
processedOperations
|
|
544
|
+
).when(operation.when).addToList(
|
|
539
545
|
fieldSelection,
|
|
540
546
|
target,
|
|
541
547
|
variables,
|
|
@@ -543,7 +549,12 @@ class CacheInternal {
|
|
|
543
549
|
layer
|
|
544
550
|
);
|
|
545
551
|
} else if (operation.action === "toggle" && target instanceof Object && fieldSelection && operation.list) {
|
|
546
|
-
this.cache.list(
|
|
552
|
+
this.cache.list(
|
|
553
|
+
operation.list,
|
|
554
|
+
parentID,
|
|
555
|
+
operation.target === "all",
|
|
556
|
+
processedOperations
|
|
557
|
+
).when(operation.when).toggleElement({
|
|
547
558
|
selection: fieldSelection,
|
|
548
559
|
data: target,
|
|
549
560
|
variables,
|
|
@@ -551,7 +562,12 @@ class CacheInternal {
|
|
|
551
562
|
layer
|
|
552
563
|
});
|
|
553
564
|
} else if (operation.action === "remove" && target instanceof Object && fieldSelection && operation.list) {
|
|
554
|
-
this.cache.list(
|
|
565
|
+
this.cache.list(
|
|
566
|
+
operation.list,
|
|
567
|
+
parentID,
|
|
568
|
+
operation.target === "all",
|
|
569
|
+
processedOperations
|
|
570
|
+
).when(operation.when).remove(target, variables, layer);
|
|
555
571
|
} else if (operation.action === "delete" && operation.type && target) {
|
|
556
572
|
const targetID = this.id(operation.type, target);
|
|
557
573
|
if (!targetID) {
|
|
@@ -563,6 +579,16 @@ class CacheInternal {
|
|
|
563
579
|
this.cache.delete(targetID, layer);
|
|
564
580
|
}
|
|
565
581
|
}
|
|
582
|
+
if (operation.list) {
|
|
583
|
+
const matchingLists = this.cache.list(
|
|
584
|
+
operation.list,
|
|
585
|
+
parentID,
|
|
586
|
+
operation.target === "all"
|
|
587
|
+
);
|
|
588
|
+
for (const list of matchingLists.lists) {
|
|
589
|
+
processedOperations.add(list.fieldRef);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
566
592
|
}
|
|
567
593
|
}
|
|
568
594
|
return toNotify;
|
|
@@ -7,7 +7,8 @@ export declare class ListManager {
|
|
|
7
7
|
constructor(cache: Cache, rootID: string);
|
|
8
8
|
lists: Map<string, Map<string, ListCollection>>;
|
|
9
9
|
private listsByField;
|
|
10
|
-
get(listName: string, id?: string, allLists?: boolean): ListCollection | null
|
|
10
|
+
get(listName: string, id?: string, allLists?: boolean, skipMatches?: Set<string>): ListCollection | null;
|
|
11
|
+
getLists(listName: string, id?: string, allLists?: boolean): ListCollection | null | undefined;
|
|
11
12
|
remove(listName: string, id: string): void;
|
|
12
13
|
add(list: {
|
|
13
14
|
name: string;
|
|
@@ -41,6 +42,7 @@ export declare class List {
|
|
|
41
42
|
constructor({ name, recordID, recordType, key, listType, selection, when, filters, connection, manager, abstract, }: Parameters<ListManager['add']>[0] & {
|
|
42
43
|
manager: ListManager;
|
|
43
44
|
});
|
|
45
|
+
get fieldRef(): string;
|
|
44
46
|
when(when?: ListWhen): ListCollection;
|
|
45
47
|
append({ selection, data, variables, layer, }: {
|
|
46
48
|
selection: SubscriptionSelection;
|
|
@@ -34,7 +34,18 @@ class ListManager {
|
|
|
34
34
|
}
|
|
35
35
|
lists = /* @__PURE__ */ new Map();
|
|
36
36
|
listsByField = /* @__PURE__ */ new Map();
|
|
37
|
-
get(listName, id, allLists) {
|
|
37
|
+
get(listName, id, allLists, skipMatches) {
|
|
38
|
+
const lists = this.getLists(listName, id, allLists);
|
|
39
|
+
if (!lists) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (skipMatches) {
|
|
43
|
+
return new ListCollection(lists.lists.filter((list) => !skipMatches.has(list.fieldRef)));
|
|
44
|
+
} else {
|
|
45
|
+
return lists;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
getLists(listName, id, allLists) {
|
|
38
49
|
const matches = this.lists.get(listName);
|
|
39
50
|
if (!matches || matches.size === 0) {
|
|
40
51
|
return null;
|
|
@@ -156,6 +167,9 @@ class List {
|
|
|
156
167
|
this.manager = manager;
|
|
157
168
|
this.abstract = abstract;
|
|
158
169
|
}
|
|
170
|
+
get fieldRef() {
|
|
171
|
+
return `${this.recordID}.${this.key}`;
|
|
172
|
+
}
|
|
159
173
|
when(when) {
|
|
160
174
|
return this.manager.lists.get(this.name).get(this.recordID).when(when);
|
|
161
175
|
}
|
|
@@ -42,7 +42,8 @@ class DocumentStore extends import_store.Writable {
|
|
|
42
42
|
pendingPromise = null;
|
|
43
43
|
serverSideFallback;
|
|
44
44
|
controllerKey(variables) {
|
|
45
|
-
|
|
45
|
+
const usedVariables = "dedupe" in this.artifact && this.artifact.dedupe?.match !== import_types.DedupeMatchMode.Variables ? {} : variables;
|
|
46
|
+
return `${this.artifact.name}@${stableStringify(usedVariables)}`;
|
|
46
47
|
}
|
|
47
48
|
constructor({
|
|
48
49
|
artifact,
|
|
@@ -104,16 +105,20 @@ class DocumentStore extends import_store.Writable {
|
|
|
104
105
|
silenceEcho = false,
|
|
105
106
|
abortController = new AbortController()
|
|
106
107
|
} = {}) {
|
|
107
|
-
if ("dedupe" in this.artifact) {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
inflightRequests[
|
|
108
|
+
if ("dedupe" in this.artifact && this.artifact.dedupe && this.artifact.dedupe.match !== "None") {
|
|
109
|
+
const dedupeKey = this.controllerKey(variables);
|
|
110
|
+
if (inflightRequests[dedupeKey]) {
|
|
111
|
+
if (this.artifact.dedupe.cancel === "first") {
|
|
112
|
+
inflightRequests[dedupeKey].controller.abort();
|
|
113
|
+
inflightRequests[dedupeKey].controller = abortController;
|
|
112
114
|
} else {
|
|
113
115
|
abortController.abort();
|
|
114
116
|
}
|
|
115
117
|
} else {
|
|
116
|
-
inflightRequests[
|
|
118
|
+
inflightRequests[dedupeKey] = {
|
|
119
|
+
variables,
|
|
120
|
+
controller: abortController
|
|
121
|
+
};
|
|
117
122
|
}
|
|
118
123
|
}
|
|
119
124
|
let context = new ClientPluginContextWrapper({
|
|
@@ -435,6 +440,21 @@ function marshalVariables(ctx) {
|
|
|
435
440
|
function variablesChanged(ctx) {
|
|
436
441
|
return ctx.stuff.inputs?.changed;
|
|
437
442
|
}
|
|
443
|
+
function stableStringify(obj) {
|
|
444
|
+
return JSON.stringify(sortObject(obj));
|
|
445
|
+
}
|
|
446
|
+
function sortObject(obj) {
|
|
447
|
+
if (obj === null || typeof obj !== "object") {
|
|
448
|
+
return obj;
|
|
449
|
+
}
|
|
450
|
+
if (Array.isArray(obj)) {
|
|
451
|
+
return obj.map(sortObject);
|
|
452
|
+
}
|
|
453
|
+
return Object.keys(obj).sort().reduce((result, key) => {
|
|
454
|
+
result[key] = sortObject(obj[key]);
|
|
455
|
+
return result;
|
|
456
|
+
}, {});
|
|
457
|
+
}
|
|
438
458
|
// Annotate the CommonJS export names for ESM import in node:
|
|
439
459
|
0 && (module.exports = {
|
|
440
460
|
DocumentStore
|
|
@@ -91,6 +91,11 @@ const defaultFetch = (url, params) => {
|
|
|
91
91
|
...params?.headers
|
|
92
92
|
}
|
|
93
93
|
});
|
|
94
|
+
if (!result.ok && !result.headers.get("content-type")?.startsWith("application/json") && !result.headers.get("content-type")?.startsWith("application/graphql+json")) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`Failed to fetch: server returned invalid response with error ${result.status}: ${result.statusText}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
94
99
|
return await result.json();
|
|
95
100
|
};
|
|
96
101
|
};
|
|
@@ -73,6 +73,10 @@ export type ConfigFile = {
|
|
|
73
73
|
* Specifies whether the default paginate mode is Infinite or SinglePage. (default: `Infinite`)
|
|
74
74
|
*/
|
|
75
75
|
defaultPaginateMode?: PaginateModes;
|
|
76
|
+
/**
|
|
77
|
+
* Prevents the runtime from deduplicating pagination requests
|
|
78
|
+
*/
|
|
79
|
+
supressPaginationDeduplication?: boolean;
|
|
76
80
|
/**
|
|
77
81
|
* A list of fields to use when computing a record’s id. The default value is ['id']. For more information: https://www.houdinigraphql.com/guides/caching-data#custom-ids
|
|
78
82
|
*/
|
|
@@ -95,7 +99,7 @@ export type ConfigFile = {
|
|
|
95
99
|
*/
|
|
96
100
|
watchSchema?: WatchSchemaConfig;
|
|
97
101
|
/**
|
|
98
|
-
* Specifies the the persisted queries path and file. (default:
|
|
102
|
+
* Specifies the the persisted queries path and file. (default: `<rootDir>/persisted_queries.json`)
|
|
99
103
|
*/
|
|
100
104
|
persistedQueriesPath?: string;
|
|
101
105
|
/**
|
|
@@ -107,6 +111,11 @@ export type ConfigFile = {
|
|
|
107
111
|
* @default process.cwd()
|
|
108
112
|
*/
|
|
109
113
|
projectDir?: string;
|
|
114
|
+
/**
|
|
115
|
+
* The relative path from your project directory pointing to your output directory.
|
|
116
|
+
* @default `$houdini`
|
|
117
|
+
*/
|
|
118
|
+
runtimeDir?: string;
|
|
110
119
|
/**
|
|
111
120
|
* For now, the cache's imperative API is considered unstable. In order to suppress the warning,
|
|
112
121
|
* you must enable this flag.
|
|
@@ -7,6 +7,12 @@ export declare const CachePolicy: {
|
|
|
7
7
|
readonly NoCache: "NoCache";
|
|
8
8
|
};
|
|
9
9
|
export type CachePolicies = ValuesOf<typeof CachePolicy>;
|
|
10
|
+
export declare const DedupeMatchMode: {
|
|
11
|
+
readonly Variables: "Variables";
|
|
12
|
+
readonly Operation: "Operation";
|
|
13
|
+
readonly None: "None";
|
|
14
|
+
};
|
|
15
|
+
export type DedupeMatchModes = ValuesOf<typeof DedupeMatchMode>;
|
|
10
16
|
export declare const PaginateMode: {
|
|
11
17
|
readonly Infinite: "Infinite";
|
|
12
18
|
readonly SinglePage: "SinglePage";
|
|
@@ -60,11 +66,17 @@ export type QueryArtifact = BaseCompiledDocument<'HoudiniQuery'> & {
|
|
|
60
66
|
policy?: CachePolicies;
|
|
61
67
|
partial?: boolean;
|
|
62
68
|
enableLoadingState?: 'global' | 'local';
|
|
63
|
-
dedupe?:
|
|
69
|
+
dedupe?: {
|
|
70
|
+
cancel: 'first' | 'last';
|
|
71
|
+
match: DedupeMatchModes;
|
|
72
|
+
};
|
|
64
73
|
};
|
|
65
74
|
export type MutationArtifact = BaseCompiledDocument<'HoudiniMutation'> & {
|
|
66
75
|
optimisticKeys?: boolean;
|
|
67
|
-
dedupe?:
|
|
76
|
+
dedupe?: {
|
|
77
|
+
cancel: 'first' | 'last';
|
|
78
|
+
match: DedupeMatchModes;
|
|
79
|
+
};
|
|
68
80
|
};
|
|
69
81
|
export type FragmentArtifact = BaseCompiledDocument<'HoudiniFragment'> & {
|
|
70
82
|
enableLoadingState?: 'global' | 'local';
|
|
@@ -26,6 +26,7 @@ __export(types_exports, {
|
|
|
26
26
|
CompiledQueryKind: () => CompiledQueryKind,
|
|
27
27
|
CompiledSubscriptionKind: () => CompiledSubscriptionKind,
|
|
28
28
|
DataSource: () => DataSource,
|
|
29
|
+
DedupeMatchMode: () => DedupeMatchMode,
|
|
29
30
|
PaginateMode: () => PaginateMode,
|
|
30
31
|
PendingValue: () => PendingValue,
|
|
31
32
|
RefetchUpdateMode: () => RefetchUpdateMode,
|
|
@@ -41,6 +42,11 @@ const CachePolicy = {
|
|
|
41
42
|
CacheAndNetwork: "CacheAndNetwork",
|
|
42
43
|
NoCache: "NoCache"
|
|
43
44
|
};
|
|
45
|
+
const DedupeMatchMode = {
|
|
46
|
+
Variables: "Variables",
|
|
47
|
+
Operation: "Operation",
|
|
48
|
+
None: "None"
|
|
49
|
+
};
|
|
44
50
|
const PaginateMode = {
|
|
45
51
|
Infinite: "Infinite",
|
|
46
52
|
SinglePage: "SinglePage"
|
|
@@ -79,6 +85,7 @@ function isPending(value) {
|
|
|
79
85
|
CompiledQueryKind,
|
|
80
86
|
CompiledSubscriptionKind,
|
|
81
87
|
DataSource,
|
|
88
|
+
DedupeMatchMode,
|
|
82
89
|
PaginateMode,
|
|
83
90
|
PendingValue,
|
|
84
91
|
RefetchUpdateMode,
|
|
@@ -35,7 +35,7 @@ export declare class Cache {
|
|
|
35
35
|
};
|
|
36
36
|
subscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
37
37
|
unsubscribe(spec: SubscriptionSpec, variables?: {}): void;
|
|
38
|
-
list(name: string, parentID?: string, allLists?: boolean): ListCollection;
|
|
38
|
+
list(name: string, parentID?: string, allLists?: boolean, skipMatches?: Set<string>): ListCollection;
|
|
39
39
|
registerKeyMap(source: string, mapped: string): void;
|
|
40
40
|
delete(id: string, layer?: Layer): void;
|
|
41
41
|
setConfig(config: ConfigFile): void;
|