@valbuild/server 0.125.0 → 0.127.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,215 @@
|
|
|
1
1
|
# @valbuild/server
|
|
2
2
|
|
|
3
|
+
## 0.127.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#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.
|
|
8
|
+
|
|
9
|
+
Two key schemas enumerate their keys: `s.locale()`, whose set is the project's
|
|
10
|
+
`locales.available`, and a union of literals. For those, the keys are part of the
|
|
11
|
+
schema, so a missing one is a hole in the content rather than content nobody has
|
|
12
|
+
written yet — and validation now says so, naming what is missing.
|
|
13
|
+
|
|
14
|
+
```typescript
|
|
15
|
+
s.record(s.locale(), s.object({ title: s.string() }));
|
|
16
|
+
// Missing key: 'nb-NO'. This record's keys are declared by its schema, so
|
|
17
|
+
// every one of them is an entry — an entry nobody has written yet is null,
|
|
18
|
+
// not absent.
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**An entry nobody has written yet is `null`.** Not an absent key: a null entry is
|
|
22
|
+
data you can count, filter and see in a diff, and it means half-translated
|
|
23
|
+
content stays _valid_ rather than blocking a publish. The value type of such a
|
|
24
|
+
record widens by `null` to match, so writing one in a `.val.ts` type-checks:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
c.define(
|
|
28
|
+
"/content/jacket.val.ts",
|
|
29
|
+
s.record(s.locale(), s.object({ title: s.string() })),
|
|
30
|
+
{
|
|
31
|
+
"en-US": { title: "Winter jacket" },
|
|
32
|
+
"nb-NO": null, // nobody has translated this yet
|
|
33
|
+
},
|
|
34
|
+
);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**This changes `s.record(s.union(...), item)`**, and closes a gap that was
|
|
38
|
+
already there: `s.record(s.union(s.literal("a"), s.literal("b")), item)` types as
|
|
39
|
+
`Record<"a" | "b", T>`, so TypeScript demanded both keys while the validator only
|
|
40
|
+
checked the ones present. It now checks them too, and — as above — accepts `null`
|
|
41
|
+
for an entry that has not been filled in. If you have such a record with keys
|
|
42
|
+
missing, validation will report them; adding the keys with `null` values is the
|
|
43
|
+
fix, and creating one from the Studio does it for you.
|
|
44
|
+
|
|
45
|
+
`emptyOf` creates these records with every key already in them rather than
|
|
46
|
+
empty, since an empty one is already missing keys. In the Studio use the
|
|
47
|
+
`useEmptyOf()` hook rather than importing `emptyOf` directly: a locale record's
|
|
48
|
+
keys are in the settings module, and the hook is what has read it.
|
|
49
|
+
|
|
50
|
+
- [#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.
|
|
51
|
+
|
|
52
|
+
The languages themselves are declared in the settings module (`locales.available`);
|
|
53
|
+
this says that a value is one of them.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// a field: everything in this entry is in this language
|
|
57
|
+
s.record(s.string(), s.object({ locale: s.locale(), title: s.string() }));
|
|
58
|
+
|
|
59
|
+
// a key: one entry per language
|
|
60
|
+
s.record(s.locale(), s.object({ title: s.string() }));
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Every locale in content is checked against the project's list, the way `keyOf`
|
|
64
|
+
and `route` are checked against what they point at. An undeclared language names
|
|
65
|
+
the ones the project has; a project that has declared none is told to declare
|
|
66
|
+
them rather than told the value is wrong.
|
|
67
|
+
|
|
68
|
+
A locale is stored as the tag itself — the value in content is `nb-NO`, and a
|
|
69
|
+
record keyed by `s.locale()` has `nb-NO` as its key. Spelling one differently
|
|
70
|
+
where it is stored (`/no/…` as a URL segment) is a real need and is deliberately
|
|
71
|
+
not in this release: it changes what is accepted as well as what is shown, so it
|
|
72
|
+
is being designed on its own rather than folded in here.
|
|
73
|
+
|
|
74
|
+
A locale is **never stega encoded**: it ends up in `<html lang>`, in `hreflang`
|
|
75
|
+
and in `Intl` constructors, none of which survive invisible characters.
|
|
76
|
+
|
|
77
|
+
`assistant.translation` joins the settings module alongside `context` and `tone`
|
|
78
|
+
— a note per language, keyed by language, so only the target language's rules are
|
|
79
|
+
sent when translating into it.
|
|
80
|
+
|
|
81
|
+
### Patch Changes
|
|
82
|
+
|
|
83
|
+
- 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)]:
|
|
84
|
+
- @valbuild/core@0.127.0
|
|
85
|
+
- @valbuild/shared@0.127.0
|
|
86
|
+
- @valbuild/ui@0.127.0
|
|
87
|
+
|
|
88
|
+
## 0.126.0
|
|
89
|
+
|
|
90
|
+
### Patch Changes
|
|
91
|
+
|
|
92
|
+
- [#664](https://github.com/valbuild/val/pull/664) [`5bfd630`](https://github.com/valbuild/val/commit/5bfd630b63dee2189e238f20fe72ecc5537160f7) Thanks [@freekh](https://github.com/freekh)! - Show the git message on deployments Val did not publish
|
|
93
|
+
|
|
94
|
+
The deploy feed could only name a publish when Val itself had made the commit:
|
|
95
|
+
the message came off Val's own `ValCommit`, and every other deployment — a
|
|
96
|
+
developer's push, a merged pull request, a revert — showed a seven-character
|
|
97
|
+
sha. On most projects those are the majority, so "what went out at 14:02?" had
|
|
98
|
+
no answer in the Studio.
|
|
99
|
+
|
|
100
|
+
A deployment can now carry its own `commitMessage`, which the Studio uses
|
|
101
|
+
wherever there is no Val commit to prefer. It is optional and nullable, so a
|
|
102
|
+
content service that does not report messages is unaffected — those publishes
|
|
103
|
+
keep showing the short sha, exactly as before.
|
|
104
|
+
|
|
105
|
+
Deployment rows also show only the subject line of a message now. A git message
|
|
106
|
+
is a subject, a blank line and a body, and the rows are one truncated line — so
|
|
107
|
+
a real push arrived as "Subject The body went on like this…". The classic
|
|
108
|
+
Draft changes view still has the whole message in its tooltip.
|
|
109
|
+
|
|
110
|
+
- [#652](https://github.com/valbuild/val/pull/652) [`f2fe70d`](https://github.com/valbuild/val/commit/f2fe70dab2b65000dfaf289f09c70b4a8291467a) Thanks [@freekh](https://github.com/freekh)! - `s.union` is now `s.discriminatedUnion` and `s.enum`.
|
|
111
|
+
|
|
112
|
+
`s.union` did two unrelated jobs and worked out which one you meant from its
|
|
113
|
+
first argument: a string key meant a tagged union of objects, literal schemas
|
|
114
|
+
meant a set of allowed strings. Those are now two schemas with two names.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// A fixed set of strings — presents as a dropdown
|
|
118
|
+
s.enum("primary", "secondary", "ghost"); // Schema<"primary" | "secondary" | "ghost">
|
|
119
|
+
|
|
120
|
+
// One of several object shapes, told apart by a tag field
|
|
121
|
+
s.discriminatedUnion(
|
|
122
|
+
"type",
|
|
123
|
+
s.object({ type: s.literal("hero"), heading: s.string() }),
|
|
124
|
+
s.object({ type: s.literal("quote"), text: s.string() }),
|
|
125
|
+
);
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`s.enum` takes the strings directly, so the `s.literal(...)` wrapper is gone.
|
|
129
|
+
|
|
130
|
+
**`s.union` still works** — it is deprecated, and it builds exactly the schema
|
|
131
|
+
above, so nothing has to change today:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
s.union(s.literal("one"), s.literal("two")); // → s.enum("one", "two")
|
|
135
|
+
s.union("type", pageA, pageB); // → s.discriminatedUnion("type", pageA, pageB)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
The two are different kinds of node, and that is the reason for the split. A
|
|
139
|
+
discriminated union is a container: the selected variant's fields are the fields
|
|
140
|
+
being edited, and everything that walks a schema descends through it. An enum is
|
|
141
|
+
a leaf — a string with a closed domain — so nothing recurses into it. Told apart
|
|
142
|
+
only by the shape of `key`, every consumer had to re-derive which one it was
|
|
143
|
+
holding; each now has its own serialized type (`"discriminated-union"` and
|
|
144
|
+
`"enum"`) and Val Studio has a field per kind rather than one field that
|
|
145
|
+
branches.
|
|
146
|
+
|
|
147
|
+
Two behaviour changes fall out of the split, both of them fixes:
|
|
148
|
+
|
|
149
|
+
- A value that is not a string at all now fails an enum's validation with a
|
|
150
|
+
type error. `s.union` of literals only ever checked the value against its
|
|
151
|
+
literals when the value WAS a string, so a number or an object where an enum
|
|
152
|
+
was declared validated clean.
|
|
153
|
+
- An enum field now shows its validation errors in Val Studio where the field
|
|
154
|
+
is opened on its own — the module editor and the canvas's fields column — and
|
|
155
|
+
gets the compact error layout inside an inline list row. It is a leaf now, so
|
|
156
|
+
it goes through the same error rendering as every other leaf field; the string
|
|
157
|
+
union bypassed it and showed nothing in those places.
|
|
158
|
+
|
|
159
|
+
Several latent crashes in the old `s.union` are fixed on the way past, all of
|
|
160
|
+
them cases where it threw a `TypeError` instead of reporting:
|
|
161
|
+
|
|
162
|
+
- A required discriminated union holding `null` now reports a type error rather
|
|
163
|
+
than throwing, and resolving a path underneath a nullable one that is `null`
|
|
164
|
+
gives the error the API promises instead of a crash.
|
|
165
|
+
- `s.literal("")` is a legal discriminator tag, and `s.enum("")` a legal value.
|
|
166
|
+
Both used to be treated as absent by a truthiness check — in path resolution,
|
|
167
|
+
in stega encoding, and in the message that lists a union's valid tags. The
|
|
168
|
+
editor's dropdowns handle them too: an empty value is reserved by the select
|
|
169
|
+
component and had to be mapped around.
|
|
170
|
+
- A variant that omits the discriminator entirely is now reported as the schema
|
|
171
|
+
error it is, instead of throwing while the check looked for it.
|
|
172
|
+
- An enum's value is now indexed for search, like every other string leaf. The
|
|
173
|
+
old string union was never indexed at all, so searching for one of its values
|
|
174
|
+
could not find the field.
|
|
175
|
+
- A nullable discriminated union set to `null` no longer renders a spinner that
|
|
176
|
+
never resolves.
|
|
177
|
+
|
|
178
|
+
`s.discriminatedUnion` also requires at least one variant, as `s.enum` requires
|
|
179
|
+
at least one value: a union with nothing to select is not a thing to write, and
|
|
180
|
+
everything downstream reads the first variant where it needs any.
|
|
181
|
+
|
|
182
|
+
If you read serialized schemas yourself, that is the breaking part: `type` is no
|
|
183
|
+
longer `"union"`, an enum carries `values: string[]` instead of a `key` plus
|
|
184
|
+
`items` of literal schemas, and `UnionSchema` is no longer a class.
|
|
185
|
+
`SerializedUnionSchema`, `SerializedStringUnionSchema`,
|
|
186
|
+
`SerializedObjectUnionSchema` and `UnionSchema` remain as deprecated type
|
|
187
|
+
aliases.
|
|
188
|
+
|
|
189
|
+
- [#666](https://github.com/valbuild/val/pull/666) [`5c18c99`](https://github.com/valbuild/val/commit/5c18c99ecc84651f82123481fc042063db953833) Thanks [@freekh](https://github.com/freekh)! - `next build` no longer warns `module.createRequire failed parsing argument.`
|
|
190
|
+
|
|
191
|
+
Every Next app that bundles `@valbuild/server` into its Val API route got this
|
|
192
|
+
on every build, twice, with an import trace that led from `route.ts` down into
|
|
193
|
+
`valbuild-server.esm.js` and stopped there:
|
|
194
|
+
|
|
195
|
+
```
|
|
196
|
+
⚠ ./node_modules/.../@valbuild/server/dist/valbuild-server.esm.js
|
|
197
|
+
module.createRequire failed parsing argument.
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
Nothing was wrong. webpack special-cases a `createRequire` binding imported from
|
|
201
|
+
`node:module` and tries to resolve the call's argument at build time; the two
|
|
202
|
+
calls in this package take a path inside the user's project, known only at
|
|
203
|
+
runtime, so there was nothing to resolve and nothing the warning could tell
|
|
204
|
+
anyone. Both now go through a helper that reaches the same function through the
|
|
205
|
+
`Module` class, which that analysis does not tag. Runtime behaviour is
|
|
206
|
+
unchanged, and a lint rule keeps the direct import from coming back.
|
|
207
|
+
|
|
208
|
+
- Updated dependencies [[`719ad6b`](https://github.com/valbuild/val/commit/719ad6b607bcf136d0dbde9e90bf4b8a843561a4), [`9830277`](https://github.com/valbuild/val/commit/9830277e9aaca8da3030f629c2656ec58da47e45), [`64bfd0a`](https://github.com/valbuild/val/commit/64bfd0a6c85832ea5169b53e47087f22e193df36), [`7782979`](https://github.com/valbuild/val/commit/7782979e9b52f2015a6e72dc981e630d4f8c78e2), [`5bfd630`](https://github.com/valbuild/val/commit/5bfd630b63dee2189e238f20fe72ecc5537160f7), [`ccbcda6`](https://github.com/valbuild/val/commit/ccbcda60b3e3c465071229ae1ba28ac735483e63), [`f2fe70d`](https://github.com/valbuild/val/commit/f2fe70dab2b65000dfaf289f09c70b4a8291467a), [`755e1a3`](https://github.com/valbuild/val/commit/755e1a3953775cb8d2c2dce87d6810d3dc329640), [`c6b1ec8`](https://github.com/valbuild/val/commit/c6b1ec84f1883750a4cfe5f70470b177621e971f), [`656f680`](https://github.com/valbuild/val/commit/656f680043c640f678625a64e690389ab23a0a69), [`610a041`](https://github.com/valbuild/val/commit/610a0414b120b521f38a2eb1182b3778bf778b2b), [`171208a`](https://github.com/valbuild/val/commit/171208a20177e68ed5a8b1a6fdaabfe893a6aa5f)]:
|
|
209
|
+
- @valbuild/ui@0.126.0
|
|
210
|
+
- @valbuild/shared@0.126.0
|
|
211
|
+
- @valbuild/core@0.126.0
|
|
212
|
+
|
|
3
213
|
## 0.125.0
|
|
4
214
|
|
|
5
215
|
### Patch Changes
|
|
@@ -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;
|
|
@@ -696,6 +696,32 @@ const getCompilerOptions = (rootDir, parseConfigHost) => {
|
|
|
696
696
|
return parsedConfigFile.options;
|
|
697
697
|
};
|
|
698
698
|
|
|
699
|
+
/**
|
|
700
|
+
* Node's `require`, resolving as if from `filename`.
|
|
701
|
+
*
|
|
702
|
+
* Use this instead of importing `createRequire` from `node:module` directly.
|
|
703
|
+
* webpack special-cases a `createRequire` binding imported from `module` /
|
|
704
|
+
* `node:module`: it tries to resolve the call's argument at build time, and
|
|
705
|
+
* when the argument is not a literal it gives up with
|
|
706
|
+
*
|
|
707
|
+
* module.createRequire failed parsing argument.
|
|
708
|
+
*
|
|
709
|
+
* Our argument is never a literal — it is a path inside the user's project,
|
|
710
|
+
* known only at runtime — so there is nothing for that analysis to find, and
|
|
711
|
+
* nothing the warning can tell anyone. It is emitted on every build of every
|
|
712
|
+
* Next app that bundles `@valbuild/server` into its Val API route, which is
|
|
713
|
+
* all of them. Reaching `createRequire` through the `Module` class is the same
|
|
714
|
+
* function and is not what webpack tags, so the call is invisible to it.
|
|
715
|
+
*
|
|
716
|
+
* It has to stay a real `node:module` import: jest's module registry hands out
|
|
717
|
+
* its own `node:module`, and a `require` obtained around it (via
|
|
718
|
+
* `process.getBuiltinModule`, say) would resolve against the real filesystem
|
|
719
|
+
* rather than the registry the tests run in.
|
|
720
|
+
*/
|
|
721
|
+
function createNodeRequire(filename) {
|
|
722
|
+
return node_module.Module.createRequire(filename);
|
|
723
|
+
}
|
|
724
|
+
|
|
699
725
|
/**
|
|
700
726
|
* The filesystem seam `loadValModules` reads through.
|
|
701
727
|
*
|
|
@@ -829,7 +855,7 @@ function loadModule(absPath, cache, compilerOptions, host) {
|
|
|
829
855
|
// Insert into the cache before evaluating so cyclic imports resolve.
|
|
830
856
|
cache[absPath] = moduleObj;
|
|
831
857
|
const dirName = path__namespace["default"].dirname(absPath);
|
|
832
|
-
const realRequire =
|
|
858
|
+
const realRequire = createNodeRequire(absPath);
|
|
833
859
|
const customRequire = spec => {
|
|
834
860
|
var _ts$resolveModuleName;
|
|
835
861
|
if (isStubbedSpecifier(spec)) {
|
|
@@ -1136,7 +1162,7 @@ function findNestedJsonValuesRecords(schema, path = []) {
|
|
|
1136
1162
|
case "array":
|
|
1137
1163
|
rec(current.item, currentPath.concat("*"));
|
|
1138
1164
|
return;
|
|
1139
|
-
case "union":
|
|
1165
|
+
case "discriminated-union":
|
|
1140
1166
|
for (let i = 0; i < current.items.length; i++) {
|
|
1141
1167
|
rec(current.items[i], currentPath.concat(`union[${i}]`));
|
|
1142
1168
|
}
|
|
@@ -1722,6 +1748,7 @@ async function createService(projectRoot, host = {
|
|
|
1722
1748
|
return new Service(projectRoot, sourceFileHandler, extracted);
|
|
1723
1749
|
}
|
|
1724
1750
|
class Service {
|
|
1751
|
+
projectRoot;
|
|
1725
1752
|
constructor(projectRoot, sourceFileHandler, extracted) {
|
|
1726
1753
|
this.sourceFileHandler = sourceFileHandler;
|
|
1727
1754
|
this.extracted = extracted;
|
|
@@ -2361,17 +2388,18 @@ function findNestedJsonValuesModuleErrors(schemas) {
|
|
|
2361
2388
|
// #region ValOps
|
|
2362
2389
|
class ValOps {
|
|
2363
2390
|
/** Sources from val modules, immutable (without patches or anything) */
|
|
2364
|
-
|
|
2391
|
+
sources;
|
|
2365
2392
|
/** The sha256 / hash of all sources + all schemas + config */
|
|
2366
|
-
|
|
2393
|
+
baseSha;
|
|
2367
2394
|
/** The sha256 / hash of all sources */
|
|
2368
|
-
|
|
2395
|
+
sourcesSha;
|
|
2369
2396
|
/** The sha256 / hash of config */
|
|
2370
|
-
|
|
2397
|
+
configSha;
|
|
2371
2398
|
/** Schema from val modules, immutable */
|
|
2372
|
-
|
|
2399
|
+
schemas;
|
|
2373
2400
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
2374
|
-
|
|
2401
|
+
schemaSha;
|
|
2402
|
+
modulesErrors;
|
|
2375
2403
|
/**
|
|
2376
2404
|
* What the SHAs above are a fold over, so they can be recomputed.
|
|
2377
2405
|
*
|
|
@@ -2379,7 +2407,7 @@ class ValOps {
|
|
|
2379
2407
|
* without re-evaluating the modules is a save, and it has to be able to move
|
|
2380
2408
|
* the SHAs with them.
|
|
2381
2409
|
*/
|
|
2382
|
-
|
|
2410
|
+
shaEntries;
|
|
2383
2411
|
/**
|
|
2384
2412
|
* The extraction's OWN module errors, which are what the fold was given.
|
|
2385
2413
|
*
|
|
@@ -2387,7 +2415,7 @@ class ValOps {
|
|
|
2387
2415
|
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
2388
2416
|
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
2389
2417
|
*/
|
|
2390
|
-
|
|
2418
|
+
shaModuleErrors;
|
|
2391
2419
|
/**
|
|
2392
2420
|
* What a save has told us each `.jsonValues()` entry now holds.
|
|
2393
2421
|
*
|
|
@@ -3147,7 +3175,8 @@ class ValOps {
|
|
|
3147
3175
|
// (must include all modules, not just those being validated, since conflicts can come from any module)
|
|
3148
3176
|
const galleryDirectoryToModules = new Map();
|
|
3149
3177
|
// Build a schema/source snapshot so the shared resolver can cross-reference
|
|
3150
|
-
//
|
|
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`.
|
|
3151
3180
|
const snapshot = {
|
|
3152
3181
|
schemas: {},
|
|
3153
3182
|
sources: {}
|
|
@@ -3227,7 +3256,7 @@ class ValOps {
|
|
|
3227
3256
|
};
|
|
3228
3257
|
if (validationErrors) {
|
|
3229
3258
|
for (const validationError of validationErrors) {
|
|
3230
|
-
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;
|
|
3231
3260
|
if (isOnlyFileCheckValidationError(validationError)) {
|
|
3232
3261
|
if (files[sourcePath]) {
|
|
3233
3262
|
addError({
|
|
@@ -3241,13 +3270,13 @@ class ValOps {
|
|
|
3241
3270
|
}
|
|
3242
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")) {
|
|
3243
3272
|
remoteFiles[sourcePath] = validationError.value;
|
|
3244
|
-
} else if (
|
|
3273
|
+
} else if (internal.isSchemaSourceFixError(validationError)) {
|
|
3245
3274
|
const resolved = internal.resolveSchemaSourceFixForError(validationError, snapshot);
|
|
3246
3275
|
if (resolved && resolved.status === "remaining") {
|
|
3247
3276
|
addError(resolved.error);
|
|
3248
3277
|
}
|
|
3249
3278
|
// resolved.status === "resolved" → drop silently
|
|
3250
|
-
} 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")) {
|
|
3251
3280
|
const TYPE_ERROR_MESSAGE = `This is most likely a Val version mismatch or Val bug.`;
|
|
3252
3281
|
if (!validationError.value || typeof validationError.value !== "object") {
|
|
3253
3282
|
addError({
|
|
@@ -3272,7 +3301,7 @@ class ValOps {
|
|
|
3272
3301
|
// If conflictingModules is empty, directory is unique — silently drop the error.
|
|
3273
3302
|
}
|
|
3274
3303
|
}
|
|
3275
|
-
} 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 {
|
|
3276
3305
|
addError(validationError);
|
|
3277
3306
|
}
|
|
3278
3307
|
}
|
|
@@ -4132,8 +4161,8 @@ class ValOps {
|
|
|
4132
4161
|
// #endregion history
|
|
4133
4162
|
}
|
|
4134
4163
|
function isOnlyFileCheckValidationError(validationError) {
|
|
4135
|
-
var _validationError$
|
|
4136
|
-
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")) {
|
|
4137
4166
|
return true;
|
|
4138
4167
|
}
|
|
4139
4168
|
return false;
|
|
@@ -5654,6 +5683,7 @@ function serializeSchemaSafely(schema) {
|
|
|
5654
5683
|
}
|
|
5655
5684
|
class ValOpsFS extends ValOps {
|
|
5656
5685
|
static VAL_DIR = ".val";
|
|
5686
|
+
host;
|
|
5657
5687
|
constructor(contentUrl, rootDir, valModules, options) {
|
|
5658
5688
|
super(valModules, options);
|
|
5659
5689
|
this.contentUrl = contentUrl;
|
|
@@ -5666,6 +5696,7 @@ class ValOpsFS extends ValOps {
|
|
|
5666
5696
|
* Change detection for `.jsonValues()` entry files, which no sha can see (their
|
|
5667
5697
|
* content lives behind a thunk that `JSON.stringify` drops).
|
|
5668
5698
|
*/
|
|
5699
|
+
jsonEntryFilesFingerprint;
|
|
5669
5700
|
|
|
5670
5701
|
/**
|
|
5671
5702
|
* Unpublished changes repair threw away, waiting to be told to somebody.
|
|
@@ -7015,7 +7046,11 @@ const GetApplicablePatches = z.z.object({
|
|
|
7015
7046
|
commitSha: z.z.string(),
|
|
7016
7047
|
deploymentState: z.z.string(),
|
|
7017
7048
|
createdAt: z.z.string(),
|
|
7018
|
-
updatedAt: z.z.string()
|
|
7049
|
+
updatedAt: z.z.string(),
|
|
7050
|
+
// The git message, where the content service knows it. See
|
|
7051
|
+
// `ValDeployment`: this is the only source for a deployment that Val
|
|
7052
|
+
// did not publish, and zod would otherwise strip it here.
|
|
7053
|
+
commitMessage: z.z.string().nullable().optional()
|
|
7019
7054
|
})).optional()
|
|
7020
7055
|
});
|
|
7021
7056
|
const FilesResponse = z.z.object({
|
|
@@ -7191,6 +7226,8 @@ const NonceResponse = z.z.object({
|
|
|
7191
7226
|
*/
|
|
7192
7227
|
const PATCH_GROUPS_CACHE_MS = 1000;
|
|
7193
7228
|
class ValOpsHttp extends ValOps {
|
|
7229
|
+
authHeaders;
|
|
7230
|
+
root;
|
|
7194
7231
|
constructor(contentUrl, project, commitSha,
|
|
7195
7232
|
// TODO: CommitSha
|
|
7196
7233
|
branch,
|
|
@@ -7616,7 +7653,8 @@ class ValOpsHttp extends ValOps {
|
|
|
7616
7653
|
deploymentId: deployment.deploymentId,
|
|
7617
7654
|
deploymentState: deployment.deploymentState,
|
|
7618
7655
|
createdAt: deployment.createdAt,
|
|
7619
|
-
updatedAt: deployment.updatedAt
|
|
7656
|
+
updatedAt: deployment.updatedAt,
|
|
7657
|
+
commitMessage: deployment.commitMessage
|
|
7620
7658
|
});
|
|
7621
7659
|
}
|
|
7622
7660
|
}
|
|
@@ -13545,6 +13583,8 @@ const MAX_CACHE_SIZE = 100 * 1024 * 1024; // 100 mb
|
|
|
13545
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
|
|
13546
13584
|
|
|
13547
13585
|
class ValModuleLoader {
|
|
13586
|
+
cache;
|
|
13587
|
+
cacheSize;
|
|
13548
13588
|
constructor(projectRoot, compilerOptions,
|
|
13549
13589
|
// TODO: remove this?
|
|
13550
13590
|
sourceFileHandler, host = {
|
|
@@ -15224,9 +15264,10 @@ async function handleExternalUpload() {
|
|
|
15224
15264
|
};
|
|
15225
15265
|
}
|
|
15226
15266
|
|
|
15227
|
-
// Fix handler registry. `keyof:check-keys
|
|
15228
|
-
// resolved upfront by the
|
|
15229
|
-
// 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.
|
|
15230
15271
|
const currentFixHandlers = {
|
|
15231
15272
|
"image:check-metadata": handleFileMetadata,
|
|
15232
15273
|
"image:add-metadata": handleFileMetadata,
|
|
@@ -15386,7 +15427,7 @@ async function evalValConfigFile(projectRoot, configFileName) {
|
|
|
15386
15427
|
},
|
|
15387
15428
|
fileName: valConfigPath
|
|
15388
15429
|
});
|
|
15389
|
-
const projectRootRequire =
|
|
15430
|
+
const projectRootRequire = createNodeRequire(valConfigPath);
|
|
15390
15431
|
const exportsObj = {};
|
|
15391
15432
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15392
15433
|
const sandbox = {
|
|
@@ -696,6 +696,32 @@ const getCompilerOptions = (rootDir, parseConfigHost) => {
|
|
|
696
696
|
return parsedConfigFile.options;
|
|
697
697
|
};
|
|
698
698
|
|
|
699
|
+
/**
|
|
700
|
+
* Node's `require`, resolving as if from `filename`.
|
|
701
|
+
*
|
|
702
|
+
* Use this instead of importing `createRequire` from `node:module` directly.
|
|
703
|
+
* webpack special-cases a `createRequire` binding imported from `module` /
|
|
704
|
+
* `node:module`: it tries to resolve the call's argument at build time, and
|
|
705
|
+
* when the argument is not a literal it gives up with
|
|
706
|
+
*
|
|
707
|
+
* module.createRequire failed parsing argument.
|
|
708
|
+
*
|
|
709
|
+
* Our argument is never a literal — it is a path inside the user's project,
|
|
710
|
+
* known only at runtime — so there is nothing for that analysis to find, and
|
|
711
|
+
* nothing the warning can tell anyone. It is emitted on every build of every
|
|
712
|
+
* Next app that bundles `@valbuild/server` into its Val API route, which is
|
|
713
|
+
* all of them. Reaching `createRequire` through the `Module` class is the same
|
|
714
|
+
* function and is not what webpack tags, so the call is invisible to it.
|
|
715
|
+
*
|
|
716
|
+
* It has to stay a real `node:module` import: jest's module registry hands out
|
|
717
|
+
* its own `node:module`, and a `require` obtained around it (via
|
|
718
|
+
* `process.getBuiltinModule`, say) would resolve against the real filesystem
|
|
719
|
+
* rather than the registry the tests run in.
|
|
720
|
+
*/
|
|
721
|
+
function createNodeRequire(filename) {
|
|
722
|
+
return node_module.Module.createRequire(filename);
|
|
723
|
+
}
|
|
724
|
+
|
|
699
725
|
/**
|
|
700
726
|
* The filesystem seam `loadValModules` reads through.
|
|
701
727
|
*
|
|
@@ -829,7 +855,7 @@ function loadModule(absPath, cache, compilerOptions, host) {
|
|
|
829
855
|
// Insert into the cache before evaluating so cyclic imports resolve.
|
|
830
856
|
cache[absPath] = moduleObj;
|
|
831
857
|
const dirName = path__namespace["default"].dirname(absPath);
|
|
832
|
-
const realRequire =
|
|
858
|
+
const realRequire = createNodeRequire(absPath);
|
|
833
859
|
const customRequire = spec => {
|
|
834
860
|
var _ts$resolveModuleName;
|
|
835
861
|
if (isStubbedSpecifier(spec)) {
|
|
@@ -1136,7 +1162,7 @@ function findNestedJsonValuesRecords(schema, path = []) {
|
|
|
1136
1162
|
case "array":
|
|
1137
1163
|
rec(current.item, currentPath.concat("*"));
|
|
1138
1164
|
return;
|
|
1139
|
-
case "union":
|
|
1165
|
+
case "discriminated-union":
|
|
1140
1166
|
for (let i = 0; i < current.items.length; i++) {
|
|
1141
1167
|
rec(current.items[i], currentPath.concat(`union[${i}]`));
|
|
1142
1168
|
}
|
|
@@ -1722,6 +1748,7 @@ async function createService(projectRoot, host = {
|
|
|
1722
1748
|
return new Service(projectRoot, sourceFileHandler, extracted);
|
|
1723
1749
|
}
|
|
1724
1750
|
class Service {
|
|
1751
|
+
projectRoot;
|
|
1725
1752
|
constructor(projectRoot, sourceFileHandler, extracted) {
|
|
1726
1753
|
this.sourceFileHandler = sourceFileHandler;
|
|
1727
1754
|
this.extracted = extracted;
|
|
@@ -2361,17 +2388,18 @@ function findNestedJsonValuesModuleErrors(schemas) {
|
|
|
2361
2388
|
// #region ValOps
|
|
2362
2389
|
class ValOps {
|
|
2363
2390
|
/** Sources from val modules, immutable (without patches or anything) */
|
|
2364
|
-
|
|
2391
|
+
sources;
|
|
2365
2392
|
/** The sha256 / hash of all sources + all schemas + config */
|
|
2366
|
-
|
|
2393
|
+
baseSha;
|
|
2367
2394
|
/** The sha256 / hash of all sources */
|
|
2368
|
-
|
|
2395
|
+
sourcesSha;
|
|
2369
2396
|
/** The sha256 / hash of config */
|
|
2370
|
-
|
|
2397
|
+
configSha;
|
|
2371
2398
|
/** Schema from val modules, immutable */
|
|
2372
|
-
|
|
2399
|
+
schemas;
|
|
2373
2400
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
2374
|
-
|
|
2401
|
+
schemaSha;
|
|
2402
|
+
modulesErrors;
|
|
2375
2403
|
/**
|
|
2376
2404
|
* What the SHAs above are a fold over, so they can be recomputed.
|
|
2377
2405
|
*
|
|
@@ -2379,7 +2407,7 @@ class ValOps {
|
|
|
2379
2407
|
* without re-evaluating the modules is a save, and it has to be able to move
|
|
2380
2408
|
* the SHAs with them.
|
|
2381
2409
|
*/
|
|
2382
|
-
|
|
2410
|
+
shaEntries;
|
|
2383
2411
|
/**
|
|
2384
2412
|
* The extraction's OWN module errors, which are what the fold was given.
|
|
2385
2413
|
*
|
|
@@ -2387,7 +2415,7 @@ class ValOps {
|
|
|
2387
2415
|
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
2388
2416
|
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
2389
2417
|
*/
|
|
2390
|
-
|
|
2418
|
+
shaModuleErrors;
|
|
2391
2419
|
/**
|
|
2392
2420
|
* What a save has told us each `.jsonValues()` entry now holds.
|
|
2393
2421
|
*
|
|
@@ -3147,7 +3175,8 @@ class ValOps {
|
|
|
3147
3175
|
// (must include all modules, not just those being validated, since conflicts can come from any module)
|
|
3148
3176
|
const galleryDirectoryToModules = new Map();
|
|
3149
3177
|
// Build a schema/source snapshot so the shared resolver can cross-reference
|
|
3150
|
-
//
|
|
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`.
|
|
3151
3180
|
const snapshot = {
|
|
3152
3181
|
schemas: {},
|
|
3153
3182
|
sources: {}
|
|
@@ -3227,7 +3256,7 @@ class ValOps {
|
|
|
3227
3256
|
};
|
|
3228
3257
|
if (validationErrors) {
|
|
3229
3258
|
for (const validationError of validationErrors) {
|
|
3230
|
-
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;
|
|
3231
3260
|
if (isOnlyFileCheckValidationError(validationError)) {
|
|
3232
3261
|
if (files[sourcePath]) {
|
|
3233
3262
|
addError({
|
|
@@ -3241,13 +3270,13 @@ class ValOps {
|
|
|
3241
3270
|
}
|
|
3242
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")) {
|
|
3243
3272
|
remoteFiles[sourcePath] = validationError.value;
|
|
3244
|
-
} else if (
|
|
3273
|
+
} else if (internal.isSchemaSourceFixError(validationError)) {
|
|
3245
3274
|
const resolved = internal.resolveSchemaSourceFixForError(validationError, snapshot);
|
|
3246
3275
|
if (resolved && resolved.status === "remaining") {
|
|
3247
3276
|
addError(resolved.error);
|
|
3248
3277
|
}
|
|
3249
3278
|
// resolved.status === "resolved" → drop silently
|
|
3250
|
-
} 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")) {
|
|
3251
3280
|
const TYPE_ERROR_MESSAGE = `This is most likely a Val version mismatch or Val bug.`;
|
|
3252
3281
|
if (!validationError.value || typeof validationError.value !== "object") {
|
|
3253
3282
|
addError({
|
|
@@ -3272,7 +3301,7 @@ class ValOps {
|
|
|
3272
3301
|
// If conflictingModules is empty, directory is unique — silently drop the error.
|
|
3273
3302
|
}
|
|
3274
3303
|
}
|
|
3275
|
-
} 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 {
|
|
3276
3305
|
addError(validationError);
|
|
3277
3306
|
}
|
|
3278
3307
|
}
|
|
@@ -4132,8 +4161,8 @@ class ValOps {
|
|
|
4132
4161
|
// #endregion history
|
|
4133
4162
|
}
|
|
4134
4163
|
function isOnlyFileCheckValidationError(validationError) {
|
|
4135
|
-
var _validationError$
|
|
4136
|
-
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")) {
|
|
4137
4166
|
return true;
|
|
4138
4167
|
}
|
|
4139
4168
|
return false;
|
|
@@ -5654,6 +5683,7 @@ function serializeSchemaSafely(schema) {
|
|
|
5654
5683
|
}
|
|
5655
5684
|
class ValOpsFS extends ValOps {
|
|
5656
5685
|
static VAL_DIR = ".val";
|
|
5686
|
+
host;
|
|
5657
5687
|
constructor(contentUrl, rootDir, valModules, options) {
|
|
5658
5688
|
super(valModules, options);
|
|
5659
5689
|
this.contentUrl = contentUrl;
|
|
@@ -5666,6 +5696,7 @@ class ValOpsFS extends ValOps {
|
|
|
5666
5696
|
* Change detection for `.jsonValues()` entry files, which no sha can see (their
|
|
5667
5697
|
* content lives behind a thunk that `JSON.stringify` drops).
|
|
5668
5698
|
*/
|
|
5699
|
+
jsonEntryFilesFingerprint;
|
|
5669
5700
|
|
|
5670
5701
|
/**
|
|
5671
5702
|
* Unpublished changes repair threw away, waiting to be told to somebody.
|
|
@@ -7015,7 +7046,11 @@ const GetApplicablePatches = z.z.object({
|
|
|
7015
7046
|
commitSha: z.z.string(),
|
|
7016
7047
|
deploymentState: z.z.string(),
|
|
7017
7048
|
createdAt: z.z.string(),
|
|
7018
|
-
updatedAt: z.z.string()
|
|
7049
|
+
updatedAt: z.z.string(),
|
|
7050
|
+
// The git message, where the content service knows it. See
|
|
7051
|
+
// `ValDeployment`: this is the only source for a deployment that Val
|
|
7052
|
+
// did not publish, and zod would otherwise strip it here.
|
|
7053
|
+
commitMessage: z.z.string().nullable().optional()
|
|
7019
7054
|
})).optional()
|
|
7020
7055
|
});
|
|
7021
7056
|
const FilesResponse = z.z.object({
|
|
@@ -7191,6 +7226,8 @@ const NonceResponse = z.z.object({
|
|
|
7191
7226
|
*/
|
|
7192
7227
|
const PATCH_GROUPS_CACHE_MS = 1000;
|
|
7193
7228
|
class ValOpsHttp extends ValOps {
|
|
7229
|
+
authHeaders;
|
|
7230
|
+
root;
|
|
7194
7231
|
constructor(contentUrl, project, commitSha,
|
|
7195
7232
|
// TODO: CommitSha
|
|
7196
7233
|
branch,
|
|
@@ -7616,7 +7653,8 @@ class ValOpsHttp extends ValOps {
|
|
|
7616
7653
|
deploymentId: deployment.deploymentId,
|
|
7617
7654
|
deploymentState: deployment.deploymentState,
|
|
7618
7655
|
createdAt: deployment.createdAt,
|
|
7619
|
-
updatedAt: deployment.updatedAt
|
|
7656
|
+
updatedAt: deployment.updatedAt,
|
|
7657
|
+
commitMessage: deployment.commitMessage
|
|
7620
7658
|
});
|
|
7621
7659
|
}
|
|
7622
7660
|
}
|
|
@@ -13545,6 +13583,8 @@ const MAX_CACHE_SIZE = 100 * 1024 * 1024; // 100 mb
|
|
|
13545
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
|
|
13546
13584
|
|
|
13547
13585
|
class ValModuleLoader {
|
|
13586
|
+
cache;
|
|
13587
|
+
cacheSize;
|
|
13548
13588
|
constructor(projectRoot, compilerOptions,
|
|
13549
13589
|
// TODO: remove this?
|
|
13550
13590
|
sourceFileHandler, host = {
|
|
@@ -15224,9 +15264,10 @@ async function handleExternalUpload() {
|
|
|
15224
15264
|
};
|
|
15225
15265
|
}
|
|
15226
15266
|
|
|
15227
|
-
// Fix handler registry. `keyof:check-keys
|
|
15228
|
-
// resolved upfront by the
|
|
15229
|
-
// 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.
|
|
15230
15271
|
const currentFixHandlers = {
|
|
15231
15272
|
"image:check-metadata": handleFileMetadata,
|
|
15232
15273
|
"image:add-metadata": handleFileMetadata,
|
|
@@ -15386,7 +15427,7 @@ async function evalValConfigFile(projectRoot, configFileName) {
|
|
|
15386
15427
|
},
|
|
15387
15428
|
fileName: valConfigPath
|
|
15388
15429
|
});
|
|
15389
|
-
const projectRootRequire =
|
|
15430
|
+
const projectRootRequire = createNodeRequire(valConfigPath);
|
|
15390
15431
|
const exportsObj = {};
|
|
15391
15432
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15392
15433
|
const sandbox = {
|
|
@@ -7,8 +7,8 @@ import * as path from 'path';
|
|
|
7
7
|
import path__default from 'path';
|
|
8
8
|
import fs, { promises } from 'fs';
|
|
9
9
|
import vm from 'node:vm';
|
|
10
|
-
import { 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';
|
|
10
|
+
import { Module } from 'node:module';
|
|
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';
|
|
@@ -662,6 +662,32 @@ const getCompilerOptions = (rootDir, parseConfigHost) => {
|
|
|
662
662
|
return parsedConfigFile.options;
|
|
663
663
|
};
|
|
664
664
|
|
|
665
|
+
/**
|
|
666
|
+
* Node's `require`, resolving as if from `filename`.
|
|
667
|
+
*
|
|
668
|
+
* Use this instead of importing `createRequire` from `node:module` directly.
|
|
669
|
+
* webpack special-cases a `createRequire` binding imported from `module` /
|
|
670
|
+
* `node:module`: it tries to resolve the call's argument at build time, and
|
|
671
|
+
* when the argument is not a literal it gives up with
|
|
672
|
+
*
|
|
673
|
+
* module.createRequire failed parsing argument.
|
|
674
|
+
*
|
|
675
|
+
* Our argument is never a literal — it is a path inside the user's project,
|
|
676
|
+
* known only at runtime — so there is nothing for that analysis to find, and
|
|
677
|
+
* nothing the warning can tell anyone. It is emitted on every build of every
|
|
678
|
+
* Next app that bundles `@valbuild/server` into its Val API route, which is
|
|
679
|
+
* all of them. Reaching `createRequire` through the `Module` class is the same
|
|
680
|
+
* function and is not what webpack tags, so the call is invisible to it.
|
|
681
|
+
*
|
|
682
|
+
* It has to stay a real `node:module` import: jest's module registry hands out
|
|
683
|
+
* its own `node:module`, and a `require` obtained around it (via
|
|
684
|
+
* `process.getBuiltinModule`, say) would resolve against the real filesystem
|
|
685
|
+
* rather than the registry the tests run in.
|
|
686
|
+
*/
|
|
687
|
+
function createNodeRequire(filename) {
|
|
688
|
+
return Module.createRequire(filename);
|
|
689
|
+
}
|
|
690
|
+
|
|
665
691
|
/**
|
|
666
692
|
* The filesystem seam `loadValModules` reads through.
|
|
667
693
|
*
|
|
@@ -795,7 +821,7 @@ function loadModule(absPath, cache, compilerOptions, host) {
|
|
|
795
821
|
// Insert into the cache before evaluating so cyclic imports resolve.
|
|
796
822
|
cache[absPath] = moduleObj;
|
|
797
823
|
const dirName = path__default.dirname(absPath);
|
|
798
|
-
const realRequire =
|
|
824
|
+
const realRequire = createNodeRequire(absPath);
|
|
799
825
|
const customRequire = spec => {
|
|
800
826
|
var _ts$resolveModuleName;
|
|
801
827
|
if (isStubbedSpecifier(spec)) {
|
|
@@ -1102,7 +1128,7 @@ function findNestedJsonValuesRecords(schema, path = []) {
|
|
|
1102
1128
|
case "array":
|
|
1103
1129
|
rec(current.item, currentPath.concat("*"));
|
|
1104
1130
|
return;
|
|
1105
|
-
case "union":
|
|
1131
|
+
case "discriminated-union":
|
|
1106
1132
|
for (let i = 0; i < current.items.length; i++) {
|
|
1107
1133
|
rec(current.items[i], currentPath.concat(`union[${i}]`));
|
|
1108
1134
|
}
|
|
@@ -1688,6 +1714,7 @@ async function createService(projectRoot, host = {
|
|
|
1688
1714
|
return new Service(projectRoot, sourceFileHandler, extracted);
|
|
1689
1715
|
}
|
|
1690
1716
|
class Service {
|
|
1717
|
+
projectRoot;
|
|
1691
1718
|
constructor(projectRoot, sourceFileHandler, extracted) {
|
|
1692
1719
|
this.sourceFileHandler = sourceFileHandler;
|
|
1693
1720
|
this.extracted = extracted;
|
|
@@ -2327,17 +2354,18 @@ function findNestedJsonValuesModuleErrors(schemas) {
|
|
|
2327
2354
|
// #region ValOps
|
|
2328
2355
|
class ValOps {
|
|
2329
2356
|
/** Sources from val modules, immutable (without patches or anything) */
|
|
2330
|
-
|
|
2357
|
+
sources;
|
|
2331
2358
|
/** The sha256 / hash of all sources + all schemas + config */
|
|
2332
|
-
|
|
2359
|
+
baseSha;
|
|
2333
2360
|
/** The sha256 / hash of all sources */
|
|
2334
|
-
|
|
2361
|
+
sourcesSha;
|
|
2335
2362
|
/** The sha256 / hash of config */
|
|
2336
|
-
|
|
2363
|
+
configSha;
|
|
2337
2364
|
/** Schema from val modules, immutable */
|
|
2338
|
-
|
|
2365
|
+
schemas;
|
|
2339
2366
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
2340
|
-
|
|
2367
|
+
schemaSha;
|
|
2368
|
+
modulesErrors;
|
|
2341
2369
|
/**
|
|
2342
2370
|
* What the SHAs above are a fold over, so they can be recomputed.
|
|
2343
2371
|
*
|
|
@@ -2345,7 +2373,7 @@ class ValOps {
|
|
|
2345
2373
|
* without re-evaluating the modules is a save, and it has to be able to move
|
|
2346
2374
|
* the SHAs with them.
|
|
2347
2375
|
*/
|
|
2348
|
-
|
|
2376
|
+
shaEntries;
|
|
2349
2377
|
/**
|
|
2350
2378
|
* The extraction's OWN module errors, which are what the fold was given.
|
|
2351
2379
|
*
|
|
@@ -2353,7 +2381,7 @@ class ValOps {
|
|
|
2353
2381
|
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
2354
2382
|
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
2355
2383
|
*/
|
|
2356
|
-
|
|
2384
|
+
shaModuleErrors;
|
|
2357
2385
|
/**
|
|
2358
2386
|
* What a save has told us each `.jsonValues()` entry now holds.
|
|
2359
2387
|
*
|
|
@@ -3113,7 +3141,8 @@ class ValOps {
|
|
|
3113
3141
|
// (must include all modules, not just those being validated, since conflicts can come from any module)
|
|
3114
3142
|
const galleryDirectoryToModules = new Map();
|
|
3115
3143
|
// Build a schema/source snapshot so the shared resolver can cross-reference
|
|
3116
|
-
//
|
|
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`.
|
|
3117
3146
|
const snapshot = {
|
|
3118
3147
|
schemas: {},
|
|
3119
3148
|
sources: {}
|
|
@@ -3193,7 +3222,7 @@ class ValOps {
|
|
|
3193
3222
|
};
|
|
3194
3223
|
if (validationErrors) {
|
|
3195
3224
|
for (const validationError of validationErrors) {
|
|
3196
|
-
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;
|
|
3197
3226
|
if (isOnlyFileCheckValidationError(validationError)) {
|
|
3198
3227
|
if (files[sourcePath]) {
|
|
3199
3228
|
addError({
|
|
@@ -3207,13 +3236,13 @@ class ValOps {
|
|
|
3207
3236
|
}
|
|
3208
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")) {
|
|
3209
3238
|
remoteFiles[sourcePath] = validationError.value;
|
|
3210
|
-
} else if ((
|
|
3239
|
+
} else if (isSchemaSourceFixError(validationError)) {
|
|
3211
3240
|
const resolved = resolveSchemaSourceFixForError(validationError, snapshot);
|
|
3212
3241
|
if (resolved && resolved.status === "remaining") {
|
|
3213
3242
|
addError(resolved.error);
|
|
3214
3243
|
}
|
|
3215
3244
|
// resolved.status === "resolved" → drop silently
|
|
3216
|
-
} 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")) {
|
|
3217
3246
|
const TYPE_ERROR_MESSAGE = `This is most likely a Val version mismatch or Val bug.`;
|
|
3218
3247
|
if (!validationError.value || typeof validationError.value !== "object") {
|
|
3219
3248
|
addError({
|
|
@@ -3238,7 +3267,7 @@ class ValOps {
|
|
|
3238
3267
|
// If conflictingModules is empty, directory is unique — silently drop the error.
|
|
3239
3268
|
}
|
|
3240
3269
|
}
|
|
3241
|
-
} 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 {
|
|
3242
3271
|
addError(validationError);
|
|
3243
3272
|
}
|
|
3244
3273
|
}
|
|
@@ -4098,8 +4127,8 @@ class ValOps {
|
|
|
4098
4127
|
// #endregion history
|
|
4099
4128
|
}
|
|
4100
4129
|
function isOnlyFileCheckValidationError(validationError) {
|
|
4101
|
-
var _validationError$
|
|
4102
|
-
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")) {
|
|
4103
4132
|
return true;
|
|
4104
4133
|
}
|
|
4105
4134
|
return false;
|
|
@@ -5620,6 +5649,7 @@ function serializeSchemaSafely(schema) {
|
|
|
5620
5649
|
}
|
|
5621
5650
|
class ValOpsFS extends ValOps {
|
|
5622
5651
|
static VAL_DIR = ".val";
|
|
5652
|
+
host;
|
|
5623
5653
|
constructor(contentUrl, rootDir, valModules, options) {
|
|
5624
5654
|
super(valModules, options);
|
|
5625
5655
|
this.contentUrl = contentUrl;
|
|
@@ -5632,6 +5662,7 @@ class ValOpsFS extends ValOps {
|
|
|
5632
5662
|
* Change detection for `.jsonValues()` entry files, which no sha can see (their
|
|
5633
5663
|
* content lives behind a thunk that `JSON.stringify` drops).
|
|
5634
5664
|
*/
|
|
5665
|
+
jsonEntryFilesFingerprint;
|
|
5635
5666
|
|
|
5636
5667
|
/**
|
|
5637
5668
|
* Unpublished changes repair threw away, waiting to be told to somebody.
|
|
@@ -6981,7 +7012,11 @@ const GetApplicablePatches = z.object({
|
|
|
6981
7012
|
commitSha: z.string(),
|
|
6982
7013
|
deploymentState: z.string(),
|
|
6983
7014
|
createdAt: z.string(),
|
|
6984
|
-
updatedAt: z.string()
|
|
7015
|
+
updatedAt: z.string(),
|
|
7016
|
+
// The git message, where the content service knows it. See
|
|
7017
|
+
// `ValDeployment`: this is the only source for a deployment that Val
|
|
7018
|
+
// did not publish, and zod would otherwise strip it here.
|
|
7019
|
+
commitMessage: z.string().nullable().optional()
|
|
6985
7020
|
})).optional()
|
|
6986
7021
|
});
|
|
6987
7022
|
const FilesResponse = z.object({
|
|
@@ -7157,6 +7192,8 @@ const NonceResponse = z.object({
|
|
|
7157
7192
|
*/
|
|
7158
7193
|
const PATCH_GROUPS_CACHE_MS = 1000;
|
|
7159
7194
|
class ValOpsHttp extends ValOps {
|
|
7195
|
+
authHeaders;
|
|
7196
|
+
root;
|
|
7160
7197
|
constructor(contentUrl, project, commitSha,
|
|
7161
7198
|
// TODO: CommitSha
|
|
7162
7199
|
branch,
|
|
@@ -7582,7 +7619,8 @@ class ValOpsHttp extends ValOps {
|
|
|
7582
7619
|
deploymentId: deployment.deploymentId,
|
|
7583
7620
|
deploymentState: deployment.deploymentState,
|
|
7584
7621
|
createdAt: deployment.createdAt,
|
|
7585
|
-
updatedAt: deployment.updatedAt
|
|
7622
|
+
updatedAt: deployment.updatedAt,
|
|
7623
|
+
commitMessage: deployment.commitMessage
|
|
7586
7624
|
});
|
|
7587
7625
|
}
|
|
7588
7626
|
}
|
|
@@ -13511,6 +13549,8 @@ const MAX_CACHE_SIZE = 100 * 1024 * 1024; // 100 mb
|
|
|
13511
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
|
|
13512
13550
|
|
|
13513
13551
|
class ValModuleLoader {
|
|
13552
|
+
cache;
|
|
13553
|
+
cacheSize;
|
|
13514
13554
|
constructor(projectRoot, compilerOptions,
|
|
13515
13555
|
// TODO: remove this?
|
|
13516
13556
|
sourceFileHandler, host = {
|
|
@@ -15190,9 +15230,10 @@ async function handleExternalUpload() {
|
|
|
15190
15230
|
};
|
|
15191
15231
|
}
|
|
15192
15232
|
|
|
15193
|
-
// Fix handler registry. `keyof:check-keys
|
|
15194
|
-
// resolved upfront by the
|
|
15195
|
-
// 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.
|
|
15196
15237
|
const currentFixHandlers = {
|
|
15197
15238
|
"image:check-metadata": handleFileMetadata,
|
|
15198
15239
|
"image:add-metadata": handleFileMetadata,
|
|
@@ -15352,7 +15393,7 @@ async function evalValConfigFile(projectRoot, configFileName) {
|
|
|
15352
15393
|
},
|
|
15353
15394
|
fileName: valConfigPath
|
|
15354
15395
|
});
|
|
15355
|
-
const projectRootRequire =
|
|
15396
|
+
const projectRootRequire = createNodeRequire(valConfigPath);
|
|
15356
15397
|
const exportsObj = {};
|
|
15357
15398
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15358
15399
|
const sandbox = {
|
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.127.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/
|
|
34
|
-
"@valbuild/
|
|
32
|
+
"@valbuild/shared": "0.127.0",
|
|
33
|
+
"@valbuild/ui": "0.127.0",
|
|
34
|
+
"@valbuild/core": "0.127.0"
|
|
35
35
|
},
|
|
36
36
|
"engines": {
|
|
37
37
|
"node": "^20.19.0 || >=22"
|