@valbuild/shared 0.123.2 → 0.124.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/dist/declarations/src/internal/ApiRoutes.d.ts +77 -0
- package/dist/declarations/src/internal/search/searchIndex.d.ts +31 -2
- package/internal/dist/valbuild-shared-internal.cjs.dev.js +183 -145
- package/internal/dist/valbuild-shared-internal.cjs.prod.js +183 -145
- package/internal/dist/valbuild-shared-internal.esm.js +183 -145
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,113 @@
|
|
|
1
1
|
# @valbuild/shared
|
|
2
2
|
|
|
3
|
+
## 0.124.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#639](https://github.com/valbuild/val/pull/639) [`ad7fff4`](https://github.com/valbuild/val/commit/ad7fff4cc8cea98c506cf7ff9b4e8d6e5ffa4055) Thanks [@freekh](https://github.com/freekh)! - Show `.jsonValues()` entries in the history pane
|
|
8
|
+
|
|
9
|
+
A `.jsonValues()` record keeps each entry's content in its own `*.val.json`
|
|
10
|
+
file; the module's own content is just markers pointing at them. The history
|
|
11
|
+
pane had no way to fetch those files for a past commit, so every entry rendered
|
|
12
|
+
as an **empty field** — which reads as "the author left this blank", about
|
|
13
|
+
content that was simply stored somewhere else.
|
|
14
|
+
|
|
15
|
+
Entries now load in the history pane the same way they load in the Studio: one
|
|
16
|
+
at a time, when you open one. A commit with a thousand support pages costs
|
|
17
|
+
nothing until you look at one of them.
|
|
18
|
+
|
|
19
|
+
An entry that cannot be read says so instead of rendering blank — including the
|
|
20
|
+
case where the key did not exist yet at that commit, which is a real answer
|
|
21
|
+
rather than an error.
|
|
22
|
+
|
|
23
|
+
### Patch Changes
|
|
24
|
+
|
|
25
|
+
- [#639](https://github.com/valbuild/val/pull/639) [`ad7fff4`](https://github.com/valbuild/val/commit/ad7fff4cc8cea98c506cf7ff9b4e8d6e5ffa4055) Thanks [@freekh](https://github.com/freekh)! - Require a session to read a file from history
|
|
26
|
+
|
|
27
|
+
`GET /api/val/history/files` served a file at a given commit to anyone who
|
|
28
|
+
asked. It followed the reasoning of `/api/val/files`, which is deliberately
|
|
29
|
+
open — and neither half of that reasoning applies to it:
|
|
30
|
+
|
|
31
|
+
- `/files` stands on `patch_id` being an unguessable UUID. A **commit sha is
|
|
32
|
+
published** — `git log`, the GitHub UI, every pull request — so it is no
|
|
33
|
+
substitute for a credential.
|
|
34
|
+
- `/files` also _cannot_ require auth: draft images are fetched by the app's own
|
|
35
|
+
backend during Next image optimisation, with no cookies to send. Nothing
|
|
36
|
+
fetches history files server-side; both callers are the Studio, in a browser
|
|
37
|
+
that already holds the session.
|
|
38
|
+
|
|
39
|
+
So history files now require a session. `/files` is unchanged, and the reason
|
|
40
|
+
the two differ is written down in `architecture/media.md` so it is not "fixed"
|
|
41
|
+
in either direction later.
|
|
42
|
+
|
|
43
|
+
No action needed: the Studio sends its session cookie automatically.
|
|
44
|
+
|
|
45
|
+
- Updated dependencies [[`aa89fc2`](https://github.com/valbuild/val/commit/aa89fc26de7028b3c5a1666b99afc03b39e92769)]:
|
|
46
|
+
- @valbuild/core@0.124.0
|
|
47
|
+
|
|
48
|
+
## 0.123.3
|
|
49
|
+
|
|
50
|
+
### Patch Changes
|
|
51
|
+
|
|
52
|
+
- [#633](https://github.com/valbuild/val/pull/633) [`accf4f8`](https://github.com/valbuild/val/commit/accf4f852fe3400d762cc14e80316da741a69a9a) Thanks [@freekh](https://github.com/freekh)! - Stop `@valbuild/shared` replacing a consumer's own flexsearch types
|
|
53
|
+
|
|
54
|
+
`@valbuild/shared` gained a flexsearch dependency in 0.123.0, for
|
|
55
|
+
`search_content`, and typed its exported `SearchIndex.index` as flexsearch's
|
|
56
|
+
own `Index`. That put `import { Index } from "flexsearch"` into the published
|
|
57
|
+
`searchIndex.d.ts` — and flexsearch's type entry opens with
|
|
58
|
+
`declare module "flexsearch"`, which is an AMBIENT module declaration and so
|
|
59
|
+
global to a whole TypeScript program.
|
|
60
|
+
|
|
61
|
+
The effect on a project that uses flexsearch itself, at a different version:
|
|
62
|
+
its own calls are checked against the copy Val dragged in. valbuild/web pins
|
|
63
|
+
flexsearch 0.7 and builds an index with
|
|
64
|
+
`new flexsearch.Document({ language: "en", … })`; on `@valbuild/shared@0.123.2`
|
|
65
|
+
that stopped compiling, because 0.8's `DocumentOptions` has no `language`. Its
|
|
66
|
+
resolved copy was still 0.7 — only the types had been swapped underneath it.
|
|
67
|
+
|
|
68
|
+
`SearchIndex.index` is now a structural type covering the three methods this
|
|
69
|
+
package calls, so nothing in the published declarations names flexsearch. The
|
|
70
|
+
library is still used to build the index; that is a value import, which never
|
|
71
|
+
reaches a `.d.ts`.
|
|
72
|
+
|
|
73
|
+
No API change: `SearchIndex` is still assignable from a real flexsearch
|
|
74
|
+
`Index`, and `noFlexsearchInPublishedTypes.test.ts` asserts both halves of that
|
|
75
|
+
— that no source file names flexsearch in a type position, and that a real
|
|
76
|
+
`Index` still satisfies the stand-in, so it cannot drift from the library
|
|
77
|
+
unnoticed.
|
|
78
|
+
|
|
79
|
+
- [#628](https://github.com/valbuild/val/pull/628) [`aef45ce`](https://github.com/valbuild/val/commit/aef45ce3ef269f1b6221de44a56df0f6a0d9dbbd) Thanks [@freekh](https://github.com/freekh)! - Stop the serialized-schema parser dropping schema metadata
|
|
80
|
+
|
|
81
|
+
`SerializedSchema` in `@valbuild/shared` is a zod mirror of the serialized
|
|
82
|
+
schema type, and its `z.object`s strip keys they do not declare. Five fields
|
|
83
|
+
were declared on some schemas and forgotten on others:
|
|
84
|
+
|
|
85
|
+
- `customValidate` — missing on twelve of the eighteen schemas. This is the flag
|
|
86
|
+
that says a schema declares a `.validate()`; the function itself cannot
|
|
87
|
+
serialize, so the flag is the only thing that tells the Studio to run the
|
|
88
|
+
custom validators against the real instance.
|
|
89
|
+
- `description` — missing on thirteen, so a `.describe()` went unseen.
|
|
90
|
+
- `remote` and `referencedModule` — missing on `s.image()` and `s.file()`, so a
|
|
91
|
+
remote field read as local and a gallery-backed field lost the gallery it
|
|
92
|
+
reads its dimensions and mime type from.
|
|
93
|
+
- the `message` on a `.regexp(pattern, message)` — so a field with a custom
|
|
94
|
+
pattern message fell back to the generic "Expected string to match reg
|
|
95
|
+
exp: …".
|
|
96
|
+
|
|
97
|
+
Because it strips rather than rejects, nothing failed and nothing said so. The
|
|
98
|
+
live `/schema` route was unaffected — `ValClient` validates the response and
|
|
99
|
+
then returns the raw JSON — but the history path consumes the parsed output, so
|
|
100
|
+
in a commit or historical patch-set view (`getModuleAtCommit`,
|
|
101
|
+
`getHistoricalPatchSet`) a schema's custom validators, description, remoteness
|
|
102
|
+
and backing gallery all quietly disappeared.
|
|
103
|
+
|
|
104
|
+
The fields every serialized schema shares are now spread from one
|
|
105
|
+
`commonSchemaFields` object instead of being retyped eighteen times, which is
|
|
106
|
+
how they drifted apart in the first place. A round-trip test walks each schema's
|
|
107
|
+
serialized output against the parsed result and fails with the path of any key
|
|
108
|
+
that did not survive, so a field added to a serialized schema and forgotten in
|
|
109
|
+
the parser is caught without anyone having to remember to assert it.
|
|
110
|
+
|
|
3
111
|
## 0.123.2
|
|
4
112
|
|
|
5
113
|
### Patch Changes
|
|
@@ -1329,6 +1329,80 @@ export declare const Api: {
|
|
|
1329
1329
|
* actually mounts. A file at a fixed commit cannot change, so the response is
|
|
1330
1330
|
* immutable and the browser's own cache handles flipping between commits.
|
|
1331
1331
|
*/
|
|
1332
|
+
/**
|
|
1333
|
+
* One `.jsonValues()` entry's content, as it was at a commit.
|
|
1334
|
+
*
|
|
1335
|
+
* The history pane's counterpart to `/json`. A `.jsonValues()` record's
|
|
1336
|
+
* source is only `{_type:"json"}` markers - the content is per entry, fetched
|
|
1337
|
+
* on demand - so without this the commit pane rendered every entry as an
|
|
1338
|
+
* empty field, which is a claim that the author left it blank.
|
|
1339
|
+
*
|
|
1340
|
+
* One entry per request, deliberately: the store fetches an entry when
|
|
1341
|
+
* something reads inside it, so a batch would mean guessing which entries the
|
|
1342
|
+
* pane is about to show. Authenticated for the same reasons as
|
|
1343
|
+
* `/history/files` below.
|
|
1344
|
+
*/
|
|
1345
|
+
"/history/json": {
|
|
1346
|
+
GET: {
|
|
1347
|
+
req: {
|
|
1348
|
+
query: {
|
|
1349
|
+
commit_sha: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string, string[]>>;
|
|
1350
|
+
path: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string, string[]>>;
|
|
1351
|
+
key: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string, string[]>>;
|
|
1352
|
+
};
|
|
1353
|
+
cookies: {
|
|
1354
|
+
val_session: z.ZodOptional<z.ZodString>;
|
|
1355
|
+
};
|
|
1356
|
+
};
|
|
1357
|
+
res: z.ZodUnion<readonly [z.ZodObject<{
|
|
1358
|
+
status: z.ZodLiteral<401>;
|
|
1359
|
+
json: z.ZodObject<{
|
|
1360
|
+
message: z.ZodString;
|
|
1361
|
+
}, z.core.$strip>;
|
|
1362
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1363
|
+
status: z.ZodLiteral<404>;
|
|
1364
|
+
json: z.ZodObject<{
|
|
1365
|
+
message: z.ZodString;
|
|
1366
|
+
}, z.core.$strip>;
|
|
1367
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1368
|
+
status: z.ZodLiteral<400>;
|
|
1369
|
+
json: z.ZodIntersection<z.ZodObject<{
|
|
1370
|
+
message: z.ZodString;
|
|
1371
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1372
|
+
kind: z.ZodOptional<z.ZodString>;
|
|
1373
|
+
}, z.core.$strip>>;
|
|
1374
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1375
|
+
status: z.ZodLiteral<500>;
|
|
1376
|
+
json: z.ZodIntersection<z.ZodObject<{
|
|
1377
|
+
message: z.ZodString;
|
|
1378
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1379
|
+
kind: z.ZodOptional<z.ZodString>;
|
|
1380
|
+
}, z.core.$strip>>;
|
|
1381
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1382
|
+
status: z.ZodLiteral<200>;
|
|
1383
|
+
json: z.ZodObject<{
|
|
1384
|
+
path: z.ZodString & z.ZodType<ModuleFilePath, string, z.core.$ZodTypeInternals<ModuleFilePath, string>>;
|
|
1385
|
+
key: z.ZodString;
|
|
1386
|
+
content: z.ZodUnknown;
|
|
1387
|
+
}, z.core.$strip>;
|
|
1388
|
+
}, z.core.$strip>]>;
|
|
1389
|
+
};
|
|
1390
|
+
};
|
|
1391
|
+
/**
|
|
1392
|
+
* A binary file as it was at a commit.
|
|
1393
|
+
*
|
|
1394
|
+
* AUTHENTICATED, unlike `/files` below - and the difference is not an
|
|
1395
|
+
* oversight in either direction. See the comment on `/files`: what makes it
|
|
1396
|
+
* safe to leave open is that a `patch_id` is an unguessable UUID, and what
|
|
1397
|
+
* makes leaving it open NECESSARY is that a draft image is fetched by the
|
|
1398
|
+
* app's own backend during Next image optimisation, with no cookies.
|
|
1399
|
+
*
|
|
1400
|
+
* Neither holds here. A commit sha is published - `git log`, the GitHub UI,
|
|
1401
|
+
* every PR - so it is not a secret to stand in for a credential. And nothing
|
|
1402
|
+
* fetches these server-side: they are read by the Studio, in a browser that
|
|
1403
|
+
* has the session cookie, for the history pane and for staging a restore.
|
|
1404
|
+
* So this one asks.
|
|
1405
|
+
*/
|
|
1332
1406
|
"/history/files": {
|
|
1333
1407
|
GET: {
|
|
1334
1408
|
req: {
|
|
@@ -1337,6 +1411,9 @@ export declare const Api: {
|
|
|
1337
1411
|
path: z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string, string[]>>;
|
|
1338
1412
|
remote: z.ZodOptional<z.ZodPipe<z.ZodArray<z.ZodString>, z.ZodTransform<string, string[]>>>;
|
|
1339
1413
|
};
|
|
1414
|
+
cookies: {
|
|
1415
|
+
val_session: z.ZodOptional<z.ZodString>;
|
|
1416
|
+
};
|
|
1340
1417
|
};
|
|
1341
1418
|
res: z.ZodUnion<readonly [z.ZodObject<{
|
|
1342
1419
|
status: z.ZodLiteral<401>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Json, ModuleFilePath, SerializedSchema, SourcePath } from "@valbuild/core";
|
|
2
|
-
import { Index } from "flexsearch";
|
|
3
2
|
/**
|
|
4
3
|
* The search index and the labels to render for its hits.
|
|
5
4
|
*
|
|
@@ -15,8 +14,37 @@ import { Index } from "flexsearch";
|
|
|
15
14
|
* them — an agent and an editor searching the same project should find the same
|
|
16
15
|
* things.
|
|
17
16
|
*/
|
|
17
|
+
/**
|
|
18
|
+
* The parts of FlexSearch's `Index` this module uses.
|
|
19
|
+
*
|
|
20
|
+
* Structural, rather than importing flexsearch's own `Index`, because
|
|
21
|
+
* {@link SearchIndex} is EXPORTED — and a `.d.ts` that names `flexsearch` pulls
|
|
22
|
+
* that package's `declare module "flexsearch"` into every consumer's TypeScript
|
|
23
|
+
* program. Ambient module declarations are global to a program, so a consumer
|
|
24
|
+
* with its own flexsearch at another version then checks its OWN calls against
|
|
25
|
+
* the copy we dragged in, whichever of the two wins.
|
|
26
|
+
*
|
|
27
|
+
* That is not hypothetical: `@valbuild/shared` gained a flexsearch dependency
|
|
28
|
+
* in 0.123.0 for `search_content`, and valbuild/web — which pins flexsearch
|
|
29
|
+
* 0.7 and calls `new flexsearch.Document({ language: "en", … })` — stopped
|
|
30
|
+
* building on 0.123.2, because 0.8's `DocumentOptions` has no `language`. Its
|
|
31
|
+
* own resolved copy was still 0.7; only the types had been replaced.
|
|
32
|
+
*
|
|
33
|
+
* Three methods is all this module calls, and none of their signatures here is
|
|
34
|
+
* a guess: `add` and `remove` are used in `indexModule`/`removeModule`, and
|
|
35
|
+
* `search`'s result is only ever `.length`-ed, `.slice`-d and mapped over as
|
|
36
|
+
* ids. `FlexSearch.Index` is still constructed with the real library in
|
|
37
|
+
* {@link createSearchIndex} — a value import, which does not reach the `.d.ts`.
|
|
38
|
+
*/
|
|
39
|
+
type SearchableIndex = {
|
|
40
|
+
add(id: string, content: string): void;
|
|
41
|
+
remove(id: string): void;
|
|
42
|
+
search(query: string, options: {
|
|
43
|
+
limit: number;
|
|
44
|
+
}): (string | number)[];
|
|
45
|
+
};
|
|
18
46
|
export type SearchIndex = {
|
|
19
|
-
index:
|
|
47
|
+
index: SearchableIndex;
|
|
20
48
|
pathToLabel: Map<string, string>;
|
|
21
49
|
/**
|
|
22
50
|
* Which document ids belong to which module, so one module can be re-indexed
|
|
@@ -74,3 +102,4 @@ export type SearchResults = {
|
|
|
74
102
|
totalIsLowerBound: boolean;
|
|
75
103
|
};
|
|
76
104
|
export declare function performSearch(searchIndex: SearchIndex | null, query: string, limit?: number, offset?: number): SearchResults;
|
|
105
|
+
export {};
|