@valbuild/server 0.132.0 → 0.133.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 +122 -0
- package/dist/declarations/src/ValOps.d.ts +50 -1
- package/dist/declarations/src/ValOpsHttp.d.ts +87 -6
- package/dist/declarations/src/ValRouter.d.ts +23 -10
- package/dist/declarations/src/ValServer.d.ts +42 -2
- package/dist/declarations/src/history/types.d.ts +4 -2
- package/dist/declarations/src/patch/jsonValuesPatch.d.ts +69 -1
- package/dist/valbuild-server.cjs.dev.js +1106 -350
- package/dist/valbuild-server.cjs.prod.js +1106 -350
- package/dist/valbuild-server.esm.js +1107 -351
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,127 @@
|
|
|
1
1
|
# @valbuild/server
|
|
2
2
|
|
|
3
|
+
## 0.133.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#700](https://github.com/valbuild/val/pull/700) [`802412b`](https://github.com/valbuild/val/commit/802412b92c06bc1abbca78c86885e39c8710dd83) Thanks [@freekh](https://github.com/freekh)! - http mode no longer needs a git repository
|
|
8
|
+
|
|
9
|
+
A Val app can now run in http mode with no commit and no branch — its content
|
|
10
|
+
service is the store of record, and git is an optional mirror of the code. This
|
|
11
|
+
is what `fs` mode has always done: it has never had git, and it works.
|
|
12
|
+
|
|
13
|
+
Before this, `VAL_API_KEY` and `VAL_SECRET` were not enough. `VAL_GIT_COMMIT`
|
|
14
|
+
and `VAL_GIT_BRANCH` were required too, so a deployment with no commit to name
|
|
15
|
+
either threw at boot or fell through to `fs` mode and reached for a working
|
|
16
|
+
tree that was not there.
|
|
17
|
+
|
|
18
|
+
**Breaking, if you pass `http` options in code.** `gitCommit` and `gitBranch`
|
|
19
|
+
are replaced by one optional `git`:
|
|
20
|
+
|
|
21
|
+
```diff
|
|
22
|
+
initValServer(valModules, config, {
|
|
23
|
+
http: {
|
|
24
|
+
apiKey,
|
|
25
|
+
valSecret,
|
|
26
|
+
- gitCommit: process.env.VAL_GIT_COMMIT,
|
|
27
|
+
- gitBranch: "main",
|
|
28
|
+
+ // Only for a project whose content is mirrored into a repository.
|
|
29
|
+
+ // Omit it entirely otherwise.
|
|
30
|
+
+ git: { commit: process.env.VAL_GIT_COMMIT, branch: "main" },
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`VAL_GIT_COMMIT` and `VAL_GIT_BRANCH` still work and are still read; they are
|
|
36
|
+
simply no longer required. Set both or neither — a commit without a branch, or
|
|
37
|
+
a branch without a commit, is refused at startup with a message naming the
|
|
38
|
+
missing half, rather than failing later at a publish.
|
|
39
|
+
|
|
40
|
+
**What a commit is for, where you have one.** Turning pending patches into new
|
|
41
|
+
`.val.ts` text means reading the current text first, and that read goes to the
|
|
42
|
+
content service at that commit. It is the publish path, not the serving path: a
|
|
43
|
+
committed render reads the source compiled into the build and asks the content
|
|
44
|
+
service nothing. With no repository there is nothing to write `.val.ts` into,
|
|
45
|
+
so a publish records the module's data and its schema and skips the file — and
|
|
46
|
+
that data is what history reads, so nothing is lost.
|
|
47
|
+
|
|
48
|
+
**A publish can now be refused by name, before it is attempted.** If a project
|
|
49
|
+
mirrors its commits into a repository but the running deployment was built
|
|
50
|
+
before that repository existed, it has no commit to write the mirror against.
|
|
51
|
+
Publishing anyway would save the content and silently leave the repository
|
|
52
|
+
behind. The Studio now disables Publish and shows why, and `/save` refuses with
|
|
53
|
+
a `no-base` code instead of failing partway.
|
|
54
|
+
|
|
55
|
+
**Also:** `ValCommit` and `HistoricalCommit` have nullable `parentCommitSha`
|
|
56
|
+
and `clientCommitSha`, and `/stat`'s `commitSha` is optional. A root commit has
|
|
57
|
+
no parent, and a publisher with no repository does not report where it was. If
|
|
58
|
+
you read these fields, handle `null`.
|
|
59
|
+
|
|
60
|
+
### Patch Changes
|
|
61
|
+
|
|
62
|
+
- Updated dependencies [[`2b9a51b`](https://github.com/valbuild/val/commit/2b9a51b7dbe2dff53b7686a4f3b7eb9bc5784fae), [`802412b`](https://github.com/valbuild/val/commit/802412b92c06bc1abbca78c86885e39c8710dd83)]:
|
|
63
|
+
- @valbuild/ui@0.133.0
|
|
64
|
+
- @valbuild/shared@0.133.0
|
|
65
|
+
|
|
66
|
+
## 0.132.1
|
|
67
|
+
|
|
68
|
+
### Patch Changes
|
|
69
|
+
|
|
70
|
+
- [#695](https://github.com/valbuild/val/pull/695) [`c07b1ab`](https://github.com/valbuild/val/commit/c07b1abe30e226c80ef7ec4b4f0f5ccdae061c11) Thanks [@freekh](https://github.com/freekh)! - A publish result can now say which commit it was built on, and what tree it points at
|
|
71
|
+
|
|
72
|
+
`CommitResult` gains two optional fields, `parent` and `tree`, filled in from
|
|
73
|
+
the content service's commit response when it reports them.
|
|
74
|
+
|
|
75
|
+
Both matter to a host that keeps its own record of what each commit changed —
|
|
76
|
+
a build cache, or an incremental publisher that rebuilds from the last thing it
|
|
77
|
+
built rather than from scratch. Such a host can only tell whether its record is
|
|
78
|
+
COMPLETE by chaining the commits it holds back to the one it last built. With
|
|
79
|
+
just a sha per commit the record is a set of snapshots with no way to notice a
|
|
80
|
+
gap, so a commit somebody else made in between is silently absent instead of
|
|
81
|
+
detected — and the host rebuilds from a source tree that is missing a change it
|
|
82
|
+
never knew about. `parent` is what closes that.
|
|
83
|
+
|
|
84
|
+
`tree` identifies the CONTENT of a commit rather than the commit itself, so two
|
|
85
|
+
commits carrying the same tree are the same source. A host that has already
|
|
86
|
+
built one of them can recognise the other and skip the work.
|
|
87
|
+
|
|
88
|
+
Both are optional, and absent means NOT REPORTED rather than absent-in-git: a
|
|
89
|
+
content service that predates these fields sends neither, and a caller must not
|
|
90
|
+
read a missing `parent` as "this is a root commit". They are plain strings
|
|
91
|
+
rather than branded shas for the same reason — they are passed through as what
|
|
92
|
+
a separately versioned service said, not as something this end has checked.
|
|
93
|
+
|
|
94
|
+
Nothing changes for a host that does not look at them. The publish route's own
|
|
95
|
+
response is unchanged.
|
|
96
|
+
|
|
97
|
+
- [#678](https://github.com/valbuild/val/pull/678) [`cbfa2b8`](https://github.com/valbuild/val/commit/cbfa2b884898f1603bde8e5aa5cd9da78778101f) Thanks [@freekh](https://github.com/freekh)! - Putting a whole module back works for `.jsonValues()` records
|
|
98
|
+
|
|
99
|
+
A `.jsonValues()` record's entries are not in the module's source: the `.val.ts`
|
|
100
|
+
holds `c.json(() => import("./entry.val.json"))` per entry and the content lives
|
|
101
|
+
in those files. Val already routed a patch that named an entry key into the
|
|
102
|
+
right file, but a patch that replaced the **whole record** named no key — so it
|
|
103
|
+
was applied as an ordinary source edit, writing over the imports that make the
|
|
104
|
+
entries load at all. "Put everything back" in the history pane left such a module
|
|
105
|
+
out for exactly that reason.
|
|
106
|
+
|
|
107
|
+
A whole-record write is now expanded into per-entry ops before anything acts on
|
|
108
|
+
it: an entry added, one removed, one changed, and nothing at all for an entry
|
|
109
|
+
that already holds what the write says — so putting a module back does not
|
|
110
|
+
rewrite every file in it. The same expansion produces the draft the Studio shows
|
|
111
|
+
and the files a publish writes, so a draft cannot show one thing and publish
|
|
112
|
+
another.
|
|
113
|
+
|
|
114
|
+
Nothing that writes a patch has to know a record is `.jsonValues()`: write the
|
|
115
|
+
module as if it were ordinary content, and it lands in the right files.
|
|
116
|
+
|
|
117
|
+
"Put everything back" and "Restore this whole module" now cover `.jsonValues()`
|
|
118
|
+
modules. They read each entry as it was at the commit and put the content back —
|
|
119
|
+
never the recorded source, which is markers rather than content, and is now
|
|
120
|
+
refused rather than written.
|
|
121
|
+
|
|
122
|
+
- Updated dependencies [[`c9a5cd3`](https://github.com/valbuild/val/commit/c9a5cd3a4ab5908ecb9757b7a95db17a77e3b173), [`f413c5c`](https://github.com/valbuild/val/commit/f413c5cebca27ba82052825abc8c632b6177747e), [`1ddf245`](https://github.com/valbuild/val/commit/1ddf245ec73ad5af8099c3d18d4d33c6a1cc1254), [`a19997a`](https://github.com/valbuild/val/commit/a19997a542e65cc1375837b1bdb11c8af9e10160), [`76c5d41`](https://github.com/valbuild/val/commit/76c5d41c3afa7cc8180d156c9e19fb082af7fba4), [`cbfa2b8`](https://github.com/valbuild/val/commit/cbfa2b884898f1603bde8e5aa5cd9da78778101f), [`003419a`](https://github.com/valbuild/val/commit/003419ab72f3069d92e67dfea931d5accc63e730)]:
|
|
123
|
+
- @valbuild/ui@0.132.1
|
|
124
|
+
|
|
3
125
|
## 0.132.0
|
|
4
126
|
|
|
5
127
|
### Minor Changes
|
|
@@ -137,7 +137,8 @@ export declare abstract class ValOps {
|
|
|
137
137
|
nonce: string;
|
|
138
138
|
baseSha: BaseSha;
|
|
139
139
|
schemaSha: SchemaSha;
|
|
140
|
-
|
|
140
|
+
/** Absent for a project with no repository. See `git` on ValApiOptions. */
|
|
141
|
+
commitSha?: CommitSha;
|
|
141
142
|
sourcesSha: SourcesSha;
|
|
142
143
|
patches: PatchId[];
|
|
143
144
|
} | {
|
|
@@ -401,6 +402,42 @@ export declare abstract class ValOps {
|
|
|
401
402
|
} | {
|
|
402
403
|
errorType: "patch-head-conflict";
|
|
403
404
|
}>>;
|
|
405
|
+
/**
|
|
406
|
+
* Why a publish cannot happen here, or `null` when one can.
|
|
407
|
+
*
|
|
408
|
+
* Named rather than thrown, and asked BEFORE the click: the Studio shows the
|
|
409
|
+
* reason and disables the action, instead of letting someone write a commit
|
|
410
|
+
* message and then meeting a failure from four layers down.
|
|
411
|
+
*
|
|
412
|
+
* `no-base` is the only code so far and means what it says: there is nowhere
|
|
413
|
+
* for this publish's commit to be based. Note which way round that is --
|
|
414
|
+
* a project whose content service is the store of record always HAS a base
|
|
415
|
+
* (the service's own chain, which mints its own shas), so the refusal is not
|
|
416
|
+
* about missing git. It is about a deployment that cannot do what its
|
|
417
|
+
* project requires.
|
|
418
|
+
*/
|
|
419
|
+
publishRefusal(): PublishRefusal | null;
|
|
420
|
+
/**
|
|
421
|
+
* Whether a commit here produces `.val.ts` TEXT as well as data.
|
|
422
|
+
*
|
|
423
|
+
* True everywhere there is somewhere to put it: a working tree in `fs` mode,
|
|
424
|
+
* a host holding its own source in memory mode, a git repository in `http`
|
|
425
|
+
* mode. False for an `http` project whose content service is the store of
|
|
426
|
+
* record and which has no repository attached -- see `git` on
|
|
427
|
+
* {@link ValApiOptions}.
|
|
428
|
+
*
|
|
429
|
+
* WHAT IS NOT AFFECTED, and it is the part worth being sure of:
|
|
430
|
+
* `moduleVersions` -- what each changed module IS after the commit, with its
|
|
431
|
+
* schema -- comes from `getSources(analysis)`, which applies the ops to
|
|
432
|
+
* Source in the stores. It does not go near the file text. So a commit with
|
|
433
|
+
* no mirror still records everything history and a later `connect-github`
|
|
434
|
+
* fold need; what it does not record is a rendering of that data as code.
|
|
435
|
+
*
|
|
436
|
+
* WHAT IS: the ops are no longer applied to the file text as well, so a
|
|
437
|
+
* patch that would not fit the `.val.ts` is not reported here. That check
|
|
438
|
+
* only ever existed for the text being produced, and there is none.
|
|
439
|
+
*/
|
|
440
|
+
protected readonly mirrorsSourceFiles: boolean;
|
|
404
441
|
/**
|
|
405
442
|
* Take the `.val.ts` text a commit produced as the new committed source.
|
|
406
443
|
*
|
|
@@ -624,6 +661,18 @@ export type OpsMetadata<T extends "file" | "image"> = {
|
|
|
624
661
|
}))[];
|
|
625
662
|
};
|
|
626
663
|
export type BinaryFileType = "file" | "image";
|
|
664
|
+
/**
|
|
665
|
+
* Why a publish is refused, in a form a person can be shown.
|
|
666
|
+
*
|
|
667
|
+
* `code` is for the Studio to branch on and `message` is what it says. Both,
|
|
668
|
+
* rather than a code and a lookup table on the client: the server knows what
|
|
669
|
+
* is actually missing -- which branch, which commit -- and a client-side table
|
|
670
|
+
* could only ever say the generic version.
|
|
671
|
+
*/
|
|
672
|
+
export type PublishRefusal = {
|
|
673
|
+
code: "no-base";
|
|
674
|
+
message: string;
|
|
675
|
+
};
|
|
627
676
|
export type PreparedCommit = {
|
|
628
677
|
/**
|
|
629
678
|
* Updated / new source files that are ready to be committed / saved.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type PatchId, type ModuleFilePath, ValModules } from "@valbuild/core";
|
|
2
2
|
import type { Patch as PatchT, ParentRef as ParentRefT } from "@valbuild/core/patch";
|
|
3
|
-
import { type AuthorId, type BaseSha, BinaryFileType, type CommitSha, GenericErrorMessage, MetadataOfType, OpsMetadata, PreparedCommit, ValOps, ValOpsOptions, WithGenericError, SaveSourceFilePatchResult, type PatchGroupMembership, SchemaSha, OrderedPatchesMetadata, OrderedPatches, SourcesSha } from "./ValOps.js";
|
|
3
|
+
import { type AuthorId, type BaseSha, BinaryFileType, type CommitSha, GenericErrorMessage, MetadataOfType, OpsMetadata, PreparedCommit, ValOps, ValOpsOptions, WithGenericError, SaveSourceFilePatchResult, type PatchGroupMembership, SchemaSha, OrderedPatchesMetadata, OrderedPatches, SourcesSha, type PublishRefusal } from "./ValOps.js";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import type { HistoryError } from "./history/HistoryError.js";
|
|
6
6
|
import type { AffectedFile, StoredModuleVersion, CommitPage, CommitPatch, HistoricalCommit } from "./history/types.js";
|
|
@@ -23,16 +23,69 @@ export type PatchGroupMutationResult = {
|
|
|
23
23
|
export declare class ValOpsHttp extends ValOps {
|
|
24
24
|
private readonly contentUrl;
|
|
25
25
|
private readonly project;
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The repository this project's commits are mirrored into, or `null`.
|
|
28
|
+
*
|
|
29
|
+
* `null` is a project whose content service is the store of record: it
|
|
30
|
+
* mints its own commit shas, and it knows this project's branch from the
|
|
31
|
+
* project itself. Every request below that would have carried a branch and
|
|
32
|
+
* a commit omits them instead, and the service answers from the project's
|
|
33
|
+
* own chain -- which is where those answers always came from.
|
|
34
|
+
*
|
|
35
|
+
* It is NOT a degraded mode. The one thing that genuinely needs a
|
|
36
|
+
* repository is producing the `.val.ts` text a commit mirrors, and a
|
|
37
|
+
* project with no repository has nothing to mirror into. See `git` on
|
|
38
|
+
* {@link ValApiOptions}.
|
|
39
|
+
*/
|
|
40
|
+
private readonly git;
|
|
28
41
|
private readonly authHeaders;
|
|
29
42
|
private readonly root;
|
|
30
43
|
/** Val's content service owns the store. See {@link ValOps.patchesAreLocal}. */
|
|
31
44
|
readonly patchesAreLocal = false;
|
|
32
45
|
/** See {@link ValOps.requiresAuth}. */
|
|
33
46
|
readonly requiresAuth = true;
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
/**
|
|
48
|
+
* A commit mirrors into `.val.ts` only when there is a repository.
|
|
49
|
+
*
|
|
50
|
+
* See {@link ValOps.mirrorsSourceFiles}. Set in the constructor rather than
|
|
51
|
+
* as an initialiser because it depends on `git`, and a class field
|
|
52
|
+
* initialiser runs before the constructor body has assigned it.
|
|
53
|
+
*/
|
|
54
|
+
protected readonly mirrorsSourceFiles: boolean;
|
|
55
|
+
/**
|
|
56
|
+
* What the content service last said this project expects of its publisher.
|
|
57
|
+
*
|
|
58
|
+
* `null` until something has asked it, which in practice is the first poll.
|
|
59
|
+
* It is remembered rather than asked for on demand because the answer is
|
|
60
|
+
* only wanted on the publish path, and that path already fetches the
|
|
61
|
+
* patches it is publishing -- so a dedicated request would be a second round
|
|
62
|
+
* trip for two fields that just arrived.
|
|
63
|
+
*
|
|
64
|
+
* It can be one poll out of date, and that is the right amount: the thing it
|
|
65
|
+
* changes is whether this deployment can mirror commits into a repository,
|
|
66
|
+
* which changes when a project CONNECTS one -- and a project that has just
|
|
67
|
+
* connected is one whose builds are about to be replaced anyway.
|
|
68
|
+
*/
|
|
69
|
+
private projectExpectation;
|
|
70
|
+
constructor(contentUrl: string, project: string,
|
|
71
|
+
/**
|
|
72
|
+
* The repository this project's commits are mirrored into, or `null`.
|
|
73
|
+
*
|
|
74
|
+
* `null` is a project whose content service is the store of record: it
|
|
75
|
+
* mints its own commit shas, and it knows this project's branch from the
|
|
76
|
+
* project itself. Every request below that would have carried a branch and
|
|
77
|
+
* a commit omits them instead, and the service answers from the project's
|
|
78
|
+
* own chain -- which is where those answers always came from.
|
|
79
|
+
*
|
|
80
|
+
* It is NOT a degraded mode. The one thing that genuinely needs a
|
|
81
|
+
* repository is producing the `.val.ts` text a commit mirrors, and a
|
|
82
|
+
* project with no repository has nothing to mirror into. See `git` on
|
|
83
|
+
* {@link ValApiOptions}.
|
|
84
|
+
*/
|
|
85
|
+
git: {
|
|
86
|
+
commit: string;
|
|
87
|
+
branch: string;
|
|
88
|
+
} | null,
|
|
36
89
|
/**
|
|
37
90
|
* An api key (how the app itself authenticates) or a personal access token
|
|
38
91
|
* (how the CLI authenticates after `val login`). Same two shapes as
|
|
@@ -50,6 +103,29 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
50
103
|
*/
|
|
51
104
|
root?: string;
|
|
52
105
|
});
|
|
106
|
+
/**
|
|
107
|
+
* A deployment that cannot mirror a project which expects to be mirrored.
|
|
108
|
+
*
|
|
109
|
+
* This is the one shape of "no base" that exists, and it is not the one it
|
|
110
|
+
* sounds like. A project with no repository is fine: the content service is
|
|
111
|
+
* the store of record for it and mints its own commit shas, so there is
|
|
112
|
+
* always somewhere for the commit to go. What is refused is the mismatch --
|
|
113
|
+
* a project whose commits are mirrored into a repository, being published by
|
|
114
|
+
* a build that was made before it had one and so has no commit to produce
|
|
115
|
+
* that mirror against.
|
|
116
|
+
*
|
|
117
|
+
* It is a REAL state rather than a defensive check: it is exactly what a
|
|
118
|
+
* deployment looks like between a project connecting a repository and its
|
|
119
|
+
* next build going out. Left unchecked, such a publish writes the data and
|
|
120
|
+
* silently fails to mirror it, and the repository quietly falls behind the
|
|
121
|
+
* content nobody is told about.
|
|
122
|
+
*
|
|
123
|
+
* `null` when the service did not say (see `project` on the response
|
|
124
|
+
* schema): an older content service is not evidence of anything, and
|
|
125
|
+
* refusing every publish against one would be a worse failure than not
|
|
126
|
+
* checking.
|
|
127
|
+
*/
|
|
128
|
+
publishRefusal(): PublishRefusal | null;
|
|
53
129
|
onInit(): Promise<void>;
|
|
54
130
|
getPresignedAuthNonce(profileId: string, corsOrigin: string): Promise<{
|
|
55
131
|
status: "success";
|
|
@@ -80,7 +156,8 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
80
156
|
baseSha: BaseSha;
|
|
81
157
|
schemaSha: SchemaSha;
|
|
82
158
|
sourcesSha: SourcesSha;
|
|
83
|
-
|
|
159
|
+
/** Absent for a project with no repository. See `git` on ValApiOptions. */
|
|
160
|
+
commitSha?: CommitSha;
|
|
84
161
|
commits: ValCommit[];
|
|
85
162
|
deployments: ValDeployment[];
|
|
86
163
|
patches: PatchId[];
|
|
@@ -282,6 +359,10 @@ export declare class ValOpsHttp extends ValOps {
|
|
|
282
359
|
isNotFastForward?: boolean;
|
|
283
360
|
updatedFiles: string[];
|
|
284
361
|
commit: CommitSha;
|
|
362
|
+
/** See `CommitResult.parent`: absent means not reported. */
|
|
363
|
+
parent?: string;
|
|
364
|
+
/** See `CommitResult.tree`: absent means not reported. */
|
|
365
|
+
tree?: string;
|
|
285
366
|
branch: string;
|
|
286
367
|
error?: undefined;
|
|
287
368
|
} | {
|
|
@@ -84,21 +84,34 @@ type ValServerOverrides = Partial<{
|
|
|
84
84
|
*/
|
|
85
85
|
patchStore: ValPatchStore;
|
|
86
86
|
/**
|
|
87
|
-
*
|
|
87
|
+
* The git commit this code was built from, and the branch a publish mirrors
|
|
88
|
+
* into -- for a project that HAS a repository.
|
|
88
89
|
*
|
|
89
|
-
*
|
|
90
|
+
* OPTIONAL, including in http mode, and absent is the normal case for a
|
|
91
|
+
* project whose content service is the store of record. It used to be
|
|
92
|
+
* required, which made a repository a precondition for editing anything: a
|
|
93
|
+
* deployment with no commit to name fell through to `fs` mode and reached
|
|
94
|
+
* for a working tree that was not there.
|
|
90
95
|
*
|
|
91
|
-
*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
*
|
|
96
|
+
* What it is FOR, where there is one: a publish turns pending patches into
|
|
97
|
+
* new `.val.ts` text, and to patch a file you must first read it. That read
|
|
98
|
+
* goes to the content service AT THIS COMMIT. Give it a commit the deployed
|
|
99
|
+
* code did not come from and the publish writes over a different version of
|
|
100
|
+
* the file than the one the site is running.
|
|
96
101
|
*
|
|
97
|
-
*
|
|
102
|
+
* It is NOT what a committed render reads -- that reads the source compiled
|
|
103
|
+
* into the build and asks the content service nothing.
|
|
98
104
|
*
|
|
99
|
-
*
|
|
105
|
+
* A normal deploy bakes this at build time, because the commit really is a
|
|
106
|
+
* property of those bytes. `VAL_GIT_COMMIT` / `VAL_GIT_BRANCH` supply it
|
|
107
|
+
* where a build system sets environment variables instead.
|
|
108
|
+
*
|
|
109
|
+
* @example { commit: "e83c5163316f89bfbde7d9ab23ca2e25604af290", branch: "main" }
|
|
100
110
|
*/
|
|
101
|
-
|
|
111
|
+
git?: {
|
|
112
|
+
commit: string;
|
|
113
|
+
branch: string;
|
|
114
|
+
};
|
|
102
115
|
/**
|
|
103
116
|
* The base url of Val.
|
|
104
117
|
*
|
|
@@ -76,6 +76,37 @@ export type CommitResult = {
|
|
|
76
76
|
isNotFastForward?: boolean;
|
|
77
77
|
updatedFiles: string[];
|
|
78
78
|
commit: CommitSha;
|
|
79
|
+
/**
|
|
80
|
+
* The commit this one was built on.
|
|
81
|
+
*
|
|
82
|
+
* Optional because it is only as available as the content service is
|
|
83
|
+
* willing to say: a service that predates this field sends nothing, and
|
|
84
|
+
* `undefined` there means "not reported", never "this commit has no
|
|
85
|
+
* parent". A host that needs it has to handle its absence rather than
|
|
86
|
+
* treat it as a root commit.
|
|
87
|
+
*
|
|
88
|
+
* What it is FOR: a host that keeps its own record of what each commit
|
|
89
|
+
* changed -- a build cache, an incremental publisher -- can only tell
|
|
90
|
+
* whether its record is complete by chaining the commits it holds back to
|
|
91
|
+
* the one it last built. Without a parent the record is a set of
|
|
92
|
+
* snapshots with no way to notice a gap, and a commit made by somebody
|
|
93
|
+
* else in between is silently absent rather than detected.
|
|
94
|
+
*
|
|
95
|
+
* Not `CommitSha`-typed for the same reason it is optional: it is
|
|
96
|
+
* reported by a remote service and validated on arrival, and a branded
|
|
97
|
+
* type here would suggest this end had checked it.
|
|
98
|
+
*/
|
|
99
|
+
parent?: string;
|
|
100
|
+
/**
|
|
101
|
+
* The git tree this commit points at.
|
|
102
|
+
*
|
|
103
|
+
* Optional for the same reason as {@link parent}. A tree hash identifies
|
|
104
|
+
* the CONTENT of a commit rather than the commit itself, so two commits
|
|
105
|
+
* with the same tree are the same source -- which is what lets a host
|
|
106
|
+
* recognise that a commit it is being asked to build is one it has built
|
|
107
|
+
* already, under a different sha, and skip the work.
|
|
108
|
+
*/
|
|
109
|
+
tree?: string;
|
|
79
110
|
branch: string;
|
|
80
111
|
error?: undefined;
|
|
81
112
|
} | {
|
|
@@ -90,8 +121,17 @@ export type ValServerConfig = ValServerOptions & ({
|
|
|
90
121
|
mode: "http";
|
|
91
122
|
apiKey: string;
|
|
92
123
|
project: string;
|
|
93
|
-
|
|
94
|
-
|
|
124
|
+
/**
|
|
125
|
+
* The repository this project's commits are mirrored into, if any.
|
|
126
|
+
*
|
|
127
|
+
* Absent is a project whose content service is the store of record --
|
|
128
|
+
* which is every project that has not attached a repository, and the
|
|
129
|
+
* normal case. See `git` on {@link ValApiOptions}.
|
|
130
|
+
*/
|
|
131
|
+
git?: {
|
|
132
|
+
commit: string;
|
|
133
|
+
branch: string;
|
|
134
|
+
};
|
|
95
135
|
root?: string;
|
|
96
136
|
config: ValConfig;
|
|
97
137
|
}
|
|
@@ -4,8 +4,10 @@ import type { HistoryError } from "./HistoryError.js";
|
|
|
4
4
|
/** One commit, as history lists it. */
|
|
5
5
|
export type HistoricalCommit = {
|
|
6
6
|
commitSha: string;
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
/** `null` for a root commit. See `ValCommit`. */
|
|
8
|
+
parentCommitSha: string | null;
|
|
9
|
+
/** `null` when the publisher did not say where it was. See `ValCommit`. */
|
|
10
|
+
clientCommitSha: string | null;
|
|
9
11
|
branch: string;
|
|
10
12
|
createdBranch: string | null;
|
|
11
13
|
creator: string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type PatchId, type SerializedSchema } from "@valbuild/core";
|
|
2
2
|
import type { PatchSourceError } from "../ValOps.js";
|
|
3
3
|
import { result } from "@valbuild/core/fp";
|
|
4
4
|
import { JSONValue, Operation, Patch, PatchError } from "@valbuild/core/patch";
|
|
@@ -30,6 +30,74 @@ export type JsonValuesOpClass = {
|
|
|
30
30
|
* `.jsonValues()` record.
|
|
31
31
|
*/
|
|
32
32
|
export declare function classifyJsonValuesOp(schema: SerializedSchema, opPath: string[]): JsonValuesOpClass;
|
|
33
|
+
/**
|
|
34
|
+
* Is this op a write of the WHOLE record at the root of a `.jsonValues()`
|
|
35
|
+
* module?
|
|
36
|
+
*
|
|
37
|
+
* The one op {@link classifyJsonValuesOp} cannot classify: it finds the entry
|
|
38
|
+
* key by walking the op path, and the root path has no segments to walk, so a
|
|
39
|
+
* root write reads as `normal` and gets applied to the `.val.ts` - writing
|
|
40
|
+
* markers over the `c.json(() => import(...))` calls that make the entries load
|
|
41
|
+
* at all. {@link expandJsonValuesRootOp} turns it into ops that DO name a key,
|
|
42
|
+
* which everything downstream already handles.
|
|
43
|
+
*
|
|
44
|
+
* `add` counts as well as `replace`: at the root both mean "the document is now
|
|
45
|
+
* this" (see `JSONOps`), so both have to be expanded or the unexpanded one is
|
|
46
|
+
* the same bug again.
|
|
47
|
+
*
|
|
48
|
+
* The value has to BE a record, and that is part of the question rather than a
|
|
49
|
+
* check inside the expansion: a `.jsonValues()` record can be nullable, and
|
|
50
|
+
* `null` at the root means the module no longer has a record at all - there are
|
|
51
|
+
* no entries to write, and it is an ordinary `.val.ts` write, exactly as it was
|
|
52
|
+
* before any of this existed. Same for any other non-record value: not a
|
|
53
|
+
* whole-record write, so not this conversion's to route.
|
|
54
|
+
*/
|
|
55
|
+
export declare function isJsonValuesRootOp(schema: SerializedSchema, op: Operation): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* One entry as it stands right now, for {@link expandJsonValuesRootOp} to
|
|
58
|
+
* expand against.
|
|
59
|
+
*
|
|
60
|
+
* The key set decides add-vs-replace-vs-remove. The content, where the caller
|
|
61
|
+
* has it, decides whether an op is emitted at all: an entry whose content is
|
|
62
|
+
* already what the root write says is left alone rather than rewritten, so
|
|
63
|
+
* putting a module back does not touch every `*.val.json` it did not change.
|
|
64
|
+
* `undefined` means "this entry exists, content unknown" - which is what the
|
|
65
|
+
* Studio's draft source has, because the source holds markers - and yields a
|
|
66
|
+
* `replace`, the safe answer.
|
|
67
|
+
*/
|
|
68
|
+
export type CurrentJsonEntries = ReadonlyMap<string, JSONValue | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Fans a whole-record write at a `.jsonValues()` module's root out into ops
|
|
71
|
+
* that each name an entry key.
|
|
72
|
+
*
|
|
73
|
+
* This is THE conversion, and it has exactly one implementation on purpose: the
|
|
74
|
+
* commit flow (`ValOps.prepare`) and the read side that builds draft content
|
|
75
|
+
* ({@link applyJsonValuesEntryPatches}) both expand through here, so a draft
|
|
76
|
+
* cannot show something other than what publishing writes. A second
|
|
77
|
+
* implementation of the same rule would differ silently, which is the whole
|
|
78
|
+
* failure mode this exists to prevent.
|
|
79
|
+
*
|
|
80
|
+
* The value must be the entries' CONTENT. A module's Source is markers, not
|
|
81
|
+
* content, so a Source handed over here is refused rather than written: that is
|
|
82
|
+
* the shape of the original bug (a revert replaying the archived Source), and
|
|
83
|
+
* it is not recoverable afterwards - the markers replace the entries' content
|
|
84
|
+
* on disk.
|
|
85
|
+
*/
|
|
86
|
+
export declare function expandJsonValuesRootOp(op: Operation, currentEntries: CurrentJsonEntries): result.Result<Operation[], PatchError>;
|
|
87
|
+
/**
|
|
88
|
+
* What a whole-record write says about ONE entry: the same rule
|
|
89
|
+
* {@link expandJsonValuesRootOp} applies to all of them.
|
|
90
|
+
*
|
|
91
|
+
* For a reader that is about one entry. Expanding the whole record to find the
|
|
92
|
+
* one op that names its key costs an op per entry per entry read - the record
|
|
93
|
+
* squared, on exactly the large records this feature is for. The rule itself is
|
|
94
|
+
* `writeForEntry`, shared with the expansion above, so the two cannot come to
|
|
95
|
+
* disagree; only the loop around it differs.
|
|
96
|
+
*
|
|
97
|
+
* `null` means the write says nothing about this entry: it holds that content
|
|
98
|
+
* already, or the record does not name it and it does not exist.
|
|
99
|
+
*/
|
|
100
|
+
export declare function expandJsonValuesRootOpForKey(op: Operation, entryKey: string, currentEntries: CurrentJsonEntries): result.Result<Operation | null, PatchError>;
|
|
33
101
|
/**
|
|
34
102
|
* Finds every `.jsonValues()` record in a module's schema that is NOT the
|
|
35
103
|
* module's root, returning the path to each within the module source.
|