@valbuild/server 0.126.0 → 0.128.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
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# @valbuild/server
|
|
2
2
|
|
|
3
|
+
## 0.128.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`8b52b33`](https://github.com/valbuild/val/commit/8b52b33e1f629f14f66cc71dcc7cf415d210c7d4), [`362fb49`](https://github.com/valbuild/val/commit/362fb49f30d2b04c4ff78d54dca2bf5ad978a05c), [`c595799`](https://github.com/valbuild/val/commit/c59579977a436ec530c6c69f2b340ab9829d97ab)]:
|
|
8
|
+
- @valbuild/core@0.128.0
|
|
9
|
+
- @valbuild/shared@0.128.0
|
|
10
|
+
- @valbuild/ui@0.127.0
|
|
11
|
+
|
|
12
|
+
## 0.127.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- [#608](https://github.com/valbuild/val/pull/608) [`7fa8699`](https://github.com/valbuild/val/commit/7fa869974bc895af992a7d5c18b76253636d7d65) Thanks [@freekh](https://github.com/freekh)! - A record whose schema declares its keys now holds every one of them.
|
|
17
|
+
|
|
18
|
+
Two key schemas enumerate their keys: `s.locale()`, whose set is the project's
|
|
19
|
+
`locales.available`, and a union of literals. For those, the keys are part of the
|
|
20
|
+
schema, so a missing one is a hole in the content rather than content nobody has
|
|
21
|
+
written yet — and validation now says so, naming what is missing.
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
s.record(s.locale(), s.object({ title: s.string() }));
|
|
25
|
+
// Missing key: 'nb-NO'. This record's keys are declared by its schema, so
|
|
26
|
+
// every one of them is an entry — an entry nobody has written yet is null,
|
|
27
|
+
// not absent.
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**An entry nobody has written yet is `null`.** Not an absent key: a null entry is
|
|
31
|
+
data you can count, filter and see in a diff, and it means half-translated
|
|
32
|
+
content stays _valid_ rather than blocking a publish. The value type of such a
|
|
33
|
+
record widens by `null` to match, so writing one in a `.val.ts` type-checks:
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
c.define(
|
|
37
|
+
"/content/jacket.val.ts",
|
|
38
|
+
s.record(s.locale(), s.object({ title: s.string() })),
|
|
39
|
+
{
|
|
40
|
+
"en-US": { title: "Winter jacket" },
|
|
41
|
+
"nb-NO": null, // nobody has translated this yet
|
|
42
|
+
},
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**This changes `s.record(s.union(...), item)`**, and closes a gap that was
|
|
47
|
+
already there: `s.record(s.union(s.literal("a"), s.literal("b")), item)` types as
|
|
48
|
+
`Record<"a" | "b", T>`, so TypeScript demanded both keys while the validator only
|
|
49
|
+
checked the ones present. It now checks them too, and — as above — accepts `null`
|
|
50
|
+
for an entry that has not been filled in. If you have such a record with keys
|
|
51
|
+
missing, validation will report them; adding the keys with `null` values is the
|
|
52
|
+
fix, and creating one from the Studio does it for you.
|
|
53
|
+
|
|
54
|
+
`emptyOf` creates these records with every key already in them rather than
|
|
55
|
+
empty, since an empty one is already missing keys. In the Studio use the
|
|
56
|
+
`useEmptyOf()` hook rather than importing `emptyOf` directly: a locale record's
|
|
57
|
+
keys are in the settings module, and the hook is what has read it.
|
|
58
|
+
|
|
59
|
+
- [#608](https://github.com/valbuild/val/pull/608) [`5b7fe05`](https://github.com/valbuild/val/commit/5b7fe05cec6365f9cd1de9ba31e65ed4a87edb63) Thanks [@freekh](https://github.com/freekh)! - `s.locale()`: one of the project's languages.
|
|
60
|
+
|
|
61
|
+
The languages themselves are declared in the settings module (`locales.available`);
|
|
62
|
+
this says that a value is one of them.
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// a field: everything in this entry is in this language
|
|
66
|
+
s.record(s.string(), s.object({ locale: s.locale(), title: s.string() }));
|
|
67
|
+
|
|
68
|
+
// a key: one entry per language
|
|
69
|
+
s.record(s.locale(), s.object({ title: s.string() }));
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Every locale in content is checked against the project's list, the way `keyOf`
|
|
73
|
+
and `route` are checked against what they point at. An undeclared language names
|
|
74
|
+
the ones the project has; a project that has declared none is told to declare
|
|
75
|
+
them rather than told the value is wrong.
|
|
76
|
+
|
|
77
|
+
A locale is stored as the tag itself — the value in content is `nb-NO`, and a
|
|
78
|
+
record keyed by `s.locale()` has `nb-NO` as its key. Spelling one differently
|
|
79
|
+
where it is stored (`/no/…` as a URL segment) is a real need and is deliberately
|
|
80
|
+
not in this release: it changes what is accepted as well as what is shown, so it
|
|
81
|
+
is being designed on its own rather than folded in here.
|
|
82
|
+
|
|
83
|
+
A locale is **never stega encoded**: it ends up in `<html lang>`, in `hreflang`
|
|
84
|
+
and in `Intl` constructors, none of which survive invisible characters.
|
|
85
|
+
|
|
86
|
+
`assistant.translation` joins the settings module alongside `context` and `tone`
|
|
87
|
+
— a note per language, keyed by language, so only the target language's rules are
|
|
88
|
+
sent when translating into it.
|
|
89
|
+
|
|
90
|
+
### Patch Changes
|
|
91
|
+
|
|
92
|
+
- Updated dependencies [[`7fa8699`](https://github.com/valbuild/val/commit/7fa869974bc895af992a7d5c18b76253636d7d65), [`600308d`](https://github.com/valbuild/val/commit/600308d0174990ad9f5c417147d160273489c65a), [`5b7fe05`](https://github.com/valbuild/val/commit/5b7fe05cec6365f9cd1de9ba31e65ed4a87edb63), [`88262ac`](https://github.com/valbuild/val/commit/88262ac8db068650a664981ef73556457d87741a), [`7072e07`](https://github.com/valbuild/val/commit/7072e07623c953a09ac14388ae22dada0b431ce3), [`29811c3`](https://github.com/valbuild/val/commit/29811c3f8c7e001a950e6f4833af6888e6a4efea), [`9983116`](https://github.com/valbuild/val/commit/99831164c5151aad7ca69de79e1d0d59878be251)]:
|
|
93
|
+
- @valbuild/core@0.127.0
|
|
94
|
+
- @valbuild/shared@0.127.0
|
|
95
|
+
- @valbuild/ui@0.127.0
|
|
96
|
+
|
|
3
97
|
## 0.126.0
|
|
4
98
|
|
|
5
99
|
### Patch Changes
|
|
@@ -184,7 +184,7 @@ export declare function handleUniqueFolderCheck(ctx: FixHandlerContext): Promise
|
|
|
184
184
|
*/
|
|
185
185
|
export declare function checkGalleryFiles(input: {
|
|
186
186
|
entryKeys: string[];
|
|
187
|
-
|
|
187
|
+
dir: string;
|
|
188
188
|
projectRoot: string;
|
|
189
189
|
fs: Pick<IValFSHost, "fileExists" | "readDirectory">;
|
|
190
190
|
}): {
|
|
@@ -206,6 +206,6 @@ export declare function handleJsonValuesExtractEntry(ctx: FixHandlerContext): Pr
|
|
|
206
206
|
* — just not by this command.
|
|
207
207
|
*/
|
|
208
208
|
export declare function handleExternalUpload(): Promise<FixHandlerResult>;
|
|
209
|
-
export declare const currentFixHandlers: Record<Exclude<ValidationFix, "keyof:check-keys" | "router:check-route">, FixHandler>;
|
|
209
|
+
export declare const currentFixHandlers: Record<Exclude<ValidationFix, "keyof:check-keys" | "router:check-route" | "locale:check-locale" | "record:fill-keys">, FixHandler>;
|
|
210
210
|
export declare const fixHandlers: Record<string, FixHandler>;
|
|
211
211
|
export declare function createDefaultValFSHost(): IValFSHost;
|
|
@@ -1748,6 +1748,7 @@ async function createService(projectRoot, host = {
|
|
|
1748
1748
|
return new Service(projectRoot, sourceFileHandler, extracted);
|
|
1749
1749
|
}
|
|
1750
1750
|
class Service {
|
|
1751
|
+
projectRoot;
|
|
1751
1752
|
constructor(projectRoot, sourceFileHandler, extracted) {
|
|
1752
1753
|
this.sourceFileHandler = sourceFileHandler;
|
|
1753
1754
|
this.extracted = extracted;
|
|
@@ -2387,17 +2388,18 @@ function findNestedJsonValuesModuleErrors(schemas) {
|
|
|
2387
2388
|
// #region ValOps
|
|
2388
2389
|
class ValOps {
|
|
2389
2390
|
/** Sources from val modules, immutable (without patches or anything) */
|
|
2390
|
-
|
|
2391
|
+
sources;
|
|
2391
2392
|
/** The sha256 / hash of all sources + all schemas + config */
|
|
2392
|
-
|
|
2393
|
+
baseSha;
|
|
2393
2394
|
/** The sha256 / hash of all sources */
|
|
2394
|
-
|
|
2395
|
+
sourcesSha;
|
|
2395
2396
|
/** The sha256 / hash of config */
|
|
2396
|
-
|
|
2397
|
+
configSha;
|
|
2397
2398
|
/** Schema from val modules, immutable */
|
|
2398
|
-
|
|
2399
|
+
schemas;
|
|
2399
2400
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
2400
|
-
|
|
2401
|
+
schemaSha;
|
|
2402
|
+
modulesErrors;
|
|
2401
2403
|
/**
|
|
2402
2404
|
* What the SHAs above are a fold over, so they can be recomputed.
|
|
2403
2405
|
*
|
|
@@ -2405,7 +2407,7 @@ class ValOps {
|
|
|
2405
2407
|
* without re-evaluating the modules is a save, and it has to be able to move
|
|
2406
2408
|
* the SHAs with them.
|
|
2407
2409
|
*/
|
|
2408
|
-
|
|
2410
|
+
shaEntries;
|
|
2409
2411
|
/**
|
|
2410
2412
|
* The extraction's OWN module errors, which are what the fold was given.
|
|
2411
2413
|
*
|
|
@@ -2413,7 +2415,7 @@ class ValOps {
|
|
|
2413
2415
|
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
2414
2416
|
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
2415
2417
|
*/
|
|
2416
|
-
|
|
2418
|
+
shaModuleErrors;
|
|
2417
2419
|
/**
|
|
2418
2420
|
* What a save has told us each `.jsonValues()` entry now holds.
|
|
2419
2421
|
*
|
|
@@ -3173,7 +3175,8 @@ class ValOps {
|
|
|
3173
3175
|
// (must include all modules, not just those being validated, since conflicts can come from any module)
|
|
3174
3176
|
const galleryDirectoryToModules = new Map();
|
|
3175
3177
|
// Build a schema/source snapshot so the shared resolver can cross-reference
|
|
3176
|
-
//
|
|
3178
|
+
// the marker fixes — a keyOf's key, a route, a locale tag, a record's
|
|
3179
|
+
// declared keys — against every module's data. See `SCHEMA_SOURCE_FIXES`.
|
|
3177
3180
|
const snapshot = {
|
|
3178
3181
|
schemas: {},
|
|
3179
3182
|
sources: {}
|
|
@@ -3186,8 +3189,8 @@ class ValOps {
|
|
|
3186
3189
|
if (sourceForModule !== undefined) {
|
|
3187
3190
|
snapshot.sources[moduleFilePath] = sourceForModule;
|
|
3188
3191
|
}
|
|
3189
|
-
if (serialized.type === "record" && serialized.mediaType && serialized.
|
|
3190
|
-
const dir = serialized.
|
|
3192
|
+
if (serialized.type === "record" && serialized.mediaType && serialized.dir) {
|
|
3193
|
+
const dir = serialized.dir;
|
|
3191
3194
|
const existing = galleryDirectoryToModules.get(dir);
|
|
3192
3195
|
if (existing) {
|
|
3193
3196
|
existing.push(moduleFilePath);
|
|
@@ -3253,7 +3256,7 @@ class ValOps {
|
|
|
3253
3256
|
};
|
|
3254
3257
|
if (validationErrors) {
|
|
3255
3258
|
for (const validationError of validationErrors) {
|
|
3256
|
-
var _validationError$fixe, _validationError$fixe2, _validationError$fixe3, _validationError$fixe4, _validationError$fixe5, _validationError$fixe6
|
|
3259
|
+
var _validationError$fixe, _validationError$fixe2, _validationError$fixe3, _validationError$fixe4, _validationError$fixe5, _validationError$fixe6;
|
|
3257
3260
|
if (isOnlyFileCheckValidationError(validationError)) {
|
|
3258
3261
|
if (files[sourcePath]) {
|
|
3259
3262
|
addError({
|
|
@@ -3267,13 +3270,13 @@ class ValOps {
|
|
|
3267
3270
|
}
|
|
3268
3271
|
} else if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.includes("image:check-remote") || (_validationError$fixe2 = validationError.fixes) !== null && _validationError$fixe2 !== void 0 && _validationError$fixe2.includes("file:check-remote")) {
|
|
3269
3272
|
remoteFiles[sourcePath] = validationError.value;
|
|
3270
|
-
} else if (
|
|
3273
|
+
} else if (internal.isSchemaSourceFixError(validationError)) {
|
|
3271
3274
|
const resolved = internal.resolveSchemaSourceFixForError(validationError, snapshot);
|
|
3272
3275
|
if (resolved && resolved.status === "remaining") {
|
|
3273
3276
|
addError(resolved.error);
|
|
3274
3277
|
}
|
|
3275
3278
|
// resolved.status === "resolved" → drop silently
|
|
3276
|
-
} else if ((_validationError$
|
|
3279
|
+
} else if ((_validationError$fixe3 = validationError.fixes) !== null && _validationError$fixe3 !== void 0 && _validationError$fixe3.includes("images:check-unique-folder") || (_validationError$fixe4 = validationError.fixes) !== null && _validationError$fixe4 !== void 0 && _validationError$fixe4.includes("files:check-unique-folder")) {
|
|
3277
3280
|
const TYPE_ERROR_MESSAGE = `This is most likely a Val version mismatch or Val bug.`;
|
|
3278
3281
|
if (!validationError.value || typeof validationError.value !== "object") {
|
|
3279
3282
|
addError({
|
|
@@ -3281,10 +3284,10 @@ class ValOps {
|
|
|
3281
3284
|
typeError: true
|
|
3282
3285
|
});
|
|
3283
3286
|
} else {
|
|
3284
|
-
const directory = "
|
|
3287
|
+
const directory = "dir" in validationError.value && validationError.value.dir;
|
|
3285
3288
|
if (typeof directory !== "string") {
|
|
3286
3289
|
addError({
|
|
3287
|
-
message: `Expected gallery validation error 'value' to have property '
|
|
3290
|
+
message: `Expected gallery validation error 'value' to have property 'dir' of type 'string'. Found: ${typeof directory}. ${TYPE_ERROR_MESSAGE}`,
|
|
3288
3291
|
typeError: true
|
|
3289
3292
|
});
|
|
3290
3293
|
} else {
|
|
@@ -3298,7 +3301,7 @@ class ValOps {
|
|
|
3298
3301
|
// If conflictingModules is empty, directory is unique — silently drop the error.
|
|
3299
3302
|
}
|
|
3300
3303
|
}
|
|
3301
|
-
} else if ((_validationError$
|
|
3304
|
+
} else if ((_validationError$fixe5 = validationError.fixes) !== null && _validationError$fixe5 !== void 0 && _validationError$fixe5.includes("images:check-all-files") || (_validationError$fixe6 = validationError.fixes) !== null && _validationError$fixe6 !== void 0 && _validationError$fixe6.includes("files:check-all-files")) ; else {
|
|
3302
3305
|
addError(validationError);
|
|
3303
3306
|
}
|
|
3304
3307
|
}
|
|
@@ -4158,8 +4161,8 @@ class ValOps {
|
|
|
4158
4161
|
// #endregion history
|
|
4159
4162
|
}
|
|
4160
4163
|
function isOnlyFileCheckValidationError(validationError) {
|
|
4161
|
-
var _validationError$
|
|
4162
|
-
if ((_validationError$
|
|
4164
|
+
var _validationError$fixe7;
|
|
4165
|
+
if ((_validationError$fixe7 = validationError.fixes) !== null && _validationError$fixe7 !== void 0 && _validationError$fixe7.every(f => f === "file:check-metadata" || f === "image:check-metadata")) {
|
|
4163
4166
|
return true;
|
|
4164
4167
|
}
|
|
4165
4168
|
return false;
|
|
@@ -5680,6 +5683,7 @@ function serializeSchemaSafely(schema) {
|
|
|
5680
5683
|
}
|
|
5681
5684
|
class ValOpsFS extends ValOps {
|
|
5682
5685
|
static VAL_DIR = ".val";
|
|
5686
|
+
host;
|
|
5683
5687
|
constructor(contentUrl, rootDir, valModules, options) {
|
|
5684
5688
|
super(valModules, options);
|
|
5685
5689
|
this.contentUrl = contentUrl;
|
|
@@ -5692,6 +5696,7 @@ class ValOpsFS extends ValOps {
|
|
|
5692
5696
|
* Change detection for `.jsonValues()` entry files, which no sha can see (their
|
|
5693
5697
|
* content lives behind a thunk that `JSON.stringify` drops).
|
|
5694
5698
|
*/
|
|
5699
|
+
jsonEntryFilesFingerprint;
|
|
5695
5700
|
|
|
5696
5701
|
/**
|
|
5697
5702
|
* Unpublished changes repair threw away, waiting to be told to somebody.
|
|
@@ -7221,6 +7226,8 @@ const NonceResponse = z.z.object({
|
|
|
7221
7226
|
*/
|
|
7222
7227
|
const PATCH_GROUPS_CACHE_MS = 1000;
|
|
7223
7228
|
class ValOpsHttp extends ValOps {
|
|
7229
|
+
authHeaders;
|
|
7230
|
+
root;
|
|
7224
7231
|
constructor(contentUrl, project, commitSha,
|
|
7225
7232
|
// TODO: CommitSha
|
|
7226
7233
|
branch,
|
|
@@ -13576,6 +13583,8 @@ const MAX_CACHE_SIZE = 100 * 1024 * 1024; // 100 mb
|
|
|
13576
13583
|
const MAX_OBJECT_KEY_SIZE = 2 ** 27; // https://stackoverflow.com/questions/13367391/is-there-a-limit-on-length-of-the-key-string-in-js-object
|
|
13577
13584
|
|
|
13578
13585
|
class ValModuleLoader {
|
|
13586
|
+
cache;
|
|
13587
|
+
cacheSize;
|
|
13579
13588
|
constructor(projectRoot, compilerOptions,
|
|
13580
13589
|
// TODO: remove this?
|
|
13581
13590
|
sourceFileHandler, host = {
|
|
@@ -14955,7 +14964,7 @@ async function handleRemoteFileUpload(ctx) {
|
|
|
14955
14964
|
return uploadRemoteFileCore(ctx, fileRefProp, fileSourceMetadata, resolveRemoteFileSchema);
|
|
14956
14965
|
}
|
|
14957
14966
|
|
|
14958
|
-
// Gallery (s.
|
|
14967
|
+
// Gallery (s.imageset({ ... }).remote() / s.fileset({ ... }).remote()) upload.
|
|
14959
14968
|
// Unlike a single image/file field, a gallery entry is keyed by its local file
|
|
14960
14969
|
// path and the value is bare metadata (no FileSource), so we derive the file
|
|
14961
14970
|
// ref from the key and synthesize the image/file schema from the record's
|
|
@@ -14996,10 +15005,10 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
14996
15005
|
// synthesize the serialized image/file schema (matching how single fields
|
|
14997
15006
|
// serialize) for the remote ref's validation hash.
|
|
14998
15007
|
//
|
|
14999
|
-
// `accept`/`
|
|
15008
|
+
// `accept`/`dir` come from the RECORD that holds the entry, resolved
|
|
15000
15009
|
// from the entry's PARENT path - not from the module root, which is only the
|
|
15001
15010
|
// record when the gallery is the whole module. A nested gallery
|
|
15002
|
-
// (s.object({ gallery: s.
|
|
15011
|
+
// (s.object({ gallery: s.imageset(...) })) would otherwise synthesize a schema
|
|
15003
15012
|
// with no options and bake a validation hash into the remote ref that can
|
|
15004
15013
|
// never validate, so a mismatch fails fast instead of uploading.
|
|
15005
15014
|
const [, parentModulePath] = core.Internal.splitModuleFilePathAndModulePath(core.Internal.parentOfSourcePath(ctx.sourcePath));
|
|
@@ -15012,7 +15021,7 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
15012
15021
|
}
|
|
15013
15022
|
const {
|
|
15014
15023
|
accept,
|
|
15015
|
-
|
|
15024
|
+
dir
|
|
15016
15025
|
} = recordSchema;
|
|
15017
15026
|
const schema = mediaType === "image" ? {
|
|
15018
15027
|
type: "image",
|
|
@@ -15021,8 +15030,8 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
15021
15030
|
...(accept ? {
|
|
15022
15031
|
accept
|
|
15023
15032
|
} : {}),
|
|
15024
|
-
...(
|
|
15025
|
-
|
|
15033
|
+
...(dir ? {
|
|
15034
|
+
dir
|
|
15026
15035
|
} : {})
|
|
15027
15036
|
}
|
|
15028
15037
|
} : {
|
|
@@ -15062,14 +15071,14 @@ async function handleRemoteFileCheck() {
|
|
|
15062
15071
|
}
|
|
15063
15072
|
async function handleUniqueFolderCheck(ctx) {
|
|
15064
15073
|
const value = ctx.validationError.value;
|
|
15065
|
-
if (!value || typeof value.
|
|
15074
|
+
if (!value || typeof value.dir !== "string") {
|
|
15066
15075
|
return {
|
|
15067
15076
|
success: false,
|
|
15068
15077
|
errorMessage: `Unexpected value in unique folder check for ${ctx.sourcePath}`
|
|
15069
15078
|
};
|
|
15070
15079
|
}
|
|
15071
15080
|
const {
|
|
15072
|
-
|
|
15081
|
+
dir
|
|
15073
15082
|
} = value;
|
|
15074
15083
|
const conflicts = [];
|
|
15075
15084
|
for (const file of ctx.valFiles) {
|
|
@@ -15079,14 +15088,14 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
15079
15088
|
validate: false
|
|
15080
15089
|
});
|
|
15081
15090
|
const schema = otherModule.schema;
|
|
15082
|
-
if ((schema === null || schema === void 0 ? void 0 : schema.type) === "record" && schema.
|
|
15091
|
+
if ((schema === null || schema === void 0 ? void 0 : schema.type) === "record" && schema.dir === dir && schema.mediaType) {
|
|
15083
15092
|
conflicts.push(otherModuleFilePath);
|
|
15084
15093
|
}
|
|
15085
15094
|
}
|
|
15086
15095
|
if (conflicts.length > 0) {
|
|
15087
15096
|
return {
|
|
15088
15097
|
success: false,
|
|
15089
|
-
errorMessage: `Gallery directory '${
|
|
15098
|
+
errorMessage: `Gallery directory '${dir}' in ${ctx.moduleFilePath} is also used by: ${conflicts.join(", ")}. Each gallery must use a unique directory.`
|
|
15090
15099
|
};
|
|
15091
15100
|
}
|
|
15092
15101
|
return {
|
|
@@ -15116,7 +15125,7 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
15116
15125
|
*/
|
|
15117
15126
|
function checkGalleryFiles(input) {
|
|
15118
15127
|
const {
|
|
15119
|
-
|
|
15128
|
+
dir,
|
|
15120
15129
|
projectRoot,
|
|
15121
15130
|
fs
|
|
15122
15131
|
} = input;
|
|
@@ -15125,7 +15134,7 @@ function checkGalleryFiles(input) {
|
|
|
15125
15134
|
const missingTrackedFiles = entries.filter(entry => !entry.remote && !fs.fileExists(path__namespace["default"].join(projectRoot, entry.localPath))).map(entry => entry.localPath);
|
|
15126
15135
|
const filesInDir = [];
|
|
15127
15136
|
try {
|
|
15128
|
-
const found = fs.readDirectory(path__namespace["default"].join(projectRoot,
|
|
15137
|
+
const found = fs.readDirectory(path__namespace["default"].join(projectRoot, dir), undefined, undefined, ["**/*"]);
|
|
15129
15138
|
for (const entry of found) {
|
|
15130
15139
|
filesInDir.push("/" + path__namespace["default"].relative(projectRoot, entry).split(path__namespace["default"].sep).join("/"));
|
|
15131
15140
|
}
|
|
@@ -15139,14 +15148,14 @@ function checkGalleryFiles(input) {
|
|
|
15139
15148
|
}
|
|
15140
15149
|
async function handleCheckAllFiles(ctx) {
|
|
15141
15150
|
const value = ctx.validationError.value;
|
|
15142
|
-
if (!value || typeof value.
|
|
15151
|
+
if (!value || typeof value.dir !== "string") {
|
|
15143
15152
|
return {
|
|
15144
15153
|
success: false,
|
|
15145
15154
|
errorMessage: `Unexpected value in check-all-files for ${ctx.sourcePath}`
|
|
15146
15155
|
};
|
|
15147
15156
|
}
|
|
15148
15157
|
const {
|
|
15149
|
-
|
|
15158
|
+
dir
|
|
15150
15159
|
} = value;
|
|
15151
15160
|
const source = ctx.valModule.source;
|
|
15152
15161
|
if (!source || typeof source !== "object" || Array.isArray(source)) {
|
|
@@ -15160,7 +15169,7 @@ async function handleCheckAllFiles(ctx) {
|
|
|
15160
15169
|
untrackedFiles
|
|
15161
15170
|
} = checkGalleryFiles({
|
|
15162
15171
|
entryKeys: Object.keys(source),
|
|
15163
|
-
|
|
15172
|
+
dir,
|
|
15164
15173
|
projectRoot: ctx.projectRoot,
|
|
15165
15174
|
fs: ctx.fs
|
|
15166
15175
|
});
|
|
@@ -15255,9 +15264,10 @@ async function handleExternalUpload() {
|
|
|
15255
15264
|
};
|
|
15256
15265
|
}
|
|
15257
15266
|
|
|
15258
|
-
// Fix handler registry. `keyof:check-keys
|
|
15259
|
-
// resolved upfront by the
|
|
15260
|
-
// this registry, so they're
|
|
15267
|
+
// Fix handler registry. `keyof:check-keys`, `router:check-route`,
|
|
15268
|
+
// `locale:check-locale` and `record:fill-keys` are resolved upfront by the
|
|
15269
|
+
// shared resolveSchemaSourceFixes — they never reach this registry, so they're
|
|
15270
|
+
// excluded from the key set.
|
|
15261
15271
|
const currentFixHandlers = {
|
|
15262
15272
|
"image:check-metadata": handleFileMetadata,
|
|
15263
15273
|
"image:add-metadata": handleFileMetadata,
|
|
@@ -1748,6 +1748,7 @@ async function createService(projectRoot, host = {
|
|
|
1748
1748
|
return new Service(projectRoot, sourceFileHandler, extracted);
|
|
1749
1749
|
}
|
|
1750
1750
|
class Service {
|
|
1751
|
+
projectRoot;
|
|
1751
1752
|
constructor(projectRoot, sourceFileHandler, extracted) {
|
|
1752
1753
|
this.sourceFileHandler = sourceFileHandler;
|
|
1753
1754
|
this.extracted = extracted;
|
|
@@ -2387,17 +2388,18 @@ function findNestedJsonValuesModuleErrors(schemas) {
|
|
|
2387
2388
|
// #region ValOps
|
|
2388
2389
|
class ValOps {
|
|
2389
2390
|
/** Sources from val modules, immutable (without patches or anything) */
|
|
2390
|
-
|
|
2391
|
+
sources;
|
|
2391
2392
|
/** The sha256 / hash of all sources + all schemas + config */
|
|
2392
|
-
|
|
2393
|
+
baseSha;
|
|
2393
2394
|
/** The sha256 / hash of all sources */
|
|
2394
|
-
|
|
2395
|
+
sourcesSha;
|
|
2395
2396
|
/** The sha256 / hash of config */
|
|
2396
|
-
|
|
2397
|
+
configSha;
|
|
2397
2398
|
/** Schema from val modules, immutable */
|
|
2398
|
-
|
|
2399
|
+
schemas;
|
|
2399
2400
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
2400
|
-
|
|
2401
|
+
schemaSha;
|
|
2402
|
+
modulesErrors;
|
|
2401
2403
|
/**
|
|
2402
2404
|
* What the SHAs above are a fold over, so they can be recomputed.
|
|
2403
2405
|
*
|
|
@@ -2405,7 +2407,7 @@ class ValOps {
|
|
|
2405
2407
|
* without re-evaluating the modules is a save, and it has to be able to move
|
|
2406
2408
|
* the SHAs with them.
|
|
2407
2409
|
*/
|
|
2408
|
-
|
|
2410
|
+
shaEntries;
|
|
2409
2411
|
/**
|
|
2410
2412
|
* The extraction's OWN module errors, which are what the fold was given.
|
|
2411
2413
|
*
|
|
@@ -2413,7 +2415,7 @@ class ValOps {
|
|
|
2413
2415
|
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
2414
2416
|
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
2415
2417
|
*/
|
|
2416
|
-
|
|
2418
|
+
shaModuleErrors;
|
|
2417
2419
|
/**
|
|
2418
2420
|
* What a save has told us each `.jsonValues()` entry now holds.
|
|
2419
2421
|
*
|
|
@@ -3173,7 +3175,8 @@ class ValOps {
|
|
|
3173
3175
|
// (must include all modules, not just those being validated, since conflicts can come from any module)
|
|
3174
3176
|
const galleryDirectoryToModules = new Map();
|
|
3175
3177
|
// Build a schema/source snapshot so the shared resolver can cross-reference
|
|
3176
|
-
//
|
|
3178
|
+
// the marker fixes — a keyOf's key, a route, a locale tag, a record's
|
|
3179
|
+
// declared keys — against every module's data. See `SCHEMA_SOURCE_FIXES`.
|
|
3177
3180
|
const snapshot = {
|
|
3178
3181
|
schemas: {},
|
|
3179
3182
|
sources: {}
|
|
@@ -3186,8 +3189,8 @@ class ValOps {
|
|
|
3186
3189
|
if (sourceForModule !== undefined) {
|
|
3187
3190
|
snapshot.sources[moduleFilePath] = sourceForModule;
|
|
3188
3191
|
}
|
|
3189
|
-
if (serialized.type === "record" && serialized.mediaType && serialized.
|
|
3190
|
-
const dir = serialized.
|
|
3192
|
+
if (serialized.type === "record" && serialized.mediaType && serialized.dir) {
|
|
3193
|
+
const dir = serialized.dir;
|
|
3191
3194
|
const existing = galleryDirectoryToModules.get(dir);
|
|
3192
3195
|
if (existing) {
|
|
3193
3196
|
existing.push(moduleFilePath);
|
|
@@ -3253,7 +3256,7 @@ class ValOps {
|
|
|
3253
3256
|
};
|
|
3254
3257
|
if (validationErrors) {
|
|
3255
3258
|
for (const validationError of validationErrors) {
|
|
3256
|
-
var _validationError$fixe, _validationError$fixe2, _validationError$fixe3, _validationError$fixe4, _validationError$fixe5, _validationError$fixe6
|
|
3259
|
+
var _validationError$fixe, _validationError$fixe2, _validationError$fixe3, _validationError$fixe4, _validationError$fixe5, _validationError$fixe6;
|
|
3257
3260
|
if (isOnlyFileCheckValidationError(validationError)) {
|
|
3258
3261
|
if (files[sourcePath]) {
|
|
3259
3262
|
addError({
|
|
@@ -3267,13 +3270,13 @@ class ValOps {
|
|
|
3267
3270
|
}
|
|
3268
3271
|
} else if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.includes("image:check-remote") || (_validationError$fixe2 = validationError.fixes) !== null && _validationError$fixe2 !== void 0 && _validationError$fixe2.includes("file:check-remote")) {
|
|
3269
3272
|
remoteFiles[sourcePath] = validationError.value;
|
|
3270
|
-
} else if (
|
|
3273
|
+
} else if (internal.isSchemaSourceFixError(validationError)) {
|
|
3271
3274
|
const resolved = internal.resolveSchemaSourceFixForError(validationError, snapshot);
|
|
3272
3275
|
if (resolved && resolved.status === "remaining") {
|
|
3273
3276
|
addError(resolved.error);
|
|
3274
3277
|
}
|
|
3275
3278
|
// resolved.status === "resolved" → drop silently
|
|
3276
|
-
} else if ((_validationError$
|
|
3279
|
+
} else if ((_validationError$fixe3 = validationError.fixes) !== null && _validationError$fixe3 !== void 0 && _validationError$fixe3.includes("images:check-unique-folder") || (_validationError$fixe4 = validationError.fixes) !== null && _validationError$fixe4 !== void 0 && _validationError$fixe4.includes("files:check-unique-folder")) {
|
|
3277
3280
|
const TYPE_ERROR_MESSAGE = `This is most likely a Val version mismatch or Val bug.`;
|
|
3278
3281
|
if (!validationError.value || typeof validationError.value !== "object") {
|
|
3279
3282
|
addError({
|
|
@@ -3281,10 +3284,10 @@ class ValOps {
|
|
|
3281
3284
|
typeError: true
|
|
3282
3285
|
});
|
|
3283
3286
|
} else {
|
|
3284
|
-
const directory = "
|
|
3287
|
+
const directory = "dir" in validationError.value && validationError.value.dir;
|
|
3285
3288
|
if (typeof directory !== "string") {
|
|
3286
3289
|
addError({
|
|
3287
|
-
message: `Expected gallery validation error 'value' to have property '
|
|
3290
|
+
message: `Expected gallery validation error 'value' to have property 'dir' of type 'string'. Found: ${typeof directory}. ${TYPE_ERROR_MESSAGE}`,
|
|
3288
3291
|
typeError: true
|
|
3289
3292
|
});
|
|
3290
3293
|
} else {
|
|
@@ -3298,7 +3301,7 @@ class ValOps {
|
|
|
3298
3301
|
// If conflictingModules is empty, directory is unique — silently drop the error.
|
|
3299
3302
|
}
|
|
3300
3303
|
}
|
|
3301
|
-
} else if ((_validationError$
|
|
3304
|
+
} else if ((_validationError$fixe5 = validationError.fixes) !== null && _validationError$fixe5 !== void 0 && _validationError$fixe5.includes("images:check-all-files") || (_validationError$fixe6 = validationError.fixes) !== null && _validationError$fixe6 !== void 0 && _validationError$fixe6.includes("files:check-all-files")) ; else {
|
|
3302
3305
|
addError(validationError);
|
|
3303
3306
|
}
|
|
3304
3307
|
}
|
|
@@ -4158,8 +4161,8 @@ class ValOps {
|
|
|
4158
4161
|
// #endregion history
|
|
4159
4162
|
}
|
|
4160
4163
|
function isOnlyFileCheckValidationError(validationError) {
|
|
4161
|
-
var _validationError$
|
|
4162
|
-
if ((_validationError$
|
|
4164
|
+
var _validationError$fixe7;
|
|
4165
|
+
if ((_validationError$fixe7 = validationError.fixes) !== null && _validationError$fixe7 !== void 0 && _validationError$fixe7.every(f => f === "file:check-metadata" || f === "image:check-metadata")) {
|
|
4163
4166
|
return true;
|
|
4164
4167
|
}
|
|
4165
4168
|
return false;
|
|
@@ -5680,6 +5683,7 @@ function serializeSchemaSafely(schema) {
|
|
|
5680
5683
|
}
|
|
5681
5684
|
class ValOpsFS extends ValOps {
|
|
5682
5685
|
static VAL_DIR = ".val";
|
|
5686
|
+
host;
|
|
5683
5687
|
constructor(contentUrl, rootDir, valModules, options) {
|
|
5684
5688
|
super(valModules, options);
|
|
5685
5689
|
this.contentUrl = contentUrl;
|
|
@@ -5692,6 +5696,7 @@ class ValOpsFS extends ValOps {
|
|
|
5692
5696
|
* Change detection for `.jsonValues()` entry files, which no sha can see (their
|
|
5693
5697
|
* content lives behind a thunk that `JSON.stringify` drops).
|
|
5694
5698
|
*/
|
|
5699
|
+
jsonEntryFilesFingerprint;
|
|
5695
5700
|
|
|
5696
5701
|
/**
|
|
5697
5702
|
* Unpublished changes repair threw away, waiting to be told to somebody.
|
|
@@ -7221,6 +7226,8 @@ const NonceResponse = z.z.object({
|
|
|
7221
7226
|
*/
|
|
7222
7227
|
const PATCH_GROUPS_CACHE_MS = 1000;
|
|
7223
7228
|
class ValOpsHttp extends ValOps {
|
|
7229
|
+
authHeaders;
|
|
7230
|
+
root;
|
|
7224
7231
|
constructor(contentUrl, project, commitSha,
|
|
7225
7232
|
// TODO: CommitSha
|
|
7226
7233
|
branch,
|
|
@@ -13576,6 +13583,8 @@ const MAX_CACHE_SIZE = 100 * 1024 * 1024; // 100 mb
|
|
|
13576
13583
|
const MAX_OBJECT_KEY_SIZE = 2 ** 27; // https://stackoverflow.com/questions/13367391/is-there-a-limit-on-length-of-the-key-string-in-js-object
|
|
13577
13584
|
|
|
13578
13585
|
class ValModuleLoader {
|
|
13586
|
+
cache;
|
|
13587
|
+
cacheSize;
|
|
13579
13588
|
constructor(projectRoot, compilerOptions,
|
|
13580
13589
|
// TODO: remove this?
|
|
13581
13590
|
sourceFileHandler, host = {
|
|
@@ -14955,7 +14964,7 @@ async function handleRemoteFileUpload(ctx) {
|
|
|
14955
14964
|
return uploadRemoteFileCore(ctx, fileRefProp, fileSourceMetadata, resolveRemoteFileSchema);
|
|
14956
14965
|
}
|
|
14957
14966
|
|
|
14958
|
-
// Gallery (s.
|
|
14967
|
+
// Gallery (s.imageset({ ... }).remote() / s.fileset({ ... }).remote()) upload.
|
|
14959
14968
|
// Unlike a single image/file field, a gallery entry is keyed by its local file
|
|
14960
14969
|
// path and the value is bare metadata (no FileSource), so we derive the file
|
|
14961
14970
|
// ref from the key and synthesize the image/file schema from the record's
|
|
@@ -14996,10 +15005,10 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
14996
15005
|
// synthesize the serialized image/file schema (matching how single fields
|
|
14997
15006
|
// serialize) for the remote ref's validation hash.
|
|
14998
15007
|
//
|
|
14999
|
-
// `accept`/`
|
|
15008
|
+
// `accept`/`dir` come from the RECORD that holds the entry, resolved
|
|
15000
15009
|
// from the entry's PARENT path - not from the module root, which is only the
|
|
15001
15010
|
// record when the gallery is the whole module. A nested gallery
|
|
15002
|
-
// (s.object({ gallery: s.
|
|
15011
|
+
// (s.object({ gallery: s.imageset(...) })) would otherwise synthesize a schema
|
|
15003
15012
|
// with no options and bake a validation hash into the remote ref that can
|
|
15004
15013
|
// never validate, so a mismatch fails fast instead of uploading.
|
|
15005
15014
|
const [, parentModulePath] = core.Internal.splitModuleFilePathAndModulePath(core.Internal.parentOfSourcePath(ctx.sourcePath));
|
|
@@ -15012,7 +15021,7 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
15012
15021
|
}
|
|
15013
15022
|
const {
|
|
15014
15023
|
accept,
|
|
15015
|
-
|
|
15024
|
+
dir
|
|
15016
15025
|
} = recordSchema;
|
|
15017
15026
|
const schema = mediaType === "image" ? {
|
|
15018
15027
|
type: "image",
|
|
@@ -15021,8 +15030,8 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
15021
15030
|
...(accept ? {
|
|
15022
15031
|
accept
|
|
15023
15032
|
} : {}),
|
|
15024
|
-
...(
|
|
15025
|
-
|
|
15033
|
+
...(dir ? {
|
|
15034
|
+
dir
|
|
15026
15035
|
} : {})
|
|
15027
15036
|
}
|
|
15028
15037
|
} : {
|
|
@@ -15062,14 +15071,14 @@ async function handleRemoteFileCheck() {
|
|
|
15062
15071
|
}
|
|
15063
15072
|
async function handleUniqueFolderCheck(ctx) {
|
|
15064
15073
|
const value = ctx.validationError.value;
|
|
15065
|
-
if (!value || typeof value.
|
|
15074
|
+
if (!value || typeof value.dir !== "string") {
|
|
15066
15075
|
return {
|
|
15067
15076
|
success: false,
|
|
15068
15077
|
errorMessage: `Unexpected value in unique folder check for ${ctx.sourcePath}`
|
|
15069
15078
|
};
|
|
15070
15079
|
}
|
|
15071
15080
|
const {
|
|
15072
|
-
|
|
15081
|
+
dir
|
|
15073
15082
|
} = value;
|
|
15074
15083
|
const conflicts = [];
|
|
15075
15084
|
for (const file of ctx.valFiles) {
|
|
@@ -15079,14 +15088,14 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
15079
15088
|
validate: false
|
|
15080
15089
|
});
|
|
15081
15090
|
const schema = otherModule.schema;
|
|
15082
|
-
if ((schema === null || schema === void 0 ? void 0 : schema.type) === "record" && schema.
|
|
15091
|
+
if ((schema === null || schema === void 0 ? void 0 : schema.type) === "record" && schema.dir === dir && schema.mediaType) {
|
|
15083
15092
|
conflicts.push(otherModuleFilePath);
|
|
15084
15093
|
}
|
|
15085
15094
|
}
|
|
15086
15095
|
if (conflicts.length > 0) {
|
|
15087
15096
|
return {
|
|
15088
15097
|
success: false,
|
|
15089
|
-
errorMessage: `Gallery directory '${
|
|
15098
|
+
errorMessage: `Gallery directory '${dir}' in ${ctx.moduleFilePath} is also used by: ${conflicts.join(", ")}. Each gallery must use a unique directory.`
|
|
15090
15099
|
};
|
|
15091
15100
|
}
|
|
15092
15101
|
return {
|
|
@@ -15116,7 +15125,7 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
15116
15125
|
*/
|
|
15117
15126
|
function checkGalleryFiles(input) {
|
|
15118
15127
|
const {
|
|
15119
|
-
|
|
15128
|
+
dir,
|
|
15120
15129
|
projectRoot,
|
|
15121
15130
|
fs
|
|
15122
15131
|
} = input;
|
|
@@ -15125,7 +15134,7 @@ function checkGalleryFiles(input) {
|
|
|
15125
15134
|
const missingTrackedFiles = entries.filter(entry => !entry.remote && !fs.fileExists(path__namespace["default"].join(projectRoot, entry.localPath))).map(entry => entry.localPath);
|
|
15126
15135
|
const filesInDir = [];
|
|
15127
15136
|
try {
|
|
15128
|
-
const found = fs.readDirectory(path__namespace["default"].join(projectRoot,
|
|
15137
|
+
const found = fs.readDirectory(path__namespace["default"].join(projectRoot, dir), undefined, undefined, ["**/*"]);
|
|
15129
15138
|
for (const entry of found) {
|
|
15130
15139
|
filesInDir.push("/" + path__namespace["default"].relative(projectRoot, entry).split(path__namespace["default"].sep).join("/"));
|
|
15131
15140
|
}
|
|
@@ -15139,14 +15148,14 @@ function checkGalleryFiles(input) {
|
|
|
15139
15148
|
}
|
|
15140
15149
|
async function handleCheckAllFiles(ctx) {
|
|
15141
15150
|
const value = ctx.validationError.value;
|
|
15142
|
-
if (!value || typeof value.
|
|
15151
|
+
if (!value || typeof value.dir !== "string") {
|
|
15143
15152
|
return {
|
|
15144
15153
|
success: false,
|
|
15145
15154
|
errorMessage: `Unexpected value in check-all-files for ${ctx.sourcePath}`
|
|
15146
15155
|
};
|
|
15147
15156
|
}
|
|
15148
15157
|
const {
|
|
15149
|
-
|
|
15158
|
+
dir
|
|
15150
15159
|
} = value;
|
|
15151
15160
|
const source = ctx.valModule.source;
|
|
15152
15161
|
if (!source || typeof source !== "object" || Array.isArray(source)) {
|
|
@@ -15160,7 +15169,7 @@ async function handleCheckAllFiles(ctx) {
|
|
|
15160
15169
|
untrackedFiles
|
|
15161
15170
|
} = checkGalleryFiles({
|
|
15162
15171
|
entryKeys: Object.keys(source),
|
|
15163
|
-
|
|
15172
|
+
dir,
|
|
15164
15173
|
projectRoot: ctx.projectRoot,
|
|
15165
15174
|
fs: ctx.fs
|
|
15166
15175
|
});
|
|
@@ -15255,9 +15264,10 @@ async function handleExternalUpload() {
|
|
|
15255
15264
|
};
|
|
15256
15265
|
}
|
|
15257
15266
|
|
|
15258
|
-
// Fix handler registry. `keyof:check-keys
|
|
15259
|
-
// resolved upfront by the
|
|
15260
|
-
// this registry, so they're
|
|
15267
|
+
// Fix handler registry. `keyof:check-keys`, `router:check-route`,
|
|
15268
|
+
// `locale:check-locale` and `record:fill-keys` are resolved upfront by the
|
|
15269
|
+
// shared resolveSchemaSourceFixes — they never reach this registry, so they're
|
|
15270
|
+
// excluded from the key set.
|
|
15261
15271
|
const currentFixHandlers = {
|
|
15262
15272
|
"image:check-metadata": handleFileMetadata,
|
|
15263
15273
|
"image:add-metadata": handleFileMetadata,
|
|
@@ -8,7 +8,7 @@ import path__default from 'path';
|
|
|
8
8
|
import fs, { promises } from 'fs';
|
|
9
9
|
import vm from 'node:vm';
|
|
10
10
|
import { Module } from 'node:module';
|
|
11
|
-
import { resolveSchemaSourceFixForError, Patch, getErrorMessageFromUnknownJson, JSONValue, PatchGroup, newestCommitSha, SerializedSchema, VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE, VAL_SESSION_COOKIE, Api } from '@valbuild/shared/internal';
|
|
11
|
+
import { isSchemaSourceFixError, resolveSchemaSourceFixForError, Patch, getErrorMessageFromUnknownJson, JSONValue, PatchGroup, newestCommitSha, SerializedSchema, VAL_ENABLE_COOKIE_NAME, VAL_STATE_COOKIE, VAL_SESSION_COOKIE, Api } from '@valbuild/shared/internal';
|
|
12
12
|
import { createUIRequestHandler } from '@valbuild/ui/server';
|
|
13
13
|
import crypto$1 from 'crypto';
|
|
14
14
|
import z$1, { z } from 'zod';
|
|
@@ -1714,6 +1714,7 @@ async function createService(projectRoot, host = {
|
|
|
1714
1714
|
return new Service(projectRoot, sourceFileHandler, extracted);
|
|
1715
1715
|
}
|
|
1716
1716
|
class Service {
|
|
1717
|
+
projectRoot;
|
|
1717
1718
|
constructor(projectRoot, sourceFileHandler, extracted) {
|
|
1718
1719
|
this.sourceFileHandler = sourceFileHandler;
|
|
1719
1720
|
this.extracted = extracted;
|
|
@@ -2353,17 +2354,18 @@ function findNestedJsonValuesModuleErrors(schemas) {
|
|
|
2353
2354
|
// #region ValOps
|
|
2354
2355
|
class ValOps {
|
|
2355
2356
|
/** Sources from val modules, immutable (without patches or anything) */
|
|
2356
|
-
|
|
2357
|
+
sources;
|
|
2357
2358
|
/** The sha256 / hash of all sources + all schemas + config */
|
|
2358
|
-
|
|
2359
|
+
baseSha;
|
|
2359
2360
|
/** The sha256 / hash of all sources */
|
|
2360
|
-
|
|
2361
|
+
sourcesSha;
|
|
2361
2362
|
/** The sha256 / hash of config */
|
|
2362
|
-
|
|
2363
|
+
configSha;
|
|
2363
2364
|
/** Schema from val modules, immutable */
|
|
2364
|
-
|
|
2365
|
+
schemas;
|
|
2365
2366
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
2366
|
-
|
|
2367
|
+
schemaSha;
|
|
2368
|
+
modulesErrors;
|
|
2367
2369
|
/**
|
|
2368
2370
|
* What the SHAs above are a fold over, so they can be recomputed.
|
|
2369
2371
|
*
|
|
@@ -2371,7 +2373,7 @@ class ValOps {
|
|
|
2371
2373
|
* without re-evaluating the modules is a save, and it has to be able to move
|
|
2372
2374
|
* the SHAs with them.
|
|
2373
2375
|
*/
|
|
2374
|
-
|
|
2376
|
+
shaEntries;
|
|
2375
2377
|
/**
|
|
2376
2378
|
* The extraction's OWN module errors, which are what the fold was given.
|
|
2377
2379
|
*
|
|
@@ -2379,7 +2381,7 @@ class ValOps {
|
|
|
2379
2381
|
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
2380
2382
|
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
2381
2383
|
*/
|
|
2382
|
-
|
|
2384
|
+
shaModuleErrors;
|
|
2383
2385
|
/**
|
|
2384
2386
|
* What a save has told us each `.jsonValues()` entry now holds.
|
|
2385
2387
|
*
|
|
@@ -3139,7 +3141,8 @@ class ValOps {
|
|
|
3139
3141
|
// (must include all modules, not just those being validated, since conflicts can come from any module)
|
|
3140
3142
|
const galleryDirectoryToModules = new Map();
|
|
3141
3143
|
// Build a schema/source snapshot so the shared resolver can cross-reference
|
|
3142
|
-
//
|
|
3144
|
+
// the marker fixes — a keyOf's key, a route, a locale tag, a record's
|
|
3145
|
+
// declared keys — against every module's data. See `SCHEMA_SOURCE_FIXES`.
|
|
3143
3146
|
const snapshot = {
|
|
3144
3147
|
schemas: {},
|
|
3145
3148
|
sources: {}
|
|
@@ -3152,8 +3155,8 @@ class ValOps {
|
|
|
3152
3155
|
if (sourceForModule !== undefined) {
|
|
3153
3156
|
snapshot.sources[moduleFilePath] = sourceForModule;
|
|
3154
3157
|
}
|
|
3155
|
-
if (serialized.type === "record" && serialized.mediaType && serialized.
|
|
3156
|
-
const dir = serialized.
|
|
3158
|
+
if (serialized.type === "record" && serialized.mediaType && serialized.dir) {
|
|
3159
|
+
const dir = serialized.dir;
|
|
3157
3160
|
const existing = galleryDirectoryToModules.get(dir);
|
|
3158
3161
|
if (existing) {
|
|
3159
3162
|
existing.push(moduleFilePath);
|
|
@@ -3219,7 +3222,7 @@ class ValOps {
|
|
|
3219
3222
|
};
|
|
3220
3223
|
if (validationErrors) {
|
|
3221
3224
|
for (const validationError of validationErrors) {
|
|
3222
|
-
var _validationError$fixe, _validationError$fixe2, _validationError$fixe3, _validationError$fixe4, _validationError$fixe5, _validationError$fixe6
|
|
3225
|
+
var _validationError$fixe, _validationError$fixe2, _validationError$fixe3, _validationError$fixe4, _validationError$fixe5, _validationError$fixe6;
|
|
3223
3226
|
if (isOnlyFileCheckValidationError(validationError)) {
|
|
3224
3227
|
if (files[sourcePath]) {
|
|
3225
3228
|
addError({
|
|
@@ -3233,13 +3236,13 @@ class ValOps {
|
|
|
3233
3236
|
}
|
|
3234
3237
|
} else if ((_validationError$fixe = validationError.fixes) !== null && _validationError$fixe !== void 0 && _validationError$fixe.includes("image:check-remote") || (_validationError$fixe2 = validationError.fixes) !== null && _validationError$fixe2 !== void 0 && _validationError$fixe2.includes("file:check-remote")) {
|
|
3235
3238
|
remoteFiles[sourcePath] = validationError.value;
|
|
3236
|
-
} else if ((
|
|
3239
|
+
} else if (isSchemaSourceFixError(validationError)) {
|
|
3237
3240
|
const resolved = resolveSchemaSourceFixForError(validationError, snapshot);
|
|
3238
3241
|
if (resolved && resolved.status === "remaining") {
|
|
3239
3242
|
addError(resolved.error);
|
|
3240
3243
|
}
|
|
3241
3244
|
// resolved.status === "resolved" → drop silently
|
|
3242
|
-
} else if ((_validationError$
|
|
3245
|
+
} else if ((_validationError$fixe3 = validationError.fixes) !== null && _validationError$fixe3 !== void 0 && _validationError$fixe3.includes("images:check-unique-folder") || (_validationError$fixe4 = validationError.fixes) !== null && _validationError$fixe4 !== void 0 && _validationError$fixe4.includes("files:check-unique-folder")) {
|
|
3243
3246
|
const TYPE_ERROR_MESSAGE = `This is most likely a Val version mismatch or Val bug.`;
|
|
3244
3247
|
if (!validationError.value || typeof validationError.value !== "object") {
|
|
3245
3248
|
addError({
|
|
@@ -3247,10 +3250,10 @@ class ValOps {
|
|
|
3247
3250
|
typeError: true
|
|
3248
3251
|
});
|
|
3249
3252
|
} else {
|
|
3250
|
-
const directory = "
|
|
3253
|
+
const directory = "dir" in validationError.value && validationError.value.dir;
|
|
3251
3254
|
if (typeof directory !== "string") {
|
|
3252
3255
|
addError({
|
|
3253
|
-
message: `Expected gallery validation error 'value' to have property '
|
|
3256
|
+
message: `Expected gallery validation error 'value' to have property 'dir' of type 'string'. Found: ${typeof directory}. ${TYPE_ERROR_MESSAGE}`,
|
|
3254
3257
|
typeError: true
|
|
3255
3258
|
});
|
|
3256
3259
|
} else {
|
|
@@ -3264,7 +3267,7 @@ class ValOps {
|
|
|
3264
3267
|
// If conflictingModules is empty, directory is unique — silently drop the error.
|
|
3265
3268
|
}
|
|
3266
3269
|
}
|
|
3267
|
-
} else if ((_validationError$
|
|
3270
|
+
} else if ((_validationError$fixe5 = validationError.fixes) !== null && _validationError$fixe5 !== void 0 && _validationError$fixe5.includes("images:check-all-files") || (_validationError$fixe6 = validationError.fixes) !== null && _validationError$fixe6 !== void 0 && _validationError$fixe6.includes("files:check-all-files")) ; else {
|
|
3268
3271
|
addError(validationError);
|
|
3269
3272
|
}
|
|
3270
3273
|
}
|
|
@@ -4124,8 +4127,8 @@ class ValOps {
|
|
|
4124
4127
|
// #endregion history
|
|
4125
4128
|
}
|
|
4126
4129
|
function isOnlyFileCheckValidationError(validationError) {
|
|
4127
|
-
var _validationError$
|
|
4128
|
-
if ((_validationError$
|
|
4130
|
+
var _validationError$fixe7;
|
|
4131
|
+
if ((_validationError$fixe7 = validationError.fixes) !== null && _validationError$fixe7 !== void 0 && _validationError$fixe7.every(f => f === "file:check-metadata" || f === "image:check-metadata")) {
|
|
4129
4132
|
return true;
|
|
4130
4133
|
}
|
|
4131
4134
|
return false;
|
|
@@ -5646,6 +5649,7 @@ function serializeSchemaSafely(schema) {
|
|
|
5646
5649
|
}
|
|
5647
5650
|
class ValOpsFS extends ValOps {
|
|
5648
5651
|
static VAL_DIR = ".val";
|
|
5652
|
+
host;
|
|
5649
5653
|
constructor(contentUrl, rootDir, valModules, options) {
|
|
5650
5654
|
super(valModules, options);
|
|
5651
5655
|
this.contentUrl = contentUrl;
|
|
@@ -5658,6 +5662,7 @@ class ValOpsFS extends ValOps {
|
|
|
5658
5662
|
* Change detection for `.jsonValues()` entry files, which no sha can see (their
|
|
5659
5663
|
* content lives behind a thunk that `JSON.stringify` drops).
|
|
5660
5664
|
*/
|
|
5665
|
+
jsonEntryFilesFingerprint;
|
|
5661
5666
|
|
|
5662
5667
|
/**
|
|
5663
5668
|
* Unpublished changes repair threw away, waiting to be told to somebody.
|
|
@@ -7187,6 +7192,8 @@ const NonceResponse = z.object({
|
|
|
7187
7192
|
*/
|
|
7188
7193
|
const PATCH_GROUPS_CACHE_MS = 1000;
|
|
7189
7194
|
class ValOpsHttp extends ValOps {
|
|
7195
|
+
authHeaders;
|
|
7196
|
+
root;
|
|
7190
7197
|
constructor(contentUrl, project, commitSha,
|
|
7191
7198
|
// TODO: CommitSha
|
|
7192
7199
|
branch,
|
|
@@ -13542,6 +13549,8 @@ const MAX_CACHE_SIZE = 100 * 1024 * 1024; // 100 mb
|
|
|
13542
13549
|
const MAX_OBJECT_KEY_SIZE = 2 ** 27; // https://stackoverflow.com/questions/13367391/is-there-a-limit-on-length-of-the-key-string-in-js-object
|
|
13543
13550
|
|
|
13544
13551
|
class ValModuleLoader {
|
|
13552
|
+
cache;
|
|
13553
|
+
cacheSize;
|
|
13545
13554
|
constructor(projectRoot, compilerOptions,
|
|
13546
13555
|
// TODO: remove this?
|
|
13547
13556
|
sourceFileHandler, host = {
|
|
@@ -14921,7 +14930,7 @@ async function handleRemoteFileUpload(ctx) {
|
|
|
14921
14930
|
return uploadRemoteFileCore(ctx, fileRefProp, fileSourceMetadata, resolveRemoteFileSchema);
|
|
14922
14931
|
}
|
|
14923
14932
|
|
|
14924
|
-
// Gallery (s.
|
|
14933
|
+
// Gallery (s.imageset({ ... }).remote() / s.fileset({ ... }).remote()) upload.
|
|
14925
14934
|
// Unlike a single image/file field, a gallery entry is keyed by its local file
|
|
14926
14935
|
// path and the value is bare metadata (no FileSource), so we derive the file
|
|
14927
14936
|
// ref from the key and synthesize the image/file schema from the record's
|
|
@@ -14962,10 +14971,10 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
14962
14971
|
// synthesize the serialized image/file schema (matching how single fields
|
|
14963
14972
|
// serialize) for the remote ref's validation hash.
|
|
14964
14973
|
//
|
|
14965
|
-
// `accept`/`
|
|
14974
|
+
// `accept`/`dir` come from the RECORD that holds the entry, resolved
|
|
14966
14975
|
// from the entry's PARENT path - not from the module root, which is only the
|
|
14967
14976
|
// record when the gallery is the whole module. A nested gallery
|
|
14968
|
-
// (s.object({ gallery: s.
|
|
14977
|
+
// (s.object({ gallery: s.imageset(...) })) would otherwise synthesize a schema
|
|
14969
14978
|
// with no options and bake a validation hash into the remote ref that can
|
|
14970
14979
|
// never validate, so a mismatch fails fast instead of uploading.
|
|
14971
14980
|
const [, parentModulePath] = Internal.splitModuleFilePathAndModulePath(Internal.parentOfSourcePath(ctx.sourcePath));
|
|
@@ -14978,7 +14987,7 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
14978
14987
|
}
|
|
14979
14988
|
const {
|
|
14980
14989
|
accept,
|
|
14981
|
-
|
|
14990
|
+
dir
|
|
14982
14991
|
} = recordSchema;
|
|
14983
14992
|
const schema = mediaType === "image" ? {
|
|
14984
14993
|
type: "image",
|
|
@@ -14987,8 +14996,8 @@ async function handleRemoteGalleryFileUpload(ctx) {
|
|
|
14987
14996
|
...(accept ? {
|
|
14988
14997
|
accept
|
|
14989
14998
|
} : {}),
|
|
14990
|
-
...(
|
|
14991
|
-
|
|
14999
|
+
...(dir ? {
|
|
15000
|
+
dir
|
|
14992
15001
|
} : {})
|
|
14993
15002
|
}
|
|
14994
15003
|
} : {
|
|
@@ -15028,14 +15037,14 @@ async function handleRemoteFileCheck() {
|
|
|
15028
15037
|
}
|
|
15029
15038
|
async function handleUniqueFolderCheck(ctx) {
|
|
15030
15039
|
const value = ctx.validationError.value;
|
|
15031
|
-
if (!value || typeof value.
|
|
15040
|
+
if (!value || typeof value.dir !== "string") {
|
|
15032
15041
|
return {
|
|
15033
15042
|
success: false,
|
|
15034
15043
|
errorMessage: `Unexpected value in unique folder check for ${ctx.sourcePath}`
|
|
15035
15044
|
};
|
|
15036
15045
|
}
|
|
15037
15046
|
const {
|
|
15038
|
-
|
|
15047
|
+
dir
|
|
15039
15048
|
} = value;
|
|
15040
15049
|
const conflicts = [];
|
|
15041
15050
|
for (const file of ctx.valFiles) {
|
|
@@ -15045,14 +15054,14 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
15045
15054
|
validate: false
|
|
15046
15055
|
});
|
|
15047
15056
|
const schema = otherModule.schema;
|
|
15048
|
-
if ((schema === null || schema === void 0 ? void 0 : schema.type) === "record" && schema.
|
|
15057
|
+
if ((schema === null || schema === void 0 ? void 0 : schema.type) === "record" && schema.dir === dir && schema.mediaType) {
|
|
15049
15058
|
conflicts.push(otherModuleFilePath);
|
|
15050
15059
|
}
|
|
15051
15060
|
}
|
|
15052
15061
|
if (conflicts.length > 0) {
|
|
15053
15062
|
return {
|
|
15054
15063
|
success: false,
|
|
15055
|
-
errorMessage: `Gallery directory '${
|
|
15064
|
+
errorMessage: `Gallery directory '${dir}' in ${ctx.moduleFilePath} is also used by: ${conflicts.join(", ")}. Each gallery must use a unique directory.`
|
|
15056
15065
|
};
|
|
15057
15066
|
}
|
|
15058
15067
|
return {
|
|
@@ -15082,7 +15091,7 @@ async function handleUniqueFolderCheck(ctx) {
|
|
|
15082
15091
|
*/
|
|
15083
15092
|
function checkGalleryFiles(input) {
|
|
15084
15093
|
const {
|
|
15085
|
-
|
|
15094
|
+
dir,
|
|
15086
15095
|
projectRoot,
|
|
15087
15096
|
fs
|
|
15088
15097
|
} = input;
|
|
@@ -15091,7 +15100,7 @@ function checkGalleryFiles(input) {
|
|
|
15091
15100
|
const missingTrackedFiles = entries.filter(entry => !entry.remote && !fs.fileExists(path__default.join(projectRoot, entry.localPath))).map(entry => entry.localPath);
|
|
15092
15101
|
const filesInDir = [];
|
|
15093
15102
|
try {
|
|
15094
|
-
const found = fs.readDirectory(path__default.join(projectRoot,
|
|
15103
|
+
const found = fs.readDirectory(path__default.join(projectRoot, dir), undefined, undefined, ["**/*"]);
|
|
15095
15104
|
for (const entry of found) {
|
|
15096
15105
|
filesInDir.push("/" + path__default.relative(projectRoot, entry).split(path__default.sep).join("/"));
|
|
15097
15106
|
}
|
|
@@ -15105,14 +15114,14 @@ function checkGalleryFiles(input) {
|
|
|
15105
15114
|
}
|
|
15106
15115
|
async function handleCheckAllFiles(ctx) {
|
|
15107
15116
|
const value = ctx.validationError.value;
|
|
15108
|
-
if (!value || typeof value.
|
|
15117
|
+
if (!value || typeof value.dir !== "string") {
|
|
15109
15118
|
return {
|
|
15110
15119
|
success: false,
|
|
15111
15120
|
errorMessage: `Unexpected value in check-all-files for ${ctx.sourcePath}`
|
|
15112
15121
|
};
|
|
15113
15122
|
}
|
|
15114
15123
|
const {
|
|
15115
|
-
|
|
15124
|
+
dir
|
|
15116
15125
|
} = value;
|
|
15117
15126
|
const source = ctx.valModule.source;
|
|
15118
15127
|
if (!source || typeof source !== "object" || Array.isArray(source)) {
|
|
@@ -15126,7 +15135,7 @@ async function handleCheckAllFiles(ctx) {
|
|
|
15126
15135
|
untrackedFiles
|
|
15127
15136
|
} = checkGalleryFiles({
|
|
15128
15137
|
entryKeys: Object.keys(source),
|
|
15129
|
-
|
|
15138
|
+
dir,
|
|
15130
15139
|
projectRoot: ctx.projectRoot,
|
|
15131
15140
|
fs: ctx.fs
|
|
15132
15141
|
});
|
|
@@ -15221,9 +15230,10 @@ async function handleExternalUpload() {
|
|
|
15221
15230
|
};
|
|
15222
15231
|
}
|
|
15223
15232
|
|
|
15224
|
-
// Fix handler registry. `keyof:check-keys
|
|
15225
|
-
// resolved upfront by the
|
|
15226
|
-
// this registry, so they're
|
|
15233
|
+
// Fix handler registry. `keyof:check-keys`, `router:check-route`,
|
|
15234
|
+
// `locale:check-locale` and `record:fill-keys` are resolved upfront by the
|
|
15235
|
+
// shared resolveSchemaSourceFixes — they never reach this registry, so they're
|
|
15236
|
+
// excluded from the key set.
|
|
15227
15237
|
const currentFixHandlers = {
|
|
15228
15238
|
"image:check-metadata": handleFileMetadata,
|
|
15229
15239
|
"image:add-metadata": handleFileMetadata,
|
package/package.json
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"./package.json": "./package.json"
|
|
17
17
|
},
|
|
18
18
|
"types": "dist/valbuild-server.cjs.d.ts",
|
|
19
|
-
"version": "0.
|
|
19
|
+
"version": "0.128.0",
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@prettier/sync": "^0.6.1",
|
|
22
22
|
"@types/jest": "^30.0.0"
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
31
|
"zod-validation-error": "^5.0.0",
|
|
32
|
-
"@valbuild/
|
|
33
|
-
"@valbuild/shared": "0.
|
|
34
|
-
"@valbuild/
|
|
32
|
+
"@valbuild/ui": "0.127.0",
|
|
33
|
+
"@valbuild/shared": "0.128.0",
|
|
34
|
+
"@valbuild/core": "0.128.0"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": "^20.19.0 || >=22"
|