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.
Files changed (88) hide show
  1. package/README.md +1 -1
  2. package/build/cmd-cjs/index.js +1739 -1256
  3. package/build/cmd-esm/index.js +1739 -1256
  4. package/build/codegen/generators/artifacts/selection.d.ts +2 -1
  5. package/build/codegen/generators/typescript/inlineType.d.ts +5 -2
  6. package/build/codegen/generators/typescript/loadingState.d.ts +8 -0
  7. package/build/codegen-cjs/index.js +1701 -1241
  8. package/build/codegen-esm/index.js +1701 -1241
  9. package/build/lib/config.d.ts +5 -0
  10. package/build/lib/graphql.d.ts +5 -1
  11. package/build/lib/parse.d.ts +11 -1
  12. package/build/lib/types.d.ts +4 -1
  13. package/build/lib-cjs/index.js +611 -493
  14. package/build/lib-esm/index.js +608 -493
  15. package/build/runtime/cache/cache.d.ts +7 -8
  16. package/build/runtime/cache/stuff.d.ts +1 -4
  17. package/build/runtime/client/documentStore.d.ts +6 -3
  18. package/build/runtime/client/index.d.ts +9 -8
  19. package/build/runtime/client/plugins/cache.d.ts +1 -1
  20. package/build/runtime/client/plugins/fetch.d.ts +1 -0
  21. package/build/runtime/client/plugins/subscription.d.ts +1 -0
  22. package/build/runtime/client/plugins/throwOnError.d.ts +2 -1
  23. package/build/runtime/lib/pageInfo.d.ts +7 -0
  24. package/build/runtime/lib/pagination.d.ts +27 -0
  25. package/build/runtime/lib/selection.d.ts +1 -1
  26. package/build/runtime/lib/types.d.ts +79 -4
  27. package/build/runtime-cjs/cache/cache.d.ts +7 -8
  28. package/build/runtime-cjs/cache/cache.js +78 -36
  29. package/build/runtime-cjs/cache/stuff.d.ts +1 -4
  30. package/build/runtime-cjs/cache/stuff.js +2 -2
  31. package/build/runtime-cjs/cache/subscription.js +5 -5
  32. package/build/runtime-cjs/client/documentStore.d.ts +6 -3
  33. package/build/runtime-cjs/client/documentStore.js +20 -7
  34. package/build/runtime-cjs/client/index.d.ts +9 -8
  35. package/build/runtime-cjs/client/index.js +12 -4
  36. package/build/runtime-cjs/client/plugins/cache.d.ts +1 -1
  37. package/build/runtime-cjs/client/plugins/cache.js +12 -2
  38. package/build/runtime-cjs/client/plugins/fetch.d.ts +1 -0
  39. package/build/runtime-cjs/client/plugins/fetch.js +3 -2
  40. package/build/runtime-cjs/client/plugins/fragment.js +8 -1
  41. package/build/runtime-cjs/client/plugins/query.js +2 -1
  42. package/build/runtime-cjs/client/plugins/subscription.d.ts +1 -0
  43. package/build/runtime-cjs/client/plugins/subscription.js +1 -0
  44. package/build/runtime-cjs/client/plugins/throwOnError.d.ts +2 -1
  45. package/build/runtime-cjs/lib/config.js +2 -1
  46. package/build/runtime-cjs/lib/pageInfo.d.ts +7 -0
  47. package/build/runtime-cjs/lib/pageInfo.js +79 -0
  48. package/build/runtime-cjs/lib/pagination.d.ts +27 -0
  49. package/build/runtime-cjs/lib/pagination.js +219 -0
  50. package/build/runtime-cjs/lib/scalars.js +1 -1
  51. package/build/runtime-cjs/lib/selection.d.ts +1 -1
  52. package/build/runtime-cjs/lib/selection.js +28 -1
  53. package/build/runtime-cjs/lib/types.d.ts +79 -4
  54. package/build/runtime-cjs/lib/types.js +3 -0
  55. package/build/runtime-esm/cache/cache.d.ts +7 -8
  56. package/build/runtime-esm/cache/cache.js +79 -37
  57. package/build/runtime-esm/cache/stuff.d.ts +1 -4
  58. package/build/runtime-esm/cache/stuff.js +2 -2
  59. package/build/runtime-esm/cache/subscription.js +5 -5
  60. package/build/runtime-esm/client/documentStore.d.ts +6 -3
  61. package/build/runtime-esm/client/documentStore.js +20 -7
  62. package/build/runtime-esm/client/index.d.ts +9 -8
  63. package/build/runtime-esm/client/index.js +15 -7
  64. package/build/runtime-esm/client/plugins/cache.d.ts +1 -1
  65. package/build/runtime-esm/client/plugins/cache.js +12 -2
  66. package/build/runtime-esm/client/plugins/fetch.d.ts +1 -0
  67. package/build/runtime-esm/client/plugins/fetch.js +3 -2
  68. package/build/runtime-esm/client/plugins/fragment.js +8 -1
  69. package/build/runtime-esm/client/plugins/query.js +2 -1
  70. package/build/runtime-esm/client/plugins/subscription.d.ts +1 -0
  71. package/build/runtime-esm/client/plugins/subscription.js +1 -0
  72. package/build/runtime-esm/client/plugins/throwOnError.d.ts +2 -1
  73. package/build/runtime-esm/lib/config.js +2 -1
  74. package/build/runtime-esm/lib/pageInfo.d.ts +7 -0
  75. package/build/runtime-esm/lib/pageInfo.js +52 -0
  76. package/build/runtime-esm/lib/pagination.d.ts +27 -0
  77. package/build/runtime-esm/lib/pagination.js +194 -0
  78. package/build/runtime-esm/lib/scalars.js +1 -1
  79. package/build/runtime-esm/lib/selection.d.ts +1 -1
  80. package/build/runtime-esm/lib/selection.js +28 -1
  81. package/build/runtime-esm/lib/types.d.ts +79 -4
  82. package/build/runtime-esm/lib/types.js +2 -0
  83. package/build/test/index.d.ts +15 -0
  84. package/build/test-cjs/index.js +1706 -1223
  85. package/build/test-esm/index.js +1706 -1223
  86. package/build/vite-cjs/index.js +1757 -1274
  87. package/build/vite-esm/index.js +1757 -1274
  88. 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(selection, data["__typename"]);
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] = Object.fromEntries(
458
- Object.entries(selection.fragments).map(([key, value]) => [
459
- key,
460
- {
461
- parent,
462
- variables: evaluateFragmentVariables(value, variables ?? {})
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
- { type, keyRaw, selection: fieldSelection, nullable, list, visible, directives }
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
- const { value } = this.storage.get(parent, key);
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 (typeof value === "undefined" || value === null) {
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
- cascadeNull = true;
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 @@
1
- import type { GraphQLValue } from '../lib/types';
2
- export declare function evaluateKey(key: string, variables?: {
3
- [key: string]: GraphQLValue;
4
- }): string;
1
+ export declare function evaluateKey(key: string, variables?: Record<string, any> | null): string;
@@ -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 Record<string, any>> extends Writable<QueryResult<_Data, _Input>> {
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 {}>(ctx: ClientPluginContext): Record<string, any>;
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) => this.update((state) => ({ ...state, fetching: 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
- return await new Promise((resolve, reject) => {
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 { ClientPlugin, ClientHooks } from './documentStore';
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 { type FetchParamFn, type ThrowOnErrorParams } from './plugins';
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 ConstructorArgs = {
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
- constructor({ url, fetchParams, plugins, pipeline, throwOnError }: ConstructorArgs);
25
- observe<_Data extends GraphQLObject, _Input extends Record<string, any>>({ artifact, cache, initialValue, fetching, }: ObserveParams<_Data>): DocumentStore<_Data, _Input>;
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
- fragment as fragmentPlugin,
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
- #plugins;
17
- constructor({ url, fetchParams, plugins, pipeline, throwOnError }) {
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.#plugins = flatten(
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.#plugins),
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
- setFetching(!useCache);
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
- if (variablesChanged(ctx) && !ctx.cacheParams?.disableSubscriptions) {
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: () => lastVariables,
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: {
@@ -32,6 +32,7 @@ function subscription(factory) {
32
32
  clearSubscription?.();
33
33
  clearSubscription = client.subscribe(
34
34
  {
35
+ operationName: ctx.artifact.name,
35
36
  query: ctx.artifact.raw,
36
37
  variables: marshalVariables(ctx)
37
38
  },
@@ -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: ('all' | 'query' | 'mutation' | 'subscription')[];
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
- return configFile.types?.[type]?.keys || configFile.defaultKeys;
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;