@volter/world-core 3.0.155 → 3.0.156
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/generated/pack-facts.json +143 -12
- package/dist/inject.cjs +150 -86
- package/dist/src/actions.d.ts +15 -0
- package/dist/src/actions.js +82 -21
- package/dist/src/ancestry.d.ts +5 -4
- package/dist/src/ancestry.js +53 -28
- package/dist/src/changeset.js +1 -1
- package/dist/src/clickhouse/compression.d.ts +28 -0
- package/dist/src/clickhouse/compression.js +281 -0
- package/dist/src/clickhouse/index.d.ts +1 -0
- package/dist/src/clickhouse/index.js +1 -0
- package/dist/src/derived-core.d.ts +12 -1
- package/dist/src/derived-core.js +145 -11
- package/dist/src/derived.js +3 -0
- package/dist/src/fork.js +1 -1
- package/dist/src/grpc-wire.js +2 -1
- package/dist/src/h2.js +63 -10
- package/dist/src/head.d.ts +3 -0
- package/dist/src/head.js +9 -0
- package/dist/src/history.d.ts +1 -1
- package/dist/src/history.js +7 -7
- package/dist/src/index.d.ts +4 -1
- package/dist/src/index.js +5 -1
- package/dist/src/log.d.ts +23 -3
- package/dist/src/log.js +160 -37
- package/dist/src/managed-original-inputs.d.ts +101 -0
- package/dist/src/managed-original-inputs.js +125 -0
- package/dist/src/mongodb/client.d.ts +8 -0
- package/dist/src/mongodb/client.js +27 -0
- package/dist/src/mongodb/index.d.ts +2 -0
- package/dist/src/mongodb/index.js +5 -0
- package/dist/src/mongodb/stream.d.ts +74 -0
- package/dist/src/mongodb/stream.js +206 -0
- package/dist/src/observe.js +1 -1
- package/dist/src/pack-fetch.js +20 -8
- package/dist/src/packRegistry.d.ts +10 -14
- package/dist/src/packRegistry.js +2 -13
- package/dist/src/protocol.d.ts +13 -0
- package/dist/src/protocol.js +13 -0
- package/dist/src/redis/engine.d.ts +10 -4
- package/dist/src/redis/engine.js +103 -32
- package/dist/src/redis/member-storage.js +20 -8
- package/dist/src/redis/service-times.d.ts +25 -0
- package/dist/src/redis/service-times.js +87 -0
- package/dist/src/redis/stream.d.ts +2 -1
- package/dist/src/redis/stream.js +109 -20
- package/dist/src/runtime-state.d.ts +11 -0
- package/dist/src/runtime-state.js +13 -0
- package/dist/src/runtime.d.ts +4 -2
- package/dist/src/runtime.js +5 -2
- package/dist/src/serve-http.d.ts +2 -0
- package/dist/src/serve-http.js +21 -4
- package/dist/src/serve.d.ts +10 -0
- package/dist/src/serve.js +43 -3
- package/dist/src/storage.d.ts +2 -1
- package/dist/src/storage.js +6 -3
- package/dist/src/world-boot.d.ts +1 -0
- package/dist/src/world-boot.js +6 -0
- package/dist/src/world-clock.js +6 -2
- package/dist/src/world-store.d.ts +108 -7
- package/dist/src/world-store.js +883 -103
- package/dist/src/xml.d.ts +30 -0
- package/dist/src/xml.js +74 -0
- package/generated/pack-facts.json +143 -12
- package/inject.cjs +150 -86
- package/package.json +20 -1
- package/src/actions.ts +78 -21
- package/src/ancestry.ts +46 -24
- package/src/changeset.ts +1 -1
- package/src/clickhouse/compression.ts +172 -0
- package/src/clickhouse/index.ts +2 -0
- package/src/derived-core.ts +142 -11
- package/src/derived.ts +3 -0
- package/src/fork.ts +1 -1
- package/src/grpc-wire.ts +2 -1
- package/src/h2.ts +46 -5
- package/src/head.ts +9 -0
- package/src/history.ts +7 -7
- package/src/index.ts +6 -1
- package/src/log.ts +147 -32
- package/src/managed-original-inputs.ts +163 -0
- package/src/mongodb/client.ts +27 -0
- package/src/mongodb/index.ts +5 -0
- package/src/mongodb/stream.ts +213 -0
- package/src/observe.ts +1 -1
- package/src/pack-fetch.ts +20 -8
- package/src/packRegistry.ts +3 -15
- package/src/protocol.ts +13 -0
- package/src/redis/engine.ts +100 -57
- package/src/redis/member-storage.ts +17 -9
- package/src/redis/service-times.ts +81 -0
- package/src/redis/stream.ts +66 -14
- package/src/runtime-state.ts +14 -0
- package/src/runtime.ts +6 -1
- package/src/serve-http.ts +23 -4
- package/src/serve.ts +45 -3
- package/src/storage.ts +5 -3
- package/src/world-boot.ts +6 -0
- package/src/world-clock.ts +6 -2
- package/src/world-store.ts +704 -91
- package/src/xml.ts +71 -0
package/dist/src/head.d.ts
CHANGED
|
@@ -174,6 +174,9 @@ export declare function performEntries(opts: {
|
|
|
174
174
|
* `auto` is performed now. Returns the vendor's id when it minted one, so the answer carries it.
|
|
175
175
|
* Raises `RefusedWriteError` / `VendorWriteError` for the pack to answer in the vendor's shape.
|
|
176
176
|
*/
|
|
177
|
+
/** Whether `performAtHead` would perform an entry now (a twin whose root says `auto`, outside a pack fetch's deferred
|
|
178
|
+
* group): a caller appending several writes at once appends them one at a time then, each performed before the next. */
|
|
179
|
+
export declare function performsAtHeadNow(service: string, root?: string): boolean;
|
|
177
180
|
export declare function performAtHead(service: string, action: Pick<TwinAction, 'id'>, root?: string): Promise<{
|
|
178
181
|
performed: boolean;
|
|
179
182
|
externalId?: string;
|
package/dist/src/head.js
CHANGED
|
@@ -464,6 +464,15 @@ async function performNow(opts) {
|
|
|
464
464
|
* `auto` is performed now. Returns the vendor's id when it minted one, so the answer carries it.
|
|
465
465
|
* Raises `RefusedWriteError` / `VendorWriteError` for the pack to answer in the vendor's shape.
|
|
466
466
|
*/
|
|
467
|
+
/** Whether `performAtHead` would perform an entry now (a twin whose root says `auto`, outside a pack fetch's deferred
|
|
468
|
+
* group): a caller appending several writes at once appends them one at a time then, each performed before the next. */
|
|
469
|
+
export function performsAtHeadNow(service, root) {
|
|
470
|
+
const request = currentCorrelationId();
|
|
471
|
+
if (request !== undefined && deferred.has(request))
|
|
472
|
+
return false;
|
|
473
|
+
const head = headOf(service, root);
|
|
474
|
+
return head.kind === 'real' && head.deploy === 'auto';
|
|
475
|
+
}
|
|
467
476
|
export async function performAtHead(service, action, root) {
|
|
468
477
|
// a pack fetch performs its request's entries as one group after the handler (performRequestGroup)
|
|
469
478
|
const request = currentCorrelationId();
|
package/dist/src/history.d.ts
CHANGED
|
@@ -51,7 +51,7 @@ export declare function saveHistoryView(directory: string, view: HistoryView): s
|
|
|
51
51
|
* (and the view document itself) and each named directory's ancestry record (its generation). A read cache keyed by this sees an
|
|
52
52
|
* ancestor's retained history truncated, replaced or its directory re-created, which the full read
|
|
53
53
|
* refuses (`historyEntries`), instead of serving a tree folded from the history it replaced. */
|
|
54
|
-
export declare function inheritedHistoryKey(service: string, root?: string): string;
|
|
54
|
+
export declare function inheritedHistoryKey(service: string, root?: string, meta?: string | null): string;
|
|
55
55
|
export declare function inheritedHistory(service: string, root?: string): HistoryView | undefined;
|
|
56
56
|
/** Capture under the directory's history lock, as appends and complete observation batches are made. */
|
|
57
57
|
export declare function captureHistory(service: string, root?: string): {
|
package/dist/src/history.js
CHANGED
|
@@ -108,14 +108,14 @@ export function saveHistoryView(directory, view) {
|
|
|
108
108
|
for (const dependency of dependencies)
|
|
109
109
|
commitParentPin(dependency.directory, file);
|
|
110
110
|
return id;
|
|
111
|
-
});
|
|
111
|
+
}, { operation: 'view pin publication' });
|
|
112
112
|
}
|
|
113
113
|
/** What an inherited history's content stands on, as file facts: every segment file the view names
|
|
114
114
|
* (and the view document itself) and each named directory's ancestry record (its generation). A read cache keyed by this sees an
|
|
115
115
|
* ancestor's retained history truncated, replaced or its directory re-created, which the full read
|
|
116
116
|
* refuses (`historyEntries`), instead of serving a tree folded from the history it replaced. */
|
|
117
|
-
export function inheritedHistoryKey(service, root) {
|
|
118
|
-
const parent = readBranchMeta(service, root)?.parent;
|
|
117
|
+
export function inheritedHistoryKey(service, root, meta) {
|
|
118
|
+
const parent = readBranchMeta(service, root, meta)?.parent;
|
|
119
119
|
if (!parent?.view)
|
|
120
120
|
return '';
|
|
121
121
|
const store = getActiveWorldStore();
|
|
@@ -170,7 +170,7 @@ export function captureHistory(service, root) {
|
|
|
170
170
|
descriptor.segments.push({ directory, generation, file, start: 0, count: entries.length, digest: historyDigest(entries) });
|
|
171
171
|
}
|
|
172
172
|
return { view: saveHistoryView(directory, descriptor), position: historyLength(descriptor.layout), descriptor };
|
|
173
|
-
});
|
|
173
|
+
}, { operation: 'capture' });
|
|
174
174
|
}
|
|
175
175
|
export function originHead(service, root) {
|
|
176
176
|
const raw = getActiveWorldStore().read(join(worldPaths(service, root).dir, 'origin-head.json'));
|
|
@@ -213,7 +213,7 @@ export function publishOriginHistory(service, root, remoteView, layout, entries)
|
|
|
213
213
|
const view = saveHistoryView(directory, { version: 1, owner: { directory, generation }, layout, segments });
|
|
214
214
|
store.writeAtomic(join(directory, 'origin-head.json'), JSON.stringify({ view, remoteView }));
|
|
215
215
|
return { view, appended };
|
|
216
|
-
});
|
|
216
|
+
}, { operation: 'origin fetch' });
|
|
217
217
|
}
|
|
218
218
|
/** A changeset binds the complete inherited view, including this root's observations. */
|
|
219
219
|
export function captureParentHistory(service, root) {
|
|
@@ -221,7 +221,7 @@ export function captureParentHistory(service, root) {
|
|
|
221
221
|
const head = captureHistory(service, root);
|
|
222
222
|
const position = head.position - head.descriptor.layout.branch;
|
|
223
223
|
return { view: saveHistoryView(worldPaths(service, root).dir, historyPrefix(head.descriptor, position)), position };
|
|
224
|
-
});
|
|
224
|
+
}, { operation: 'capture' });
|
|
225
225
|
}
|
|
226
226
|
/** Compare evaluated views, so removals, reordered rows and layout changes count as drift. */
|
|
227
227
|
export function historyChanges(service, before, after) {
|
|
@@ -295,7 +295,7 @@ export function historyAtInstant(service, instant, root, selectedView) {
|
|
|
295
295
|
}
|
|
296
296
|
const view = saveHistoryView(directory, { version: 1, owner: source.owner, layout, segments, ...(source.origin ? { origin: { ...source.origin, ...(keep.slice(0, source.origin.position).some(v => !v) ? { incomplete: true } : {}) } } : {}) });
|
|
297
297
|
return { view, position: historyLength(layout) };
|
|
298
|
-
});
|
|
298
|
+
}, { operation: 'capture' });
|
|
299
299
|
}
|
|
300
300
|
/** Replace only the tracked origin layer; inherited local layers keep their exact projection order. */
|
|
301
301
|
export function replaceHistoryOrigin(previous, origin, next) {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -40,7 +40,7 @@ export { answerVendorErrors, RefusedWriteError } from './head.js';
|
|
|
40
40
|
export { GraphqlError, type GraphqlPart, type GraphqlResolver } from './graphql-wire.js';
|
|
41
41
|
export { VendorUnreachableError } from './vendor-call.js';
|
|
42
42
|
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER } from './request-scope.js';
|
|
43
|
-
export { serveHttp, serveStream, StreamListenerUnavailable, type HttpHandler, type HttpServer, type ServeHttpOptions } from './serve-http.js';
|
|
43
|
+
export { serveHttp, serveStream, nodeBuiltin, StreamListenerUnavailable, type HttpHandler, type HttpServer, type ServeHttpOptions } from './serve-http.js';
|
|
44
44
|
export type { TwinStream, TwinStreamConnection, TwinStreamSink } from './twin-fetch.js';
|
|
45
45
|
export { privateTransportKey } from './private-transport.js';
|
|
46
46
|
export { siteLabel, siteUrlOf, twinSiteUrl, twinVendorUrl } from './twin-fetch.js';
|
|
@@ -58,6 +58,7 @@ export { EngineDatabaseError, EngineUnavailableError, quoteIdent } from './manag
|
|
|
58
58
|
export type { Batch as EngineBatch, ManagedDatabase, Statement as EngineStatement, StatementResult as EngineStatementResult } from './managed-database.js';
|
|
59
59
|
export type { Mail, SmtpRoute } from './smtp.js';
|
|
60
60
|
export * as s3 from './s3/wire.js';
|
|
61
|
+
export * as xml from './xml.js';
|
|
61
62
|
export * as clickhouse from './clickhouse/index.js';
|
|
62
63
|
export { sampleFromSchema } from './schema-sample.js';
|
|
63
64
|
export * as openaiWire from './openai-wire.js';
|
|
@@ -70,6 +71,7 @@ export { presignSigV4, signSigV4, verifySigV4, type SigV4Verdict } from './sigv4
|
|
|
70
71
|
export * as redis from './redis/index.js';
|
|
71
72
|
export * as mysql from './mysql/index.js';
|
|
72
73
|
export * as live from './live/index.js';
|
|
74
|
+
export * as mongodb from './mongodb/index.js';
|
|
73
75
|
export * as git from './git/index.js';
|
|
74
76
|
export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError } from './scenario.js';
|
|
75
77
|
export type { PackScenarioAdapter, ScenarioDecision, ScenarioDocument, ScenarioExtractorSpec, ScenarioFault, ScenarioFaultResult, ScenarioFeatures, ScenarioHandler, ScenarioMatcher, ScenarioMissRecord, ScenarioStatus } from './scenario.js';
|
|
@@ -77,3 +79,4 @@ export { verifyAttestationBundle } from './attestation.js';
|
|
|
77
79
|
export { browserSessionToken, startBrowserSession, endBrowserSession } from './browser-session.js';
|
|
78
80
|
export { readHostPort } from './host-port.js';
|
|
79
81
|
export { assertBrowserName, browserOrigin, validateBrowserState, validateBrowserStorageState, validateBrowserContext, browserAcceptLanguage, cookieMatchesHost, type BrowserCookie, type BrowserState, type BrowserStorageState, type BrowserContext, type BrowserIndexedDB } from './browser-state.js';
|
|
82
|
+
export * as managedOriginalInputs from './managed-original-inputs.js';
|
package/dist/src/index.js
CHANGED
|
@@ -29,7 +29,7 @@ export { GraphqlError } from "./graphql-wire.js";
|
|
|
29
29
|
export { VendorUnreachableError } from "./vendor-call.js";
|
|
30
30
|
export { isReadOnlyRequest, READ_ONLY_REQUEST_HEADER } from "./request-scope.js";
|
|
31
31
|
// ── the serve factory ──────────────────────────────────────────────────────────────────────────
|
|
32
|
-
export { serveHttp, serveStream, StreamListenerUnavailable } from "./serve-http.js";
|
|
32
|
+
export { serveHttp, serveStream, nodeBuiltin, StreamListenerUnavailable } from "./serve-http.js";
|
|
33
33
|
export { privateTransportKey } from "./private-transport.js";
|
|
34
34
|
// where a page links a hostname its twin answers, inside the World that shows it
|
|
35
35
|
export { siteLabel, siteUrlOf, twinSiteUrl, twinVendorUrl } from "./twin-fetch.js";
|
|
@@ -49,6 +49,8 @@ export { passwordHash, personOf, personWith, recordPerson } from "./people.js";
|
|
|
49
49
|
export { EngineDatabaseError, EngineUnavailableError, quoteIdent } from "./managed-database.js";
|
|
50
50
|
// S3's wire (contract "S3's wire is a kernel library too") and the git plane (contract "The git plane is a kernel library")
|
|
51
51
|
export * as s3 from "./s3/wire.js";
|
|
52
|
+
// Generic strict XML grammar; vendor interpretation remains in its consumer.
|
|
53
|
+
export * as xml from "./xml.js";
|
|
52
54
|
export * as clickhouse from "./clickhouse/index.js";
|
|
53
55
|
export { sampleFromSchema } from "./schema-sample.js";
|
|
54
56
|
export * as openaiWire from "./openai-wire.js";
|
|
@@ -61,6 +63,7 @@ export { presignSigV4, signSigV4, verifySigV4 } from "./sigv4.js";
|
|
|
61
63
|
export * as redis from "./redis/index.js";
|
|
62
64
|
export * as mysql from "./mysql/index.js";
|
|
63
65
|
export * as live from "./live/index.js";
|
|
66
|
+
export * as mongodb from "./mongodb/index.js";
|
|
64
67
|
export * as git from "./git/index.js";
|
|
65
68
|
// ── the scenario grammar (architecture, "Behaviour") ───────────────────────────────────────────
|
|
66
69
|
export { parseScenarioDocument, scenarioFaultResult, ScenarioEngine, ScenarioError } from "./scenario.js";
|
|
@@ -68,3 +71,4 @@ export { verifyAttestationBundle } from "./attestation.js";
|
|
|
68
71
|
export { browserSessionToken, startBrowserSession, endBrowserSession } from "./browser-session.js";
|
|
69
72
|
export { readHostPort } from "./host-port.js";
|
|
70
73
|
export { assertBrowserName, browserOrigin, validateBrowserState, validateBrowserStorageState, validateBrowserContext, browserAcceptLanguage, cookieMatchesHost } from "./browser-state.js";
|
|
74
|
+
export * as managedOriginalInputs from "./managed-original-inputs.js";
|
package/dist/src/log.d.ts
CHANGED
|
@@ -102,7 +102,7 @@ export declare function originLogPath(service: string, root?: string): string;
|
|
|
102
102
|
/** A parent is at a URL when it is not a path on this machine. */
|
|
103
103
|
export declare function isUrlParent(at: string): boolean;
|
|
104
104
|
export declare function checkpointPath(service: string, root?: string): string;
|
|
105
|
-
export declare function readBranchMeta(service: string, root?: string): BranchMeta | null;
|
|
105
|
+
export declare function readBranchMeta(service: string, root?: string, read?: string | null): BranchMeta | null;
|
|
106
106
|
export declare function writeBranchMeta(service: string, meta: BranchMeta, root?: string): void;
|
|
107
107
|
/** A v1 observed row as an entry: a delta event folds its `changed.*.after`; anything else folds
|
|
108
108
|
* nothing and rides along for `listEvents`. An entry row is itself. */
|
|
@@ -130,13 +130,21 @@ export declare function landedIds(parent: Entry[]): Set<string>;
|
|
|
130
130
|
* before it had observed the vendor's own subject under that id (its tree was behind) must not fold
|
|
131
131
|
* the vendor's subject onto the landed one, nor send a caller who addresses the vendor's id there. */
|
|
132
132
|
export declare function aliasesFrom(parent: Entry[]): Map<string, string>;
|
|
133
|
-
type Subject = {
|
|
133
|
+
export type Subject = {
|
|
134
134
|
type: string;
|
|
135
135
|
id: string;
|
|
136
136
|
updatedAt: string;
|
|
137
137
|
fields: SubjectFields;
|
|
138
138
|
};
|
|
139
139
|
export type Tree = Map<string, Subject>;
|
|
140
|
+
/** One subject read by the same guarded key as a write's answer; restore the vendor's own metadata fields. */
|
|
141
|
+
export declare function heldSubject(service: string, type: string, id: string, root?: string): Subject | undefined;
|
|
142
|
+
/**
|
|
143
|
+
* One local write folded onto its subject as the tree folds its entry (`overlay`): the subject as it was (undefined
|
|
144
|
+
* for one new to the tree) is copied, never changed. A command's writes staged in `ctx.batch` are read back by
|
|
145
|
+
* folding them this way, so a read inside the batch sees what the tree will hold once they land (derived-core.ts).
|
|
146
|
+
*/
|
|
147
|
+
export declare function foldLocalWrite(previous: Subject | undefined, type: string, id: string, fields: SubjectFields, at: string): Subject;
|
|
140
148
|
/** Fold entries onto a tree, in order: `set` overlays its fields and applies its projection; a
|
|
141
149
|
* reverted entry folds nothing; a `confirm` row (v1) folds nothing. `skip` names entries the
|
|
142
150
|
* parent already holds. */
|
|
@@ -152,6 +160,15 @@ export declare function ownFields(r: TwinResource): Record<string, unknown>;
|
|
|
152
160
|
export declare function dropCheckpoint(service: string, root?: string): void;
|
|
153
161
|
/** Preserve each ancestor's observed-then-local overlay, including landed IDs and aliases. */
|
|
154
162
|
export declare function foldHistory(entries: Entry[], layout: HistoryLayout, service?: string): Tree;
|
|
163
|
+
/**
|
|
164
|
+
* One subject of the current tree as a resource, by its type and id: the resource `projectResources(...).find` gives
|
|
165
|
+
* for the same type and id, read by the subject's key without cloning or projecting the rest of the tree. Every subject is
|
|
166
|
+
* held under `${type}:${id}` (overlay is the only setter, and an alias re-keys through it), so the key is the
|
|
167
|
+
* subject. A write's answer read back the whole tree this way (serve.ts, applyTwinWrite's `resource`), once per
|
|
168
|
+
* written subject: a derived pack writing each document, index and collection of a database's startup paid a
|
|
169
|
+
* projection of every subject the World holds for each (S2 R17).
|
|
170
|
+
*/
|
|
171
|
+
export declare function readSubject(service: string, type: string, id: string, root?: string): TwinResource | undefined;
|
|
155
172
|
export declare function readTree(service: string, root?: string, opts?: {
|
|
156
173
|
until?: string;
|
|
157
174
|
at?: number;
|
|
@@ -171,6 +188,10 @@ export declare function readTreeMap(service: string, root?: string, opts?: {
|
|
|
171
188
|
at?: number;
|
|
172
189
|
view?: string;
|
|
173
190
|
}): Tree;
|
|
191
|
+
/** Append `data` (whole JSONL lines of a service's branch log, `append` writing them) and, when the reads' memo held
|
|
192
|
+
* the tree as it stood, extend it by them. Called holding the directory's history lock. Answers the log's facts
|
|
193
|
+
* after the append (`size:mtimeMs`) when it read them, for a caller keyed on the same. */
|
|
194
|
+
export declare function appendToBranchLog(service: string, root: string | undefined, data: string, append: () => void): string | undefined;
|
|
174
195
|
/** What changed in a service's tree since `since` (a `treeStamp` an earlier read was made at): the subjects
|
|
175
196
|
* written since, as resources; the keys (`type:id`) of those no longer in the tree; and, of the changed, the keys
|
|
176
197
|
* now at the tree's end in the order they stand there (new to the tree, or deleted and made again), which a
|
|
@@ -257,4 +278,3 @@ export declare function subjectHistory(service: string, subject: {
|
|
|
257
278
|
type: string;
|
|
258
279
|
id?: string;
|
|
259
280
|
}, root?: string): Entry[];
|
|
260
|
-
export {};
|
package/dist/src/log.js
CHANGED
|
@@ -29,14 +29,14 @@ import { canonicalStatePath, checkParent, commitParentPin, pinParent, withAncest
|
|
|
29
29
|
import { resolveReferences } from "./references.js";
|
|
30
30
|
import { hashFieldValue } from "./hash.js";
|
|
31
31
|
import { worldPaths } from "./storage.js";
|
|
32
|
-
import { getActiveWorldStore } from "./world-store.js";
|
|
32
|
+
import { getActiveWorldStore, TREE_FILES } from "./world-store.js";
|
|
33
33
|
export const CHECKPOINT_EVERY = 100;
|
|
34
34
|
// Retained checkpoints and process memos are disposable projections, never history.
|
|
35
35
|
const TREE_PROJECTION_VERSION = 2;
|
|
36
36
|
export const DELTA_SUFFIX = '.delta';
|
|
37
37
|
export function parentLogPath(service, root) { return worldPaths(service, root).events; }
|
|
38
|
-
export function branchLogPath(service, root) { return join(dirname(worldPaths(service, root).events),
|
|
39
|
-
export function branchMetaPath(service, root) { return join(dirname(worldPaths(service, root).events),
|
|
38
|
+
export function branchLogPath(service, root) { return join(dirname(worldPaths(service, root).events), TREE_FILES.branch); }
|
|
39
|
+
export function branchMetaPath(service, root) { return join(dirname(worldPaths(service, root).events), TREE_FILES.pointer); }
|
|
40
40
|
/** The fetched cache of a URL parent's whole log — what `fetch` extends and a read folds up to the position. */
|
|
41
41
|
export function originLogPath(service, root) { return join(dirname(worldPaths(service, root).events), 'origin.jsonl'); }
|
|
42
42
|
/** A parent is at a URL when it is not a path on this machine. */
|
|
@@ -114,8 +114,9 @@ function readRows(path) {
|
|
|
114
114
|
cache.set(path, tail !== undefined ? { rows, lines: lines.length - 1, bytes: Buffer.byteLength(content), tail } : { content, rows, lines: lines.length - 1 });
|
|
115
115
|
return rows.slice();
|
|
116
116
|
}
|
|
117
|
-
export function readBranchMeta(service, root) {
|
|
118
|
-
|
|
117
|
+
export function readBranchMeta(service, root, read) {
|
|
118
|
+
// `read`: branch.json's text where the caller has just read it (a tree's stamp reads it once for both uses).
|
|
119
|
+
const raw = read !== undefined ? read : getActiveWorldStore().read(branchMetaPath(service, root));
|
|
119
120
|
if (raw === null)
|
|
120
121
|
return null;
|
|
121
122
|
const meta = parseExactJson(raw);
|
|
@@ -179,8 +180,8 @@ export function writeBranchMeta(service, meta, root) {
|
|
|
179
180
|
getActiveWorldStore().writeAtomic(path, `${JSON.stringify(meta, null, 2)}\n`);
|
|
180
181
|
if (meta.parent?.directory && !isUrlParent(meta.parent.at))
|
|
181
182
|
commitParentPin(meta.parent.directory, path);
|
|
182
|
-
});
|
|
183
|
-
});
|
|
183
|
+
}, { operation: 'pointer publication' });
|
|
184
|
+
}, { operation: 'pointer publication' });
|
|
184
185
|
}
|
|
185
186
|
/** A v1 observed row as an entry: a delta event folds its `changed.*.after`; anything else folds
|
|
186
187
|
* nothing and rides along for `listEvents`. An entry row is itself. */
|
|
@@ -251,7 +252,7 @@ export function appendOriginEntry(entry, root) {
|
|
|
251
252
|
return { appended: false };
|
|
252
253
|
store.append(path, `${JSON.stringify(entry)}\n`);
|
|
253
254
|
return { appended: true };
|
|
254
|
-
}));
|
|
255
|
+
}, { operation: 'origin append' }), { operation: 'origin append' });
|
|
255
256
|
}
|
|
256
257
|
/** Where the parent stands now: the length of its whole log (live at a path, the cache for a URL). */
|
|
257
258
|
export function parentPosition(service, root) {
|
|
@@ -300,6 +301,22 @@ function overlay(tree, type, id, fields, at) {
|
|
|
300
301
|
delete merged.deleted;
|
|
301
302
|
tree.set(key, { ...existing, updatedAt: at, fields: merged });
|
|
302
303
|
}
|
|
304
|
+
/** One subject read by the same guarded key as a write's answer; restore the vendor's own metadata fields. */
|
|
305
|
+
export function heldSubject(service, type, id, root) {
|
|
306
|
+
const row = readSubject(service, type, id, root);
|
|
307
|
+
return row ? { type: row.type, id: row.id, updatedAt: row.updatedAt, fields: ownFields(row) } : undefined;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* One local write folded onto its subject as the tree folds its entry (`overlay`): the subject as it was (undefined
|
|
311
|
+
* for one new to the tree) is copied, never changed. A command's writes staged in `ctx.batch` are read back by
|
|
312
|
+
* folding them this way, so a read inside the batch sees what the tree will hold once they land (derived-core.ts).
|
|
313
|
+
*/
|
|
314
|
+
export function foldLocalWrite(previous, type, id, fields, at) {
|
|
315
|
+
const key = `${type}:${id}`;
|
|
316
|
+
const tree = previous ? new Map([[key, { ...previous, fields: { ...previous.fields } }]]) : new Map();
|
|
317
|
+
overlay(tree, type, id, fields, at);
|
|
318
|
+
return tree.get(key);
|
|
319
|
+
}
|
|
303
320
|
/** Fold entries onto a tree, in order: `set` overlays its fields and applies its projection; a
|
|
304
321
|
* reverted entry folds nothing; a `confirm` row (v1) folds nothing. `skip` names entries the
|
|
305
322
|
* parent already holds. */
|
|
@@ -402,6 +419,22 @@ export function foldHistory(entries, layout, service) {
|
|
|
402
419
|
foldAliases(tree, aliasesFrom(parent), service);
|
|
403
420
|
return tree;
|
|
404
421
|
}
|
|
422
|
+
/**
|
|
423
|
+
* One subject of the current tree as a resource, by its type and id: the resource `projectResources(...).find` gives
|
|
424
|
+
* for the same type and id, read by the subject's key without cloning or projecting the rest of the tree. Every subject is
|
|
425
|
+
* held under `${type}:${id}` (overlay is the only setter, and an alias re-keys through it), so the key is the
|
|
426
|
+
* subject. A write's answer read back the whole tree this way (serve.ts, applyTwinWrite's `resource`), once per
|
|
427
|
+
* written subject: a derived pack writing each document, index and collection of a database's startup paid a
|
|
428
|
+
* projection of every subject the World holds for each (S2 R17).
|
|
429
|
+
*/
|
|
430
|
+
export function readSubject(service, type, id, root) {
|
|
431
|
+
const key = `${type}:${id}`;
|
|
432
|
+
const held = currentTree(service, root).tree.get(key);
|
|
433
|
+
// a type or id holding ':' can share a key with another (type, id): only the subject itself is it
|
|
434
|
+
if (!held || held.type !== type || held.id !== id)
|
|
435
|
+
return undefined;
|
|
436
|
+
return treeResources(new Map([[key, { ...held, fields: { ...held.fields } }]]))[0];
|
|
437
|
+
}
|
|
405
438
|
export function readTree(service, root, opts = {}) {
|
|
406
439
|
return treeResources(readTreeMap(service, root, opts));
|
|
407
440
|
}
|
|
@@ -414,7 +447,7 @@ export function readParentTreeMap(service, root) {
|
|
|
414
447
|
return foldHistory([...(inherited ? historyEntries(inherited) : []), ...own], {
|
|
415
448
|
...(inherited ? { base: inherited.layout } : {}), parent: own.length, branch: 0,
|
|
416
449
|
}, service);
|
|
417
|
-
});
|
|
450
|
+
}, { operation: 'tree fold' });
|
|
418
451
|
}
|
|
419
452
|
const treeMemos = new WeakMap();
|
|
420
453
|
/** How many extensions a memo remembers the touched subjects of; a projection further behind refolds. */
|
|
@@ -422,11 +455,44 @@ const TREE_STEPS_KEPT = 64;
|
|
|
422
455
|
function statKey(path) { const s = getActiveWorldStore().stat(path); return s ? `${s.size}:${s.mtimeMs}` : '-'; }
|
|
423
456
|
/** What a service's PARENT side at `root` is folded from (its parent log, branch.json and inherited history), as one
|
|
424
457
|
* string: while it stands, its aliases and landed ids are the same, whatever the branch's own log does. */
|
|
425
|
-
export function parentStamp(service, root) { return
|
|
426
|
-
function parentKeyOf(service, root) { return
|
|
458
|
+
export function parentStamp(service, root) { return treeFacts(service, root).parentKey; }
|
|
459
|
+
function parentKeyOf(service, root) { return parentFacts(service, root).key; }
|
|
460
|
+
/** The parent side's key, and whether it names a file outside the tree's own directory (an inherited view). */
|
|
461
|
+
function parentFacts(service, root) {
|
|
462
|
+
// branch.json is small and every stamp needs it: kept while its own facts stand (world-store.ts readKept), so an
|
|
463
|
+
// unchanged pointer costs one check. Its text is still in the key, so a changed pointer still moves the stamp.
|
|
464
|
+
const store = getActiveWorldStore(), pointer = branchMetaPath(service, root);
|
|
465
|
+
const meta = store.readKept ? store.readKept(pointer) : store.read(pointer);
|
|
466
|
+
const inherited = inheritedHistoryKey(service, root, meta);
|
|
467
|
+
return { key: `${TREE_PROJECTION_VERSION}|${statKey(parentLogPath(service, root))}|${meta ?? ''}|${inherited}`, inherits: inherited !== '' };
|
|
468
|
+
}
|
|
469
|
+
const keptFacts = new WeakMap();
|
|
470
|
+
function treeFacts(service, root) {
|
|
471
|
+
const store = getActiveWorldStore();
|
|
472
|
+
const branchLog = branchLogPath(service, root);
|
|
473
|
+
if (!store.generation)
|
|
474
|
+
return { parentKey: parentKeyOf(service, root), branchKey: statKey(branchLog) };
|
|
475
|
+
const directory = dirname(branchLog);
|
|
476
|
+
const generation = store.generation(directory);
|
|
477
|
+
let kept = keptFacts.get(store);
|
|
478
|
+
if (!kept) {
|
|
479
|
+
kept = new Map();
|
|
480
|
+
keptFacts.set(store, kept);
|
|
481
|
+
}
|
|
482
|
+
const held = kept.get(directory);
|
|
483
|
+
if (generation !== null && held?.generation === generation)
|
|
484
|
+
return held;
|
|
485
|
+
const parent = parentFacts(service, root);
|
|
486
|
+
const facts = { parentKey: parent.key, branchKey: statKey(branchLog) };
|
|
487
|
+
if (generation !== null && !parent.inherits)
|
|
488
|
+
kept.set(directory, { ...facts, generation });
|
|
489
|
+
else
|
|
490
|
+
kept.delete(directory);
|
|
491
|
+
return facts;
|
|
492
|
+
}
|
|
427
493
|
/** What a service's tree (and every subject's history) at `root` is folded from, as one string: while it
|
|
428
494
|
* stands, nothing was written. A pack that projects the tree into its own state memoizes on it. */
|
|
429
|
-
export function treeStamp(service, root) {
|
|
495
|
+
export function treeStamp(service, root) { const facts = treeFacts(service, root); return `${facts.parentKey}#${facts.branchKey}`; }
|
|
430
496
|
const cloneTree = (tree) => new Map([...tree].map(([k, s]) => [k, { ...s, fields: { ...s.fields } }]));
|
|
431
497
|
const memoStamp = (m) => `${m.parentKey}#${m.branchKey}`;
|
|
432
498
|
/** The subject keys entries write (as foldEntries folds them), and the vendor rows an alias moves a local one onto. */
|
|
@@ -484,8 +550,11 @@ function currentTree(service, root) {
|
|
|
484
550
|
// A hit needs no lock: a memo is only ever stored from a fold made under the history lock, and while the
|
|
485
551
|
// facts still match that fold, nothing was written since. A writer mid-batch has moved them.
|
|
486
552
|
const unlocked = memos.get(slot);
|
|
487
|
-
if (unlocked
|
|
488
|
-
|
|
553
|
+
if (unlocked) {
|
|
554
|
+
const facts = treeFacts(service, root);
|
|
555
|
+
if (unlocked.parentKey === facts.parentKey && unlocked.branchKey === facts.branchKey)
|
|
556
|
+
return { tree: unlocked.tree, memo: unlocked };
|
|
557
|
+
}
|
|
489
558
|
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
490
559
|
const parentKey = parentKeyOf(service, root);
|
|
491
560
|
const branchKey = statKey(branchLogPath(service, root));
|
|
@@ -497,24 +566,7 @@ function currentTree(service, root) {
|
|
|
497
566
|
if (held && held.parentKey === parentKey && branch.length >= held.branchCount
|
|
498
567
|
&& (held.branchCount === 0 ? held.lastBranchId === null : branch[held.branchCount - 1]?.id === held.lastBranchId)
|
|
499
568
|
&& !branch.slice(held.branchCount).some((e) => e.op === 'revert')) {
|
|
500
|
-
|
|
501
|
-
const keys = touchedKeys(fresh, held.aliases);
|
|
502
|
-
const from = memoStamp(held);
|
|
503
|
-
let appended;
|
|
504
|
-
try {
|
|
505
|
-
appended = insertionsDuring(held.tree, () => {
|
|
506
|
-
foldEntries(held.tree, fresh, held.landed);
|
|
507
|
-
foldAliases(held.tree, held.aliases, service, keys);
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
catch (error) {
|
|
511
|
-
memos.delete(slot);
|
|
512
|
-
throw error;
|
|
513
|
-
} // a half-folded memo is never read again
|
|
514
|
-
Object.assign(held, { branchKey, branchCount: branch.length, lastBranchId: last(branch) });
|
|
515
|
-
held.steps.push({ from, to: memoStamp(held), keys, appended });
|
|
516
|
-
if (held.steps.length > TREE_STEPS_KEPT)
|
|
517
|
-
held.steps.splice(0, held.steps.length - TREE_STEPS_KEPT);
|
|
569
|
+
extendMemo(memos, slot, held, branch.slice(held.branchCount), branchKey, service);
|
|
518
570
|
return { tree: held.tree, memo: held };
|
|
519
571
|
}
|
|
520
572
|
const tree = readTreeMapFull(service, root);
|
|
@@ -526,7 +578,78 @@ function currentTree(service, root) {
|
|
|
526
578
|
return { tree, memo };
|
|
527
579
|
}
|
|
528
580
|
return { tree };
|
|
529
|
-
});
|
|
581
|
+
}, { operation: 'tree fold' });
|
|
582
|
+
}
|
|
583
|
+
/** The memo extended in place by `fresh`, the branch log's entries after its own, which leave the log at `branchKey`,
|
|
584
|
+
* with the step that records the subjects they touched. */
|
|
585
|
+
function extendMemo(memos, slot, held, fresh, branchKey, service) {
|
|
586
|
+
const keys = touchedKeys(fresh, held.aliases);
|
|
587
|
+
const from = memoStamp(held);
|
|
588
|
+
let appended;
|
|
589
|
+
try {
|
|
590
|
+
appended = insertionsDuring(held.tree, () => {
|
|
591
|
+
foldEntries(held.tree, fresh, held.landed);
|
|
592
|
+
foldAliases(held.tree, held.aliases, service, keys);
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
catch (error) {
|
|
596
|
+
memos.delete(slot);
|
|
597
|
+
throw error;
|
|
598
|
+
} // a half-folded memo is never read again
|
|
599
|
+
Object.assign(held, { branchKey, branchCount: held.branchCount + fresh.length, lastBranchId: fresh.length ? fresh[fresh.length - 1].id : held.lastBranchId });
|
|
600
|
+
held.steps.push({ from, to: memoStamp(held), keys, appended });
|
|
601
|
+
if (held.steps.length > TREE_STEPS_KEPT)
|
|
602
|
+
held.steps.splice(0, held.steps.length - TREE_STEPS_KEPT);
|
|
603
|
+
}
|
|
604
|
+
// AN OWN APPEND EXTENDS THE READS' MEMO (S2 R17c). A write appended its entries and the next read found the facts
|
|
605
|
+
// moved, so it took the history lock, read the facts again and the log's new bytes, and extended the memo with the
|
|
606
|
+
// entries this process had just written: in a tab, where each of those is a call into the kernel, about twenty calls
|
|
607
|
+
// per command that writes, taken again by the command after it. The writer, still holding the history lock, extends
|
|
608
|
+
// the memo with its own entries and keeps the tree's facts under the generation its own write left, so the next read
|
|
609
|
+
// asks one question. It does so only where the store can say its write was the one write since the generation it
|
|
610
|
+
// read just before (`generationAfterOwnWrite`), the facts were kept under that generation and the memo stood at them,
|
|
611
|
+
// the parent side's facts read after the append are still the kept ones, and the log grew by exactly its bytes;
|
|
612
|
+
// otherwise it extends nothing, and the next read checks as before.
|
|
613
|
+
/** Append `data` (whole JSONL lines of a service's branch log, `append` writing them) and, when the reads' memo held
|
|
614
|
+
* the tree as it stood, extend it by them. Called holding the directory's history lock. Answers the log's facts
|
|
615
|
+
* after the append (`size:mtimeMs`) when it read them, for a caller keyed on the same. */
|
|
616
|
+
export function appendToBranchLog(service, root, data, append) {
|
|
617
|
+
const store = getActiveWorldStore();
|
|
618
|
+
const memos = treeMemos.get(store);
|
|
619
|
+
const slot = `${service}\u0000${root ?? ''}`;
|
|
620
|
+
const held = memos?.get(slot);
|
|
621
|
+
const branchLog = branchLogPath(service, root);
|
|
622
|
+
const directory = dirname(branchLog);
|
|
623
|
+
const kept = keptFacts.get(store)?.get(directory);
|
|
624
|
+
const standing = held !== undefined && kept !== undefined && kept.parentKey === held.parentKey && kept.branchKey === held.branchKey;
|
|
625
|
+
const before = standing && store.generation && store.generationAfterOwnWrite ? store.generation(directory) : null;
|
|
626
|
+
append();
|
|
627
|
+
if (!memos || !held || !kept || before === null || kept.generation !== before)
|
|
628
|
+
return undefined;
|
|
629
|
+
const after = store.generationAfterOwnWrite(directory, before);
|
|
630
|
+
if (after === null)
|
|
631
|
+
return undefined;
|
|
632
|
+
// read after the generation, as treeFacts reads its facts. The parent side is read again too: a writer the generation
|
|
633
|
+
// does not see (an older version's, or one that died before its second byte) may have moved it under the kept
|
|
634
|
+
// generation, and carried forward its old key would outlive every append this process makes (S2 R17c review).
|
|
635
|
+
const branchKey = statKey(branchLog);
|
|
636
|
+
if (parentKeyOf(service, root) !== kept.parentKey)
|
|
637
|
+
return branchKey;
|
|
638
|
+
const grown = (key) => (key === '-' ? 0 : Number(key.slice(0, key.indexOf(':'))));
|
|
639
|
+
const fresh = [];
|
|
640
|
+
// line numbers in a refusal count from this append's first line
|
|
641
|
+
parseLines(`${branchLog} (appended)`, data.split('\n'), 0, fresh);
|
|
642
|
+
if (grown(branchKey) !== grown(held.branchKey) + Buffer.byteLength(data) || fresh.some((e) => e.op === 'revert'))
|
|
643
|
+
return branchKey;
|
|
644
|
+
// the write has landed: a fold that fails here drops the memo (extendMemo) and the next read folds in full, never failing the write
|
|
645
|
+
try {
|
|
646
|
+
extendMemo(memos, slot, held, fresh, branchKey, service);
|
|
647
|
+
}
|
|
648
|
+
catch {
|
|
649
|
+
return branchKey;
|
|
650
|
+
}
|
|
651
|
+
keptFacts.get(store).set(directory, { parentKey: kept.parentKey, branchKey, generation: after });
|
|
652
|
+
return branchKey;
|
|
530
653
|
}
|
|
531
654
|
/** What changed in a service's tree since `since` (a `treeStamp` an earlier read was made at): the subjects
|
|
532
655
|
* written since, as resources; the keys (`type:id`) of those no longer in the tree; and, of the changed, the keys
|
|
@@ -637,7 +760,7 @@ function readTreeMapFull(service, root, opts = {}) {
|
|
|
637
760
|
getActiveWorldStore().writeAtomic(checkpointPath(service, root), JSON.stringify({ parentDigest, branchDigest, branchCount: branch.length, subjects: [...tree.values()], ...(now === facts ? { facts } : {}) }));
|
|
638
761
|
}
|
|
639
762
|
return tree;
|
|
640
|
-
});
|
|
763
|
+
}, { operation: 'tree fold' });
|
|
641
764
|
}
|
|
642
765
|
export function cutCheckpoint(service, root) {
|
|
643
766
|
return withHistoryLock(worldPaths(service, root).dir, () => {
|
|
@@ -646,7 +769,7 @@ export function cutCheckpoint(service, root) {
|
|
|
646
769
|
const inherited = inheritedHistory(service, root);
|
|
647
770
|
const own = ownParentEntries(service, root);
|
|
648
771
|
getActiveWorldStore().writeAtomic(checkpointPath(service, root), JSON.stringify({ parentDigest: hashFieldValue({ projectionVersion: TREE_PROJECTION_VERSION, inherited, own }), branchDigest: hashFieldValue(branchEntries(service, root)), branchCount: branchEntries(service, root).length, subjects }));
|
|
649
|
-
});
|
|
772
|
+
}, { operation: 'checkpoint' });
|
|
650
773
|
}
|
|
651
774
|
/** The branch's entries the parent does not hold: `set` rows, not reverted, not landed. */
|
|
652
775
|
export function unpushedEntries(service, root) {
|
|
@@ -745,7 +868,7 @@ export function appendParentEntry(entry, root) {
|
|
|
745
868
|
index.ids.add(entry.id);
|
|
746
869
|
index.key = statKey(path);
|
|
747
870
|
return { appended: true };
|
|
748
|
-
}));
|
|
871
|
+
}, { operation: 'parent append' }), { operation: 'parent append' });
|
|
749
872
|
}
|
|
750
873
|
/** The whole log of a twin as a served world hands it out: the parent view, then the branch's own
|
|
751
874
|
* entries, one sequence with a position. A clone's parent is exactly this. */
|
|
@@ -823,7 +946,7 @@ export function rebaseBranch(service, root, opts = {}) {
|
|
|
823
946
|
dropCheckpoint(service, root);
|
|
824
947
|
}
|
|
825
948
|
return { moved, from, to, conflicts };
|
|
826
|
-
});
|
|
949
|
+
}, { operation: 'branch-pointer adjustment' });
|
|
827
950
|
}
|
|
828
951
|
/**
|
|
829
952
|
* HISTORY through the kernel: every entry that touched a subject (or every subject of a type), parent
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
export interface OriginalInputReference {
|
|
2
|
+
version: 1;
|
|
3
|
+
/** Relative to the needs file, or to the World configuration after init copies it. */
|
|
4
|
+
root: string;
|
|
5
|
+
manifest: "manifest.json";
|
|
6
|
+
sha256: string;
|
|
7
|
+
inventoryDigest: string;
|
|
8
|
+
}
|
|
9
|
+
export interface OriginalInputCapability {
|
|
10
|
+
version: 1;
|
|
11
|
+
manifestArg: "--original-inputs";
|
|
12
|
+
rootArg: "--original-root";
|
|
13
|
+
digestArg: "--original-inputs-sha256";
|
|
14
|
+
/** Image paths whose complete overlay contents the consumer requires. */
|
|
15
|
+
paths: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface OriginalInputEntry {
|
|
18
|
+
target: string;
|
|
19
|
+
type: "file" | "directory" | "link";
|
|
20
|
+
mode: number;
|
|
21
|
+
bytes?: number;
|
|
22
|
+
sha256?: string;
|
|
23
|
+
object?: string;
|
|
24
|
+
link?: string;
|
|
25
|
+
source: {
|
|
26
|
+
kind: "image" | "project";
|
|
27
|
+
path: string;
|
|
28
|
+
layer?: string;
|
|
29
|
+
blob?: string;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export interface ManagedOriginalInputs {
|
|
33
|
+
kind: "volter.managed-original-inputs";
|
|
34
|
+
version: 1;
|
|
35
|
+
service: string;
|
|
36
|
+
family: string;
|
|
37
|
+
/** Canonical selected service declaration; used to refuse a different stack on reuse. */
|
|
38
|
+
declaration: string;
|
|
39
|
+
source: {
|
|
40
|
+
image: string;
|
|
41
|
+
manifest: string;
|
|
42
|
+
config: string;
|
|
43
|
+
layers: string[];
|
|
44
|
+
commit: string;
|
|
45
|
+
compose: string;
|
|
46
|
+
composeSha256: string;
|
|
47
|
+
composeBytes: number;
|
|
48
|
+
composeObject: string;
|
|
49
|
+
};
|
|
50
|
+
/** Authenticated complete image metadata, before the declared mounts overlay it. */
|
|
51
|
+
imageInventory: Array<{
|
|
52
|
+
target: string;
|
|
53
|
+
type: string;
|
|
54
|
+
mode: number;
|
|
55
|
+
bytes: number;
|
|
56
|
+
layer: string;
|
|
57
|
+
link?: string;
|
|
58
|
+
}>;
|
|
59
|
+
imageInventoryDigest: string;
|
|
60
|
+
projectInventory: Array<{
|
|
61
|
+
path: string;
|
|
62
|
+
mode: number;
|
|
63
|
+
blob: string;
|
|
64
|
+
}>;
|
|
65
|
+
projectInventoryDigest: string;
|
|
66
|
+
roots: string[];
|
|
67
|
+
/** Complete contents beneath roots, plus every original project bind mount. */
|
|
68
|
+
inventory: OriginalInputEntry[];
|
|
69
|
+
inventoryDigest: string;
|
|
70
|
+
start: {
|
|
71
|
+
imageConfig: Record<string, unknown>;
|
|
72
|
+
service: Record<string, unknown>;
|
|
73
|
+
imageEntrypoint: string[] | null;
|
|
74
|
+
imageCommand: string[] | null;
|
|
75
|
+
command?: string[];
|
|
76
|
+
entrypoint?: string[];
|
|
77
|
+
environment: Record<string, string>;
|
|
78
|
+
envFiles: Array<{
|
|
79
|
+
path: string;
|
|
80
|
+
bytes: number;
|
|
81
|
+
sha256: string;
|
|
82
|
+
object: string;
|
|
83
|
+
}>;
|
|
84
|
+
unset: string[];
|
|
85
|
+
selfHosts: string[];
|
|
86
|
+
mounts: Array<{
|
|
87
|
+
kind: string;
|
|
88
|
+
source?: string;
|
|
89
|
+
target: string;
|
|
90
|
+
readOnly: boolean;
|
|
91
|
+
}>;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export declare const originalTarget: (path: string) => boolean;
|
|
95
|
+
export declare const originalRelative: (path: string) => boolean;
|
|
96
|
+
export declare function referenceOf(value: unknown): OriginalInputReference;
|
|
97
|
+
/** Hash and validate neutral carrier data. The caller supplies I/O; no pack/vendor behavior or import effects. */
|
|
98
|
+
export declare function readSnapshot(bytes: Uint8Array, expected: string, readObject: (path: string, bytes: number) => Uint8Array): {
|
|
99
|
+
manifest: ManagedOriginalInputs;
|
|
100
|
+
objects: ReadonlyMap<string, Uint8Array>;
|
|
101
|
+
};
|