@valbuild/next 0.99.0 → 0.100.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.
- package/client/dist/valbuild-next-client.cjs.dev.js +162 -2
- package/client/dist/valbuild-next-client.cjs.prod.js +162 -2
- package/client/dist/valbuild-next-client.esm.js +162 -2
- package/dist/declarations/src/client/initValClient.d.ts +15 -2
- package/dist/declarations/src/external_exempt_from_val_quickjs.d.ts +3 -0
- package/dist/declarations/src/rsc/initValRsc.d.ts +61 -2
- package/dist/{routeFromVal-8855a5cc.esm.js → routeFromVal-263eec96.esm.js} +41 -1
- package/dist/{routeFromVal-13c832b2.cjs.prod.js → routeFromVal-8ac2f984.cjs.prod.js} +43 -0
- package/dist/{routeFromVal-9b610e77.cjs.dev.js → routeFromVal-b48a454a.cjs.dev.js} +43 -0
- package/package.json +7 -7
- package/rsc/dist/valbuild-next-rsc.cjs.dev.js +398 -74
- package/rsc/dist/valbuild-next-rsc.cjs.prod.js +398 -74
- package/rsc/dist/valbuild-next-rsc.esm.js +398 -74
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
require('client-only');
|
|
6
|
+
var routeFromVal = require('../../dist/routeFromVal-b48a454a.cjs.dev.js');
|
|
6
7
|
var core = require('@valbuild/core');
|
|
7
8
|
var stega = require('@valbuild/react/stega');
|
|
8
9
|
var React = require('react');
|
|
9
10
|
var ValOverlayContext = require('../../dist/ValOverlayContext-c6f27a6d.cjs.dev.js');
|
|
10
|
-
var routeFromVal = require('../../dist/routeFromVal-9b610e77.cjs.dev.js');
|
|
11
11
|
require('../../dist/createForOfIteratorHelper-0445603c.cjs.dev.js');
|
|
12
12
|
require('../../dist/unsupportedIterableToArray-c8ab77c9.cjs.dev.js');
|
|
13
13
|
require('../../dist/objectSpread2-58024783.cjs.dev.js');
|
|
@@ -58,6 +58,133 @@ function useValStega(selector) {
|
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The module's source as the overlay currently sees it — i.e. WITH the editor's
|
|
64
|
+
* unpublished changes — or undefined when there is no draft view to be had
|
|
65
|
+
* (production, draft mode off, or the overlay has not pushed this module yet).
|
|
66
|
+
*
|
|
67
|
+
* This is what lets the single-entry readers show drafts. They otherwise resolve
|
|
68
|
+
* an entry through its local import thunk, which is the content that was bundled:
|
|
69
|
+
* correct in production, and stale the moment anyone edits in the Studio.
|
|
70
|
+
*/
|
|
71
|
+
function useDraftModuleSource(moduleFilePath) {
|
|
72
|
+
var valOverlayContext = ValOverlayContext.useValOverlayContext();
|
|
73
|
+
var store = valOverlayContext.store;
|
|
74
|
+
var moduleIds = React__default["default"].useMemo(function () {
|
|
75
|
+
return moduleFilePath ? [moduleFilePath] : [];
|
|
76
|
+
}, [moduleFilePath]);
|
|
77
|
+
var moduleMap = React__default["default"].useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
|
|
78
|
+
return function () {};
|
|
79
|
+
}, store ? store.getSnapshot(moduleIds) : function () {
|
|
80
|
+
return undefined;
|
|
81
|
+
}, store ? store.getServerSnapshot(moduleIds) : function () {
|
|
82
|
+
return undefined;
|
|
83
|
+
});
|
|
84
|
+
if (!valOverlayContext.draftMode || !moduleFilePath) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return moduleMap === null || moduleMap === void 0 ? void 0 : moduleMap[moduleFilePath];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* What the draft view says about one `.jsonValues()` entry.
|
|
92
|
+
*
|
|
93
|
+
* Mirrors the server-side rule in `fetchValKey`/`fetchValRoute`: a draft view
|
|
94
|
+
* that HAS an answer wins, including the answer "this entry is gone", and the
|
|
95
|
+
* bundled content is used only when there is no draft view.
|
|
96
|
+
*/
|
|
97
|
+
function draftJsonEntry(draftSource, key) {
|
|
98
|
+
if (draftSource === undefined || draftSource === null || routeFromVal._typeof(draftSource) !== "object" || Array.isArray(draftSource)) {
|
|
99
|
+
return {
|
|
100
|
+
status: "unavailable"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
var entry = draftSource[key];
|
|
104
|
+
if (entry === undefined) {
|
|
105
|
+
// The module IS in the draft view and this key is not: it was deleted.
|
|
106
|
+
return {
|
|
107
|
+
status: "absent"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (core.Internal.isJson(entry)) {
|
|
111
|
+
// An un-loaded marker: the Studio has not fetched this entry's content, so
|
|
112
|
+
// the draft view cannot answer. (The engine asks for entries that pending
|
|
113
|
+
// patches touch, so this resolves itself for anything actually edited.)
|
|
114
|
+
return {
|
|
115
|
+
status: "unavailable"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
status: "content",
|
|
120
|
+
content: entry
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// The (loosened) content type a single `.jsonValues()` entry resolves to.
|
|
125
|
+
|
|
126
|
+
// Module-level cache of in-flight/resolved entry loads, so `React.use` gets a
|
|
127
|
+
// stable promise across renders (keyed by module path + entry key).
|
|
128
|
+
var jsonEntryPromiseCache = new Map();
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Client counterpart to `fetchValKey`: resolves a SINGLE `.jsonValues()` entry
|
|
132
|
+
* by key, loading only that entry's backing `*.val.json` (one dynamic import).
|
|
133
|
+
* Suspends (via `React.use`) until the entry loads, so it must be rendered
|
|
134
|
+
* inside a `<Suspense>` boundary.
|
|
135
|
+
*
|
|
136
|
+
* In draft mode it renders the editor's unpublished content, taken from the
|
|
137
|
+
* overlay; in production — and whenever there is no draft view — it resolves the
|
|
138
|
+
* entry's lazy import thunk from the local module.
|
|
139
|
+
*/
|
|
140
|
+
function useValKeyStega(selector, key) {
|
|
141
|
+
var valOverlayContext = ValOverlayContext.useValOverlayContext();
|
|
142
|
+
var moduleFilePath = selector && core.Internal.getValPath(selector);
|
|
143
|
+
var draftSource = useDraftModuleSource(moduleFilePath || undefined);
|
|
144
|
+
var draft = draftJsonEntry(draftSource, key);
|
|
145
|
+
if (draft.status === "absent") {
|
|
146
|
+
// Deleted in the draft state. Falling back to the bundled entry here would
|
|
147
|
+
// render content the editor has just removed.
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
var content = draft.status === "content" ? draft.content : undefined;
|
|
151
|
+
if (content === undefined) {
|
|
152
|
+
content = readCommittedJsonEntry(selector, key);
|
|
153
|
+
}
|
|
154
|
+
return stega.stegaEncode(content, {
|
|
155
|
+
disabled: !valOverlayContext.draftMode,
|
|
156
|
+
root: routeFromVal.getJsonEntryStegaRoot(selector, key)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The entry's content as bundled: its lazy import thunk, resolved through
|
|
162
|
+
* `React.use` so the caller suspends until it lands.
|
|
163
|
+
*
|
|
164
|
+
* Deliberately not named `use*`: it is called conditionally, which is fine
|
|
165
|
+
* because `React.use` is not a hook, but a `use*` name would read like one.
|
|
166
|
+
*/
|
|
167
|
+
function readCommittedJsonEntry(selector, key) {
|
|
168
|
+
var _Internal$getValPath;
|
|
169
|
+
var source = selector && core.Internal.getSource(selector);
|
|
170
|
+
var marker = source && routeFromVal._typeof(source) === "object" ? source[key] : undefined;
|
|
171
|
+
if (!core.Internal.isJson(marker)) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
var thunk = core.Internal.getJsonImport(marker);
|
|
175
|
+
if (!thunk) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
var cacheKey = "".concat((_Internal$getValPath = core.Internal.getValPath(selector)) !== null && _Internal$getValPath !== void 0 ? _Internal$getValPath : "", " ").concat(key);
|
|
179
|
+
var promise = jsonEntryPromiseCache.get(cacheKey);
|
|
180
|
+
if (!promise) {
|
|
181
|
+
promise = thunk().then(function (mod) {
|
|
182
|
+
return mod["default"];
|
|
183
|
+
});
|
|
184
|
+
jsonEntryPromiseCache.set(cacheKey, promise);
|
|
185
|
+
}
|
|
186
|
+
return React__default["default"].use(promise);
|
|
187
|
+
}
|
|
61
188
|
function resolveParams(params) {
|
|
62
189
|
if (!params) {
|
|
63
190
|
return null;
|
|
@@ -76,13 +203,45 @@ function resolveParams(params) {
|
|
|
76
203
|
return params;
|
|
77
204
|
}
|
|
78
205
|
function useValRouteStega(selector, params) {
|
|
206
|
+
var valOverlayContext = ValOverlayContext.useValOverlayContext();
|
|
207
|
+
// Both called unconditionally to keep hook order stable. For a `.jsonValues()`
|
|
208
|
+
// router `val` is unused (we resolve a single entry below instead); for any
|
|
209
|
+
// other router `draftSource` is.
|
|
79
210
|
var val = useValStega(selector);
|
|
211
|
+
var draftSource = useDraftModuleSource(selector && core.Internal.getValPath(selector) || undefined);
|
|
80
212
|
var resolvedParams = resolveParams(params);
|
|
81
213
|
// Careful: null means there was an error - undefined means no params
|
|
82
214
|
if (resolvedParams === null) {
|
|
83
215
|
return null;
|
|
84
216
|
}
|
|
85
|
-
var
|
|
217
|
+
var path = selector && core.Internal.getValPath(selector);
|
|
218
|
+
var schema = selector && core.Internal.getSchema(selector);
|
|
219
|
+
// `.jsonValues()` router: map params → the entry key and load ONLY that
|
|
220
|
+
// entry's backing `*.val.json` (one dynamic import), like `useValKey`.
|
|
221
|
+
if (routeFromVal.isJsonValuesRecordSchema(schema)) {
|
|
222
|
+
var source = selector && core.Internal.getSource(selector);
|
|
223
|
+
var url = routeFromVal.getValRouteUrlFromVal(resolvedParams || {}, "useValRoute", path, schema, source);
|
|
224
|
+
if (!url) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
var draft = draftJsonEntry(draftSource, url);
|
|
228
|
+
if (draft.status === "absent") {
|
|
229
|
+
// The draft state says this route is gone — see useValKeyStega.
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
var content = draft.status === "content" ? draft.content : undefined;
|
|
233
|
+
if (content === undefined) {
|
|
234
|
+
content = readCommittedJsonEntry(selector, url);
|
|
235
|
+
}
|
|
236
|
+
if (content === undefined) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
return stega.stegaEncode(content, {
|
|
240
|
+
disabled: !valOverlayContext.draftMode,
|
|
241
|
+
root: routeFromVal.getJsonEntryStegaRoot(selector, url)
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
var route = routeFromVal.initValRouteFromVal(resolvedParams || {}, "useValRoute", path, schema, val);
|
|
86
245
|
return route;
|
|
87
246
|
}
|
|
88
247
|
function useValRouteUrl(selector, params) {
|
|
@@ -100,6 +259,7 @@ function useValRouteUrl(selector, params) {
|
|
|
100
259
|
function initValClient(config) {
|
|
101
260
|
return {
|
|
102
261
|
useValStega: useValStega,
|
|
262
|
+
useValKeyStega: useValKeyStega,
|
|
103
263
|
useValRouteStega: useValRouteStega,
|
|
104
264
|
useValRouteUrl: useValRouteUrl
|
|
105
265
|
};
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
require('client-only');
|
|
6
|
+
var routeFromVal = require('../../dist/routeFromVal-8ac2f984.cjs.prod.js');
|
|
6
7
|
var core = require('@valbuild/core');
|
|
7
8
|
var stega = require('@valbuild/react/stega');
|
|
8
9
|
var React = require('react');
|
|
9
10
|
var ValOverlayContext = require('../../dist/ValOverlayContext-f7f45bc7.cjs.prod.js');
|
|
10
|
-
var routeFromVal = require('../../dist/routeFromVal-13c832b2.cjs.prod.js');
|
|
11
11
|
require('../../dist/createForOfIteratorHelper-d4afcad8.cjs.prod.js');
|
|
12
12
|
require('../../dist/unsupportedIterableToArray-0d2087a2.cjs.prod.js');
|
|
13
13
|
require('../../dist/objectSpread2-13f847a9.cjs.prod.js');
|
|
@@ -58,6 +58,133 @@ function useValStega(selector) {
|
|
|
58
58
|
}
|
|
59
59
|
});
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* The module's source as the overlay currently sees it — i.e. WITH the editor's
|
|
64
|
+
* unpublished changes — or undefined when there is no draft view to be had
|
|
65
|
+
* (production, draft mode off, or the overlay has not pushed this module yet).
|
|
66
|
+
*
|
|
67
|
+
* This is what lets the single-entry readers show drafts. They otherwise resolve
|
|
68
|
+
* an entry through its local import thunk, which is the content that was bundled:
|
|
69
|
+
* correct in production, and stale the moment anyone edits in the Studio.
|
|
70
|
+
*/
|
|
71
|
+
function useDraftModuleSource(moduleFilePath) {
|
|
72
|
+
var valOverlayContext = ValOverlayContext.useValOverlayContext();
|
|
73
|
+
var store = valOverlayContext.store;
|
|
74
|
+
var moduleIds = React__default["default"].useMemo(function () {
|
|
75
|
+
return moduleFilePath ? [moduleFilePath] : [];
|
|
76
|
+
}, [moduleFilePath]);
|
|
77
|
+
var moduleMap = React__default["default"].useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
|
|
78
|
+
return function () {};
|
|
79
|
+
}, store ? store.getSnapshot(moduleIds) : function () {
|
|
80
|
+
return undefined;
|
|
81
|
+
}, store ? store.getServerSnapshot(moduleIds) : function () {
|
|
82
|
+
return undefined;
|
|
83
|
+
});
|
|
84
|
+
if (!valOverlayContext.draftMode || !moduleFilePath) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return moduleMap === null || moduleMap === void 0 ? void 0 : moduleMap[moduleFilePath];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* What the draft view says about one `.jsonValues()` entry.
|
|
92
|
+
*
|
|
93
|
+
* Mirrors the server-side rule in `fetchValKey`/`fetchValRoute`: a draft view
|
|
94
|
+
* that HAS an answer wins, including the answer "this entry is gone", and the
|
|
95
|
+
* bundled content is used only when there is no draft view.
|
|
96
|
+
*/
|
|
97
|
+
function draftJsonEntry(draftSource, key) {
|
|
98
|
+
if (draftSource === undefined || draftSource === null || routeFromVal._typeof(draftSource) !== "object" || Array.isArray(draftSource)) {
|
|
99
|
+
return {
|
|
100
|
+
status: "unavailable"
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
var entry = draftSource[key];
|
|
104
|
+
if (entry === undefined) {
|
|
105
|
+
// The module IS in the draft view and this key is not: it was deleted.
|
|
106
|
+
return {
|
|
107
|
+
status: "absent"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
if (core.Internal.isJson(entry)) {
|
|
111
|
+
// An un-loaded marker: the Studio has not fetched this entry's content, so
|
|
112
|
+
// the draft view cannot answer. (The engine asks for entries that pending
|
|
113
|
+
// patches touch, so this resolves itself for anything actually edited.)
|
|
114
|
+
return {
|
|
115
|
+
status: "unavailable"
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
status: "content",
|
|
120
|
+
content: entry
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// The (loosened) content type a single `.jsonValues()` entry resolves to.
|
|
125
|
+
|
|
126
|
+
// Module-level cache of in-flight/resolved entry loads, so `React.use` gets a
|
|
127
|
+
// stable promise across renders (keyed by module path + entry key).
|
|
128
|
+
var jsonEntryPromiseCache = new Map();
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Client counterpart to `fetchValKey`: resolves a SINGLE `.jsonValues()` entry
|
|
132
|
+
* by key, loading only that entry's backing `*.val.json` (one dynamic import).
|
|
133
|
+
* Suspends (via `React.use`) until the entry loads, so it must be rendered
|
|
134
|
+
* inside a `<Suspense>` boundary.
|
|
135
|
+
*
|
|
136
|
+
* In draft mode it renders the editor's unpublished content, taken from the
|
|
137
|
+
* overlay; in production — and whenever there is no draft view — it resolves the
|
|
138
|
+
* entry's lazy import thunk from the local module.
|
|
139
|
+
*/
|
|
140
|
+
function useValKeyStega(selector, key) {
|
|
141
|
+
var valOverlayContext = ValOverlayContext.useValOverlayContext();
|
|
142
|
+
var moduleFilePath = selector && core.Internal.getValPath(selector);
|
|
143
|
+
var draftSource = useDraftModuleSource(moduleFilePath || undefined);
|
|
144
|
+
var draft = draftJsonEntry(draftSource, key);
|
|
145
|
+
if (draft.status === "absent") {
|
|
146
|
+
// Deleted in the draft state. Falling back to the bundled entry here would
|
|
147
|
+
// render content the editor has just removed.
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
var content = draft.status === "content" ? draft.content : undefined;
|
|
151
|
+
if (content === undefined) {
|
|
152
|
+
content = readCommittedJsonEntry(selector, key);
|
|
153
|
+
}
|
|
154
|
+
return stega.stegaEncode(content, {
|
|
155
|
+
disabled: !valOverlayContext.draftMode,
|
|
156
|
+
root: routeFromVal.getJsonEntryStegaRoot(selector, key)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* The entry's content as bundled: its lazy import thunk, resolved through
|
|
162
|
+
* `React.use` so the caller suspends until it lands.
|
|
163
|
+
*
|
|
164
|
+
* Deliberately not named `use*`: it is called conditionally, which is fine
|
|
165
|
+
* because `React.use` is not a hook, but a `use*` name would read like one.
|
|
166
|
+
*/
|
|
167
|
+
function readCommittedJsonEntry(selector, key) {
|
|
168
|
+
var _Internal$getValPath;
|
|
169
|
+
var source = selector && core.Internal.getSource(selector);
|
|
170
|
+
var marker = source && routeFromVal._typeof(source) === "object" ? source[key] : undefined;
|
|
171
|
+
if (!core.Internal.isJson(marker)) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
var thunk = core.Internal.getJsonImport(marker);
|
|
175
|
+
if (!thunk) {
|
|
176
|
+
return undefined;
|
|
177
|
+
}
|
|
178
|
+
var cacheKey = "".concat((_Internal$getValPath = core.Internal.getValPath(selector)) !== null && _Internal$getValPath !== void 0 ? _Internal$getValPath : "", " ").concat(key);
|
|
179
|
+
var promise = jsonEntryPromiseCache.get(cacheKey);
|
|
180
|
+
if (!promise) {
|
|
181
|
+
promise = thunk().then(function (mod) {
|
|
182
|
+
return mod["default"];
|
|
183
|
+
});
|
|
184
|
+
jsonEntryPromiseCache.set(cacheKey, promise);
|
|
185
|
+
}
|
|
186
|
+
return React__default["default"].use(promise);
|
|
187
|
+
}
|
|
61
188
|
function resolveParams(params) {
|
|
62
189
|
if (!params) {
|
|
63
190
|
return null;
|
|
@@ -76,13 +203,45 @@ function resolveParams(params) {
|
|
|
76
203
|
return params;
|
|
77
204
|
}
|
|
78
205
|
function useValRouteStega(selector, params) {
|
|
206
|
+
var valOverlayContext = ValOverlayContext.useValOverlayContext();
|
|
207
|
+
// Both called unconditionally to keep hook order stable. For a `.jsonValues()`
|
|
208
|
+
// router `val` is unused (we resolve a single entry below instead); for any
|
|
209
|
+
// other router `draftSource` is.
|
|
79
210
|
var val = useValStega(selector);
|
|
211
|
+
var draftSource = useDraftModuleSource(selector && core.Internal.getValPath(selector) || undefined);
|
|
80
212
|
var resolvedParams = resolveParams(params);
|
|
81
213
|
// Careful: null means there was an error - undefined means no params
|
|
82
214
|
if (resolvedParams === null) {
|
|
83
215
|
return null;
|
|
84
216
|
}
|
|
85
|
-
var
|
|
217
|
+
var path = selector && core.Internal.getValPath(selector);
|
|
218
|
+
var schema = selector && core.Internal.getSchema(selector);
|
|
219
|
+
// `.jsonValues()` router: map params → the entry key and load ONLY that
|
|
220
|
+
// entry's backing `*.val.json` (one dynamic import), like `useValKey`.
|
|
221
|
+
if (routeFromVal.isJsonValuesRecordSchema(schema)) {
|
|
222
|
+
var source = selector && core.Internal.getSource(selector);
|
|
223
|
+
var url = routeFromVal.getValRouteUrlFromVal(resolvedParams || {}, "useValRoute", path, schema, source);
|
|
224
|
+
if (!url) {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
var draft = draftJsonEntry(draftSource, url);
|
|
228
|
+
if (draft.status === "absent") {
|
|
229
|
+
// The draft state says this route is gone — see useValKeyStega.
|
|
230
|
+
return null;
|
|
231
|
+
}
|
|
232
|
+
var content = draft.status === "content" ? draft.content : undefined;
|
|
233
|
+
if (content === undefined) {
|
|
234
|
+
content = readCommittedJsonEntry(selector, url);
|
|
235
|
+
}
|
|
236
|
+
if (content === undefined) {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
return stega.stegaEncode(content, {
|
|
240
|
+
disabled: !valOverlayContext.draftMode,
|
|
241
|
+
root: routeFromVal.getJsonEntryStegaRoot(selector, url)
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
var route = routeFromVal.initValRouteFromVal(resolvedParams || {}, "useValRoute", path, schema, val);
|
|
86
245
|
return route;
|
|
87
246
|
}
|
|
88
247
|
function useValRouteUrl(selector, params) {
|
|
@@ -100,6 +259,7 @@ function useValRouteUrl(selector, params) {
|
|
|
100
259
|
function initValClient(config) {
|
|
101
260
|
return {
|
|
102
261
|
useValStega: useValStega,
|
|
262
|
+
useValKeyStega: useValKeyStega,
|
|
103
263
|
useValRouteStega: useValRouteStega,
|
|
104
264
|
useValRouteUrl: useValRouteUrl
|
|
105
265
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import 'client-only';
|
|
2
|
+
import { g as getJsonEntryStegaRoot, _ as _typeof, a as isJsonValuesRecordSchema, b as getValRouteUrlFromVal, i as initValRouteFromVal } from '../../dist/routeFromVal-263eec96.esm.js';
|
|
2
3
|
import { Internal } from '@valbuild/core';
|
|
3
4
|
import { getModuleIds, stegaEncode } from '@valbuild/react/stega';
|
|
4
5
|
import React from 'react';
|
|
5
6
|
import { useValOverlayContext } from '../../dist/ValOverlayContext-3c37e5a7.esm.js';
|
|
6
|
-
import { i as initValRouteFromVal, g as getValRouteUrlFromVal } from '../../dist/routeFromVal-8855a5cc.esm.js';
|
|
7
7
|
import '../../dist/createForOfIteratorHelper-5758a730.esm.js';
|
|
8
8
|
import '../../dist/unsupportedIterableToArray-5baabfdc.esm.js';
|
|
9
9
|
import '../../dist/objectSpread2-60d1bd93.esm.js';
|
|
@@ -50,6 +50,133 @@ function useValStega(selector) {
|
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The module's source as the overlay currently sees it — i.e. WITH the editor's
|
|
56
|
+
* unpublished changes — or undefined when there is no draft view to be had
|
|
57
|
+
* (production, draft mode off, or the overlay has not pushed this module yet).
|
|
58
|
+
*
|
|
59
|
+
* This is what lets the single-entry readers show drafts. They otherwise resolve
|
|
60
|
+
* an entry through its local import thunk, which is the content that was bundled:
|
|
61
|
+
* correct in production, and stale the moment anyone edits in the Studio.
|
|
62
|
+
*/
|
|
63
|
+
function useDraftModuleSource(moduleFilePath) {
|
|
64
|
+
var valOverlayContext = useValOverlayContext();
|
|
65
|
+
var store = valOverlayContext.store;
|
|
66
|
+
var moduleIds = React.useMemo(function () {
|
|
67
|
+
return moduleFilePath ? [moduleFilePath] : [];
|
|
68
|
+
}, [moduleFilePath]);
|
|
69
|
+
var moduleMap = React.useSyncExternalStore(store ? store.subscribe(moduleIds) : function () {
|
|
70
|
+
return function () {};
|
|
71
|
+
}, store ? store.getSnapshot(moduleIds) : function () {
|
|
72
|
+
return undefined;
|
|
73
|
+
}, store ? store.getServerSnapshot(moduleIds) : function () {
|
|
74
|
+
return undefined;
|
|
75
|
+
});
|
|
76
|
+
if (!valOverlayContext.draftMode || !moduleFilePath) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
return moduleMap === null || moduleMap === void 0 ? void 0 : moduleMap[moduleFilePath];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* What the draft view says about one `.jsonValues()` entry.
|
|
84
|
+
*
|
|
85
|
+
* Mirrors the server-side rule in `fetchValKey`/`fetchValRoute`: a draft view
|
|
86
|
+
* that HAS an answer wins, including the answer "this entry is gone", and the
|
|
87
|
+
* bundled content is used only when there is no draft view.
|
|
88
|
+
*/
|
|
89
|
+
function draftJsonEntry(draftSource, key) {
|
|
90
|
+
if (draftSource === undefined || draftSource === null || _typeof(draftSource) !== "object" || Array.isArray(draftSource)) {
|
|
91
|
+
return {
|
|
92
|
+
status: "unavailable"
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
var entry = draftSource[key];
|
|
96
|
+
if (entry === undefined) {
|
|
97
|
+
// The module IS in the draft view and this key is not: it was deleted.
|
|
98
|
+
return {
|
|
99
|
+
status: "absent"
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
if (Internal.isJson(entry)) {
|
|
103
|
+
// An un-loaded marker: the Studio has not fetched this entry's content, so
|
|
104
|
+
// the draft view cannot answer. (The engine asks for entries that pending
|
|
105
|
+
// patches touch, so this resolves itself for anything actually edited.)
|
|
106
|
+
return {
|
|
107
|
+
status: "unavailable"
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
status: "content",
|
|
112
|
+
content: entry
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// The (loosened) content type a single `.jsonValues()` entry resolves to.
|
|
117
|
+
|
|
118
|
+
// Module-level cache of in-flight/resolved entry loads, so `React.use` gets a
|
|
119
|
+
// stable promise across renders (keyed by module path + entry key).
|
|
120
|
+
var jsonEntryPromiseCache = new Map();
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Client counterpart to `fetchValKey`: resolves a SINGLE `.jsonValues()` entry
|
|
124
|
+
* by key, loading only that entry's backing `*.val.json` (one dynamic import).
|
|
125
|
+
* Suspends (via `React.use`) until the entry loads, so it must be rendered
|
|
126
|
+
* inside a `<Suspense>` boundary.
|
|
127
|
+
*
|
|
128
|
+
* In draft mode it renders the editor's unpublished content, taken from the
|
|
129
|
+
* overlay; in production — and whenever there is no draft view — it resolves the
|
|
130
|
+
* entry's lazy import thunk from the local module.
|
|
131
|
+
*/
|
|
132
|
+
function useValKeyStega(selector, key) {
|
|
133
|
+
var valOverlayContext = useValOverlayContext();
|
|
134
|
+
var moduleFilePath = selector && Internal.getValPath(selector);
|
|
135
|
+
var draftSource = useDraftModuleSource(moduleFilePath || undefined);
|
|
136
|
+
var draft = draftJsonEntry(draftSource, key);
|
|
137
|
+
if (draft.status === "absent") {
|
|
138
|
+
// Deleted in the draft state. Falling back to the bundled entry here would
|
|
139
|
+
// render content the editor has just removed.
|
|
140
|
+
return undefined;
|
|
141
|
+
}
|
|
142
|
+
var content = draft.status === "content" ? draft.content : undefined;
|
|
143
|
+
if (content === undefined) {
|
|
144
|
+
content = readCommittedJsonEntry(selector, key);
|
|
145
|
+
}
|
|
146
|
+
return stegaEncode(content, {
|
|
147
|
+
disabled: !valOverlayContext.draftMode,
|
|
148
|
+
root: getJsonEntryStegaRoot(selector, key)
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The entry's content as bundled: its lazy import thunk, resolved through
|
|
154
|
+
* `React.use` so the caller suspends until it lands.
|
|
155
|
+
*
|
|
156
|
+
* Deliberately not named `use*`: it is called conditionally, which is fine
|
|
157
|
+
* because `React.use` is not a hook, but a `use*` name would read like one.
|
|
158
|
+
*/
|
|
159
|
+
function readCommittedJsonEntry(selector, key) {
|
|
160
|
+
var _Internal$getValPath;
|
|
161
|
+
var source = selector && Internal.getSource(selector);
|
|
162
|
+
var marker = source && _typeof(source) === "object" ? source[key] : undefined;
|
|
163
|
+
if (!Internal.isJson(marker)) {
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
var thunk = Internal.getJsonImport(marker);
|
|
167
|
+
if (!thunk) {
|
|
168
|
+
return undefined;
|
|
169
|
+
}
|
|
170
|
+
var cacheKey = "".concat((_Internal$getValPath = Internal.getValPath(selector)) !== null && _Internal$getValPath !== void 0 ? _Internal$getValPath : "", " ").concat(key);
|
|
171
|
+
var promise = jsonEntryPromiseCache.get(cacheKey);
|
|
172
|
+
if (!promise) {
|
|
173
|
+
promise = thunk().then(function (mod) {
|
|
174
|
+
return mod["default"];
|
|
175
|
+
});
|
|
176
|
+
jsonEntryPromiseCache.set(cacheKey, promise);
|
|
177
|
+
}
|
|
178
|
+
return React.use(promise);
|
|
179
|
+
}
|
|
53
180
|
function resolveParams(params) {
|
|
54
181
|
if (!params) {
|
|
55
182
|
return null;
|
|
@@ -68,13 +195,45 @@ function resolveParams(params) {
|
|
|
68
195
|
return params;
|
|
69
196
|
}
|
|
70
197
|
function useValRouteStega(selector, params) {
|
|
198
|
+
var valOverlayContext = useValOverlayContext();
|
|
199
|
+
// Both called unconditionally to keep hook order stable. For a `.jsonValues()`
|
|
200
|
+
// router `val` is unused (we resolve a single entry below instead); for any
|
|
201
|
+
// other router `draftSource` is.
|
|
71
202
|
var val = useValStega(selector);
|
|
203
|
+
var draftSource = useDraftModuleSource(selector && Internal.getValPath(selector) || undefined);
|
|
72
204
|
var resolvedParams = resolveParams(params);
|
|
73
205
|
// Careful: null means there was an error - undefined means no params
|
|
74
206
|
if (resolvedParams === null) {
|
|
75
207
|
return null;
|
|
76
208
|
}
|
|
77
|
-
var
|
|
209
|
+
var path = selector && Internal.getValPath(selector);
|
|
210
|
+
var schema = selector && Internal.getSchema(selector);
|
|
211
|
+
// `.jsonValues()` router: map params → the entry key and load ONLY that
|
|
212
|
+
// entry's backing `*.val.json` (one dynamic import), like `useValKey`.
|
|
213
|
+
if (isJsonValuesRecordSchema(schema)) {
|
|
214
|
+
var source = selector && Internal.getSource(selector);
|
|
215
|
+
var url = getValRouteUrlFromVal(resolvedParams || {}, "useValRoute", path, schema, source);
|
|
216
|
+
if (!url) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
var draft = draftJsonEntry(draftSource, url);
|
|
220
|
+
if (draft.status === "absent") {
|
|
221
|
+
// The draft state says this route is gone — see useValKeyStega.
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
var content = draft.status === "content" ? draft.content : undefined;
|
|
225
|
+
if (content === undefined) {
|
|
226
|
+
content = readCommittedJsonEntry(selector, url);
|
|
227
|
+
}
|
|
228
|
+
if (content === undefined) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
return stegaEncode(content, {
|
|
232
|
+
disabled: !valOverlayContext.draftMode,
|
|
233
|
+
root: getJsonEntryStegaRoot(selector, url)
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
var route = initValRouteFromVal(resolvedParams || {}, "useValRoute", path, schema, val);
|
|
78
237
|
return route;
|
|
79
238
|
}
|
|
80
239
|
function useValRouteUrl(selector, params) {
|
|
@@ -92,6 +251,7 @@ function useValRouteUrl(selector, params) {
|
|
|
92
251
|
function initValClient(config) {
|
|
93
252
|
return {
|
|
94
253
|
useValStega: useValStega,
|
|
254
|
+
useValKeyStega: useValKeyStega,
|
|
95
255
|
useValRouteStega: useValRouteStega,
|
|
96
256
|
useValRouteUrl: useValRouteUrl
|
|
97
257
|
};
|
|
@@ -1,13 +1,26 @@
|
|
|
1
|
-
import { GenericSelector, SelectorOf, SelectorSource, SourceObject, ValModule } from "@valbuild/core";
|
|
1
|
+
import { GenericSelector, JsonSource, SelectorOf, SelectorSource, SourceObject, ValModule } from "@valbuild/core";
|
|
2
2
|
import { StegaOfSource } from "@valbuild/react/stega";
|
|
3
3
|
import { ValConfig } from "@valbuild/core";
|
|
4
4
|
export type UseValType<T extends SelectorSource> = SelectorOf<T> extends GenericSelector<infer S> ? StegaOfSource<S> : never;
|
|
5
5
|
declare function useValStega<T extends SelectorSource>(selector: T): UseValType<T>;
|
|
6
|
-
type
|
|
6
|
+
type JsonEntryContentOf<T extends ValModule<GenericSelector<SourceObject>>> = T extends ValModule<infer S> ? S extends Record<string, infer V> ? V extends JsonSource<infer C> ? C : never : never : never;
|
|
7
|
+
/**
|
|
8
|
+
* Client counterpart to `fetchValKey`: resolves a SINGLE `.jsonValues()` entry
|
|
9
|
+
* by key, loading only that entry's backing `*.val.json` (one dynamic import).
|
|
10
|
+
* Suspends (via `React.use`) until the entry loads, so it must be rendered
|
|
11
|
+
* inside a `<Suspense>` boundary.
|
|
12
|
+
*
|
|
13
|
+
* In draft mode it renders the editor's unpublished content, taken from the
|
|
14
|
+
* overlay; in production — and whenever there is no draft view — it resolves the
|
|
15
|
+
* entry's lazy import thunk from the local module.
|
|
16
|
+
*/
|
|
17
|
+
declare function useValKeyStega<T extends ValModule<GenericSelector<SourceObject>>>(selector: T, key: string): JsonEntryContentOf<T> | undefined;
|
|
18
|
+
type UseValRouteReturnType<T extends ValModule<GenericSelector<SourceObject>>> = T extends ValModule<infer S> ? S extends SourceObject ? NonNullable<S>[string] extends JsonSource<infer C> ? C | null : StegaOfSource<NonNullable<S>[string]> | null : never : never;
|
|
7
19
|
declare function useValRouteStega<T extends ValModule<GenericSelector<SourceObject>>>(selector: T, params: Record<string, string | string[]> | Promise<Record<string, string | string[]>>): UseValRouteReturnType<T>;
|
|
8
20
|
declare function useValRouteUrl<T extends ValModule<GenericSelector<SourceObject>>>(selector: T, params?: Record<string, string | string[]> | Promise<Record<string, string | string[]>>): string | null;
|
|
9
21
|
export declare function initValClient(config: ValConfig): {
|
|
10
22
|
useValStega: typeof useValStega;
|
|
23
|
+
useValKeyStega: typeof useValKeyStega;
|
|
11
24
|
useValRouteStega: typeof useValRouteStega;
|
|
12
25
|
useValRouteUrl: typeof useValRouteUrl;
|
|
13
26
|
};
|
|
@@ -48,6 +48,9 @@ export declare const Internal: {
|
|
|
48
48
|
validate: (val: import("@valbuild/core").ValModule<import("@valbuild/core").SelectorSource>, path: import("@valbuild/core").SourcePath, src: unknown) => import("@valbuild/core").ValidationErrors | undefined;
|
|
49
49
|
isVal: typeof import("@valbuild/core/dist/declarations/src/val").isVal;
|
|
50
50
|
isFile: typeof import("@valbuild/core/dist/declarations/src/source/file").isFile;
|
|
51
|
+
isJson: typeof import("@valbuild/core/dist/declarations/src/source/json").isJson;
|
|
52
|
+
getJsonImport: typeof import("@valbuild/core/dist/declarations/src/source/json").getJsonImport;
|
|
53
|
+
resolveJsonValues: typeof import("@valbuild/core/dist/declarations/src/source/json").resolveJsonValues;
|
|
51
54
|
createValPathOfItem: typeof import("@valbuild/core/dist/declarations/src/selector/SelectorProxy").createValPathOfItem;
|
|
52
55
|
getSHA256Hash: (bits: Uint8Array) => string;
|
|
53
56
|
initSchema: typeof import("@valbuild/core/dist/declarations/src/initSchema").initSchema;
|