houdini-react 1.2.45 → 1.2.47

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.
@@ -76800,9 +76800,12 @@ var InMemorySubscriptions = class {
76800
76800
  removeSubscribers(id, fieldName, specs) {
76801
76801
  let targets = [];
76802
76802
  const subscriber = this.subscribers.get(id);
76803
- const subscriberField = subscriber?.get(fieldName);
76803
+ if (!subscriber) {
76804
+ return;
76805
+ }
76806
+ const subscriberField = subscriber.get(fieldName);
76804
76807
  for (const spec of specs) {
76805
- const counts = subscriber?.get(fieldName)?.referenceCounts;
76808
+ const counts = subscriber.get(fieldName)?.referenceCounts;
76806
76809
  if (!counts?.has(spec.set)) {
76807
76810
  continue;
76808
76811
  }
@@ -76812,12 +76815,18 @@ var InMemorySubscriptions = class {
76812
76815
  targets.push(spec.set);
76813
76816
  counts.delete(spec.set);
76814
76817
  }
76818
+ if (counts.size === 0) {
76819
+ subscriber.delete(fieldName);
76820
+ }
76815
76821
  }
76816
76822
  if (subscriberField) {
76817
76823
  subscriberField.selections = this.get(id, fieldName).filter(
76818
76824
  ([{ set }]) => !targets.includes(set)
76819
76825
  );
76820
76826
  }
76827
+ if (subscriber.size === 0) {
76828
+ this.subscribers.delete(id);
76829
+ }
76821
76830
  }
76822
76831
  removeAllSubscribers(id, targets, visited = []) {
76823
76832
  visited.push(id);
@@ -76838,6 +76847,15 @@ var InMemorySubscriptions = class {
76838
76847
  }
76839
76848
  }
76840
76849
  }
76850
+ get size() {
76851
+ let size = 0;
76852
+ for (const [, nodeCounts] of this.subscribers) {
76853
+ for (const [, { referenceCounts }] of nodeCounts) {
76854
+ size += [...referenceCounts.values()].reduce((size2, count) => size2 + count, 0);
76855
+ }
76856
+ }
76857
+ return size;
76858
+ }
76841
76859
  };
76842
76860
  var Cache = class {
76843
76861
  _internal_unstable;
@@ -76884,6 +76902,9 @@ var Cache = class {
76884
76902
  };
76885
76903
  }
76886
76904
  subscribe(spec, variables = {}) {
76905
+ if (this._internal_unstable.disabled) {
76906
+ return;
76907
+ }
76887
76908
  return this._internal_unstable.subscriptions.add({
76888
76909
  parent: spec.parentID || rootID,
76889
76910
  spec,
@@ -77023,7 +77044,7 @@ var Cache = class {
77023
77044
  }
77024
77045
  };
77025
77046
  var CacheInternal = class {
77026
- _disabled = false;
77047
+ disabled = false;
77027
77048
  _config;
77028
77049
  storage;
77029
77050
  subscriptions;
@@ -77054,10 +77075,10 @@ var CacheInternal = class {
77054
77075
  this._config = config;
77055
77076
  this.componentCache = componentCache ?? {};
77056
77077
  this.createComponent = createComponent ?? (() => ({}));
77057
- this._disabled = disabled;
77078
+ this.disabled = disabled;
77058
77079
  try {
77059
77080
  if (process.env.HOUDINI_TEST === "true") {
77060
- this._disabled = false;
77081
+ this.disabled = false;
77061
77082
  }
77062
77083
  } catch {
77063
77084
  }
@@ -77079,7 +77100,7 @@ var CacheInternal = class {
77079
77100
  forceNotify,
77080
77101
  forceStale
77081
77102
  }) {
77082
- if (this._disabled) {
77103
+ if (this.disabled) {
77083
77104
  return [];
77084
77105
  }
77085
77106
  let targetSelection = getFieldsForType(
@@ -77863,7 +77884,12 @@ function deepMerge2(filepath, ...targets) {
77863
77884
  }
77864
77885
  function parseJS(str, config) {
77865
77886
  const defaultConfig = {
77866
- plugins: ["typescript", "importAssertions", "decorators-legacy"],
77887
+ plugins: [
77888
+ "typescript",
77889
+ "importAssertions",
77890
+ "decorators-legacy",
77891
+ "explicitResourceManagement"
77892
+ ],
77867
77893
  sourceType: "module"
77868
77894
  };
77869
77895
  return (0, import_parser.parse)(str || "", config ? deepMerge2("", defaultConfig, config) : defaultConfig).program;
@@ -78809,7 +78835,18 @@ async function extractQueries(source) {
78809
78835
  } else {
78810
78836
  return [];
78811
78837
  }
78812
- return props.filter((p) => p !== "children");
78838
+ return props.reduce((queries, query2) => {
78839
+ if (query2 === "children") {
78840
+ return queries;
78841
+ }
78842
+ if (query2.endsWith("$handle")) {
78843
+ query2 = query2.substring(0, query2.length - "$handle".length);
78844
+ }
78845
+ if (queries.includes(query2)) {
78846
+ return queries;
78847
+ }
78848
+ return queries.concat([query2]);
78849
+ }, []);
78813
78850
  }
78814
78851
  function isSecondaryBuild() {
78815
78852
  return process.env.HOUDINI_SECONDARY_BUILD && process.env.HOUDINI_SECONDARY_BUILD !== "false";
@@ -79850,6 +79887,13 @@ var vite_default = {
79850
79887
  initialVariables: variables,
79851
79888
  })
79852
79889
 
79890
+ // initialize the observer we just created
79891
+ observer.send({
79892
+ setup: true,
79893
+ variables,
79894
+ session: window.__houdini__initial__session__,
79895
+ })
79896
+
79853
79897
  // save it in the cache
79854
79898
  initialData[artifactName] = observer
79855
79899
  initialVariables[artifactName] = variables
@@ -76790,9 +76790,12 @@ var InMemorySubscriptions = class {
76790
76790
  removeSubscribers(id, fieldName, specs) {
76791
76791
  let targets = [];
76792
76792
  const subscriber = this.subscribers.get(id);
76793
- const subscriberField = subscriber?.get(fieldName);
76793
+ if (!subscriber) {
76794
+ return;
76795
+ }
76796
+ const subscriberField = subscriber.get(fieldName);
76794
76797
  for (const spec of specs) {
76795
- const counts = subscriber?.get(fieldName)?.referenceCounts;
76798
+ const counts = subscriber.get(fieldName)?.referenceCounts;
76796
76799
  if (!counts?.has(spec.set)) {
76797
76800
  continue;
76798
76801
  }
@@ -76802,12 +76805,18 @@ var InMemorySubscriptions = class {
76802
76805
  targets.push(spec.set);
76803
76806
  counts.delete(spec.set);
76804
76807
  }
76808
+ if (counts.size === 0) {
76809
+ subscriber.delete(fieldName);
76810
+ }
76805
76811
  }
76806
76812
  if (subscriberField) {
76807
76813
  subscriberField.selections = this.get(id, fieldName).filter(
76808
76814
  ([{ set }]) => !targets.includes(set)
76809
76815
  );
76810
76816
  }
76817
+ if (subscriber.size === 0) {
76818
+ this.subscribers.delete(id);
76819
+ }
76811
76820
  }
76812
76821
  removeAllSubscribers(id, targets, visited = []) {
76813
76822
  visited.push(id);
@@ -76828,6 +76837,15 @@ var InMemorySubscriptions = class {
76828
76837
  }
76829
76838
  }
76830
76839
  }
76840
+ get size() {
76841
+ let size = 0;
76842
+ for (const [, nodeCounts] of this.subscribers) {
76843
+ for (const [, { referenceCounts }] of nodeCounts) {
76844
+ size += [...referenceCounts.values()].reduce((size2, count) => size2 + count, 0);
76845
+ }
76846
+ }
76847
+ return size;
76848
+ }
76831
76849
  };
76832
76850
  var Cache = class {
76833
76851
  _internal_unstable;
@@ -76874,6 +76892,9 @@ var Cache = class {
76874
76892
  };
76875
76893
  }
76876
76894
  subscribe(spec, variables = {}) {
76895
+ if (this._internal_unstable.disabled) {
76896
+ return;
76897
+ }
76877
76898
  return this._internal_unstable.subscriptions.add({
76878
76899
  parent: spec.parentID || rootID,
76879
76900
  spec,
@@ -77013,7 +77034,7 @@ var Cache = class {
77013
77034
  }
77014
77035
  };
77015
77036
  var CacheInternal = class {
77016
- _disabled = false;
77037
+ disabled = false;
77017
77038
  _config;
77018
77039
  storage;
77019
77040
  subscriptions;
@@ -77044,10 +77065,10 @@ var CacheInternal = class {
77044
77065
  this._config = config;
77045
77066
  this.componentCache = componentCache ?? {};
77046
77067
  this.createComponent = createComponent ?? (() => ({}));
77047
- this._disabled = disabled;
77068
+ this.disabled = disabled;
77048
77069
  try {
77049
77070
  if (process.env.HOUDINI_TEST === "true") {
77050
- this._disabled = false;
77071
+ this.disabled = false;
77051
77072
  }
77052
77073
  } catch {
77053
77074
  }
@@ -77069,7 +77090,7 @@ var CacheInternal = class {
77069
77090
  forceNotify,
77070
77091
  forceStale
77071
77092
  }) {
77072
- if (this._disabled) {
77093
+ if (this.disabled) {
77073
77094
  return [];
77074
77095
  }
77075
77096
  let targetSelection = getFieldsForType(
@@ -77853,7 +77874,12 @@ function deepMerge2(filepath, ...targets) {
77853
77874
  }
77854
77875
  function parseJS(str, config) {
77855
77876
  const defaultConfig = {
77856
- plugins: ["typescript", "importAssertions", "decorators-legacy"],
77877
+ plugins: [
77878
+ "typescript",
77879
+ "importAssertions",
77880
+ "decorators-legacy",
77881
+ "explicitResourceManagement"
77882
+ ],
77857
77883
  sourceType: "module"
77858
77884
  };
77859
77885
  return (0, import_parser.parse)(str || "", config ? deepMerge2("", defaultConfig, config) : defaultConfig).program;
@@ -78799,7 +78825,18 @@ async function extractQueries(source) {
78799
78825
  } else {
78800
78826
  return [];
78801
78827
  }
78802
- return props.filter((p) => p !== "children");
78828
+ return props.reduce((queries, query2) => {
78829
+ if (query2 === "children") {
78830
+ return queries;
78831
+ }
78832
+ if (query2.endsWith("$handle")) {
78833
+ query2 = query2.substring(0, query2.length - "$handle".length);
78834
+ }
78835
+ if (queries.includes(query2)) {
78836
+ return queries;
78837
+ }
78838
+ return queries.concat([query2]);
78839
+ }, []);
78803
78840
  }
78804
78841
  function isSecondaryBuild() {
78805
78842
  return process.env.HOUDINI_SECONDARY_BUILD && process.env.HOUDINI_SECONDARY_BUILD !== "false";
@@ -79840,6 +79877,13 @@ var vite_default = {
79840
79877
  initialVariables: variables,
79841
79878
  })
79842
79879
 
79880
+ // initialize the observer we just created
79881
+ observer.send({
79882
+ setup: true,
79883
+ variables,
79884
+ session: window.__houdini__initial__session__,
79885
+ })
79886
+
79843
79887
  // save it in the cache
79844
79888
  initialData[artifactName] = observer
79845
79889
  initialVariables[artifactName] = variables
@@ -10,6 +10,8 @@ export declare function useDocumentHandle<_Artifact extends QueryArtifact, _Data
10
10
  export type DocumentHandle<_Artifact extends QueryArtifact, _Data extends GraphQLObject = GraphQLObject, _Input extends GraphQLVariables = GraphQLVariables> = {
11
11
  data: _Data;
12
12
  partial: boolean;
13
+ fetch: FetchFn<_Data, Partial<_Input>>;
14
+ variables: _Input;
13
15
  } & RefetchHandlers<_Artifact, _Data, _Input>;
14
16
  type RefetchHandlers<_Artifact extends QueryArtifact, _Data extends GraphQLObject, _Input> = _Artifact extends {
15
17
  refetch: {
@@ -5,6 +5,7 @@ import { GraphQLObject, GraphQLVariables } from '$houdini/runtime/lib/types';
5
5
  import { QueryArtifact } from '$houdini/runtime/lib/types';
6
6
  import type { RouterManifest } from '$houdini/runtime/router/types';
7
7
  import React from 'react';
8
+ import { DocumentHandle } from '../hooks/useDocumentHandle';
8
9
  import { SuspenseCache } from './cache';
9
10
  type ComponentType = any;
10
11
  /**
@@ -21,6 +22,7 @@ export declare function Router({ manifest, initialURL, assetPrefix, injectToStre
21
22
  export declare const useLocation: () => {
22
23
  pathname: string;
23
24
  params: Record<string, any>;
25
+ goto: (url: string) => void;
24
26
  };
25
27
  export declare function RouterContextProvider({ children, client, cache, artifact_cache, component_cache, data_cache, ssr_signals, last_variables, session: ssrSession, }: {
26
28
  children: React.ReactElement;
@@ -54,7 +56,7 @@ export declare function useCache(): Cache;
54
56
  export declare function updateLocalSession(session: App.Session): void;
55
57
  export declare function useSession(): [App.Session, (newSession: Partial<App.Session>) => void];
56
58
  export declare function useCurrentVariables(): GraphQLVariables;
57
- export declare function useQueryResult<_Data extends GraphQLObject, _Input extends GraphQLVariables>(name: string): [_Data | null, DocumentStore<_Data, _Input>];
59
+ export declare function useQueryResult<_Data extends GraphQLObject, _Input extends GraphQLVariables>(name: string): [_Data | null, DocumentHandle<any, _Data, _Input>];
58
60
  export type RouterCache = {
59
61
  artifact_cache: SuspenseCache<QueryArtifact>;
60
62
  component_cache: SuspenseCache<(props: any) => React.ReactElement>;
@@ -23,11 +23,11 @@ __export(clientPlugin_exports, {
23
23
  module.exports = __toCommonJS(clientPlugin_exports);
24
24
  const plugin = () => () => {
25
25
  return {
26
- beforeNetwork(ctx, { next }) {
26
+ start(ctx, { next }) {
27
27
  next({
28
28
  ...ctx,
29
29
  cacheParams: {
30
- ...ctx.fetchParams,
30
+ ...ctx.cacheParams,
31
31
  serverSideFallback: false
32
32
  }
33
33
  });
@@ -10,6 +10,8 @@ export declare function useDocumentHandle<_Artifact extends QueryArtifact, _Data
10
10
  export type DocumentHandle<_Artifact extends QueryArtifact, _Data extends GraphQLObject = GraphQLObject, _Input extends GraphQLVariables = GraphQLVariables> = {
11
11
  data: _Data;
12
12
  partial: boolean;
13
+ fetch: FetchFn<_Data, Partial<_Input>>;
14
+ variables: _Input;
13
15
  } & RefetchHandlers<_Artifact, _Data, _Input>;
14
16
  type RefetchHandlers<_Artifact extends QueryArtifact, _Data extends GraphQLObject, _Input> = _Artifact extends {
15
17
  refetch: {
@@ -39,7 +39,15 @@ function useDocumentHandle({
39
39
  }) {
40
40
  const [forwardPending, setForwardPending] = import_react.default.useState(false);
41
41
  const [backwardPending, setBackwardPending] = import_react.default.useState(false);
42
+ const location = (0, import_Router.useLocation)();
42
43
  const [session] = (0, import_Router.useSession)();
44
+ const client = (0, import_Router.useClient)();
45
+ const paginationObserver = import_react.default.useMemo(() => {
46
+ if (!artifact.refetch?.paginated) {
47
+ return null;
48
+ }
49
+ return client.observe({ artifact });
50
+ }, [artifact.name]);
43
51
  return import_react.default.useMemo(() => {
44
52
  const wrapLoad = (setLoading, fn) => {
45
53
  return async (value) => {
@@ -49,13 +57,27 @@ function useDocumentHandle({
49
57
  return result;
50
58
  };
51
59
  };
52
- const fetchQuery = (args) => observer.send({
53
- ...args,
54
- session
55
- });
60
+ const fetchQuery = (args) => {
61
+ const usedVariables = Object.fromEntries(
62
+ Object.keys(observer.artifact.input?.fields ?? {}).map((fieldName) => [
63
+ fieldName,
64
+ location.params[fieldName]
65
+ ])
66
+ );
67
+ return observer.send({
68
+ ...args,
69
+ variables: {
70
+ ...usedVariables,
71
+ ...args?.variables
72
+ },
73
+ session
74
+ });
75
+ };
56
76
  if (artifact.kind !== import_types.ArtifactKind.Query || !artifact.refetch?.paginated) {
57
77
  return {
78
+ artifact,
58
79
  data: storeValue.data,
80
+ variables: storeValue.variables,
59
81
  fetch: fetchQuery,
60
82
  partial: storeValue.partial
61
83
  };
@@ -67,12 +89,12 @@ function useDocumentHandle({
67
89
  getVariables: () => storeValue.variables,
68
90
  fetch: fetchQuery,
69
91
  fetchUpdate: (args, updates) => {
70
- return observer.send({
92
+ return paginationObserver.send({
71
93
  ...args,
72
94
  cacheParams: {
95
+ ...args?.cacheParams,
73
96
  disableSubscriptions: true,
74
- applyUpdates: updates,
75
- ...args?.cacheParams
97
+ applyUpdates: updates
76
98
  },
77
99
  session
78
100
  });
@@ -80,7 +102,9 @@ function useDocumentHandle({
80
102
  getSession: async () => session
81
103
  });
82
104
  return {
105
+ artifact,
83
106
  data: storeValue.data,
107
+ variables: storeValue.variables,
84
108
  fetch: handlers.fetch,
85
109
  partial: storeValue.partial,
86
110
  loadNext: wrapLoad(setForwardPending, handlers.loadNextPage),
@@ -98,7 +122,7 @@ function useDocumentHandle({
98
122
  storeName: artifact.name,
99
123
  fetch: fetchQuery,
100
124
  fetchUpdate: async (args, updates = ["append"]) => {
101
- return observer.send({
125
+ return paginationObserver.send({
102
126
  ...args,
103
127
  cacheParams: {
104
128
  disableSubscriptions: true,
@@ -110,7 +134,9 @@ function useDocumentHandle({
110
134
  getSession: async () => session
111
135
  });
112
136
  return {
137
+ artifact,
113
138
  data: storeValue.data,
139
+ variables: storeValue.variables,
114
140
  fetch: handlers.fetch,
115
141
  partial: storeValue.partial,
116
142
  loadNext: wrapLoad(setForwardPending, handlers.loadNextPage),
@@ -118,12 +144,14 @@ function useDocumentHandle({
118
144
  };
119
145
  }
120
146
  return {
147
+ artifact,
121
148
  data: storeValue.data,
149
+ variables: storeValue.variables,
122
150
  fetch: fetchQuery,
123
151
  refetch: fetchQuery,
124
152
  partial: storeValue.partial
125
153
  };
126
- }, [artifact, observer, session, storeValue, true, true]);
154
+ }, [artifact, observer, session, storeValue]);
127
155
  }
128
156
  // Annotate the CommonJS export names for ESM import in node:
129
157
  0 && (module.exports = {
@@ -5,6 +5,7 @@ import { GraphQLObject, GraphQLVariables } from '$houdini/runtime/lib/types';
5
5
  import { QueryArtifact } from '$houdini/runtime/lib/types';
6
6
  import type { RouterManifest } from '$houdini/runtime/router/types';
7
7
  import React from 'react';
8
+ import { DocumentHandle } from '../hooks/useDocumentHandle';
8
9
  import { SuspenseCache } from './cache';
9
10
  type ComponentType = any;
10
11
  /**
@@ -21,6 +22,7 @@ export declare function Router({ manifest, initialURL, assetPrefix, injectToStre
21
22
  export declare const useLocation: () => {
22
23
  pathname: string;
23
24
  params: Record<string, any>;
25
+ goto: (url: string) => void;
24
26
  };
25
27
  export declare function RouterContextProvider({ children, client, cache, artifact_cache, component_cache, data_cache, ssr_signals, last_variables, session: ssrSession, }: {
26
28
  children: React.ReactElement;
@@ -54,7 +56,7 @@ export declare function useCache(): Cache;
54
56
  export declare function updateLocalSession(session: App.Session): void;
55
57
  export declare function useSession(): [App.Session, (newSession: Partial<App.Session>) => void];
56
58
  export declare function useCurrentVariables(): GraphQLVariables;
57
- export declare function useQueryResult<_Data extends GraphQLObject, _Input extends GraphQLVariables>(name: string): [_Data | null, DocumentStore<_Data, _Input>];
59
+ export declare function useQueryResult<_Data extends GraphQLObject, _Input extends GraphQLVariables>(name: string): [_Data | null, DocumentHandle<any, _Data, _Input>];
58
60
  export type RouterCache = {
59
61
  artifact_cache: SuspenseCache<QueryArtifact>;
60
62
  component_cache: SuspenseCache<(props: any) => React.ReactElement>;
@@ -46,6 +46,7 @@ var import_scalars = require("$houdini/runtime/lib/scalars");
46
46
  var import_match = require("$houdini/runtime/router/match");
47
47
  var import_react = __toESM(require("react"));
48
48
  var import_react2 = require("react");
49
+ var import_useDocumentHandle = require("../hooks/useDocumentHandle");
49
50
  var import_useDocumentStore = require("../hooks/useDocumentStore");
50
51
  var import_cache = require("./cache");
51
52
  const PreloadWhich = {
@@ -62,7 +63,7 @@ function Router({
62
63
  const [currentURL, setCurrentURL] = import_react.default.useState(() => {
63
64
  return initialURL || window.location.pathname;
64
65
  });
65
- const [page, variables] = (0, import_match.find_match)(manifest, currentURL);
66
+ const [page, variables] = (0, import_match.find_match)(import_config.default, manifest, currentURL);
66
67
  if (!page) {
67
68
  throw new Error("404");
68
69
  }
@@ -72,7 +73,7 @@ function Router({
72
73
  assetPrefix,
73
74
  injectToStream
74
75
  });
75
- const { component_cache } = useRouterContext();
76
+ const { component_cache, data_cache } = useRouterContext();
76
77
  const PageComponent = component_cache.get(page.id);
77
78
  import_react.default.useEffect(() => {
78
79
  if (globalThis.window && window.location.pathname !== currentURL) {
@@ -91,21 +92,36 @@ function Router({
91
92
  window.removeEventListener("popstate", onChange);
92
93
  };
93
94
  }, []);
95
+ const goto = (url) => {
96
+ data_cache.clear();
97
+ setCurrentURL(url);
98
+ };
94
99
  useLinkBehavior({
95
- goto: (val) => {
96
- setCurrentURL(val);
97
- },
100
+ goto,
98
101
  preload(url, which) {
99
- const [page2, variables2] = (0, import_match.find_match)(manifest, url);
100
- if (["both", "component"].includes(which)) {
102
+ const [page2, variables2] = (0, import_match.find_match)(import_config.default, manifest, url);
103
+ if (!page2) {
104
+ return;
105
+ }
106
+ if (["page", "component"].includes(which)) {
101
107
  loadComponent(page2);
102
108
  }
103
- if (["both", "data"].includes(which)) {
109
+ if (["page", "data"].includes(which)) {
104
110
  loadData(page2, variables2);
105
111
  }
106
112
  }
107
113
  });
108
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VariableContext.Provider, { value: variables, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LocationContext.Provider, { value: { pathname: currentURL, params: variables ?? {} }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageComponent, { url: currentURL }, page.id) }) });
114
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(VariableContext.Provider, { value: variables, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
115
+ LocationContext.Provider,
116
+ {
117
+ value: {
118
+ pathname: currentURL,
119
+ goto,
120
+ params: variables ?? {}
121
+ },
122
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PageComponent, { url: currentURL }, page.id)
123
+ }
124
+ ) });
109
125
  }
110
126
  const useLocation = () => (0, import_react2.useContext)(LocationContext);
111
127
  function usePageData({
@@ -124,9 +140,13 @@ function usePageData({
124
140
  last_variables
125
141
  } = useRouterContext();
126
142
  const [session] = useSession();
127
- function load_query({ id, artifact }) {
143
+ function load_query({
144
+ id,
145
+ artifact,
146
+ variables: variables2
147
+ }) {
128
148
  for (const artifact2 of Object.keys(page.documents)) {
129
- last_variables.set(artifact2, variables);
149
+ last_variables.set(artifact2, variables2);
130
150
  }
131
151
  if (ssr_signals.has(id)) {
132
152
  return ssr_signals.get(id);
@@ -140,8 +160,7 @@ function usePageData({
140
160
  resolve = res;
141
161
  reject = rej;
142
162
  observer.send({
143
- variables,
144
- cacheParams: { disableSubscriptions: true },
163
+ variables: variables2,
145
164
  session
146
165
  }).then(async () => {
147
166
  data_cache.set(id, observer);
@@ -177,13 +196,14 @@ function usePageData({
177
196
  variables: ${JSON.stringify(
178
197
  (0, import_scalars.marshalInputs)({
179
198
  artifact: observer.artifact,
180
- input: variables,
199
+ input: variables2,
181
200
  config: import_config.default
182
201
  })
183
202
  )}
203
+ }).then(() => {
204
+ window.__houdini__nav_caches__?.data_cache.set(artifactName, new_store)
184
205
  })
185
206
 
186
- window.__houdini__nav_caches__?.data_cache.set(artifactName, new_store)
187
207
  }
188
208
 
189
209
 
@@ -217,7 +237,7 @@ function usePageData({
217
237
  variables: ${JSON.stringify(
218
238
  (0, import_scalars.marshalInputs)({
219
239
  artifact: observer.artifact,
220
- input: variables,
240
+ input: variables2,
221
241
  config: import_config.default
222
242
  })
223
243
  )}
@@ -242,6 +262,9 @@ function usePageData({
242
262
  return resolvable;
243
263
  }
244
264
  function loadData(targetPage, variables2) {
265
+ if (!targetPage) {
266
+ return;
267
+ }
245
268
  for (const [artifact, { variables: pageVariables }] of Object.entries(
246
269
  targetPage.documents
247
270
  )) {
@@ -274,14 +297,14 @@ function usePageData({
274
297
  injectToStream?.(`
275
298
  <script type="module" src="${assetPrefix}/artifacts/${artifact.name}.js" async=""><\/script>
276
299
  `);
277
- load_query({ id: artifact.name, artifact });
300
+ load_query({ id: artifact.name, artifact, variables: variables2 });
278
301
  }).catch((err) => {
279
302
  console.log(err);
280
303
  });
281
304
  }
282
305
  for (const artifact of Object.values(found_artifacts)) {
283
306
  if (!data_cache.has(artifact.name)) {
284
- load_query({ id: artifact.name, artifact });
307
+ load_query({ id: artifact.name, artifact, variables: variables2 });
285
308
  }
286
309
  }
287
310
  }
@@ -389,18 +412,27 @@ function useCurrentVariables() {
389
412
  const VariableContext = import_react.default.createContext(null);
390
413
  const LocationContext = import_react.default.createContext({
391
414
  pathname: "",
392
- params: {}
415
+ params: {},
416
+ goto: () => {
417
+ }
393
418
  });
394
419
  function useQueryResult(name) {
395
- const store_ref = useRouterContext().data_cache.get(name);
396
- const [{ data, errors }, observer] = (0, import_useDocumentStore.useDocumentStore)({
420
+ const { data_cache, artifact_cache } = useRouterContext();
421
+ const store_ref = data_cache.get(name);
422
+ const [storeValue, observer] = (0, import_useDocumentStore.useDocumentStore)({
397
423
  artifact: store_ref.artifact,
398
424
  observer: store_ref
399
425
  });
426
+ const { data, errors } = storeValue;
400
427
  if (errors && errors.length > 0) {
401
428
  throw new Error(JSON.stringify(errors));
402
429
  }
403
- return [data, observer];
430
+ const handle = (0, import_useDocumentHandle.useDocumentHandle)({
431
+ artifact: artifact_cache.get(name),
432
+ observer,
433
+ storeValue
434
+ });
435
+ return [data, handle];
404
436
  }
405
437
  function useLinkBehavior({
406
438
  goto,
@@ -443,10 +475,14 @@ function usePreload({ preload }) {
443
475
  import_react.default.useEffect(() => {
444
476
  const mouseMove = (e) => {
445
477
  const target = e.target;
446
- if (!(target instanceof HTMLAnchorElement)) {
478
+ if (!(target instanceof HTMLElement)) {
479
+ return;
480
+ }
481
+ const anchor = target.closest("a");
482
+ if (!anchor) {
447
483
  return;
448
484
  }
449
- let preloadWhichRaw = target.attributes.getNamedItem("data-houdini-preload")?.value;
485
+ let preloadWhichRaw = anchor.attributes.getNamedItem("data-houdini-preload")?.value;
450
486
  let preloadWhich = !preloadWhichRaw || preloadWhichRaw === "true" ? "page" : preloadWhichRaw;
451
487
  if (!PreloadWhich[preloadWhich]) {
452
488
  console.log(
@@ -458,7 +494,7 @@ function usePreload({ preload }) {
458
494
  clearTimeout(timeoutRef.current);
459
495
  }
460
496
  timeoutRef.current = setTimeout(() => {
461
- const url = target.attributes.getNamedItem("href")?.value;
497
+ const url = anchor.attributes.getNamedItem("href")?.value;
462
498
  if (!url) {
463
499
  return;
464
500
  }
@@ -1,10 +1,10 @@
1
1
  const plugin = () => () => {
2
2
  return {
3
- beforeNetwork(ctx, { next }) {
3
+ start(ctx, { next }) {
4
4
  next({
5
5
  ...ctx,
6
6
  cacheParams: {
7
- ...ctx.fetchParams,
7
+ ...ctx.cacheParams,
8
8
  serverSideFallback: false
9
9
  }
10
10
  });
@@ -10,6 +10,8 @@ export declare function useDocumentHandle<_Artifact extends QueryArtifact, _Data
10
10
  export type DocumentHandle<_Artifact extends QueryArtifact, _Data extends GraphQLObject = GraphQLObject, _Input extends GraphQLVariables = GraphQLVariables> = {
11
11
  data: _Data;
12
12
  partial: boolean;
13
+ fetch: FetchFn<_Data, Partial<_Input>>;
14
+ variables: _Input;
13
15
  } & RefetchHandlers<_Artifact, _Data, _Input>;
14
16
  type RefetchHandlers<_Artifact extends QueryArtifact, _Data extends GraphQLObject, _Input> = _Artifact extends {
15
17
  refetch: {
@@ -2,7 +2,7 @@ import { extractPageInfo } from "$houdini/runtime/lib/pageInfo";
2
2
  import { cursorHandlers, offsetHandlers } from "$houdini/runtime/lib/pagination";
3
3
  import { ArtifactKind } from "$houdini/runtime/lib/types";
4
4
  import React from "react";
5
- import { useSession } from "../routing/Router";
5
+ import { useClient, useLocation, useSession } from "../routing/Router";
6
6
  function useDocumentHandle({
7
7
  artifact,
8
8
  observer,
@@ -10,7 +10,15 @@ function useDocumentHandle({
10
10
  }) {
11
11
  const [forwardPending, setForwardPending] = React.useState(false);
12
12
  const [backwardPending, setBackwardPending] = React.useState(false);
13
+ const location = useLocation();
13
14
  const [session] = useSession();
15
+ const client = useClient();
16
+ const paginationObserver = React.useMemo(() => {
17
+ if (!artifact.refetch?.paginated) {
18
+ return null;
19
+ }
20
+ return client.observe({ artifact });
21
+ }, [artifact.name]);
14
22
  return React.useMemo(() => {
15
23
  const wrapLoad = (setLoading, fn) => {
16
24
  return async (value) => {
@@ -20,13 +28,27 @@ function useDocumentHandle({
20
28
  return result;
21
29
  };
22
30
  };
23
- const fetchQuery = (args) => observer.send({
24
- ...args,
25
- session
26
- });
31
+ const fetchQuery = (args) => {
32
+ const usedVariables = Object.fromEntries(
33
+ Object.keys(observer.artifact.input?.fields ?? {}).map((fieldName) => [
34
+ fieldName,
35
+ location.params[fieldName]
36
+ ])
37
+ );
38
+ return observer.send({
39
+ ...args,
40
+ variables: {
41
+ ...usedVariables,
42
+ ...args?.variables
43
+ },
44
+ session
45
+ });
46
+ };
27
47
  if (artifact.kind !== ArtifactKind.Query || !artifact.refetch?.paginated) {
28
48
  return {
49
+ artifact,
29
50
  data: storeValue.data,
51
+ variables: storeValue.variables,
30
52
  fetch: fetchQuery,
31
53
  partial: storeValue.partial
32
54
  };
@@ -38,12 +60,12 @@ function useDocumentHandle({
38
60
  getVariables: () => storeValue.variables,
39
61
  fetch: fetchQuery,
40
62
  fetchUpdate: (args, updates) => {
41
- return observer.send({
63
+ return paginationObserver.send({
42
64
  ...args,
43
65
  cacheParams: {
66
+ ...args?.cacheParams,
44
67
  disableSubscriptions: true,
45
- applyUpdates: updates,
46
- ...args?.cacheParams
68
+ applyUpdates: updates
47
69
  },
48
70
  session
49
71
  });
@@ -51,7 +73,9 @@ function useDocumentHandle({
51
73
  getSession: async () => session
52
74
  });
53
75
  return {
76
+ artifact,
54
77
  data: storeValue.data,
78
+ variables: storeValue.variables,
55
79
  fetch: handlers.fetch,
56
80
  partial: storeValue.partial,
57
81
  loadNext: wrapLoad(setForwardPending, handlers.loadNextPage),
@@ -69,7 +93,7 @@ function useDocumentHandle({
69
93
  storeName: artifact.name,
70
94
  fetch: fetchQuery,
71
95
  fetchUpdate: async (args, updates = ["append"]) => {
72
- return observer.send({
96
+ return paginationObserver.send({
73
97
  ...args,
74
98
  cacheParams: {
75
99
  disableSubscriptions: true,
@@ -81,7 +105,9 @@ function useDocumentHandle({
81
105
  getSession: async () => session
82
106
  });
83
107
  return {
108
+ artifact,
84
109
  data: storeValue.data,
110
+ variables: storeValue.variables,
85
111
  fetch: handlers.fetch,
86
112
  partial: storeValue.partial,
87
113
  loadNext: wrapLoad(setForwardPending, handlers.loadNextPage),
@@ -89,12 +115,14 @@ function useDocumentHandle({
89
115
  };
90
116
  }
91
117
  return {
118
+ artifact,
92
119
  data: storeValue.data,
120
+ variables: storeValue.variables,
93
121
  fetch: fetchQuery,
94
122
  refetch: fetchQuery,
95
123
  partial: storeValue.partial
96
124
  };
97
- }, [artifact, observer, session, storeValue, true, true]);
125
+ }, [artifact, observer, session, storeValue]);
98
126
  }
99
127
  export {
100
128
  useDocumentHandle
@@ -5,6 +5,7 @@ import { GraphQLObject, GraphQLVariables } from '$houdini/runtime/lib/types';
5
5
  import { QueryArtifact } from '$houdini/runtime/lib/types';
6
6
  import type { RouterManifest } from '$houdini/runtime/router/types';
7
7
  import React from 'react';
8
+ import { DocumentHandle } from '../hooks/useDocumentHandle';
8
9
  import { SuspenseCache } from './cache';
9
10
  type ComponentType = any;
10
11
  /**
@@ -21,6 +22,7 @@ export declare function Router({ manifest, initialURL, assetPrefix, injectToStre
21
22
  export declare const useLocation: () => {
22
23
  pathname: string;
23
24
  params: Record<string, any>;
25
+ goto: (url: string) => void;
24
26
  };
25
27
  export declare function RouterContextProvider({ children, client, cache, artifact_cache, component_cache, data_cache, ssr_signals, last_variables, session: ssrSession, }: {
26
28
  children: React.ReactElement;
@@ -54,7 +56,7 @@ export declare function useCache(): Cache;
54
56
  export declare function updateLocalSession(session: App.Session): void;
55
57
  export declare function useSession(): [App.Session, (newSession: Partial<App.Session>) => void];
56
58
  export declare function useCurrentVariables(): GraphQLVariables;
57
- export declare function useQueryResult<_Data extends GraphQLObject, _Input extends GraphQLVariables>(name: string): [_Data | null, DocumentStore<_Data, _Input>];
59
+ export declare function useQueryResult<_Data extends GraphQLObject, _Input extends GraphQLVariables>(name: string): [_Data | null, DocumentHandle<any, _Data, _Input>];
58
60
  export type RouterCache = {
59
61
  artifact_cache: SuspenseCache<QueryArtifact>;
60
62
  component_cache: SuspenseCache<(props: any) => React.ReactElement>;
@@ -5,6 +5,7 @@ import { marshalSelection, marshalInputs } from "$houdini/runtime/lib/scalars";
5
5
  import { find_match } from "$houdini/runtime/router/match";
6
6
  import React from "react";
7
7
  import { useContext } from "react";
8
+ import { useDocumentHandle } from "../hooks/useDocumentHandle";
8
9
  import { useDocumentStore } from "../hooks/useDocumentStore";
9
10
  import { suspense_cache } from "./cache";
10
11
  const PreloadWhich = {
@@ -21,7 +22,7 @@ function Router({
21
22
  const [currentURL, setCurrentURL] = React.useState(() => {
22
23
  return initialURL || window.location.pathname;
23
24
  });
24
- const [page, variables] = find_match(manifest, currentURL);
25
+ const [page, variables] = find_match(configFile, manifest, currentURL);
25
26
  if (!page) {
26
27
  throw new Error("404");
27
28
  }
@@ -31,7 +32,7 @@ function Router({
31
32
  assetPrefix,
32
33
  injectToStream
33
34
  });
34
- const { component_cache } = useRouterContext();
35
+ const { component_cache, data_cache } = useRouterContext();
35
36
  const PageComponent = component_cache.get(page.id);
36
37
  React.useEffect(() => {
37
38
  if (globalThis.window && window.location.pathname !== currentURL) {
@@ -50,21 +51,36 @@ function Router({
50
51
  window.removeEventListener("popstate", onChange);
51
52
  };
52
53
  }, []);
54
+ const goto = (url) => {
55
+ data_cache.clear();
56
+ setCurrentURL(url);
57
+ };
53
58
  useLinkBehavior({
54
- goto: (val) => {
55
- setCurrentURL(val);
56
- },
59
+ goto,
57
60
  preload(url, which) {
58
- const [page2, variables2] = find_match(manifest, url);
59
- if (["both", "component"].includes(which)) {
61
+ const [page2, variables2] = find_match(configFile, manifest, url);
62
+ if (!page2) {
63
+ return;
64
+ }
65
+ if (["page", "component"].includes(which)) {
60
66
  loadComponent(page2);
61
67
  }
62
- if (["both", "data"].includes(which)) {
68
+ if (["page", "data"].includes(which)) {
63
69
  loadData(page2, variables2);
64
70
  }
65
71
  }
66
72
  });
67
- return /* @__PURE__ */ jsx(VariableContext.Provider, { value: variables, children: /* @__PURE__ */ jsx(LocationContext.Provider, { value: { pathname: currentURL, params: variables ?? {} }, children: /* @__PURE__ */ jsx(PageComponent, { url: currentURL }, page.id) }) });
73
+ return /* @__PURE__ */ jsx(VariableContext.Provider, { value: variables, children: /* @__PURE__ */ jsx(
74
+ LocationContext.Provider,
75
+ {
76
+ value: {
77
+ pathname: currentURL,
78
+ goto,
79
+ params: variables ?? {}
80
+ },
81
+ children: /* @__PURE__ */ jsx(PageComponent, { url: currentURL }, page.id)
82
+ }
83
+ ) });
68
84
  }
69
85
  const useLocation = () => useContext(LocationContext);
70
86
  function usePageData({
@@ -83,9 +99,13 @@ function usePageData({
83
99
  last_variables
84
100
  } = useRouterContext();
85
101
  const [session] = useSession();
86
- function load_query({ id, artifact }) {
102
+ function load_query({
103
+ id,
104
+ artifact,
105
+ variables: variables2
106
+ }) {
87
107
  for (const artifact2 of Object.keys(page.documents)) {
88
- last_variables.set(artifact2, variables);
108
+ last_variables.set(artifact2, variables2);
89
109
  }
90
110
  if (ssr_signals.has(id)) {
91
111
  return ssr_signals.get(id);
@@ -99,8 +119,7 @@ function usePageData({
99
119
  resolve = res;
100
120
  reject = rej;
101
121
  observer.send({
102
- variables,
103
- cacheParams: { disableSubscriptions: true },
122
+ variables: variables2,
104
123
  session
105
124
  }).then(async () => {
106
125
  data_cache.set(id, observer);
@@ -136,13 +155,14 @@ function usePageData({
136
155
  variables: ${JSON.stringify(
137
156
  marshalInputs({
138
157
  artifact: observer.artifact,
139
- input: variables,
158
+ input: variables2,
140
159
  config: configFile
141
160
  })
142
161
  )}
162
+ }).then(() => {
163
+ window.__houdini__nav_caches__?.data_cache.set(artifactName, new_store)
143
164
  })
144
165
 
145
- window.__houdini__nav_caches__?.data_cache.set(artifactName, new_store)
146
166
  }
147
167
 
148
168
 
@@ -176,7 +196,7 @@ function usePageData({
176
196
  variables: ${JSON.stringify(
177
197
  marshalInputs({
178
198
  artifact: observer.artifact,
179
- input: variables,
199
+ input: variables2,
180
200
  config: configFile
181
201
  })
182
202
  )}
@@ -201,6 +221,9 @@ function usePageData({
201
221
  return resolvable;
202
222
  }
203
223
  function loadData(targetPage, variables2) {
224
+ if (!targetPage) {
225
+ return;
226
+ }
204
227
  for (const [artifact, { variables: pageVariables }] of Object.entries(
205
228
  targetPage.documents
206
229
  )) {
@@ -233,14 +256,14 @@ function usePageData({
233
256
  injectToStream?.(`
234
257
  <script type="module" src="${assetPrefix}/artifacts/${artifact.name}.js" async=""><\/script>
235
258
  `);
236
- load_query({ id: artifact.name, artifact });
259
+ load_query({ id: artifact.name, artifact, variables: variables2 });
237
260
  }).catch((err) => {
238
261
  console.log(err);
239
262
  });
240
263
  }
241
264
  for (const artifact of Object.values(found_artifacts)) {
242
265
  if (!data_cache.has(artifact.name)) {
243
- load_query({ id: artifact.name, artifact });
266
+ load_query({ id: artifact.name, artifact, variables: variables2 });
244
267
  }
245
268
  }
246
269
  }
@@ -348,18 +371,27 @@ function useCurrentVariables() {
348
371
  const VariableContext = React.createContext(null);
349
372
  const LocationContext = React.createContext({
350
373
  pathname: "",
351
- params: {}
374
+ params: {},
375
+ goto: () => {
376
+ }
352
377
  });
353
378
  function useQueryResult(name) {
354
- const store_ref = useRouterContext().data_cache.get(name);
355
- const [{ data, errors }, observer] = useDocumentStore({
379
+ const { data_cache, artifact_cache } = useRouterContext();
380
+ const store_ref = data_cache.get(name);
381
+ const [storeValue, observer] = useDocumentStore({
356
382
  artifact: store_ref.artifact,
357
383
  observer: store_ref
358
384
  });
385
+ const { data, errors } = storeValue;
359
386
  if (errors && errors.length > 0) {
360
387
  throw new Error(JSON.stringify(errors));
361
388
  }
362
- return [data, observer];
389
+ const handle = useDocumentHandle({
390
+ artifact: artifact_cache.get(name),
391
+ observer,
392
+ storeValue
393
+ });
394
+ return [data, handle];
363
395
  }
364
396
  function useLinkBehavior({
365
397
  goto,
@@ -402,10 +434,14 @@ function usePreload({ preload }) {
402
434
  React.useEffect(() => {
403
435
  const mouseMove = (e) => {
404
436
  const target = e.target;
405
- if (!(target instanceof HTMLAnchorElement)) {
437
+ if (!(target instanceof HTMLElement)) {
438
+ return;
439
+ }
440
+ const anchor = target.closest("a");
441
+ if (!anchor) {
406
442
  return;
407
443
  }
408
- let preloadWhichRaw = target.attributes.getNamedItem("data-houdini-preload")?.value;
444
+ let preloadWhichRaw = anchor.attributes.getNamedItem("data-houdini-preload")?.value;
409
445
  let preloadWhich = !preloadWhichRaw || preloadWhichRaw === "true" ? "page" : preloadWhichRaw;
410
446
  if (!PreloadWhich[preloadWhich]) {
411
447
  console.log(
@@ -417,7 +453,7 @@ function usePreload({ preload }) {
417
453
  clearTimeout(timeoutRef.current);
418
454
  }
419
455
  timeoutRef.current = setTimeout(() => {
420
- const url = target.attributes.getNamedItem("href")?.value;
456
+ const url = anchor.attributes.getNamedItem("href")?.value;
421
457
  if (!url) {
422
458
  return;
423
459
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "houdini-react",
3
- "version": "1.2.45",
3
+ "version": "1.2.47",
4
4
  "description": "The React plugin for houdini",
5
5
  "keywords": [
6
6
  "typescript",
@@ -37,13 +37,13 @@
37
37
  "express": "^4.18.2",
38
38
  "graphql": "^15.8.0",
39
39
  "graphql-yoga": "^4.0.4",
40
- "react": "18.3.0-canary-09fbee89d-20231013",
41
- "react-dom": "18.3.0-canary-09fbee89d-20231013",
40
+ "react": "19.0.0-canary-2b036d3f1-20240327",
41
+ "react-dom": "19.0.0-canary-2b036d3f1-20240327",
42
42
  "react-streaming-compat": "^0.3.18",
43
43
  "recast": "^0.23.1",
44
44
  "rollup": "^3.7.4",
45
45
  "use-deep-compare-effect": "^1.8.1",
46
- "houdini": "^1.2.45"
46
+ "houdini": "^1.2.47"
47
47
  },
48
48
  "files": [
49
49
  "build"