@valbuild/tanstack 0.124.0

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 (50) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +380 -0
  3. package/client/dist/valbuild-tanstack-client.cjs.d.ts +2 -0
  4. package/client/dist/valbuild-tanstack-client.cjs.dev.js +288 -0
  5. package/client/dist/valbuild-tanstack-client.cjs.js +7 -0
  6. package/client/dist/valbuild-tanstack-client.cjs.prod.js +288 -0
  7. package/client/dist/valbuild-tanstack-client.esm.js +280 -0
  8. package/client/package.json +4 -0
  9. package/dist/ValOverlayContext-87cb022d.esm.js +284 -0
  10. package/dist/ValOverlayContext-abd6ab9a.cjs.prod.js +292 -0
  11. package/dist/ValOverlayContext-d3bfacb1.cjs.dev.js +292 -0
  12. package/dist/createForOfIteratorHelper-0324e063.cjs.prod.js +157 -0
  13. package/dist/createForOfIteratorHelper-485c2ce1.esm.js +151 -0
  14. package/dist/createForOfIteratorHelper-e75681d7.cjs.dev.js +157 -0
  15. package/dist/declarations/src/ValApp.d.ts +6 -0
  16. package/dist/declarations/src/ValImage.d.ts +24 -0
  17. package/dist/declarations/src/ValModulesClient.d.ts +34 -0
  18. package/dist/declarations/src/ValProvider.d.ts +6 -0
  19. package/dist/declarations/src/ValTypes.d.ts +4 -0
  20. package/dist/declarations/src/client/index.d.ts +1 -0
  21. package/dist/declarations/src/client/initValClient.d.ts +27 -0
  22. package/dist/declarations/src/decodeValPathsOfString.d.ts +2 -0
  23. package/dist/declarations/src/external_exempt_from_val_quickjs.d.ts +41 -0
  24. package/dist/declarations/src/getUnpatchedUnencodedVal.d.ts +3 -0
  25. package/dist/declarations/src/index.d.ts +2 -0
  26. package/dist/declarations/src/initVal.d.ts +74 -0
  27. package/dist/declarations/src/server/index.d.ts +5 -0
  28. package/dist/declarations/src/server/initValContent.d.ts +122 -0
  29. package/dist/declarations/src/server/initValMcp.d.ts +27 -0
  30. package/dist/declarations/src/server/initValServer.d.ts +41 -0
  31. package/dist/declarations/src/server/valDraftMode.d.ts +49 -0
  32. package/dist/declarations/src/version.d.ts +1 -0
  33. package/dist/routeFromVal-6693e037.cjs.prod.js +218 -0
  34. package/dist/routeFromVal-728295a0.esm.js +212 -0
  35. package/dist/routeFromVal-a9147ceb.cjs.dev.js +218 -0
  36. package/dist/valbuild-tanstack.cjs.d.ts +2 -0
  37. package/dist/valbuild-tanstack.cjs.dev.js +2005 -0
  38. package/dist/valbuild-tanstack.cjs.js +7 -0
  39. package/dist/valbuild-tanstack.cjs.prod.js +2005 -0
  40. package/dist/valbuild-tanstack.esm.js +1950 -0
  41. package/dist/version-1a88fd21.cjs.dev.js +229 -0
  42. package/dist/version-5ac70ccf.cjs.prod.js +229 -0
  43. package/dist/version-ac8df696.esm.js +225 -0
  44. package/package.json +84 -0
  45. package/server/dist/valbuild-tanstack-server.cjs.d.ts +2 -0
  46. package/server/dist/valbuild-tanstack-server.cjs.dev.js +1032 -0
  47. package/server/dist/valbuild-tanstack-server.cjs.js +7 -0
  48. package/server/dist/valbuild-tanstack-server.cjs.prod.js +1032 -0
  49. package/server/dist/valbuild-tanstack-server.esm.js +1005 -0
  50. package/server/package.json +4 -0
@@ -0,0 +1,7 @@
1
+ 'use strict';
2
+
3
+ if (process.env.NODE_ENV === "production") {
4
+ module.exports = require("./valbuild-tanstack-client.cjs.prod.js");
5
+ } else {
6
+ module.exports = require("./valbuild-tanstack-client.cjs.dev.js");
7
+ }
@@ -0,0 +1,288 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var routeFromVal = require('../../dist/routeFromVal-6693e037.cjs.prod.js');
6
+ var core = require('@valbuild/core');
7
+ var stega = require('@valbuild/react/stega');
8
+ var React = require('react');
9
+ var ValOverlayContext = require('../../dist/ValOverlayContext-abd6ab9a.cjs.prod.js');
10
+ require('../../dist/createForOfIteratorHelper-0324e063.cjs.prod.js');
11
+ require('@valbuild/shared/client');
12
+ require('@valbuild/core/patch');
13
+ require('react/jsx-runtime');
14
+
15
+ function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
16
+
17
+ var React__default = /*#__PURE__*/_interopDefault(React);
18
+
19
+ function useValStega(selector) {
20
+ var valOverlayContext = ValOverlayContext.useValOverlayContext();
21
+ var moduleIds = React__default["default"].useMemo(function () {
22
+ return stega.getModuleIds(selector);
23
+ }, [selector]);
24
+ var store = valOverlayContext.store;
25
+ var moduleMap = React__default["default"].useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
26
+ return function () {};
27
+ }, store ? store.getSnapshot(moduleIds) : function () {
28
+ return;
29
+ }, store ? store.getServerSnapshot(moduleIds) : function () {
30
+ return;
31
+ });
32
+ // Suspense gate. `suspend` is false during SSR and hydration (so the static
33
+ // committed source is rendered, matching the server HTML exactly) and is
34
+ // activated by ValProvider after hydration — inside a transition — when the
35
+ // `suspend` prop is set AND the Val Enable cookie is present (checked
36
+ // client-side; the server store is never populated). It never deactivates.
37
+ // The production path (no cookie) skips the call entirely. The
38
+ // `draftMode !== false` check is a release valve: with draft mode off the
39
+ // store never receives source updates, so waitForLoad could only ever
40
+ // resolve via its timeout — and would then re-suspend on every subsequent
41
+ // render since the resolved promise is evicted from the cache. draftMode is
42
+ // null until the first /draft/stat poll resolves; null -> true keeps
43
+ // suspending, -> false only unblocks, and false -> true happens only on an
44
+ // explicit draft-mode enable which already refreshes the route.
45
+ // React.use is allowed inside conditionals — it is not a hook.
46
+ /**
47
+ * Wait until draft mode is KNOWN, before anything else.
48
+ *
49
+ * `draftMode === null` means `/draft/stat` has not answered yet, and the
50
+ * `getModule` below treats it as off — so a render that slips through here
51
+ * while it is unknown resolves against committed source. For an ordinary field
52
+ * that is a flash of published content; for `useValRoute` on a route that
53
+ * exists only in an uncommitted patch it is `notFound()`, which no later
54
+ * answer can undo. That was the 404 on a page you had just created.
55
+ */
56
+ if (valOverlayContext.suspend && valOverlayContext.draftMode === null && valOverlayContext.draftModeReady) {
57
+ React__default["default"].use(valOverlayContext.draftModeReady);
58
+ }
59
+ /**
60
+ * Then wait for the draft sources — but only while more might be coming.
61
+ *
62
+ * `draftSourcesSynced` is the editor saying it has sent everything it holds,
63
+ * and it only holds modules with patches: an unedited module has no draft, so
64
+ * nothing is ever sent for it. Without that signal this could not tell "not
65
+ * sent yet" from "nothing to send", and waited out `waitForLoad`'s ten second
66
+ * timeout once per unedited module the page reads — which is what left a newly
67
+ * created page sitting on its loading fallback.
68
+ */
69
+ if (valOverlayContext.suspend && valOverlayContext.draftMode !== false && !valOverlayContext.draftSourcesSynced && store && !store.hasAllLoaded(moduleIds)) {
70
+ React__default["default"].use(store.waitForLoad(moduleIds));
71
+ }
72
+ return stega.stegaEncode(selector, {
73
+ disabled: !valOverlayContext.draftMode,
74
+ getModule: function getModule(moduleId) {
75
+ if (moduleMap && valOverlayContext.draftMode) {
76
+ return moduleMap[moduleId];
77
+ }
78
+ }
79
+ });
80
+ }
81
+
82
+ /**
83
+ * The module's source as the overlay currently sees it — i.e. WITH the editor's
84
+ * unpublished changes — or undefined when there is no draft view to be had
85
+ * (production, draft mode off, or the overlay has not pushed this module yet).
86
+ *
87
+ * This is what lets the single-entry readers show drafts. They otherwise resolve
88
+ * an entry through its local import thunk, which is the content that was bundled:
89
+ * correct in production, and stale the moment anyone edits in the Studio.
90
+ */
91
+ function useDraftModuleSource(moduleFilePath) {
92
+ var valOverlayContext = ValOverlayContext.useValOverlayContext();
93
+ var store = valOverlayContext.store;
94
+ var moduleIds = React__default["default"].useMemo(function () {
95
+ return moduleFilePath ? [moduleFilePath] : [];
96
+ }, [moduleFilePath]);
97
+ var moduleMap = React__default["default"].useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
98
+ return function () {};
99
+ }, store ? store.getSnapshot(moduleIds) : function () {
100
+ return undefined;
101
+ }, store ? store.getServerSnapshot(moduleIds) : function () {
102
+ return undefined;
103
+ });
104
+ if (!valOverlayContext.draftMode || !moduleFilePath) {
105
+ return undefined;
106
+ }
107
+ return moduleMap === null || moduleMap === void 0 ? void 0 : moduleMap[moduleFilePath];
108
+ }
109
+
110
+ /**
111
+ * What the draft view says about one `.jsonValues()` entry.
112
+ *
113
+ * Mirrors the server-side rule in `fetchValKey`/`fetchValRoute`: a draft view
114
+ * that HAS an answer wins, including the answer "this entry is gone", and the
115
+ * bundled content is used only when there is no draft view.
116
+ */
117
+ function draftJsonEntry(draftSource, key) {
118
+ if (draftSource === undefined || draftSource === null || routeFromVal._typeof(draftSource) !== "object" || Array.isArray(draftSource)) {
119
+ return {
120
+ status: "unavailable"
121
+ };
122
+ }
123
+ var entry = draftSource[key];
124
+ if (entry === undefined) {
125
+ // The module IS in the draft view and this key is not: it was deleted.
126
+ return {
127
+ status: "absent"
128
+ };
129
+ }
130
+ if (core.Internal.isJson(entry)) {
131
+ // An un-loaded marker: the Studio has not fetched this entry's content, so
132
+ // the draft view cannot answer. (The engine asks for entries that pending
133
+ // patches touch, so this resolves itself for anything actually edited.)
134
+ return {
135
+ status: "unavailable"
136
+ };
137
+ }
138
+ return {
139
+ status: "content",
140
+ content: entry
141
+ };
142
+ }
143
+
144
+ // The (loosened) content type a single `.jsonValues()` entry resolves to.
145
+
146
+ // Module-level cache of in-flight/resolved entry loads, so `React.use` gets a
147
+ // stable promise across renders (keyed by module path + entry key).
148
+ var jsonEntryPromiseCache = new Map();
149
+
150
+ /**
151
+ * Client counterpart to `fetchValKey`: resolves a SINGLE `.jsonValues()` entry
152
+ * by key, loading only that entry's backing `*.val.json` (one dynamic import).
153
+ * Suspends (via `React.use`) until the entry loads, so it must be rendered
154
+ * inside a `<Suspense>` boundary.
155
+ *
156
+ * In draft mode it renders the editor's unpublished content, taken from the
157
+ * overlay; in production — and whenever there is no draft view — it resolves the
158
+ * entry's lazy import thunk from the local module.
159
+ */
160
+ function useValKeyStega(selector, key) {
161
+ var valOverlayContext = ValOverlayContext.useValOverlayContext();
162
+ var moduleFilePath = selector && core.Internal.getValPath(selector);
163
+ var draftSource = useDraftModuleSource(moduleFilePath || undefined);
164
+ var draft = draftJsonEntry(draftSource, key);
165
+ if (draft.status === "absent") {
166
+ // Deleted in the draft state. Falling back to the bundled entry here would
167
+ // render content the editor has just removed.
168
+ return undefined;
169
+ }
170
+ var content = draft.status === "content" ? draft.content : undefined;
171
+ if (content === undefined) {
172
+ content = readCommittedJsonEntry(selector, key);
173
+ }
174
+ return stega.stegaEncode(content, {
175
+ disabled: !valOverlayContext.draftMode,
176
+ root: routeFromVal.getJsonEntryStegaRoot(selector, key)
177
+ });
178
+ }
179
+
180
+ /**
181
+ * The entry's content as bundled: its lazy import thunk, resolved through
182
+ * `React.use` so the caller suspends until it lands.
183
+ *
184
+ * Deliberately not named `use*`: it is called conditionally, which is fine
185
+ * because `React.use` is not a hook, but a `use*` name would read like one.
186
+ */
187
+ function readCommittedJsonEntry(selector, key) {
188
+ var _Internal$getValPath;
189
+ var source = selector && core.Internal.getSource(selector);
190
+ var marker = source && routeFromVal._typeof(source) === "object" ? source[key] : undefined;
191
+ if (!core.Internal.isJson(marker)) {
192
+ return undefined;
193
+ }
194
+ var thunk = core.Internal.getJsonImport(marker);
195
+ if (!thunk) {
196
+ return undefined;
197
+ }
198
+ var cacheKey = "".concat((_Internal$getValPath = core.Internal.getValPath(selector)) !== null && _Internal$getValPath !== void 0 ? _Internal$getValPath : "", " ").concat(key);
199
+ var promise = jsonEntryPromiseCache.get(cacheKey);
200
+ if (!promise) {
201
+ promise = thunk().then(function (mod) {
202
+ return mod["default"];
203
+ });
204
+ jsonEntryPromiseCache.set(cacheKey, promise);
205
+ }
206
+ return React__default["default"].use(promise);
207
+ }
208
+ function resolveParams(params) {
209
+ if (!params) {
210
+ return null;
211
+ }
212
+ if ("then" in params) {
213
+ // Defensive guard: peerDependencies declare React >=19, but if a consumer
214
+ // somehow ends up on React 18 with a promise params arg, surface a
215
+ // diagnosable error instead of a cryptic `TypeError: React.use is not a
216
+ // function`. Callers treat null as the error sentinel.
217
+ if (!("use" in React__default["default"])) {
218
+ console.error("Val: useValRoute received a Promise params argument but React.use is unavailable. Upgrade to React 19+ or pre-resolve the promise before passing it.");
219
+ return null;
220
+ }
221
+ return React__default["default"].use(params);
222
+ }
223
+ return params;
224
+ }
225
+ function useValRouteStega(selector, params) {
226
+ var valOverlayContext = ValOverlayContext.useValOverlayContext();
227
+ // Both called unconditionally to keep hook order stable. For a `.jsonValues()`
228
+ // router `val` is unused (we resolve a single entry below instead); for any
229
+ // other router `draftSource` is.
230
+ var val = useValStega(selector);
231
+ var draftSource = useDraftModuleSource(selector && core.Internal.getValPath(selector) || undefined);
232
+ var resolvedParams = resolveParams(params);
233
+ // Careful: null means there was an error - undefined means no params
234
+ if (resolvedParams === null) {
235
+ return null;
236
+ }
237
+ var path = selector && core.Internal.getValPath(selector);
238
+ var schema = selector && core.Internal.getSchema(selector);
239
+ // `.jsonValues()` router: map params → the entry key and load ONLY that
240
+ // entry's backing `*.val.json` (one dynamic import), like `useValKey`.
241
+ if (routeFromVal.isJsonValuesRecordSchema(schema)) {
242
+ var source = selector && core.Internal.getSource(selector);
243
+ var url = routeFromVal.getValRouteUrlFromVal(resolvedParams || {}, "useValRoute", path, schema, source);
244
+ if (!url) {
245
+ return null;
246
+ }
247
+ var draft = draftJsonEntry(draftSource, url);
248
+ if (draft.status === "absent") {
249
+ // The draft state says this route is gone — see useValKeyStega.
250
+ return null;
251
+ }
252
+ var content = draft.status === "content" ? draft.content : undefined;
253
+ if (content === undefined) {
254
+ content = readCommittedJsonEntry(selector, url);
255
+ }
256
+ if (content === undefined) {
257
+ return null;
258
+ }
259
+ return stega.stegaEncode(content, {
260
+ disabled: !valOverlayContext.draftMode,
261
+ root: routeFromVal.getJsonEntryStegaRoot(selector, url)
262
+ });
263
+ }
264
+ var route = routeFromVal.initValRouteFromVal(resolvedParams || {}, "useValRoute", path, schema, val);
265
+ return route;
266
+ }
267
+ function useValRouteUrl(selector, params) {
268
+ var val = useValStega(selector);
269
+ var resolvedParams = params === undefined ? undefined : resolveParams(params);
270
+ // Careful: null means there was an error - undefined means no params
271
+ if (resolvedParams === null) {
272
+ return null;
273
+ }
274
+ var route = routeFromVal.getValRouteUrlFromVal(resolvedParams || {}, "useValRouteUrl", selector && core.Internal.getValPath(selector), selector && core.Internal.getSchema(selector), val);
275
+ return route;
276
+ }
277
+
278
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
279
+ function initValClient(config) {
280
+ return {
281
+ useValStega: useValStega,
282
+ useValKeyStega: useValKeyStega,
283
+ useValRouteStega: useValRouteStega,
284
+ useValRouteUrl: useValRouteUrl
285
+ };
286
+ }
287
+
288
+ exports.initValClient = initValClient;
@@ -0,0 +1,280 @@
1
+ import { g as getJsonEntryStegaRoot, _ as _typeof, i as isJsonValuesRecordSchema, a as getValRouteUrlFromVal, b as initValRouteFromVal } from '../../dist/routeFromVal-728295a0.esm.js';
2
+ import { Internal } from '@valbuild/core';
3
+ import { getModuleIds, stegaEncode } from '@valbuild/react/stega';
4
+ import React from 'react';
5
+ import { u as useValOverlayContext } from '../../dist/ValOverlayContext-87cb022d.esm.js';
6
+ import '../../dist/createForOfIteratorHelper-485c2ce1.esm.js';
7
+ import '@valbuild/shared/client';
8
+ import '@valbuild/core/patch';
9
+ import 'react/jsx-runtime';
10
+
11
+ function useValStega(selector) {
12
+ var valOverlayContext = useValOverlayContext();
13
+ var moduleIds = React.useMemo(function () {
14
+ return getModuleIds(selector);
15
+ }, [selector]);
16
+ var store = valOverlayContext.store;
17
+ var moduleMap = React.useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
18
+ return function () {};
19
+ }, store ? store.getSnapshot(moduleIds) : function () {
20
+ return;
21
+ }, store ? store.getServerSnapshot(moduleIds) : function () {
22
+ return;
23
+ });
24
+ // Suspense gate. `suspend` is false during SSR and hydration (so the static
25
+ // committed source is rendered, matching the server HTML exactly) and is
26
+ // activated by ValProvider after hydration — inside a transition — when the
27
+ // `suspend` prop is set AND the Val Enable cookie is present (checked
28
+ // client-side; the server store is never populated). It never deactivates.
29
+ // The production path (no cookie) skips the call entirely. The
30
+ // `draftMode !== false` check is a release valve: with draft mode off the
31
+ // store never receives source updates, so waitForLoad could only ever
32
+ // resolve via its timeout — and would then re-suspend on every subsequent
33
+ // render since the resolved promise is evicted from the cache. draftMode is
34
+ // null until the first /draft/stat poll resolves; null -> true keeps
35
+ // suspending, -> false only unblocks, and false -> true happens only on an
36
+ // explicit draft-mode enable which already refreshes the route.
37
+ // React.use is allowed inside conditionals — it is not a hook.
38
+ /**
39
+ * Wait until draft mode is KNOWN, before anything else.
40
+ *
41
+ * `draftMode === null` means `/draft/stat` has not answered yet, and the
42
+ * `getModule` below treats it as off — so a render that slips through here
43
+ * while it is unknown resolves against committed source. For an ordinary field
44
+ * that is a flash of published content; for `useValRoute` on a route that
45
+ * exists only in an uncommitted patch it is `notFound()`, which no later
46
+ * answer can undo. That was the 404 on a page you had just created.
47
+ */
48
+ if (valOverlayContext.suspend && valOverlayContext.draftMode === null && valOverlayContext.draftModeReady) {
49
+ React.use(valOverlayContext.draftModeReady);
50
+ }
51
+ /**
52
+ * Then wait for the draft sources — but only while more might be coming.
53
+ *
54
+ * `draftSourcesSynced` is the editor saying it has sent everything it holds,
55
+ * and it only holds modules with patches: an unedited module has no draft, so
56
+ * nothing is ever sent for it. Without that signal this could not tell "not
57
+ * sent yet" from "nothing to send", and waited out `waitForLoad`'s ten second
58
+ * timeout once per unedited module the page reads — which is what left a newly
59
+ * created page sitting on its loading fallback.
60
+ */
61
+ if (valOverlayContext.suspend && valOverlayContext.draftMode !== false && !valOverlayContext.draftSourcesSynced && store && !store.hasAllLoaded(moduleIds)) {
62
+ React.use(store.waitForLoad(moduleIds));
63
+ }
64
+ return stegaEncode(selector, {
65
+ disabled: !valOverlayContext.draftMode,
66
+ getModule: function getModule(moduleId) {
67
+ if (moduleMap && valOverlayContext.draftMode) {
68
+ return moduleMap[moduleId];
69
+ }
70
+ }
71
+ });
72
+ }
73
+
74
+ /**
75
+ * The module's source as the overlay currently sees it — i.e. WITH the editor's
76
+ * unpublished changes — or undefined when there is no draft view to be had
77
+ * (production, draft mode off, or the overlay has not pushed this module yet).
78
+ *
79
+ * This is what lets the single-entry readers show drafts. They otherwise resolve
80
+ * an entry through its local import thunk, which is the content that was bundled:
81
+ * correct in production, and stale the moment anyone edits in the Studio.
82
+ */
83
+ function useDraftModuleSource(moduleFilePath) {
84
+ var valOverlayContext = useValOverlayContext();
85
+ var store = valOverlayContext.store;
86
+ var moduleIds = React.useMemo(function () {
87
+ return moduleFilePath ? [moduleFilePath] : [];
88
+ }, [moduleFilePath]);
89
+ var moduleMap = React.useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
90
+ return function () {};
91
+ }, store ? store.getSnapshot(moduleIds) : function () {
92
+ return undefined;
93
+ }, store ? store.getServerSnapshot(moduleIds) : function () {
94
+ return undefined;
95
+ });
96
+ if (!valOverlayContext.draftMode || !moduleFilePath) {
97
+ return undefined;
98
+ }
99
+ return moduleMap === null || moduleMap === void 0 ? void 0 : moduleMap[moduleFilePath];
100
+ }
101
+
102
+ /**
103
+ * What the draft view says about one `.jsonValues()` entry.
104
+ *
105
+ * Mirrors the server-side rule in `fetchValKey`/`fetchValRoute`: a draft view
106
+ * that HAS an answer wins, including the answer "this entry is gone", and the
107
+ * bundled content is used only when there is no draft view.
108
+ */
109
+ function draftJsonEntry(draftSource, key) {
110
+ if (draftSource === undefined || draftSource === null || _typeof(draftSource) !== "object" || Array.isArray(draftSource)) {
111
+ return {
112
+ status: "unavailable"
113
+ };
114
+ }
115
+ var entry = draftSource[key];
116
+ if (entry === undefined) {
117
+ // The module IS in the draft view and this key is not: it was deleted.
118
+ return {
119
+ status: "absent"
120
+ };
121
+ }
122
+ if (Internal.isJson(entry)) {
123
+ // An un-loaded marker: the Studio has not fetched this entry's content, so
124
+ // the draft view cannot answer. (The engine asks for entries that pending
125
+ // patches touch, so this resolves itself for anything actually edited.)
126
+ return {
127
+ status: "unavailable"
128
+ };
129
+ }
130
+ return {
131
+ status: "content",
132
+ content: entry
133
+ };
134
+ }
135
+
136
+ // The (loosened) content type a single `.jsonValues()` entry resolves to.
137
+
138
+ // Module-level cache of in-flight/resolved entry loads, so `React.use` gets a
139
+ // stable promise across renders (keyed by module path + entry key).
140
+ var jsonEntryPromiseCache = new Map();
141
+
142
+ /**
143
+ * Client counterpart to `fetchValKey`: resolves a SINGLE `.jsonValues()` entry
144
+ * by key, loading only that entry's backing `*.val.json` (one dynamic import).
145
+ * Suspends (via `React.use`) until the entry loads, so it must be rendered
146
+ * inside a `<Suspense>` boundary.
147
+ *
148
+ * In draft mode it renders the editor's unpublished content, taken from the
149
+ * overlay; in production — and whenever there is no draft view — it resolves the
150
+ * entry's lazy import thunk from the local module.
151
+ */
152
+ function useValKeyStega(selector, key) {
153
+ var valOverlayContext = useValOverlayContext();
154
+ var moduleFilePath = selector && Internal.getValPath(selector);
155
+ var draftSource = useDraftModuleSource(moduleFilePath || undefined);
156
+ var draft = draftJsonEntry(draftSource, key);
157
+ if (draft.status === "absent") {
158
+ // Deleted in the draft state. Falling back to the bundled entry here would
159
+ // render content the editor has just removed.
160
+ return undefined;
161
+ }
162
+ var content = draft.status === "content" ? draft.content : undefined;
163
+ if (content === undefined) {
164
+ content = readCommittedJsonEntry(selector, key);
165
+ }
166
+ return stegaEncode(content, {
167
+ disabled: !valOverlayContext.draftMode,
168
+ root: getJsonEntryStegaRoot(selector, key)
169
+ });
170
+ }
171
+
172
+ /**
173
+ * The entry's content as bundled: its lazy import thunk, resolved through
174
+ * `React.use` so the caller suspends until it lands.
175
+ *
176
+ * Deliberately not named `use*`: it is called conditionally, which is fine
177
+ * because `React.use` is not a hook, but a `use*` name would read like one.
178
+ */
179
+ function readCommittedJsonEntry(selector, key) {
180
+ var _Internal$getValPath;
181
+ var source = selector && Internal.getSource(selector);
182
+ var marker = source && _typeof(source) === "object" ? source[key] : undefined;
183
+ if (!Internal.isJson(marker)) {
184
+ return undefined;
185
+ }
186
+ var thunk = Internal.getJsonImport(marker);
187
+ if (!thunk) {
188
+ return undefined;
189
+ }
190
+ var cacheKey = "".concat((_Internal$getValPath = Internal.getValPath(selector)) !== null && _Internal$getValPath !== void 0 ? _Internal$getValPath : "", " ").concat(key);
191
+ var promise = jsonEntryPromiseCache.get(cacheKey);
192
+ if (!promise) {
193
+ promise = thunk().then(function (mod) {
194
+ return mod["default"];
195
+ });
196
+ jsonEntryPromiseCache.set(cacheKey, promise);
197
+ }
198
+ return React.use(promise);
199
+ }
200
+ function resolveParams(params) {
201
+ if (!params) {
202
+ return null;
203
+ }
204
+ if ("then" in params) {
205
+ // Defensive guard: peerDependencies declare React >=19, but if a consumer
206
+ // somehow ends up on React 18 with a promise params arg, surface a
207
+ // diagnosable error instead of a cryptic `TypeError: React.use is not a
208
+ // function`. Callers treat null as the error sentinel.
209
+ if (!("use" in React)) {
210
+ console.error("Val: useValRoute received a Promise params argument but React.use is unavailable. Upgrade to React 19+ or pre-resolve the promise before passing it.");
211
+ return null;
212
+ }
213
+ return React.use(params);
214
+ }
215
+ return params;
216
+ }
217
+ function useValRouteStega(selector, params) {
218
+ var valOverlayContext = useValOverlayContext();
219
+ // Both called unconditionally to keep hook order stable. For a `.jsonValues()`
220
+ // router `val` is unused (we resolve a single entry below instead); for any
221
+ // other router `draftSource` is.
222
+ var val = useValStega(selector);
223
+ var draftSource = useDraftModuleSource(selector && Internal.getValPath(selector) || undefined);
224
+ var resolvedParams = resolveParams(params);
225
+ // Careful: null means there was an error - undefined means no params
226
+ if (resolvedParams === null) {
227
+ return null;
228
+ }
229
+ var path = selector && Internal.getValPath(selector);
230
+ var schema = selector && Internal.getSchema(selector);
231
+ // `.jsonValues()` router: map params → the entry key and load ONLY that
232
+ // entry's backing `*.val.json` (one dynamic import), like `useValKey`.
233
+ if (isJsonValuesRecordSchema(schema)) {
234
+ var source = selector && Internal.getSource(selector);
235
+ var url = getValRouteUrlFromVal(resolvedParams || {}, "useValRoute", path, schema, source);
236
+ if (!url) {
237
+ return null;
238
+ }
239
+ var draft = draftJsonEntry(draftSource, url);
240
+ if (draft.status === "absent") {
241
+ // The draft state says this route is gone — see useValKeyStega.
242
+ return null;
243
+ }
244
+ var content = draft.status === "content" ? draft.content : undefined;
245
+ if (content === undefined) {
246
+ content = readCommittedJsonEntry(selector, url);
247
+ }
248
+ if (content === undefined) {
249
+ return null;
250
+ }
251
+ return stegaEncode(content, {
252
+ disabled: !valOverlayContext.draftMode,
253
+ root: getJsonEntryStegaRoot(selector, url)
254
+ });
255
+ }
256
+ var route = initValRouteFromVal(resolvedParams || {}, "useValRoute", path, schema, val);
257
+ return route;
258
+ }
259
+ function useValRouteUrl(selector, params) {
260
+ var val = useValStega(selector);
261
+ var resolvedParams = params === undefined ? undefined : resolveParams(params);
262
+ // Careful: null means there was an error - undefined means no params
263
+ if (resolvedParams === null) {
264
+ return null;
265
+ }
266
+ var route = getValRouteUrlFromVal(resolvedParams || {}, "useValRouteUrl", selector && Internal.getValPath(selector), selector && Internal.getSchema(selector), val);
267
+ return route;
268
+ }
269
+
270
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
271
+ function initValClient(config) {
272
+ return {
273
+ useValStega: useValStega,
274
+ useValKeyStega: useValKeyStega,
275
+ useValRouteStega: useValRouteStega,
276
+ useValRouteUrl: useValRouteUrl
277
+ };
278
+ }
279
+
280
+ export { initValClient };
@@ -0,0 +1,4 @@
1
+ {
2
+ "main": "dist/valbuild-tanstack-client.cjs.js",
3
+ "module": "dist/valbuild-tanstack-client.esm.js"
4
+ }