@amalgm/shell 0.1.93 → 0.1.94
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/PURPOSE.md +27 -19
- package/README.md +2 -1
- package/dist/content-cache-host.d.ts +2 -4
- package/dist/content-cache-host.js +11 -37
- package/dist/content-cache-host.js.map +1 -1
- package/dist/content-direct.d.ts +31 -0
- package/dist/content-direct.js +101 -0
- package/dist/content-direct.js.map +1 -0
- package/dist/content-wire-codec.d.ts +3 -7
- package/dist/content-wire-codec.js +4 -25
- package/dist/content-wire-codec.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/user-ground-host.d.ts +1 -0
- package/dist/user-ground-host.js +38 -113
- package/dist/user-ground-host.js.map +1 -1
- package/dist/wire-client.d.ts +0 -1
- package/dist/wire-client.js +7 -16
- package/dist/wire-client.js.map +1 -1
- package/package.json +2 -2
package/dist/user-ground-host.js
CHANGED
|
@@ -12,7 +12,8 @@ import { EntityRecordSqliteStore } from "./entity-record-store.js";
|
|
|
12
12
|
import { observeEntityRecordPorts } from "./entity-record-observability.js";
|
|
13
13
|
import { indexRowsByOutermostRoot } from "./ground-root-index.js";
|
|
14
14
|
import { ContentCacheDownload, captureContentFile, hashContentFile, sealCapturedArtifact, } from "./content-cache-host.js";
|
|
15
|
-
import {
|
|
15
|
+
import { DirectContentPlane } from "./content-direct.js";
|
|
16
|
+
import { encodeContentWireBytes } from "./content-wire-codec.js";
|
|
16
17
|
import { exactTextReplay, planGroundDetection, reconcileGroundUUIDs, } from "./detection/portable.js";
|
|
17
18
|
import { AcceptedInboxResultIndex } from "./detection/accepted-result.js";
|
|
18
19
|
import { sameNotebookBasisRow } from "./detection/notebook-basis.js";
|
|
@@ -26,8 +27,13 @@ import { GroundCoordinator } from "./ground-coordination.js";
|
|
|
26
27
|
import { submitMutationOperation } from "./paged-mutation-submit.js";
|
|
27
28
|
import { WireClient, WireRequestError } from "./wire-client.js";
|
|
28
29
|
const SMALL_CONTENT_UPLOAD_CONCURRENCY = 16;
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
/** Artifact lanes for a download phase. Direct storage fetches cost the
|
|
31
|
+
* gateway nothing, so parallelism is bounded by this machine's pipe rather
|
|
32
|
+
* than authority fairness. */
|
|
33
|
+
const FILE_CONTENT_DOWNLOAD_CONCURRENCY = 16;
|
|
34
|
+
/** Block lanes within one artifact. Most files are a single block; large
|
|
35
|
+
* repository packs fan their chunks across this. */
|
|
36
|
+
const DIRECT_BLOCK_DOWNLOAD_CONCURRENCY = 8;
|
|
31
37
|
const DETECT_QUIET_MS = 12;
|
|
32
38
|
const DETECT_MAX_DEFERRAL_MS = 75;
|
|
33
39
|
const DETECT_RETRY_MS = 250;
|
|
@@ -47,6 +53,7 @@ const GROUND_ROW_COLUMNS = [
|
|
|
47
53
|
export class UserGroundHost {
|
|
48
54
|
options;
|
|
49
55
|
wire;
|
|
56
|
+
direct;
|
|
50
57
|
watchHost;
|
|
51
58
|
activeIdentity = null;
|
|
52
59
|
rescanTimer = null;
|
|
@@ -75,6 +82,9 @@ export class UserGroundHost {
|
|
|
75
82
|
runtimeVersion: options.runtimeVersion,
|
|
76
83
|
requestTimeoutMs: options.wireRequestTimeoutMs,
|
|
77
84
|
});
|
|
85
|
+
this.direct = new DirectContentPlane({
|
|
86
|
+
request: (frame, accept) => this.wire.request(frame, accept),
|
|
87
|
+
});
|
|
78
88
|
this.watchHost = new NodeWatchHost({
|
|
79
89
|
open: options.openWatch,
|
|
80
90
|
onSignal: () => this.scheduleRescan(),
|
|
@@ -670,10 +680,10 @@ export class UserGroundHost {
|
|
|
670
680
|
throw new Error("entity Record rail already started");
|
|
671
681
|
await this.wire.open();
|
|
672
682
|
// One floor, no per-feature gates: this shell and its gateway release
|
|
673
|
-
// together, and the gateway ships first.
|
|
674
|
-
// an older gateway
|
|
675
|
-
//
|
|
676
|
-
if (this.wire.protocolVersion <
|
|
683
|
+
// together, and the gateway ships first. 9 = direct content downloads;
|
|
684
|
+
// an older gateway still relays download bytes itself and drops the key
|
|
685
|
+
// and presign frames this shell depends on.
|
|
686
|
+
if (this.wire.protocolVersion < 9) {
|
|
677
687
|
throw new Error("gateway speaks an older wire protocol than this shell");
|
|
678
688
|
}
|
|
679
689
|
const store = new EntityRecordSqliteStore(initializeDatabase(this.databasePath(identity)));
|
|
@@ -1220,42 +1230,13 @@ export class UserGroundHost {
|
|
|
1220
1230
|
measurements: { journey: trace?.journey ?? "bootstrap", kind: artifact.kind },
|
|
1221
1231
|
});
|
|
1222
1232
|
const cache = { target: null };
|
|
1223
|
-
//
|
|
1224
|
-
//
|
|
1225
|
-
// the
|
|
1226
|
-
//
|
|
1227
|
-
const
|
|
1228
|
-
const sliceChunks = (packed, manifest, indexes) => {
|
|
1229
|
-
const offsets = [];
|
|
1230
|
-
let offset = 0;
|
|
1231
|
-
for (const chunk of manifest.chunks) {
|
|
1232
|
-
offsets.push(offset);
|
|
1233
|
-
offset += chunk.bytes;
|
|
1234
|
-
}
|
|
1235
|
-
return Buffer.concat(indexes.map((index) => {
|
|
1236
|
-
const chunk = manifest.chunks[index];
|
|
1237
|
-
const start = offsets[index];
|
|
1238
|
-
if (!chunk || start === undefined)
|
|
1239
|
-
throw new Error(`content manifest has no chunk ${index}`);
|
|
1240
|
-
return packed.subarray(start, start + chunk.bytes);
|
|
1241
|
-
}));
|
|
1242
|
-
};
|
|
1243
|
-
const getChunk = async (manifest, index) => {
|
|
1244
|
-
if (prefetched.bytes)
|
|
1245
|
-
return sliceChunks(prefetched.bytes, manifest, [index]);
|
|
1246
|
-
const chunk = manifest.chunks[index];
|
|
1247
|
-
if (!chunk)
|
|
1248
|
-
throw new Error(`content manifest has no chunk ${index}`);
|
|
1233
|
+
// Every storage object — the manifest and each block — is fetched
|
|
1234
|
+
// straight from content storage over a presigned URL and opened locally;
|
|
1235
|
+
// the wire carries only the key handoff and signing requests. A retry
|
|
1236
|
+
// asks for a fresh URL every attempt.
|
|
1237
|
+
const fetchObject = async (object) => {
|
|
1249
1238
|
requests += 1;
|
|
1250
|
-
const
|
|
1251
|
-
type: "private.entity-content.get",
|
|
1252
|
-
resource_id: resourceId,
|
|
1253
|
-
content_hash: artifact.contentHash,
|
|
1254
|
-
kind: "chunk",
|
|
1255
|
-
part_index: index,
|
|
1256
|
-
sha256: chunk.sha256,
|
|
1257
|
-
}, ["private.entity-content.data"]), true, retryAttempts);
|
|
1258
|
-
const bytes = binaryFrameBytes(frame);
|
|
1239
|
+
const bytes = await retryContent(() => this.direct.fetchObject(resourceId, object), true, retryAttempts);
|
|
1259
1240
|
downloadedBytes += bytes.byteLength;
|
|
1260
1241
|
return bytes;
|
|
1261
1242
|
};
|
|
@@ -1267,73 +1248,39 @@ export class UserGroundHost {
|
|
|
1267
1248
|
// proves chunk identity; downloaded bytes are still hash-verified,
|
|
1268
1249
|
// so a stale local manifest can only fail loudly, never corrupt.
|
|
1269
1250
|
const local = knownManifest ?? readCachedManifest(cacheDir, artifact.contentHash);
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
}, ["private.entity-content.artifact"]), true, retryAttempts);
|
|
1280
|
-
const manifestJson = String(frame.manifest_json ?? "");
|
|
1281
|
-
downloadedBytes += Buffer.byteLength(manifestJson);
|
|
1282
|
-
const checked = checkContentManifest(JSON.parse(manifestJson), artifact.contentHash);
|
|
1283
|
-
if (!checked.ok)
|
|
1284
|
-
throw new Error(checked.error);
|
|
1285
|
-
if (frame.complete === true) {
|
|
1286
|
-
const decoded = await decodeContentWireBytes(binaryWireFrameBytes(frame), frame.content_encoding, Number(frame.bytes));
|
|
1287
|
-
if (decoded.byteLength !== checked.value.bytes) {
|
|
1288
|
-
throw new Error("artifact payload does not match its manifest");
|
|
1289
|
-
}
|
|
1290
|
-
prefetched.bytes = decoded;
|
|
1291
|
-
downloadedBytes += Number(frame.wire_bytes ?? frame.bytes);
|
|
1292
|
-
}
|
|
1293
|
-
cache.target = new ContentCacheDownload(cacheDir, artifact, checked.value);
|
|
1294
|
-
return checked.value;
|
|
1251
|
+
const manifest = local ?? await (async () => {
|
|
1252
|
+
const bytes = await fetchObject({ kind: "manifest", sha256: artifact.contentHash });
|
|
1253
|
+
const checked = checkContentManifest(JSON.parse(bytes.toString("utf8")), artifact.contentHash);
|
|
1254
|
+
if (!checked.ok)
|
|
1255
|
+
throw new Error(checked.error);
|
|
1256
|
+
return checked.value;
|
|
1257
|
+
})();
|
|
1258
|
+
cache.target = new ContentCacheDownload(cacheDir, artifact, manifest);
|
|
1259
|
+
return manifest;
|
|
1295
1260
|
},
|
|
1296
1261
|
hasChunk: async (_candidate, _manifest, index) => {
|
|
1297
1262
|
if (!cache.target)
|
|
1298
1263
|
throw new Error("download cache has no content manifest");
|
|
1299
1264
|
return cache.target.hasChunk(index);
|
|
1300
1265
|
},
|
|
1301
|
-
getChunk: async (_candidate, manifest, index) =>
|
|
1302
|
-
|
|
1303
|
-
if (
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
type: "private.entity-content.get-batch",
|
|
1307
|
-
resource_id: resourceId,
|
|
1308
|
-
content_hash: artifact.contentHash,
|
|
1309
|
-
chunks: indexes.map((index) => ({
|
|
1310
|
-
part_index: index,
|
|
1311
|
-
sha256: manifest.chunks[index]?.sha256,
|
|
1312
|
-
bytes: manifest.chunks[index]?.bytes,
|
|
1313
|
-
})),
|
|
1314
|
-
}, ["private.entity-content.data-batch"]), true, retryAttempts);
|
|
1315
|
-
requests += 1;
|
|
1316
|
-
const decoded = await decodeContentWireBytes(binaryWireFrameBytes(frame), frame.content_encoding, Number(frame.bytes));
|
|
1317
|
-
downloadedBytes += Number(frame.wire_bytes ?? frame.bytes);
|
|
1318
|
-
return decoded;
|
|
1266
|
+
getChunk: async (_candidate, manifest, index) => {
|
|
1267
|
+
const chunk = manifest.chunks[index];
|
|
1268
|
+
if (!chunk)
|
|
1269
|
+
throw new Error(`content manifest has no chunk ${index}`);
|
|
1270
|
+
return fetchObject({ kind: "block", sha256: chunk.sha256 });
|
|
1319
1271
|
},
|
|
1320
1272
|
putChunk: async (_candidate, _manifest, index, bytes) => {
|
|
1321
1273
|
if (!cache.target)
|
|
1322
1274
|
throw new Error("download cache has no content manifest");
|
|
1323
1275
|
await cache.target.putChunk(index, bytes);
|
|
1324
1276
|
},
|
|
1325
|
-
putChunkBatch: async (_candidate, _manifest, indexes, bytes) => {
|
|
1326
|
-
if (!cache.target)
|
|
1327
|
-
throw new Error("download cache has no content manifest");
|
|
1328
|
-
await cache.target.putChunkBatch(indexes, bytes);
|
|
1329
|
-
},
|
|
1330
1277
|
sealArtifact: async () => {
|
|
1331
1278
|
if (!cache.target)
|
|
1332
1279
|
throw new Error("download cache has no content manifest");
|
|
1333
1280
|
const sealed = await cache.target.seal();
|
|
1334
1281
|
return { local: sealed, bytes: sealed.bytes, contentHash: sealed.contentHash };
|
|
1335
1282
|
},
|
|
1336
|
-
},
|
|
1283
|
+
}, { concurrency: DIRECT_BLOCK_DOWNLOAD_CONCURRENCY });
|
|
1337
1284
|
this.stage({
|
|
1338
1285
|
primitive: "download",
|
|
1339
1286
|
stage: "immutable-content",
|
|
@@ -4689,28 +4636,6 @@ function readyFromFrame(frame) {
|
|
|
4689
4636
|
},
|
|
4690
4637
|
};
|
|
4691
4638
|
}
|
|
4692
|
-
/** Expose the WebSocket payload as a view. Live verifies content blocks
|
|
4693
|
-
* against their manifest, so the host must not copy or hash those bytes a
|
|
4694
|
-
* second time before returning them to the portable operation. */
|
|
4695
|
-
function binaryFrameBytes(frame) {
|
|
4696
|
-
const bytes = binaryWireFrameBytes(frame);
|
|
4697
|
-
if (frame.content_encoding !== undefined || bytes.length !== Number(frame.bytes)) {
|
|
4698
|
-
throw new Error("wire content byte count does not match its header");
|
|
4699
|
-
}
|
|
4700
|
-
return bytes;
|
|
4701
|
-
}
|
|
4702
|
-
function binaryWireFrameBytes(frame) {
|
|
4703
|
-
if (!(frame.data_bin instanceof Uint8Array)) {
|
|
4704
|
-
throw new Error("wire content response is not a binary frame");
|
|
4705
|
-
}
|
|
4706
|
-
const bytes = Buffer.isBuffer(frame.data_bin)
|
|
4707
|
-
? frame.data_bin
|
|
4708
|
-
: Buffer.from(frame.data_bin.buffer, frame.data_bin.byteOffset, frame.data_bin.byteLength);
|
|
4709
|
-
if (bytes.length !== Number(frame.wire_bytes ?? frame.bytes)) {
|
|
4710
|
-
throw new Error("wire content byte count does not match its header");
|
|
4711
|
-
}
|
|
4712
|
-
return bytes;
|
|
4713
|
-
}
|
|
4714
4639
|
/** Immutable content reads and writes are idempotent. Retry transient wire or
|
|
4715
4640
|
* authority failures; reads additionally tolerate the brief not-found window
|
|
4716
4641
|
* between an immutable object acknowledgement and globally visible R2 state. */
|