houdini 1.2.26 → 1.2.28

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 (71) hide show
  1. package/build/adapter/index.d.ts +1 -1
  2. package/build/cmd-cjs/index.js +4169 -1854
  3. package/build/cmd-esm/index.js +4169 -1854
  4. package/build/codegen/generators/artifacts/selection.d.ts +2 -1
  5. package/build/codegen/generators/typescript/inlineType.d.ts +5 -1
  6. package/build/codegen/generators/typescript/typeReference.d.ts +1 -1
  7. package/build/codegen/generators/typescript/types.d.ts +6 -3
  8. package/build/codegen/transforms/collectDefinitions.d.ts +1 -1
  9. package/build/codegen/transforms/componentFields.d.ts +8 -0
  10. package/build/codegen/transforms/fragmentVariables.d.ts +1 -1
  11. package/build/codegen/transforms/index.d.ts +1 -0
  12. package/build/codegen/validators/componentFields.d.ts +2 -0
  13. package/build/codegen/validators/index.d.ts +1 -0
  14. package/build/codegen-cjs/index.js +3674 -1393
  15. package/build/codegen-esm/index.js +3674 -1393
  16. package/build/lib/config.d.ts +21 -1
  17. package/build/lib/detectTools.d.ts +1 -1
  18. package/build/lib/graphql.d.ts +6 -0
  19. package/build/lib/imports.d.ts +1 -1
  20. package/build/lib/router/conventions.d.ts +1 -0
  21. package/build/lib/types.d.ts +4 -2
  22. package/build/lib/walk.d.ts +1 -0
  23. package/build/lib-cjs/index.js +1120 -747
  24. package/build/lib-esm/index.js +1119 -747
  25. package/build/runtime/cache/cache.d.ts +24 -3
  26. package/build/runtime/cache/storage.d.ts +1 -1
  27. package/build/runtime/client/index.d.ts +1 -0
  28. package/build/runtime/index.d.ts +1 -1
  29. package/build/runtime/lib/config.d.ts +9 -0
  30. package/build/runtime/lib/index.d.ts +1 -0
  31. package/build/runtime/lib/types.d.ts +18 -1
  32. package/build/runtime/router/server.d.ts +3 -1
  33. package/build/runtime/router/types.d.ts +1 -0
  34. package/build/runtime-cjs/cache/cache.d.ts +24 -3
  35. package/build/runtime-cjs/cache/cache.js +78 -8
  36. package/build/runtime-cjs/cache/storage.d.ts +1 -1
  37. package/build/runtime-cjs/cache/storage.js +16 -3
  38. package/build/runtime-cjs/client/index.d.ts +1 -0
  39. package/build/runtime-cjs/client/index.js +1 -0
  40. package/build/runtime-cjs/index.d.ts +1 -1
  41. package/build/runtime-cjs/lib/config.d.ts +9 -0
  42. package/build/runtime-cjs/lib/index.d.ts +1 -0
  43. package/build/runtime-cjs/lib/index.js +1 -0
  44. package/build/runtime-cjs/lib/types.d.ts +18 -1
  45. package/build/runtime-cjs/public/cache.js +3 -2
  46. package/build/runtime-cjs/router/server.d.ts +3 -1
  47. package/build/runtime-cjs/router/server.js +5 -2
  48. package/build/runtime-cjs/router/session.js +9 -6
  49. package/build/runtime-cjs/router/types.d.ts +1 -0
  50. package/build/runtime-esm/cache/cache.d.ts +24 -3
  51. package/build/runtime-esm/cache/cache.js +76 -8
  52. package/build/runtime-esm/cache/storage.d.ts +1 -1
  53. package/build/runtime-esm/cache/storage.js +16 -3
  54. package/build/runtime-esm/client/index.d.ts +1 -0
  55. package/build/runtime-esm/client/index.js +1 -0
  56. package/build/runtime-esm/index.d.ts +1 -1
  57. package/build/runtime-esm/lib/config.d.ts +9 -0
  58. package/build/runtime-esm/lib/index.d.ts +1 -0
  59. package/build/runtime-esm/lib/index.js +1 -0
  60. package/build/runtime-esm/lib/types.d.ts +18 -1
  61. package/build/runtime-esm/public/cache.js +3 -2
  62. package/build/runtime-esm/router/server.d.ts +3 -1
  63. package/build/runtime-esm/router/server.js +5 -2
  64. package/build/runtime-esm/router/session.js +9 -6
  65. package/build/runtime-esm/router/types.d.ts +1 -0
  66. package/build/test-cjs/index.js +3556 -1373
  67. package/build/test-esm/index.js +3556 -1373
  68. package/build/vite/schema.d.ts +4 -1
  69. package/build/vite-cjs/index.js +4543 -2823
  70. package/build/vite-esm/index.js +4540 -2822
  71. package/package.json +4 -3
@@ -10,8 +10,10 @@ import { InMemorySubscriptions, type FieldSelection } from './subscription';
10
10
  export declare class Cache {
11
11
  #private;
12
12
  _internal_unstable: CacheInternal;
13
- constructor({ disabled, ...config }?: ConfigFile & {
13
+ constructor({ disabled, componentCache, createComponent, ...config }?: ConfigFile & {
14
14
  disabled?: boolean;
15
+ componentCache?: Record<string, any>;
16
+ createComponent?: (comp: any, prop: Record<string, any>) => any;
15
17
  });
16
18
  write({ layer: layerID, notifySubscribers, ...args }: {
17
19
  data: {
@@ -61,7 +63,9 @@ declare class CacheInternal {
61
63
  cache: Cache;
62
64
  lifetimes: GarbageCollector;
63
65
  staleManager: StaleManager;
64
- constructor({ storage, subscriptions, lists, cache, lifetimes, staleManager, disabled, config, }: {
66
+ componentCache: Record<string, any>;
67
+ createComponent: (component: any, props: Record<string, any>) => any;
68
+ constructor({ storage, subscriptions, lists, cache, lifetimes, staleManager, disabled, config, componentCache, createComponent, }: {
65
69
  storage: InMemoryStorage;
66
70
  subscriptions: InMemorySubscriptions;
67
71
  lists: ListManager;
@@ -70,6 +74,8 @@ declare class CacheInternal {
70
74
  staleManager: StaleManager;
71
75
  disabled: boolean;
72
76
  config?: ConfigFile;
77
+ componentCache?: Record<string, any>;
78
+ createComponent: undefined | ((component: any, props: Record<string, any>) => any);
73
79
  });
74
80
  get config(): ConfigFile;
75
81
  setConfig(config: ConfigFile): void;
@@ -108,8 +114,9 @@ declare class CacheInternal {
108
114
  idFields(type: string): string[];
109
115
  computeID(type: string, data: any): string;
110
116
  isEmbedded(linkedType: string, value: GraphQLObject): boolean;
111
- hydrateNestedList({ fields, variables, linkedList, stepsFromConnection, ignoreMasking, fullCheck, loading, }: {
117
+ hydrateNestedList({ fields, variables, linkedList, stepsFromConnection, ignoreMasking, fullCheck, loading, nullable, }: {
112
118
  fields: SubscriptionSelection;
119
+ nullable: boolean;
113
120
  variables?: {} | null;
114
121
  linkedList: NestedList;
115
122
  stepsFromConnection: number | null;
@@ -121,6 +128,7 @@ declare class CacheInternal {
121
128
  partial: boolean;
122
129
  stale: boolean;
123
130
  hasData: boolean;
131
+ cascadeNull: boolean;
124
132
  };
125
133
  extractNestedListIDs({ value, abstract, recordID, key, linkedType, fields, variables, applyUpdates, specs, layer, forceNotify, }: {
126
134
  value: GraphQLValue[];
@@ -144,4 +152,17 @@ export declare function evaluateFragmentVariables(variables: ValueMap, args: Gra
144
152
  [k: string]: GraphQLValue;
145
153
  };
146
154
  export declare const rootID = "_ROOT_";
155
+ export declare function fragmentReference({ component, prop, }: {
156
+ component: {
157
+ name: string;
158
+ };
159
+ prop: string;
160
+ }): any;
161
+ export declare function defaultComponentField({ cache, component, loading, variables, parent, }: {
162
+ cache: Cache;
163
+ component: Required<Required<SubscriptionSelection>['fields'][string]>['component'];
164
+ loading?: boolean;
165
+ variables: Record<string, GraphQLValue> | undefined | null;
166
+ parent: string;
167
+ }): (props: any) => any;
147
168
  export {};
@@ -16,7 +16,7 @@ export declare class InMemoryStorage {
16
16
  from: string;
17
17
  to: string;
18
18
  }): void;
19
- get(id: string, field: string): {
19
+ get(id: string, field: string, defaultValue?: any): {
20
20
  value: GraphQLField;
21
21
  kind: 'link' | 'scalar' | 'unknown';
22
22
  displayLayers: number[];
@@ -31,6 +31,7 @@ export declare class HoudiniClient {
31
31
  operationName: string;
32
32
  session: App.Session | null | undefined;
33
33
  }) => Promise<any>>;
34
+ componentCache: Record<string, any>;
34
35
  constructor({ url, fetchParams, plugins, pipeline, throwOnError, }?: HoudiniClientConstructorArgs);
35
36
  observe<_Data extends GraphQLObject, _Input extends GraphQLVariables>({ enableCache, fetching, ...rest }: ObserveParams<_Data, DocumentArtifact, _Input>): DocumentStore<_Data, _Input>;
36
37
  registerProxy(url: string, handler: (operation: {
@@ -3,6 +3,6 @@ import type { CacheTypeDef } from './generated';
3
3
  import { Cache } from './public';
4
4
  export * from './client';
5
5
  export * from './lib';
6
- export declare function graphql<_Payload>(str: TemplateStringsArray): _Payload;
6
+ export declare function graphql<_Payload, _Result = _Payload>(str: TemplateStringsArray): _Result;
7
7
  export declare const cache: Cache<CacheTypeDef>;
8
8
  export declare function getCache(): InternalCache;
@@ -110,12 +110,21 @@ export type ConfigFile = {
110
110
  /**
111
111
  * For now, the cache's imperative API is considered unstable. In order to suppress the warning,
112
112
  * you must enable this flag.
113
+ *
114
+ * @deprecated set features.imperativeCache instead
113
115
  */
114
116
  acceptImperativeInstability?: boolean;
115
117
  /**
116
118
  * Configure the router
117
119
  */
118
120
  router?: RouterConfig;
121
+ /**
122
+ * A collection of flags to opt-into experimental features that might break unexpectedly
123
+ */
124
+ features?: {
125
+ componentFields?: boolean;
126
+ imperativeCache?: boolean;
127
+ };
119
128
  };
120
129
  type RouterConfig = {
121
130
  auth?: AuthStrategy;
@@ -7,3 +7,4 @@ export * from './types';
7
7
  export * from './store';
8
8
  export * from './key';
9
9
  export * from './lru';
10
+ export * from './selection';
@@ -79,6 +79,7 @@ export type BaseCompiledDocument<_Kind extends ArtifactKinds> = {
79
79
  selection: SubscriptionSelection;
80
80
  rootType: string;
81
81
  input?: InputObject;
82
+ hasComponents?: boolean;
82
83
  refetch?: {
83
84
  path: string[];
84
85
  method: 'cursor' | 'offset';
@@ -156,12 +157,16 @@ export type SubscriptionSelection = {
156
157
  arguments: ValueMap;
157
158
  loading?: boolean;
158
159
  }>;
160
+ components?: Record<string, {
161
+ prop: string;
162
+ attribute: string;
163
+ }>;
159
164
  fields?: {
160
165
  [fieldName: string]: {
161
166
  type: string;
167
+ keyRaw: string;
162
168
  nullable?: boolean;
163
169
  required?: boolean;
164
- keyRaw: string;
165
170
  operations?: MutationOperation[];
166
171
  list?: {
167
172
  name: string;
@@ -182,6 +187,12 @@ export type SubscriptionSelection = {
182
187
  selection?: SubscriptionSelection;
183
188
  abstract?: boolean;
184
189
  abstractHasRequired?: boolean;
190
+ component?: {
191
+ prop: string;
192
+ key: string;
193
+ fragment: string;
194
+ variables: ValueMap | null;
195
+ };
185
196
  };
186
197
  };
187
198
  abstractFields?: {
@@ -333,6 +344,10 @@ export type ProjectManifest = {
333
344
  local_schema: boolean;
334
345
  /** Whether or not there is a custom instance of yoga defined */
335
346
  local_yoga: boolean;
347
+ /** Information about componentFields defined in the project */
348
+ component_fields: Record<string, {
349
+ filepath: string;
350
+ }>;
336
351
  };
337
352
  export type PageManifest = {
338
353
  id: string;
@@ -356,4 +371,6 @@ export type QueryManifest = {
356
371
  loading: boolean;
357
372
  /** The filepath of the unit */
358
373
  path: string;
374
+ /** The list of variables that this query cares about */
375
+ variables: string[];
359
376
  };
@@ -3,7 +3,7 @@ import { type GraphQLSchema } from 'graphql';
3
3
  import { createYoga } from 'graphql-yoga';
4
4
  import type { HoudiniClient } from '../client';
5
5
  import type { RouterManifest, RouterPageManifest, YogaServerOptions } from './types';
6
- export declare function _serverHandler<ComponentType = unknown>({ schema, yoga, client, production, manifest, graphqlEndpoint, on_render, }: {
6
+ export declare function _serverHandler<ComponentType = unknown>({ schema, yoga, client, production, manifest, graphqlEndpoint, on_render, componentCache, }: {
7
7
  schema?: GraphQLSchema | null;
8
8
  yoga?: ReturnType<typeof createYoga> | null;
9
9
  client: HoudiniClient;
@@ -11,11 +11,13 @@ export declare function _serverHandler<ComponentType = unknown>({ schema, yoga,
11
11
  manifest: RouterManifest<ComponentType> | null;
12
12
  assetPrefix: string;
13
13
  graphqlEndpoint: string;
14
+ componentCache: Record<string, any>;
14
15
  on_render: (args: {
15
16
  url: string;
16
17
  match: RouterPageManifest<ComponentType> | null;
17
18
  manifest: RouterManifest<unknown>;
18
19
  session: App.Session;
20
+ componentCache: Record<string, any>;
19
21
  }) => Response | Promise<Response | undefined> | undefined;
20
22
  } & Omit<YogaServerOptions, 'schema'>): (request: Request) => Promise<Response>;
21
23
  export declare const serverAdapterFactory: (args: Parameters<typeof _serverHandler>[0]) => ReturnType<typeof createAdapter>;
@@ -16,6 +16,7 @@ export type RouterPageManifest<_ComponentType> = {
16
16
  default: QueryArtifact;
17
17
  }>;
18
18
  loading: boolean;
19
+ variables: string[];
19
20
  }>;
20
21
  component: () => Promise<{
21
22
  default: (props: any) => _ComponentType;
@@ -10,8 +10,10 @@ import { InMemorySubscriptions, type FieldSelection } from './subscription';
10
10
  export declare class Cache {
11
11
  #private;
12
12
  _internal_unstable: CacheInternal;
13
- constructor({ disabled, ...config }?: ConfigFile & {
13
+ constructor({ disabled, componentCache, createComponent, ...config }?: ConfigFile & {
14
14
  disabled?: boolean;
15
+ componentCache?: Record<string, any>;
16
+ createComponent?: (comp: any, prop: Record<string, any>) => any;
15
17
  });
16
18
  write({ layer: layerID, notifySubscribers, ...args }: {
17
19
  data: {
@@ -61,7 +63,9 @@ declare class CacheInternal {
61
63
  cache: Cache;
62
64
  lifetimes: GarbageCollector;
63
65
  staleManager: StaleManager;
64
- constructor({ storage, subscriptions, lists, cache, lifetimes, staleManager, disabled, config, }: {
66
+ componentCache: Record<string, any>;
67
+ createComponent: (component: any, props: Record<string, any>) => any;
68
+ constructor({ storage, subscriptions, lists, cache, lifetimes, staleManager, disabled, config, componentCache, createComponent, }: {
65
69
  storage: InMemoryStorage;
66
70
  subscriptions: InMemorySubscriptions;
67
71
  lists: ListManager;
@@ -70,6 +74,8 @@ declare class CacheInternal {
70
74
  staleManager: StaleManager;
71
75
  disabled: boolean;
72
76
  config?: ConfigFile;
77
+ componentCache?: Record<string, any>;
78
+ createComponent: undefined | ((component: any, props: Record<string, any>) => any);
73
79
  });
74
80
  get config(): ConfigFile;
75
81
  setConfig(config: ConfigFile): void;
@@ -108,8 +114,9 @@ declare class CacheInternal {
108
114
  idFields(type: string): string[];
109
115
  computeID(type: string, data: any): string;
110
116
  isEmbedded(linkedType: string, value: GraphQLObject): boolean;
111
- hydrateNestedList({ fields, variables, linkedList, stepsFromConnection, ignoreMasking, fullCheck, loading, }: {
117
+ hydrateNestedList({ fields, variables, linkedList, stepsFromConnection, ignoreMasking, fullCheck, loading, nullable, }: {
112
118
  fields: SubscriptionSelection;
119
+ nullable: boolean;
113
120
  variables?: {} | null;
114
121
  linkedList: NestedList;
115
122
  stepsFromConnection: number | null;
@@ -121,6 +128,7 @@ declare class CacheInternal {
121
128
  partial: boolean;
122
129
  stale: boolean;
123
130
  hasData: boolean;
131
+ cascadeNull: boolean;
124
132
  };
125
133
  extractNestedListIDs({ value, abstract, recordID, key, linkedType, fields, variables, applyUpdates, specs, layer, forceNotify, }: {
126
134
  value: GraphQLValue[];
@@ -144,4 +152,17 @@ export declare function evaluateFragmentVariables(variables: ValueMap, args: Gra
144
152
  [k: string]: GraphQLValue;
145
153
  };
146
154
  export declare const rootID = "_ROOT_";
155
+ export declare function fragmentReference({ component, prop, }: {
156
+ component: {
157
+ name: string;
158
+ };
159
+ prop: string;
160
+ }): any;
161
+ export declare function defaultComponentField({ cache, component, loading, variables, parent, }: {
162
+ cache: Cache;
163
+ component: Required<Required<SubscriptionSelection>['fields'][string]>['component'];
164
+ loading?: boolean;
165
+ variables: Record<string, GraphQLValue> | undefined | null;
166
+ parent: string;
167
+ }): (props: any) => any;
147
168
  export {};
@@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var cache_exports = {};
20
20
  __export(cache_exports, {
21
21
  Cache: () => Cache,
22
+ defaultComponentField: () => defaultComponentField,
22
23
  evaluateFragmentVariables: () => evaluateFragmentVariables,
24
+ fragmentReference: () => fragmentReference,
23
25
  rootID: () => rootID
24
26
  });
25
27
  module.exports = __toCommonJS(cache_exports);
@@ -37,7 +39,12 @@ var import_stuff = require("./stuff");
37
39
  var import_subscription = require("./subscription");
38
40
  class Cache {
39
41
  _internal_unstable;
40
- constructor({ disabled, ...config } = {}) {
42
+ constructor({
43
+ disabled,
44
+ componentCache,
45
+ createComponent,
46
+ ...config
47
+ } = {}) {
41
48
  this._internal_unstable = new CacheInternal({
42
49
  cache: this,
43
50
  storage: new import_storage.InMemoryStorage(),
@@ -45,7 +52,9 @@ class Cache {
45
52
  lists: new import_lists.ListManager(this, rootID),
46
53
  lifetimes: new import_gc.GarbageCollector(this),
47
54
  staleManager: new import_staleManager.StaleManager(this),
48
- disabled: disabled ?? typeof globalThis.window === "undefined"
55
+ disabled: disabled ?? typeof globalThis.window === "undefined",
56
+ componentCache,
57
+ createComponent
49
58
  });
50
59
  if (Object.keys(config).length > 0) {
51
60
  this.setConfig((0, import_config.defaultConfigValues)(config));
@@ -220,6 +229,8 @@ class CacheInternal {
220
229
  cache;
221
230
  lifetimes;
222
231
  staleManager;
232
+ componentCache;
233
+ createComponent;
223
234
  constructor({
224
235
  storage,
225
236
  subscriptions,
@@ -228,7 +239,9 @@ class CacheInternal {
228
239
  lifetimes,
229
240
  staleManager,
230
241
  disabled,
231
- config
242
+ config,
243
+ componentCache,
244
+ createComponent
232
245
  }) {
233
246
  this.storage = storage;
234
247
  this.subscriptions = subscriptions;
@@ -237,6 +250,8 @@ class CacheInternal {
237
250
  this.lifetimes = lifetimes;
238
251
  this.staleManager = staleManager;
239
252
  this._config = config;
253
+ this.componentCache = componentCache ?? {};
254
+ this.createComponent = createComponent ?? (() => ({}));
240
255
  this._disabled = disabled;
241
256
  try {
242
257
  if (process.env.HOUDINI_TEST === "true") {
@@ -566,7 +581,8 @@ class CacheInternal {
566
581
  visible,
567
582
  directives,
568
583
  loading: fieldLoading,
569
- abstractHasRequired
584
+ abstractHasRequired,
585
+ component
570
586
  }
571
587
  ] of Object.entries(targetSelection)) {
572
588
  if (!visible && !ignoreMasking && !fullCheck) {
@@ -593,7 +609,13 @@ class CacheInternal {
593
609
  if (generateLoading && !fieldLoading) {
594
610
  continue;
595
611
  }
596
- let { value } = this.storage.get(parent, key);
612
+ const defaultValue = !component ? void 0 : defaultComponentField({
613
+ cache: this.cache,
614
+ component,
615
+ variables,
616
+ parent
617
+ });
618
+ let { value } = this.storage.get(parent, key, defaultValue);
597
619
  const dt_field = this.staleManager.getFieldTime(parent, key);
598
620
  if (dt_field === null) {
599
621
  stale = true;
@@ -640,12 +662,16 @@ class CacheInternal {
640
662
  stepsFromConnection: nextStep,
641
663
  ignoreMasking: !!ignoreMasking,
642
664
  fullCheck,
643
- loading: generateLoading
665
+ loading: generateLoading,
666
+ nullable: !!nullable
644
667
  });
645
668
  fieldTarget[attributeName] = listValue.data;
646
669
  if (listValue.partial) {
647
670
  partial = true;
648
671
  }
672
+ if (listValue.cascadeNull) {
673
+ cascadeNull = true;
674
+ }
649
675
  if (listValue.stale) {
650
676
  stale = true;
651
677
  }
@@ -725,16 +751,19 @@ class CacheInternal {
725
751
  stepsFromConnection,
726
752
  ignoreMasking,
727
753
  fullCheck,
728
- loading
754
+ loading,
755
+ nullable
729
756
  }) {
730
757
  const result = [];
731
758
  let partialData = false;
732
759
  let stale = false;
733
760
  let hasValues = false;
761
+ let cascadeNull = false;
734
762
  for (const entry of linkedList) {
735
763
  if (Array.isArray(entry)) {
736
764
  const nestedValue = this.hydrateNestedList({
737
765
  fields,
766
+ nullable,
738
767
  variables,
739
768
  linkedList: entry,
740
769
  stepsFromConnection,
@@ -746,6 +775,9 @@ class CacheInternal {
746
775
  if (nestedValue.partial) {
747
776
  partialData = true;
748
777
  }
778
+ if (nestedValue.cascadeNull) {
779
+ cascadeNull = true;
780
+ }
749
781
  continue;
750
782
  }
751
783
  if (entry === null) {
@@ -766,6 +798,9 @@ class CacheInternal {
766
798
  fullCheck,
767
799
  loading
768
800
  });
801
+ if (data === null && !nullable) {
802
+ cascadeNull = true;
803
+ }
769
804
  result.push(data);
770
805
  if (partial) {
771
806
  partialData = true;
@@ -781,7 +816,8 @@ class CacheInternal {
781
816
  data: result,
782
817
  partial: partialData,
783
818
  stale,
784
- hasData: hasValues
819
+ hasData: hasValues,
820
+ cascadeNull
785
821
  };
786
822
  }
787
823
  extractNestedListIDs({
@@ -910,9 +946,43 @@ function fragmentVariableValue(value, args) {
910
946
  }
911
947
  }
912
948
  const rootID = "_ROOT_";
949
+ function fragmentReference({
950
+ component,
951
+ prop
952
+ }) {
953
+ return `${component.name}.${prop}`;
954
+ }
955
+ function defaultComponentField({
956
+ cache,
957
+ component,
958
+ loading,
959
+ variables,
960
+ parent
961
+ }) {
962
+ return (props) => {
963
+ const componentFn = cache._internal_unstable.componentCache[component.key];
964
+ const args = evaluateFragmentVariables(component.variables ?? {}, variables ?? {});
965
+ return cache._internal_unstable.createComponent(componentFn, {
966
+ ...props,
967
+ [component.prop]: {
968
+ [import_types.fragmentKey]: {
969
+ loading,
970
+ values: {
971
+ [component.fragment]: {
972
+ variables: args,
973
+ parent
974
+ }
975
+ }
976
+ }
977
+ }
978
+ });
979
+ };
980
+ }
913
981
  // Annotate the CommonJS export names for ESM import in node:
914
982
  0 && (module.exports = {
915
983
  Cache,
984
+ defaultComponentField,
916
985
  evaluateFragmentVariables,
986
+ fragmentReference,
917
987
  rootID
918
988
  });
@@ -16,7 +16,7 @@ export declare class InMemoryStorage {
16
16
  from: string;
17
17
  to: string;
18
18
  }): void;
19
- get(id: string, field: string): {
19
+ get(id: string, field: string, defaultValue?: any): {
20
20
  value: GraphQLField;
21
21
  kind: 'link' | 'scalar' | 'unknown';
22
22
  displayLayers: number[];
@@ -69,7 +69,7 @@ class InMemoryStorage {
69
69
  layer.replaceID(replacement);
70
70
  }
71
71
  }
72
- get(id, field) {
72
+ get(id, field, defaultValue) {
73
73
  const operations = {
74
74
  [OperationKind.insert]: {
75
75
  [OperationLocation.start]: [],
@@ -80,7 +80,7 @@ class InMemoryStorage {
80
80
  const layerIDs = [];
81
81
  for (let i = this.data.length - 1; i >= 0; i--) {
82
82
  const layer = this.data[i];
83
- const [layerValue, kind] = layer.get(id, field);
83
+ let [layerValue, kind] = layer.get(id, field);
84
84
  const layerOperations = layer.getOperations(id, field) || [];
85
85
  layer.deletedIDs.forEach((v) => {
86
86
  if (layer.operations[v]?.undoDeletesInList?.includes(field)) {
@@ -88,6 +88,12 @@ class InMemoryStorage {
88
88
  }
89
89
  operations.remove.add(v);
90
90
  });
91
+ if (typeof layerValue === "undefined" && defaultValue) {
92
+ const targetLayer = this.topLayer;
93
+ const layerID = targetLayer.id;
94
+ targetLayer.writeField(id, field, defaultValue);
95
+ layerValue = defaultValue;
96
+ }
91
97
  if (typeof layerValue === "undefined" && layerOperations.length === 0) {
92
98
  if (layer.deletedIDs.size > 0) {
93
99
  layerIDs.push(layer.id);
@@ -188,7 +194,14 @@ class InMemoryStorage {
188
194
  serialize() {
189
195
  return JSON.stringify({
190
196
  rank: this.rank,
191
- fields: this.topLayer.fields,
197
+ fields: Object.fromEntries(
198
+ Object.entries(this.topLayer.fields).map(([id, fieldMap]) => [
199
+ id,
200
+ Object.fromEntries(
201
+ Object.entries(fieldMap).filter(([_, value]) => typeof value !== "function")
202
+ )
203
+ ])
204
+ ),
192
205
  links: this.topLayer.links
193
206
  });
194
207
  }
@@ -31,6 +31,7 @@ export declare class HoudiniClient {
31
31
  operationName: string;
32
32
  session: App.Session | null | undefined;
33
33
  }) => Promise<any>>;
34
+ componentCache: Record<string, any>;
34
35
  constructor({ url, fetchParams, plugins, pipeline, throwOnError, }?: HoudiniClientConstructorArgs);
35
36
  observe<_Data extends GraphQLObject, _Input extends GraphQLVariables>({ enableCache, fetching, ...rest }: ObserveParams<_Data, DocumentArtifact, _Input>): DocumentStore<_Data, _Input>;
36
37
  registerProxy(url: string, handler: (operation: {
@@ -45,6 +45,7 @@ class HoudiniClient {
45
45
  plugins;
46
46
  throwOnError_operations;
47
47
  proxies = {};
48
+ componentCache = {};
48
49
  constructor({
49
50
  url,
50
51
  fetchParams,
@@ -3,6 +3,6 @@ import type { CacheTypeDef } from './generated';
3
3
  import { Cache } from './public';
4
4
  export * from './client';
5
5
  export * from './lib';
6
- export declare function graphql<_Payload>(str: TemplateStringsArray): _Payload;
6
+ export declare function graphql<_Payload, _Result = _Payload>(str: TemplateStringsArray): _Result;
7
7
  export declare const cache: Cache<CacheTypeDef>;
8
8
  export declare function getCache(): InternalCache;
@@ -110,12 +110,21 @@ export type ConfigFile = {
110
110
  /**
111
111
  * For now, the cache's imperative API is considered unstable. In order to suppress the warning,
112
112
  * you must enable this flag.
113
+ *
114
+ * @deprecated set features.imperativeCache instead
113
115
  */
114
116
  acceptImperativeInstability?: boolean;
115
117
  /**
116
118
  * Configure the router
117
119
  */
118
120
  router?: RouterConfig;
121
+ /**
122
+ * A collection of flags to opt-into experimental features that might break unexpectedly
123
+ */
124
+ features?: {
125
+ componentFields?: boolean;
126
+ imperativeCache?: boolean;
127
+ };
119
128
  };
120
129
  type RouterConfig = {
121
130
  auth?: AuthStrategy;
@@ -7,3 +7,4 @@ export * from './types';
7
7
  export * from './store';
8
8
  export * from './key';
9
9
  export * from './lru';
10
+ export * from './selection';
@@ -24,3 +24,4 @@ __reExport(lib_exports, require("./types"), module.exports);
24
24
  __reExport(lib_exports, require("./store"), module.exports);
25
25
  __reExport(lib_exports, require("./key"), module.exports);
26
26
  __reExport(lib_exports, require("./lru"), module.exports);
27
+ __reExport(lib_exports, require("./selection"), module.exports);
@@ -79,6 +79,7 @@ export type BaseCompiledDocument<_Kind extends ArtifactKinds> = {
79
79
  selection: SubscriptionSelection;
80
80
  rootType: string;
81
81
  input?: InputObject;
82
+ hasComponents?: boolean;
82
83
  refetch?: {
83
84
  path: string[];
84
85
  method: 'cursor' | 'offset';
@@ -156,12 +157,16 @@ export type SubscriptionSelection = {
156
157
  arguments: ValueMap;
157
158
  loading?: boolean;
158
159
  }>;
160
+ components?: Record<string, {
161
+ prop: string;
162
+ attribute: string;
163
+ }>;
159
164
  fields?: {
160
165
  [fieldName: string]: {
161
166
  type: string;
167
+ keyRaw: string;
162
168
  nullable?: boolean;
163
169
  required?: boolean;
164
- keyRaw: string;
165
170
  operations?: MutationOperation[];
166
171
  list?: {
167
172
  name: string;
@@ -182,6 +187,12 @@ export type SubscriptionSelection = {
182
187
  selection?: SubscriptionSelection;
183
188
  abstract?: boolean;
184
189
  abstractHasRequired?: boolean;
190
+ component?: {
191
+ prop: string;
192
+ key: string;
193
+ fragment: string;
194
+ variables: ValueMap | null;
195
+ };
185
196
  };
186
197
  };
187
198
  abstractFields?: {
@@ -333,6 +344,10 @@ export type ProjectManifest = {
333
344
  local_schema: boolean;
334
345
  /** Whether or not there is a custom instance of yoga defined */
335
346
  local_yoga: boolean;
347
+ /** Information about componentFields defined in the project */
348
+ component_fields: Record<string, {
349
+ filepath: string;
350
+ }>;
336
351
  };
337
352
  export type PageManifest = {
338
353
  id: string;
@@ -356,4 +371,6 @@ export type QueryManifest = {
356
371
  loading: boolean;
357
372
  /** The filepath of the unit */
358
373
  path: string;
374
+ /** The list of variables that this query cares about */
375
+ variables: string[];
359
376
  };
@@ -30,9 +30,10 @@ class Cache {
30
30
  this._internal_unstable = cache;
31
31
  }
32
32
  validateInstabilityWarning() {
33
- if (!this.config.acceptImperativeInstability) {
33
+ if (!this.config.acceptImperativeInstability && !this.config.features?.imperativeCache) {
34
34
  console.warn(`\u26A0\uFE0F The imperative cache API is considered unstable and will change in any minor version release
35
- Please acknowledge this by setting acceptImperativeInstability to true in your config file.`);
35
+ Please acknowledge this by enabling the imperative cache feature flage in your config file.
36
+ For more information: https://houdinigraphql.com/api/cache`);
36
37
  }
37
38
  }
38
39
  get(type, data) {