@valbuild/react 0.132.1 → 0.134.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/CHANGELOG.md +87 -0
- package/dist/declarations/src/stega/index.d.ts +1 -1
- package/dist/declarations/src/stega/stegaEncode.d.ts +47 -1
- package/dist/{raw-eede220f.worker.esm.js → raw-1280c322.worker.esm.js} +165 -8
- package/dist/{raw-fe78b046.cjs.prod.js → raw-3ae44ab5.cjs.prod.js} +164 -7
- package/dist/{raw-7ce61255.esm.js → raw-bd3105cd.esm.js} +165 -8
- package/dist/{raw-57f19ada.browser.esm.js → raw-d6f65f06.browser.esm.js} +165 -8
- package/dist/{raw-512e7a0a.cjs.dev.js → raw-ec62616c.cjs.dev.js} +164 -7
- package/internal/dist/valbuild-react-internal.browser.esm.js +1 -1
- package/internal/dist/valbuild-react-internal.cjs.dev.js +1 -1
- package/internal/dist/valbuild-react-internal.cjs.prod.js +1 -1
- package/internal/dist/valbuild-react-internal.esm.js +1 -1
- package/internal/dist/valbuild-react-internal.worker.esm.js +1 -1
- package/package.json +4 -4
- package/stega/dist/valbuild-react-stega.browser.esm.js +2 -2
- package/stega/dist/valbuild-react-stega.cjs.dev.js +1 -1
- package/stega/dist/valbuild-react-stega.cjs.prod.js +1 -1
- package/stega/dist/valbuild-react-stega.esm.js +2 -2
- package/stega/dist/valbuild-react-stega.worker.esm.js +2 -2
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { b as _unsupportedIterableToArray, a as _typeof, _ as _slicedToArray } from './slicedToArray-0c0a3b4a.esm.js';
|
|
2
|
-
import { Internal } from '@valbuild/core';
|
|
2
|
+
import { Internal, isValViewSource } from '@valbuild/core';
|
|
3
3
|
import { vercelStegaDecodeAll, vercelStegaSplit, vercelStegaCombine } from '@vercel/stega';
|
|
4
4
|
|
|
5
5
|
function _createForOfIteratorHelper(r, e) {
|
|
@@ -142,6 +142,48 @@ function _objectSpread2(e) {
|
|
|
142
142
|
* RichText is accessible by users (after conversion via useVal / fetchVal)
|
|
143
143
|
**/
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* What resolving `T` gives back — the one definition the framework readers
|
|
147
|
+
* share.
|
|
148
|
+
*
|
|
149
|
+
* Two shapes go in. A module or selector resolves as it always has. A
|
|
150
|
+
* {@link ValView}, which is what a `s.view()` field reads as, resolves to the
|
|
151
|
+
* module it points at: the page declares what it shows, and a reader follows
|
|
152
|
+
* that declaration instead of importing the target a second time.
|
|
153
|
+
*
|
|
154
|
+
* One definition rather than one per reader — `useVal`, `fetchVal`,
|
|
155
|
+
* `initValContent` and the TanStack client each had their own copy of the
|
|
156
|
+
* selector half, which is four places for the view half to be forgotten in.
|
|
157
|
+
*
|
|
158
|
+
* `Target extends Source` is checked HERE rather than on `ValView` itself:
|
|
159
|
+
* `ValView` is built from `ValViewSource`, which is a member of the `Source`
|
|
160
|
+
* union, so a constraint there is a circular type reference.
|
|
161
|
+
*
|
|
162
|
+
* The outer arms are wrapped in tuples so the conditional does not DISTRIBUTE
|
|
163
|
+
* over a union: distributing it re-entered `StegaOfSource` per member and the
|
|
164
|
+
* async readers hit "Type instantiation is excessively deep and possibly
|
|
165
|
+
* infinite" — `useVal` did not, because a `Promise<...>` around it is one more
|
|
166
|
+
* level than the checker had left.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/** What a reader accepts. A view handle is a `SelectorSource`, so this is it. */
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The source of whichever arm of `ResolvableModule` a reader was given — the
|
|
173
|
+
* module's own, or that of the module a view points at.
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The (loosened) content type a single `.jsonValues()` entry resolves to.
|
|
178
|
+
*
|
|
179
|
+
* Here rather than in the framework packages because there were four identical
|
|
180
|
+
* copies of it — next's client and rsc readers, tanstack's client and server —
|
|
181
|
+
* and the view arm would have had to be added to each. Same reason
|
|
182
|
+
* {@link ResolvedVal} lives here.
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
/** What a route reader gives back for the entry the params matched. */
|
|
186
|
+
|
|
145
187
|
/**
|
|
146
188
|
* Resolves the matching variant of a discriminated union from the value's tag.
|
|
147
189
|
* Returns the matching schema or null if no match is found.
|
|
@@ -241,7 +283,55 @@ function handleRichTextSchema(sourceOrSelector, recOpts, rec) {
|
|
|
241
283
|
return sourceOrSelector;
|
|
242
284
|
}
|
|
243
285
|
function stegaEncode(input, opts) {
|
|
286
|
+
var viewModules = new Map();
|
|
287
|
+
// Handed a view handle rather than a module: resolve it and encode what it
|
|
288
|
+
// points at. This is what makes `useVal(page.header)` read the header.
|
|
289
|
+
var resolved = Internal.viewHandleModule(input);
|
|
290
|
+
if (resolved !== undefined) {
|
|
291
|
+
return stegaEncode(resolved, opts);
|
|
292
|
+
}
|
|
293
|
+
// A view pointer with no module on it. The module rides on a symbol, and
|
|
294
|
+
// symbols do not survive serialization — so this is a handle that crossed the
|
|
295
|
+
// server/client boundary as a prop, or one read out of raw JSON. Resolving it
|
|
296
|
+
// would hand back the pointer itself, which looks like content and is not, so
|
|
297
|
+
// say what happened instead.
|
|
298
|
+
if (isValViewSource(input)) {
|
|
299
|
+
throw Error("Cannot resolve the view of '".concat(input.view, "': it carries no module. ") + "Either it crossed a server/client boundary, which drops the module because it rides on a symbol, " + "or it points at a different module than its schema declares \u2014 which `val validate --fix` repairs. " + "Resolve it in the same component that read the module containing it, or read '".concat(input.view, "' directly."));
|
|
300
|
+
}
|
|
244
301
|
function rec(sourceOrSelector, recOpts) {
|
|
302
|
+
// A view is a pointer at another module. Weaving an edit tag into it would
|
|
303
|
+
// corrupt the path it holds, and there is nothing of the target here to
|
|
304
|
+
// encode — the target is its own module, encoded when it is read.
|
|
305
|
+
//
|
|
306
|
+
// The module it names rides along on a symbol, so `useVal(page.header)` can
|
|
307
|
+
// resolve it without a path-to-module registry the app does not have. The
|
|
308
|
+
// pointer itself is unchanged: symbols do not serialize, so this is still
|
|
309
|
+
// `{ view: "/foo.val.ts" }` to anything that looks at it as data.
|
|
310
|
+
if (recOpts !== null && recOpts !== void 0 && recOpts.schema && recOpts.schema.type === "view") {
|
|
311
|
+
var valModule = viewModules.get(recOpts.schema.moduleFilePath);
|
|
312
|
+
if (valModule === undefined || !isValViewSource(sourceOrSelector)) {
|
|
313
|
+
return sourceOrSelector;
|
|
314
|
+
}
|
|
315
|
+
/*
|
|
316
|
+
* The POINTER decides what may be attached, not the schema alone.
|
|
317
|
+
*
|
|
318
|
+
* The two can disagree: a `.val.ts` cannot express it (the source type is
|
|
319
|
+
* the literal path), but hand-written JSON and a patch can, which is the
|
|
320
|
+
* whole reason `view:check-module` exists as a fix. Keying only on the
|
|
321
|
+
* schema attached the schema's module to a pointer naming a different one,
|
|
322
|
+
* so `useVal(page.field)` read a module the value does not name — silently,
|
|
323
|
+
* and looking exactly like a correct read.
|
|
324
|
+
*
|
|
325
|
+
* So a mismatch gets no handle: the value stays the bare pointer, and
|
|
326
|
+
* reading it throws rather than answering with the wrong module. The
|
|
327
|
+
* Studio still renders the field and still offers the repair; nothing here
|
|
328
|
+
* refuses to encode the page over it.
|
|
329
|
+
*/
|
|
330
|
+
if (sourceOrSelector.view !== recOpts.schema.moduleFilePath) {
|
|
331
|
+
return sourceOrSelector;
|
|
332
|
+
}
|
|
333
|
+
return Internal.createViewHandle(sourceOrSelector, valModule);
|
|
334
|
+
}
|
|
245
335
|
if (recOpts !== null && recOpts !== void 0 && recOpts.schema && isKeyOfSchema(recOpts === null || recOpts === void 0 ? void 0 : recOpts.schema)) {
|
|
246
336
|
return sourceOrSelector;
|
|
247
337
|
}
|
|
@@ -304,6 +394,25 @@ function stegaEncode(input, opts) {
|
|
|
304
394
|
var selectorPath = Internal.getValPath(sourceOrSelector);
|
|
305
395
|
if (selectorPath) {
|
|
306
396
|
var newSchema = Internal.getSchema(sourceOrSelector);
|
|
397
|
+
// The modules this module's views point at. Collected HERE because this
|
|
398
|
+
// is the only place with the schema INSTANCE — everything below walks
|
|
399
|
+
// the serialized schema, which carries a path and not a module. Merged
|
|
400
|
+
// rather than replaced: a handle resolved by `useVal` re-enters here as
|
|
401
|
+
// its own module, and its parent's views must stay resolvable.
|
|
402
|
+
var _iterator = _createForOfIteratorHelper(Internal.viewModulesOf(newSchema)),
|
|
403
|
+
_step;
|
|
404
|
+
try {
|
|
405
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
406
|
+
var _step$value = _slicedToArray(_step.value, 2),
|
|
407
|
+
path = _step$value[0],
|
|
408
|
+
_valModule = _step$value[1];
|
|
409
|
+
viewModules.set(path, _valModule);
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
_iterator.e(err);
|
|
413
|
+
} finally {
|
|
414
|
+
_iterator.f();
|
|
415
|
+
}
|
|
307
416
|
return rec(opts.getModule && opts.getModule(selectorPath) !== undefined ? opts.getModule(selectorPath) : Internal.getSource(sourceOrSelector), {
|
|
308
417
|
path: selectorPath,
|
|
309
418
|
schema: newSchema === null || newSchema === void 0 ? void 0 : newSchema["executeSerialize"]()
|
|
@@ -421,24 +530,65 @@ function collectReferencedModulesFromSchema(schema, acc) {
|
|
|
421
530
|
} else if (schema.type === "array" || schema.type === "record") {
|
|
422
531
|
collectReferencedModulesFromSchema(schema.item, acc);
|
|
423
532
|
} else if (schema.type === "discriminated-union") {
|
|
424
|
-
var
|
|
425
|
-
|
|
533
|
+
var _iterator2 = _createForOfIteratorHelper(schema.items),
|
|
534
|
+
_step2;
|
|
426
535
|
try {
|
|
427
|
-
for (
|
|
428
|
-
var item =
|
|
536
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
537
|
+
var item = _step2.value;
|
|
429
538
|
collectReferencedModulesFromSchema(item, acc);
|
|
430
539
|
}
|
|
431
540
|
} catch (err) {
|
|
432
|
-
|
|
541
|
+
_iterator2.e(err);
|
|
433
542
|
} finally {
|
|
434
|
-
|
|
543
|
+
_iterator2.f();
|
|
435
544
|
}
|
|
436
545
|
}
|
|
437
546
|
}
|
|
438
547
|
function stegaClean(source) {
|
|
439
548
|
return vercelStegaSplit(source).cleaned;
|
|
440
549
|
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Answers already computed, keyed by the selector they were computed from.
|
|
553
|
+
*
|
|
554
|
+
* `getModuleIds` is not cheap: it calls `executeSerialize()`, which rebuilds the
|
|
555
|
+
* whole serialized schema tree on every call — ~31us for a 40-field schema with
|
|
556
|
+
* a nested array, against ~4us for a small one. It is called from `useValStega`
|
|
557
|
+
* on every render whose `useMemo` misses.
|
|
558
|
+
*
|
|
559
|
+
* That memo misses on every render for a VIEW, and cannot be fixed there: the
|
|
560
|
+
* handle is built by `createViewHandle` inside `stegaEncode`, so `page.authors`
|
|
561
|
+
* is a fresh object each time the page is encoded, and `[selector]` is a new
|
|
562
|
+
* dependency every render. Caching here rather than in the hooks fixes it for
|
|
563
|
+
* both copies of the hook at once, and for any other caller.
|
|
564
|
+
*
|
|
565
|
+
* Keyed on the selector, which is the module itself for the case that matters —
|
|
566
|
+
* a view resolves to it on the line below, and a module is a module-level
|
|
567
|
+
* constant, so the entry is hit for the life of the process. A fresh nested
|
|
568
|
+
* selector misses, as it did before; a `WeakMap` lets those entries go.
|
|
569
|
+
*
|
|
570
|
+
* The array is shared, so it is frozen: nothing may sort or splice it in place.
|
|
571
|
+
* Every consumer today copies first (`createSubscriberId` does `paths.slice()`),
|
|
572
|
+
* and freezing is what keeps that true.
|
|
573
|
+
*/
|
|
574
|
+
var moduleIdsCache = new WeakMap();
|
|
441
575
|
function getModuleIds(input) {
|
|
576
|
+
// A view handle names one module: the one it points at. Resolved first so a
|
|
577
|
+
// `useVal(page.header)` subscribes to the header rather than to nothing — and
|
|
578
|
+
// so the recursive call lands on the module, which is what the cache above
|
|
579
|
+
// can actually key on.
|
|
580
|
+
var resolved = Internal.viewHandleModule(input);
|
|
581
|
+
if (resolved !== undefined) {
|
|
582
|
+
return getModuleIds(resolved);
|
|
583
|
+
}
|
|
584
|
+
var cacheable = _typeof(input) === "object" && input !== null;
|
|
585
|
+
if (cacheable) {
|
|
586
|
+
var cached = moduleIdsCache.get(input);
|
|
587
|
+
if (cached) {
|
|
588
|
+
// Frozen, so handing the same array to every caller is safe.
|
|
589
|
+
return cached;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
442
592
|
var modules = new Set();
|
|
443
593
|
function rec(sourceOrSelector) {
|
|
444
594
|
if (_typeof(sourceOrSelector) === "object") {
|
|
@@ -482,7 +632,14 @@ function getModuleIds(input) {
|
|
|
482
632
|
return;
|
|
483
633
|
}
|
|
484
634
|
rec(input);
|
|
485
|
-
|
|
635
|
+
var moduleIds = Array.from(modules);
|
|
636
|
+
// Frozen before it is shared, not after: a consumer that sorts in place would
|
|
637
|
+
// otherwise corrupt every later caller's answer, and silently.
|
|
638
|
+
Object.freeze(moduleIds);
|
|
639
|
+
if (cacheable) {
|
|
640
|
+
moduleIdsCache.set(input, moduleIds);
|
|
641
|
+
}
|
|
642
|
+
return moduleIds;
|
|
486
643
|
}
|
|
487
644
|
|
|
488
645
|
function attrs(target) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { b as _unsupportedIterableToArray, a as _typeof, _ as _slicedToArray } from './slicedToArray-9cce0d9f.browser.esm.js';
|
|
2
|
-
import { Internal } from '@valbuild/core';
|
|
2
|
+
import { Internal, isValViewSource } from '@valbuild/core';
|
|
3
3
|
import { vercelStegaDecodeAll, vercelStegaSplit, vercelStegaCombine } from '@vercel/stega';
|
|
4
4
|
|
|
5
5
|
function _createForOfIteratorHelper(r, e) {
|
|
@@ -142,6 +142,48 @@ function _objectSpread2(e) {
|
|
|
142
142
|
* RichText is accessible by users (after conversion via useVal / fetchVal)
|
|
143
143
|
**/
|
|
144
144
|
|
|
145
|
+
/**
|
|
146
|
+
* What resolving `T` gives back — the one definition the framework readers
|
|
147
|
+
* share.
|
|
148
|
+
*
|
|
149
|
+
* Two shapes go in. A module or selector resolves as it always has. A
|
|
150
|
+
* {@link ValView}, which is what a `s.view()` field reads as, resolves to the
|
|
151
|
+
* module it points at: the page declares what it shows, and a reader follows
|
|
152
|
+
* that declaration instead of importing the target a second time.
|
|
153
|
+
*
|
|
154
|
+
* One definition rather than one per reader — `useVal`, `fetchVal`,
|
|
155
|
+
* `initValContent` and the TanStack client each had their own copy of the
|
|
156
|
+
* selector half, which is four places for the view half to be forgotten in.
|
|
157
|
+
*
|
|
158
|
+
* `Target extends Source` is checked HERE rather than on `ValView` itself:
|
|
159
|
+
* `ValView` is built from `ValViewSource`, which is a member of the `Source`
|
|
160
|
+
* union, so a constraint there is a circular type reference.
|
|
161
|
+
*
|
|
162
|
+
* The outer arms are wrapped in tuples so the conditional does not DISTRIBUTE
|
|
163
|
+
* over a union: distributing it re-entered `StegaOfSource` per member and the
|
|
164
|
+
* async readers hit "Type instantiation is excessively deep and possibly
|
|
165
|
+
* infinite" — `useVal` did not, because a `Promise<...>` around it is one more
|
|
166
|
+
* level than the checker had left.
|
|
167
|
+
*/
|
|
168
|
+
|
|
169
|
+
/** What a reader accepts. A view handle is a `SelectorSource`, so this is it. */
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The source of whichever arm of `ResolvableModule` a reader was given — the
|
|
173
|
+
* module's own, or that of the module a view points at.
|
|
174
|
+
*/
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* The (loosened) content type a single `.jsonValues()` entry resolves to.
|
|
178
|
+
*
|
|
179
|
+
* Here rather than in the framework packages because there were four identical
|
|
180
|
+
* copies of it — next's client and rsc readers, tanstack's client and server —
|
|
181
|
+
* and the view arm would have had to be added to each. Same reason
|
|
182
|
+
* {@link ResolvedVal} lives here.
|
|
183
|
+
*/
|
|
184
|
+
|
|
185
|
+
/** What a route reader gives back for the entry the params matched. */
|
|
186
|
+
|
|
145
187
|
/**
|
|
146
188
|
* Resolves the matching variant of a discriminated union from the value's tag.
|
|
147
189
|
* Returns the matching schema or null if no match is found.
|
|
@@ -241,7 +283,55 @@ function handleRichTextSchema(sourceOrSelector, recOpts, rec) {
|
|
|
241
283
|
return sourceOrSelector;
|
|
242
284
|
}
|
|
243
285
|
function stegaEncode(input, opts) {
|
|
286
|
+
var viewModules = new Map();
|
|
287
|
+
// Handed a view handle rather than a module: resolve it and encode what it
|
|
288
|
+
// points at. This is what makes `useVal(page.header)` read the header.
|
|
289
|
+
var resolved = Internal.viewHandleModule(input);
|
|
290
|
+
if (resolved !== undefined) {
|
|
291
|
+
return stegaEncode(resolved, opts);
|
|
292
|
+
}
|
|
293
|
+
// A view pointer with no module on it. The module rides on a symbol, and
|
|
294
|
+
// symbols do not survive serialization — so this is a handle that crossed the
|
|
295
|
+
// server/client boundary as a prop, or one read out of raw JSON. Resolving it
|
|
296
|
+
// would hand back the pointer itself, which looks like content and is not, so
|
|
297
|
+
// say what happened instead.
|
|
298
|
+
if (isValViewSource(input)) {
|
|
299
|
+
throw Error("Cannot resolve the view of '".concat(input.view, "': it carries no module. ") + "Either it crossed a server/client boundary, which drops the module because it rides on a symbol, " + "or it points at a different module than its schema declares \u2014 which `val validate --fix` repairs. " + "Resolve it in the same component that read the module containing it, or read '".concat(input.view, "' directly."));
|
|
300
|
+
}
|
|
244
301
|
function rec(sourceOrSelector, recOpts) {
|
|
302
|
+
// A view is a pointer at another module. Weaving an edit tag into it would
|
|
303
|
+
// corrupt the path it holds, and there is nothing of the target here to
|
|
304
|
+
// encode — the target is its own module, encoded when it is read.
|
|
305
|
+
//
|
|
306
|
+
// The module it names rides along on a symbol, so `useVal(page.header)` can
|
|
307
|
+
// resolve it without a path-to-module registry the app does not have. The
|
|
308
|
+
// pointer itself is unchanged: symbols do not serialize, so this is still
|
|
309
|
+
// `{ view: "/foo.val.ts" }` to anything that looks at it as data.
|
|
310
|
+
if (recOpts !== null && recOpts !== void 0 && recOpts.schema && recOpts.schema.type === "view") {
|
|
311
|
+
var valModule = viewModules.get(recOpts.schema.moduleFilePath);
|
|
312
|
+
if (valModule === undefined || !isValViewSource(sourceOrSelector)) {
|
|
313
|
+
return sourceOrSelector;
|
|
314
|
+
}
|
|
315
|
+
/*
|
|
316
|
+
* The POINTER decides what may be attached, not the schema alone.
|
|
317
|
+
*
|
|
318
|
+
* The two can disagree: a `.val.ts` cannot express it (the source type is
|
|
319
|
+
* the literal path), but hand-written JSON and a patch can, which is the
|
|
320
|
+
* whole reason `view:check-module` exists as a fix. Keying only on the
|
|
321
|
+
* schema attached the schema's module to a pointer naming a different one,
|
|
322
|
+
* so `useVal(page.field)` read a module the value does not name — silently,
|
|
323
|
+
* and looking exactly like a correct read.
|
|
324
|
+
*
|
|
325
|
+
* So a mismatch gets no handle: the value stays the bare pointer, and
|
|
326
|
+
* reading it throws rather than answering with the wrong module. The
|
|
327
|
+
* Studio still renders the field and still offers the repair; nothing here
|
|
328
|
+
* refuses to encode the page over it.
|
|
329
|
+
*/
|
|
330
|
+
if (sourceOrSelector.view !== recOpts.schema.moduleFilePath) {
|
|
331
|
+
return sourceOrSelector;
|
|
332
|
+
}
|
|
333
|
+
return Internal.createViewHandle(sourceOrSelector, valModule);
|
|
334
|
+
}
|
|
245
335
|
if (recOpts !== null && recOpts !== void 0 && recOpts.schema && isKeyOfSchema(recOpts === null || recOpts === void 0 ? void 0 : recOpts.schema)) {
|
|
246
336
|
return sourceOrSelector;
|
|
247
337
|
}
|
|
@@ -304,6 +394,25 @@ function stegaEncode(input, opts) {
|
|
|
304
394
|
var selectorPath = Internal.getValPath(sourceOrSelector);
|
|
305
395
|
if (selectorPath) {
|
|
306
396
|
var newSchema = Internal.getSchema(sourceOrSelector);
|
|
397
|
+
// The modules this module's views point at. Collected HERE because this
|
|
398
|
+
// is the only place with the schema INSTANCE — everything below walks
|
|
399
|
+
// the serialized schema, which carries a path and not a module. Merged
|
|
400
|
+
// rather than replaced: a handle resolved by `useVal` re-enters here as
|
|
401
|
+
// its own module, and its parent's views must stay resolvable.
|
|
402
|
+
var _iterator = _createForOfIteratorHelper(Internal.viewModulesOf(newSchema)),
|
|
403
|
+
_step;
|
|
404
|
+
try {
|
|
405
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
406
|
+
var _step$value = _slicedToArray(_step.value, 2),
|
|
407
|
+
path = _step$value[0],
|
|
408
|
+
_valModule = _step$value[1];
|
|
409
|
+
viewModules.set(path, _valModule);
|
|
410
|
+
}
|
|
411
|
+
} catch (err) {
|
|
412
|
+
_iterator.e(err);
|
|
413
|
+
} finally {
|
|
414
|
+
_iterator.f();
|
|
415
|
+
}
|
|
307
416
|
return rec(opts.getModule && opts.getModule(selectorPath) !== undefined ? opts.getModule(selectorPath) : Internal.getSource(sourceOrSelector), {
|
|
308
417
|
path: selectorPath,
|
|
309
418
|
schema: newSchema === null || newSchema === void 0 ? void 0 : newSchema["executeSerialize"]()
|
|
@@ -421,24 +530,65 @@ function collectReferencedModulesFromSchema(schema, acc) {
|
|
|
421
530
|
} else if (schema.type === "array" || schema.type === "record") {
|
|
422
531
|
collectReferencedModulesFromSchema(schema.item, acc);
|
|
423
532
|
} else if (schema.type === "discriminated-union") {
|
|
424
|
-
var
|
|
425
|
-
|
|
533
|
+
var _iterator2 = _createForOfIteratorHelper(schema.items),
|
|
534
|
+
_step2;
|
|
426
535
|
try {
|
|
427
|
-
for (
|
|
428
|
-
var item =
|
|
536
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
537
|
+
var item = _step2.value;
|
|
429
538
|
collectReferencedModulesFromSchema(item, acc);
|
|
430
539
|
}
|
|
431
540
|
} catch (err) {
|
|
432
|
-
|
|
541
|
+
_iterator2.e(err);
|
|
433
542
|
} finally {
|
|
434
|
-
|
|
543
|
+
_iterator2.f();
|
|
435
544
|
}
|
|
436
545
|
}
|
|
437
546
|
}
|
|
438
547
|
function stegaClean(source) {
|
|
439
548
|
return vercelStegaSplit(source).cleaned;
|
|
440
549
|
}
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Answers already computed, keyed by the selector they were computed from.
|
|
553
|
+
*
|
|
554
|
+
* `getModuleIds` is not cheap: it calls `executeSerialize()`, which rebuilds the
|
|
555
|
+
* whole serialized schema tree on every call — ~31us for a 40-field schema with
|
|
556
|
+
* a nested array, against ~4us for a small one. It is called from `useValStega`
|
|
557
|
+
* on every render whose `useMemo` misses.
|
|
558
|
+
*
|
|
559
|
+
* That memo misses on every render for a VIEW, and cannot be fixed there: the
|
|
560
|
+
* handle is built by `createViewHandle` inside `stegaEncode`, so `page.authors`
|
|
561
|
+
* is a fresh object each time the page is encoded, and `[selector]` is a new
|
|
562
|
+
* dependency every render. Caching here rather than in the hooks fixes it for
|
|
563
|
+
* both copies of the hook at once, and for any other caller.
|
|
564
|
+
*
|
|
565
|
+
* Keyed on the selector, which is the module itself for the case that matters —
|
|
566
|
+
* a view resolves to it on the line below, and a module is a module-level
|
|
567
|
+
* constant, so the entry is hit for the life of the process. A fresh nested
|
|
568
|
+
* selector misses, as it did before; a `WeakMap` lets those entries go.
|
|
569
|
+
*
|
|
570
|
+
* The array is shared, so it is frozen: nothing may sort or splice it in place.
|
|
571
|
+
* Every consumer today copies first (`createSubscriberId` does `paths.slice()`),
|
|
572
|
+
* and freezing is what keeps that true.
|
|
573
|
+
*/
|
|
574
|
+
var moduleIdsCache = new WeakMap();
|
|
441
575
|
function getModuleIds(input) {
|
|
576
|
+
// A view handle names one module: the one it points at. Resolved first so a
|
|
577
|
+
// `useVal(page.header)` subscribes to the header rather than to nothing — and
|
|
578
|
+
// so the recursive call lands on the module, which is what the cache above
|
|
579
|
+
// can actually key on.
|
|
580
|
+
var resolved = Internal.viewHandleModule(input);
|
|
581
|
+
if (resolved !== undefined) {
|
|
582
|
+
return getModuleIds(resolved);
|
|
583
|
+
}
|
|
584
|
+
var cacheable = _typeof(input) === "object" && input !== null;
|
|
585
|
+
if (cacheable) {
|
|
586
|
+
var cached = moduleIdsCache.get(input);
|
|
587
|
+
if (cached) {
|
|
588
|
+
// Frozen, so handing the same array to every caller is safe.
|
|
589
|
+
return cached;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
442
592
|
var modules = new Set();
|
|
443
593
|
function rec(sourceOrSelector) {
|
|
444
594
|
if (_typeof(sourceOrSelector) === "object") {
|
|
@@ -482,7 +632,14 @@ function getModuleIds(input) {
|
|
|
482
632
|
return;
|
|
483
633
|
}
|
|
484
634
|
rec(input);
|
|
485
|
-
|
|
635
|
+
var moduleIds = Array.from(modules);
|
|
636
|
+
// Frozen before it is shared, not after: a consumer that sorts in place would
|
|
637
|
+
// otherwise corrupt every later caller's answer, and silently.
|
|
638
|
+
Object.freeze(moduleIds);
|
|
639
|
+
if (cacheable) {
|
|
640
|
+
moduleIdsCache.set(input, moduleIds);
|
|
641
|
+
}
|
|
642
|
+
return moduleIds;
|
|
486
643
|
}
|
|
487
644
|
|
|
488
645
|
function attrs(target) {
|
|
@@ -144,6 +144,48 @@ function _objectSpread2(e) {
|
|
|
144
144
|
* RichText is accessible by users (after conversion via useVal / fetchVal)
|
|
145
145
|
**/
|
|
146
146
|
|
|
147
|
+
/**
|
|
148
|
+
* What resolving `T` gives back — the one definition the framework readers
|
|
149
|
+
* share.
|
|
150
|
+
*
|
|
151
|
+
* Two shapes go in. A module or selector resolves as it always has. A
|
|
152
|
+
* {@link ValView}, which is what a `s.view()` field reads as, resolves to the
|
|
153
|
+
* module it points at: the page declares what it shows, and a reader follows
|
|
154
|
+
* that declaration instead of importing the target a second time.
|
|
155
|
+
*
|
|
156
|
+
* One definition rather than one per reader — `useVal`, `fetchVal`,
|
|
157
|
+
* `initValContent` and the TanStack client each had their own copy of the
|
|
158
|
+
* selector half, which is four places for the view half to be forgotten in.
|
|
159
|
+
*
|
|
160
|
+
* `Target extends Source` is checked HERE rather than on `ValView` itself:
|
|
161
|
+
* `ValView` is built from `ValViewSource`, which is a member of the `Source`
|
|
162
|
+
* union, so a constraint there is a circular type reference.
|
|
163
|
+
*
|
|
164
|
+
* The outer arms are wrapped in tuples so the conditional does not DISTRIBUTE
|
|
165
|
+
* over a union: distributing it re-entered `StegaOfSource` per member and the
|
|
166
|
+
* async readers hit "Type instantiation is excessively deep and possibly
|
|
167
|
+
* infinite" — `useVal` did not, because a `Promise<...>` around it is one more
|
|
168
|
+
* level than the checker had left.
|
|
169
|
+
*/
|
|
170
|
+
|
|
171
|
+
/** What a reader accepts. A view handle is a `SelectorSource`, so this is it. */
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* The source of whichever arm of `ResolvableModule` a reader was given — the
|
|
175
|
+
* module's own, or that of the module a view points at.
|
|
176
|
+
*/
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* The (loosened) content type a single `.jsonValues()` entry resolves to.
|
|
180
|
+
*
|
|
181
|
+
* Here rather than in the framework packages because there were four identical
|
|
182
|
+
* copies of it — next's client and rsc readers, tanstack's client and server —
|
|
183
|
+
* and the view arm would have had to be added to each. Same reason
|
|
184
|
+
* {@link ResolvedVal} lives here.
|
|
185
|
+
*/
|
|
186
|
+
|
|
187
|
+
/** What a route reader gives back for the entry the params matched. */
|
|
188
|
+
|
|
147
189
|
/**
|
|
148
190
|
* Resolves the matching variant of a discriminated union from the value's tag.
|
|
149
191
|
* Returns the matching schema or null if no match is found.
|
|
@@ -243,7 +285,55 @@ function handleRichTextSchema(sourceOrSelector, recOpts, rec) {
|
|
|
243
285
|
return sourceOrSelector;
|
|
244
286
|
}
|
|
245
287
|
function stegaEncode(input, opts) {
|
|
288
|
+
var viewModules = new Map();
|
|
289
|
+
// Handed a view handle rather than a module: resolve it and encode what it
|
|
290
|
+
// points at. This is what makes `useVal(page.header)` read the header.
|
|
291
|
+
var resolved = core.Internal.viewHandleModule(input);
|
|
292
|
+
if (resolved !== undefined) {
|
|
293
|
+
return stegaEncode(resolved, opts);
|
|
294
|
+
}
|
|
295
|
+
// A view pointer with no module on it. The module rides on a symbol, and
|
|
296
|
+
// symbols do not survive serialization — so this is a handle that crossed the
|
|
297
|
+
// server/client boundary as a prop, or one read out of raw JSON. Resolving it
|
|
298
|
+
// would hand back the pointer itself, which looks like content and is not, so
|
|
299
|
+
// say what happened instead.
|
|
300
|
+
if (core.isValViewSource(input)) {
|
|
301
|
+
throw Error("Cannot resolve the view of '".concat(input.view, "': it carries no module. ") + "Either it crossed a server/client boundary, which drops the module because it rides on a symbol, " + "or it points at a different module than its schema declares \u2014 which `val validate --fix` repairs. " + "Resolve it in the same component that read the module containing it, or read '".concat(input.view, "' directly."));
|
|
302
|
+
}
|
|
246
303
|
function rec(sourceOrSelector, recOpts) {
|
|
304
|
+
// A view is a pointer at another module. Weaving an edit tag into it would
|
|
305
|
+
// corrupt the path it holds, and there is nothing of the target here to
|
|
306
|
+
// encode — the target is its own module, encoded when it is read.
|
|
307
|
+
//
|
|
308
|
+
// The module it names rides along on a symbol, so `useVal(page.header)` can
|
|
309
|
+
// resolve it without a path-to-module registry the app does not have. The
|
|
310
|
+
// pointer itself is unchanged: symbols do not serialize, so this is still
|
|
311
|
+
// `{ view: "/foo.val.ts" }` to anything that looks at it as data.
|
|
312
|
+
if (recOpts !== null && recOpts !== void 0 && recOpts.schema && recOpts.schema.type === "view") {
|
|
313
|
+
var valModule = viewModules.get(recOpts.schema.moduleFilePath);
|
|
314
|
+
if (valModule === undefined || !core.isValViewSource(sourceOrSelector)) {
|
|
315
|
+
return sourceOrSelector;
|
|
316
|
+
}
|
|
317
|
+
/*
|
|
318
|
+
* The POINTER decides what may be attached, not the schema alone.
|
|
319
|
+
*
|
|
320
|
+
* The two can disagree: a `.val.ts` cannot express it (the source type is
|
|
321
|
+
* the literal path), but hand-written JSON and a patch can, which is the
|
|
322
|
+
* whole reason `view:check-module` exists as a fix. Keying only on the
|
|
323
|
+
* schema attached the schema's module to a pointer naming a different one,
|
|
324
|
+
* so `useVal(page.field)` read a module the value does not name — silently,
|
|
325
|
+
* and looking exactly like a correct read.
|
|
326
|
+
*
|
|
327
|
+
* So a mismatch gets no handle: the value stays the bare pointer, and
|
|
328
|
+
* reading it throws rather than answering with the wrong module. The
|
|
329
|
+
* Studio still renders the field and still offers the repair; nothing here
|
|
330
|
+
* refuses to encode the page over it.
|
|
331
|
+
*/
|
|
332
|
+
if (sourceOrSelector.view !== recOpts.schema.moduleFilePath) {
|
|
333
|
+
return sourceOrSelector;
|
|
334
|
+
}
|
|
335
|
+
return core.Internal.createViewHandle(sourceOrSelector, valModule);
|
|
336
|
+
}
|
|
247
337
|
if (recOpts !== null && recOpts !== void 0 && recOpts.schema && isKeyOfSchema(recOpts === null || recOpts === void 0 ? void 0 : recOpts.schema)) {
|
|
248
338
|
return sourceOrSelector;
|
|
249
339
|
}
|
|
@@ -306,6 +396,25 @@ function stegaEncode(input, opts) {
|
|
|
306
396
|
var selectorPath = core.Internal.getValPath(sourceOrSelector);
|
|
307
397
|
if (selectorPath) {
|
|
308
398
|
var newSchema = core.Internal.getSchema(sourceOrSelector);
|
|
399
|
+
// The modules this module's views point at. Collected HERE because this
|
|
400
|
+
// is the only place with the schema INSTANCE — everything below walks
|
|
401
|
+
// the serialized schema, which carries a path and not a module. Merged
|
|
402
|
+
// rather than replaced: a handle resolved by `useVal` re-enters here as
|
|
403
|
+
// its own module, and its parent's views must stay resolvable.
|
|
404
|
+
var _iterator = _createForOfIteratorHelper(core.Internal.viewModulesOf(newSchema)),
|
|
405
|
+
_step;
|
|
406
|
+
try {
|
|
407
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
408
|
+
var _step$value = slicedToArray._slicedToArray(_step.value, 2),
|
|
409
|
+
path = _step$value[0],
|
|
410
|
+
_valModule = _step$value[1];
|
|
411
|
+
viewModules.set(path, _valModule);
|
|
412
|
+
}
|
|
413
|
+
} catch (err) {
|
|
414
|
+
_iterator.e(err);
|
|
415
|
+
} finally {
|
|
416
|
+
_iterator.f();
|
|
417
|
+
}
|
|
309
418
|
return rec(opts.getModule && opts.getModule(selectorPath) !== undefined ? opts.getModule(selectorPath) : core.Internal.getSource(sourceOrSelector), {
|
|
310
419
|
path: selectorPath,
|
|
311
420
|
schema: newSchema === null || newSchema === void 0 ? void 0 : newSchema["executeSerialize"]()
|
|
@@ -423,24 +532,65 @@ function collectReferencedModulesFromSchema(schema, acc) {
|
|
|
423
532
|
} else if (schema.type === "array" || schema.type === "record") {
|
|
424
533
|
collectReferencedModulesFromSchema(schema.item, acc);
|
|
425
534
|
} else if (schema.type === "discriminated-union") {
|
|
426
|
-
var
|
|
427
|
-
|
|
535
|
+
var _iterator2 = _createForOfIteratorHelper(schema.items),
|
|
536
|
+
_step2;
|
|
428
537
|
try {
|
|
429
|
-
for (
|
|
430
|
-
var item =
|
|
538
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
539
|
+
var item = _step2.value;
|
|
431
540
|
collectReferencedModulesFromSchema(item, acc);
|
|
432
541
|
}
|
|
433
542
|
} catch (err) {
|
|
434
|
-
|
|
543
|
+
_iterator2.e(err);
|
|
435
544
|
} finally {
|
|
436
|
-
|
|
545
|
+
_iterator2.f();
|
|
437
546
|
}
|
|
438
547
|
}
|
|
439
548
|
}
|
|
440
549
|
function stegaClean(source) {
|
|
441
550
|
return stega.vercelStegaSplit(source).cleaned;
|
|
442
551
|
}
|
|
552
|
+
|
|
553
|
+
/**
|
|
554
|
+
* Answers already computed, keyed by the selector they were computed from.
|
|
555
|
+
*
|
|
556
|
+
* `getModuleIds` is not cheap: it calls `executeSerialize()`, which rebuilds the
|
|
557
|
+
* whole serialized schema tree on every call — ~31us for a 40-field schema with
|
|
558
|
+
* a nested array, against ~4us for a small one. It is called from `useValStega`
|
|
559
|
+
* on every render whose `useMemo` misses.
|
|
560
|
+
*
|
|
561
|
+
* That memo misses on every render for a VIEW, and cannot be fixed there: the
|
|
562
|
+
* handle is built by `createViewHandle` inside `stegaEncode`, so `page.authors`
|
|
563
|
+
* is a fresh object each time the page is encoded, and `[selector]` is a new
|
|
564
|
+
* dependency every render. Caching here rather than in the hooks fixes it for
|
|
565
|
+
* both copies of the hook at once, and for any other caller.
|
|
566
|
+
*
|
|
567
|
+
* Keyed on the selector, which is the module itself for the case that matters —
|
|
568
|
+
* a view resolves to it on the line below, and a module is a module-level
|
|
569
|
+
* constant, so the entry is hit for the life of the process. A fresh nested
|
|
570
|
+
* selector misses, as it did before; a `WeakMap` lets those entries go.
|
|
571
|
+
*
|
|
572
|
+
* The array is shared, so it is frozen: nothing may sort or splice it in place.
|
|
573
|
+
* Every consumer today copies first (`createSubscriberId` does `paths.slice()`),
|
|
574
|
+
* and freezing is what keeps that true.
|
|
575
|
+
*/
|
|
576
|
+
var moduleIdsCache = new WeakMap();
|
|
443
577
|
function getModuleIds(input) {
|
|
578
|
+
// A view handle names one module: the one it points at. Resolved first so a
|
|
579
|
+
// `useVal(page.header)` subscribes to the header rather than to nothing — and
|
|
580
|
+
// so the recursive call lands on the module, which is what the cache above
|
|
581
|
+
// can actually key on.
|
|
582
|
+
var resolved = core.Internal.viewHandleModule(input);
|
|
583
|
+
if (resolved !== undefined) {
|
|
584
|
+
return getModuleIds(resolved);
|
|
585
|
+
}
|
|
586
|
+
var cacheable = slicedToArray._typeof(input) === "object" && input !== null;
|
|
587
|
+
if (cacheable) {
|
|
588
|
+
var cached = moduleIdsCache.get(input);
|
|
589
|
+
if (cached) {
|
|
590
|
+
// Frozen, so handing the same array to every caller is safe.
|
|
591
|
+
return cached;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
444
594
|
var modules = new Set();
|
|
445
595
|
function rec(sourceOrSelector) {
|
|
446
596
|
if (slicedToArray._typeof(sourceOrSelector) === "object") {
|
|
@@ -484,7 +634,14 @@ function getModuleIds(input) {
|
|
|
484
634
|
return;
|
|
485
635
|
}
|
|
486
636
|
rec(input);
|
|
487
|
-
|
|
637
|
+
var moduleIds = Array.from(modules);
|
|
638
|
+
// Frozen before it is shared, not after: a consumer that sorts in place would
|
|
639
|
+
// otherwise corrupt every later caller's answer, and silently.
|
|
640
|
+
Object.freeze(moduleIds);
|
|
641
|
+
if (cacheable) {
|
|
642
|
+
moduleIdsCache.set(input, moduleIds);
|
|
643
|
+
}
|
|
644
|
+
return moduleIds;
|
|
488
645
|
}
|
|
489
646
|
|
|
490
647
|
function attrs(target) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { c as _arrayLikeToArray, b as _unsupportedIterableToArray } from '../../dist/slicedToArray-9cce0d9f.browser.esm.js';
|
|
2
|
-
import { d as _objectSpread2, r as raw, c as attrs } from '../../dist/raw-
|
|
2
|
+
import { d as _objectSpread2, r as raw, c as attrs } from '../../dist/raw-d6f65f06.browser.esm.js';
|
|
3
3
|
import React from 'react';
|
|
4
4
|
import { jsx } from 'react/jsx-runtime';
|
|
5
5
|
import '@valbuild/core';
|