@valbuild/server 0.105.0 → 0.105.1
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/dist/declarations/src/ValOps.d.ts +112 -0
- package/dist/declarations/src/ValOpsFS.d.ts +9 -0
- package/dist/declarations/src/patchStore.d.ts +45 -0
- package/dist/valbuild-server.cjs.dev.js +554 -22
- package/dist/valbuild-server.cjs.prod.js +554 -22
- package/dist/valbuild-server.esm.js +555 -23
- package/package.json +4 -4
|
@@ -57,6 +57,40 @@ export declare abstract class ValOps {
|
|
|
57
57
|
/** The sha256 / hash of schema + config - if this changes users needs to reload */
|
|
58
58
|
private schemaSha;
|
|
59
59
|
private modulesErrors;
|
|
60
|
+
/**
|
|
61
|
+
* What the SHAs above are a fold over, so they can be recomputed.
|
|
62
|
+
*
|
|
63
|
+
* See {@link promoteCommittedSources}: the one thing that changes sources
|
|
64
|
+
* without re-evaluating the modules is a save, and it has to be able to move
|
|
65
|
+
* the SHAs with them.
|
|
66
|
+
*/
|
|
67
|
+
private shaEntries;
|
|
68
|
+
/**
|
|
69
|
+
* The extraction's OWN module errors, which are what the fold was given.
|
|
70
|
+
*
|
|
71
|
+
* Not the same list as {@link modulesErrors}: that one has the nested
|
|
72
|
+
* `.jsonValues()` errors concatenated on, and those were never part of the
|
|
73
|
+
* hash. Re-folding with the wrong list changes the base SHA for no reason.
|
|
74
|
+
*/
|
|
75
|
+
private shaModuleErrors;
|
|
76
|
+
/**
|
|
77
|
+
* What a save has told us each `.jsonValues()` entry now holds.
|
|
78
|
+
*
|
|
79
|
+
* The entry twin of {@link sources}, and it has to be separate because an
|
|
80
|
+
* entry's content is not IN the source: the source holds a marker, and
|
|
81
|
+
* {@link getJsonEntries} resolves it by awaiting the marker's own `import()`.
|
|
82
|
+
* That resolves from the module registry, so after `/save` rewrites a
|
|
83
|
+
* `*.val.json` the thunk keeps answering with the content from before — and
|
|
84
|
+
* unlike a module source there is nothing to re-extract, because the memo was
|
|
85
|
+
* never holding the content in the first place.
|
|
86
|
+
*
|
|
87
|
+
* `null` for an entry the commit deleted.
|
|
88
|
+
*
|
|
89
|
+
* Never cleared: it describes what is on disk. A host rebuild makes a new
|
|
90
|
+
* instance, which is the right reset. Bounded by the project's entry count,
|
|
91
|
+
* holding only the latest content per key.
|
|
92
|
+
*/
|
|
93
|
+
private adoptedJsonEntries;
|
|
60
94
|
constructor(valModules: ValModules, options?: ValOpsOptions | undefined);
|
|
61
95
|
/**
|
|
62
96
|
* Get the status from Val
|
|
@@ -111,6 +145,67 @@ export declare abstract class ValOps {
|
|
|
111
145
|
networkError?: boolean;
|
|
112
146
|
}>;
|
|
113
147
|
private initSources;
|
|
148
|
+
/**
|
|
149
|
+
* These patches are on disk now: adopt what they produced as the committed
|
|
150
|
+
* sources.
|
|
151
|
+
*
|
|
152
|
+
* The entry point for the mechanism {@link promoteCommittedSources} describes,
|
|
153
|
+
* and the only one — a caller hands over the analysis it just committed and
|
|
154
|
+
* this works out the rest, so the rule about which sources are adopted lives
|
|
155
|
+
* in one place rather than at each save site.
|
|
156
|
+
*
|
|
157
|
+
* A module whose patches could not be applied cleanly is left alone. `/save`
|
|
158
|
+
* refuses the whole commit before reaching here if `prepare` found errors, so
|
|
159
|
+
* this cannot normally fire — but adopting a partially patched source would
|
|
160
|
+
* put content in the memo that is not what was written, which is worse than
|
|
161
|
+
* being stale.
|
|
162
|
+
*/
|
|
163
|
+
adoptCommittedSources(analysis: PatchAnalysis & OrderedPatches, preparedCommit: Pick<PreparedCommit, "patchedJsonEntries">): Promise<void>;
|
|
164
|
+
/**
|
|
165
|
+
* Adopt sources that have just been written to disk, and move the SHAs with
|
|
166
|
+
* them.
|
|
167
|
+
*
|
|
168
|
+
* ## Why this exists rather than an invalidation
|
|
169
|
+
*
|
|
170
|
+
* The obvious thing — throw the memo away after a save so the next read
|
|
171
|
+
* re-extracts — does not work, and quietly. `extractValModules` gets a
|
|
172
|
+
* module's content by awaiting its `def`, which is the app's own `import()`:
|
|
173
|
+
* that resolves from the MODULE REGISTRY, not from the file on disk. Right
|
|
174
|
+
* after `/save` rewrites a `.val.ts`, the registry still holds the module as
|
|
175
|
+
* it was evaluated before, so a re-extraction returns the pre-save content and
|
|
176
|
+
* stores it as fresh. What actually replaces it is the host rebuilding its
|
|
177
|
+
* module graph and constructing a new `ValOps` — which happens on its own
|
|
178
|
+
* schedule, and until it does, every read is stale.
|
|
179
|
+
*
|
|
180
|
+
* Stale reads here are not abstract: `getJsonEntry` resolves a
|
|
181
|
+
* `.jsonValues()` entry from the committed source and then replays pending
|
|
182
|
+
* patches over it, so once a publish has removed the patches, a page rendering
|
|
183
|
+
* draft content gets the committed value — the one this memo is holding from
|
|
184
|
+
* before the publish.
|
|
185
|
+
*
|
|
186
|
+
* So the save tells us instead. It has just computed what the new committed
|
|
187
|
+
* sources are, and that answer does not depend on anything being
|
|
188
|
+
* re-evaluated.
|
|
189
|
+
*
|
|
190
|
+
* ## And the SHAs move
|
|
191
|
+
*
|
|
192
|
+
* Deliberately, and this is the part with consequences. `baseSha` and
|
|
193
|
+
* `sourcesSha` identify the sources being served; leaving them still while the
|
|
194
|
+
* sources move would put a value other code compares against into
|
|
195
|
+
* disagreement with what it describes. Moving them means a `fs`-mode base SHA
|
|
196
|
+
* changes within a server's lifetime for the first time, which is a signal the
|
|
197
|
+
* studio already knows how to read: `PatchStore.reconcileVanished` uses a
|
|
198
|
+
* moved base to tell "these patches were published" from "these patches were
|
|
199
|
+
* discarded", and takes them out of the chain without reverting the fields —
|
|
200
|
+
* which is what a second tab watching a publish needs and could not get
|
|
201
|
+
* before.
|
|
202
|
+
*
|
|
203
|
+
* A module the fold does not know is ignored rather than appended: the fold's
|
|
204
|
+
* order is `val.modules`, and a path that is not in it has no position, so
|
|
205
|
+
* there is no honest answer for where its hash would go. It also cannot happen
|
|
206
|
+
* — a save only ever writes modules it read from here.
|
|
207
|
+
*/
|
|
208
|
+
protected promoteCommittedSources(patched: Sources): void;
|
|
114
209
|
init(): Promise<void>;
|
|
115
210
|
getBaseSources(): Promise<Sources>;
|
|
116
211
|
/**
|
|
@@ -368,6 +463,23 @@ export type PreparedCommit = {
|
|
|
368
463
|
* A null value signals that the file at that path should be deleted.
|
|
369
464
|
*/
|
|
370
465
|
patchedSourceFiles: Record<string, string | null>;
|
|
466
|
+
/**
|
|
467
|
+
* The committed content of every `.jsonValues()` entry this commit changed,
|
|
468
|
+
* per module and entry key. `null` means the entry was deleted.
|
|
469
|
+
*
|
|
470
|
+
* Separate from {@link patchedSourceFiles} rather than folded into it, because
|
|
471
|
+
* that map is keyed by FILE PATH and a reader of an entry has a module and a
|
|
472
|
+
* key. A marker does not carry its path at read time, so the two are not
|
|
473
|
+
* interchangeable — see `jsonEntryFiles.ts`.
|
|
474
|
+
*
|
|
475
|
+
* Here for {@link ValOps.adoptCommittedSources}: an entry's committed content
|
|
476
|
+
* is resolved through the marker's own `import()`, which caches, so a save is
|
|
477
|
+
* the only thing that can tell the server what the entry now holds.
|
|
478
|
+
*
|
|
479
|
+
* Only modules whose patches applied cleanly appear; a module that errored
|
|
480
|
+
* contributes nothing, and `/save` refuses the commit anyway.
|
|
481
|
+
*/
|
|
482
|
+
patchedJsonEntries: Record<ModuleFilePath, Record<string, JSONValue | null>>;
|
|
371
483
|
/**
|
|
372
484
|
* Previous source files that were patched
|
|
373
485
|
*/
|
|
@@ -120,6 +120,15 @@ export declare class ValOpsFS extends ValOps {
|
|
|
120
120
|
patchId: PatchId;
|
|
121
121
|
filePath: string;
|
|
122
122
|
}>>;
|
|
123
|
+
/**
|
|
124
|
+
* Which of the two places a patch's file can be, if either.
|
|
125
|
+
*
|
|
126
|
+
* The bytes are in the store once the patch's record is, and in the staging
|
|
127
|
+
* area before that — see `uploadsDir`. Every reader has to accept both, and
|
|
128
|
+
* they decide it here rather than each on its own, so two readers of the same
|
|
129
|
+
* file cannot disagree about whether it exists.
|
|
130
|
+
*/
|
|
131
|
+
private wherePatchFileIs;
|
|
123
132
|
protected getBase64EncodedBinaryFileMetadataFromPatch<T extends BinaryFileType>(filePath: string, type: T, patchId: PatchId): Promise<OpsMetadata<T>>;
|
|
124
133
|
getBase64EncodedBinaryFileFromPatch(filePath: string, patchId: PatchId): Promise<Buffer | null>;
|
|
125
134
|
deletePatches(patchIds: PatchId[]): Promise<{
|
|
@@ -147,8 +147,53 @@ export declare function patchRepairLogFile(patchesDir: string): string;
|
|
|
147
147
|
export declare function patchDir(patchesDir: string, patchId: PatchId): string;
|
|
148
148
|
export declare function patchRecordFile(patchesDir: string, patchId: PatchId): string;
|
|
149
149
|
export declare function patchBaseFile(patchesDir: string, patchId: PatchId): string;
|
|
150
|
+
/**
|
|
151
|
+
* Where a patch's uploaded bytes wait for the record that will reference them.
|
|
152
|
+
*
|
|
153
|
+
* ## Why they cannot simply be written into the patch directory
|
|
154
|
+
*
|
|
155
|
+
* A patch that carries a file is written in TWO requests, and the bytes go
|
|
156
|
+
* first: the record's `file` op holds only a sha, so a record written before its
|
|
157
|
+
* bytes would point at nothing. Uploading straight into `<patchId>/files/` left
|
|
158
|
+
* the directory holding files and no `patch.json` for the length of a round
|
|
159
|
+
* trip — which is neither of the two shapes this store allows, so
|
|
160
|
+
* {@link readPatchStore} read it as a patch whose contents were lost and repair
|
|
161
|
+
* removed it, bytes and all.
|
|
162
|
+
*
|
|
163
|
+
* And that window is not passive: writing into the patches directory is exactly
|
|
164
|
+
* what ends `getStat`'s long poll, so the upload summoned the read that
|
|
165
|
+
* destroyed it. Replacing an image worked only when the two requests happened to
|
|
166
|
+
* land close enough together.
|
|
167
|
+
*
|
|
168
|
+
* So the bytes are not in the store until they belong to something.
|
|
169
|
+
* {@link appendPatch} moves them in after writing the record, under the lock, so
|
|
170
|
+
* no reader ever sees a half-built patch directory — and the invariant that a
|
|
171
|
+
* directory either holds a usable record or is named by the log holds again,
|
|
172
|
+
* with nothing to tolerate and no ambiguous state to classify.
|
|
173
|
+
*
|
|
174
|
+
* A SIBLING of the patches directory, for two reasons: nothing that reads the
|
|
175
|
+
* store lists it, and it is on the same filesystem, so moving into place is a
|
|
176
|
+
* rename rather than a copy.
|
|
177
|
+
*/
|
|
178
|
+
export declare function uploadsDir(patchesDir: string): string;
|
|
179
|
+
/** Where one patch's uploads wait. See {@link uploadsDir}. */
|
|
180
|
+
export declare function patchUploadDir(patchesDir: string, patchId: PatchId): string;
|
|
150
181
|
export declare function patchBinaryFile(patchesDir: string, patchId: PatchId, filePath: string): string;
|
|
151
182
|
export declare function patchBinaryFileMetadata(patchesDir: string, patchId: PatchId, filePath: string): string;
|
|
183
|
+
/** The staged twin of {@link patchBinaryFile}. */
|
|
184
|
+
export declare function stagedPatchBinaryFile(patchesDir: string, patchId: PatchId, filePath: string): string;
|
|
185
|
+
/** The staged twin of {@link patchBinaryFileMetadata}. */
|
|
186
|
+
export declare function stagedPatchBinaryFileMetadata(patchesDir: string, patchId: PatchId, filePath: string): string;
|
|
187
|
+
/** Drop a patch's staging directory, whatever is left of it. */
|
|
188
|
+
export declare function removeStagedUploads(patchesDir: string, patchId: PatchId): void;
|
|
189
|
+
/**
|
|
190
|
+
* Drop staged uploads whose patch never arrived.
|
|
191
|
+
*
|
|
192
|
+
* A client that dies between the upload and the `PUT` leaves its bytes here.
|
|
193
|
+
* Nothing references them — no record points at them and the log never named
|
|
194
|
+
* them — so they are removed without a word.
|
|
195
|
+
*/
|
|
196
|
+
export declare function sweepStaleUploads(patchesDir: string, now?: number): void;
|
|
152
197
|
/**
|
|
153
198
|
* Read the whole store: the order, the records, and everything wrong with it.
|
|
154
199
|
*
|