@amalgm/shell 0.1.121 → 0.1.123
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/content-direct.d.ts
CHANGED
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Downloads no longer relay bytes through the gateway. This plane asks the
|
|
5
5
|
* gateway for two control facts only — the per-resource content key, handed
|
|
6
|
-
* once per resource over the authenticated wire, and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* once per resource over the authenticated wire, and content refs, batched by
|
|
7
|
+
* Live's refs broker: a short-lived storage URL per object plus, for objects
|
|
8
|
+
* packed inside one immutable pack, the exact byte range holding their sealed
|
|
9
|
+
* envelope. Same-turn range requests against one pack merge into minimal
|
|
10
|
+
* spans — one ranged GET each — and every envelope is opened locally. Bytes
|
|
11
|
+
* travel storage → this machine; the gateway signs and revokes, nothing more.
|
|
10
12
|
*/
|
|
11
|
-
import { type
|
|
13
|
+
import { type ContentObjectName } from "@amalgm/live";
|
|
12
14
|
interface DirectContentWire {
|
|
13
15
|
request(frame: Record<string, unknown> & {
|
|
14
16
|
type: string;
|
|
@@ -19,12 +21,13 @@ export declare class DirectContentPlane {
|
|
|
19
21
|
* process is enough; it lives only in memory, never at rest. */
|
|
20
22
|
private readonly keys;
|
|
21
23
|
private readonly brokers;
|
|
24
|
+
private readonly spans;
|
|
22
25
|
private readonly wire;
|
|
23
26
|
constructor(wire: DirectContentWire);
|
|
24
27
|
/** Fetch one sealed storage object and open it. Every attempt asks for a
|
|
25
|
-
* fresh
|
|
26
|
-
* immediately and never reused. */
|
|
27
|
-
fetchObject(resourceId: string, object:
|
|
28
|
+
* fresh ref — URL expiry is the gateway's revocation lever, so URLs are
|
|
29
|
+
* used immediately and never reused. */
|
|
30
|
+
fetchObject(resourceId: string, object: ContentObjectName): Promise<Buffer>;
|
|
28
31
|
private contentKey;
|
|
29
32
|
private broker;
|
|
30
33
|
}
|
package/dist/content-direct.js
CHANGED
|
@@ -3,47 +3,75 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Downloads no longer relay bytes through the gateway. This plane asks the
|
|
5
5
|
* gateway for two control facts only — the per-resource content key, handed
|
|
6
|
-
* once per resource over the authenticated wire, and
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* once per resource over the authenticated wire, and content refs, batched by
|
|
7
|
+
* Live's refs broker: a short-lived storage URL per object plus, for objects
|
|
8
|
+
* packed inside one immutable pack, the exact byte range holding their sealed
|
|
9
|
+
* envelope. Same-turn range requests against one pack merge into minimal
|
|
10
|
+
* spans — one ranged GET each — and every envelope is opened locally. Bytes
|
|
11
|
+
* travel storage → this machine; the gateway signs and revokes, nothing more.
|
|
10
12
|
*/
|
|
11
|
-
import {
|
|
13
|
+
import { createRefsBroker, createSpanFetcher, openProtectedEnvelopeBytes, } from "@amalgm/live";
|
|
12
14
|
import { WireRequestError } from "./wire-client.js";
|
|
15
|
+
function decodeRefs(frame) {
|
|
16
|
+
const urls = frame.urls;
|
|
17
|
+
const refs = frame.refs;
|
|
18
|
+
if (!Array.isArray(urls) || !urls.every((url) => typeof url === "string")
|
|
19
|
+
|| !Array.isArray(refs)) {
|
|
20
|
+
throw new Error("content authority answered an invalid refs reply");
|
|
21
|
+
}
|
|
22
|
+
return refs.map((raw) => {
|
|
23
|
+
const ref = raw;
|
|
24
|
+
if (!Number.isSafeInteger(ref.url) || Number(ref.url) < 0 || Number(ref.url) >= urls.length) {
|
|
25
|
+
throw new Error("content authority answered an invalid refs reply");
|
|
26
|
+
}
|
|
27
|
+
const url = urls[Number(ref.url)];
|
|
28
|
+
if (ref.offset == null && ref.length == null)
|
|
29
|
+
return { url };
|
|
30
|
+
if (!Number.isSafeInteger(ref.offset) || Number(ref.offset) < 0
|
|
31
|
+
|| !Number.isSafeInteger(ref.length) || Number(ref.length) < 1
|
|
32
|
+
|| !Number.isSafeInteger(Number(ref.offset) + Number(ref.length))) {
|
|
33
|
+
throw new Error("content authority answered an invalid refs reply");
|
|
34
|
+
}
|
|
35
|
+
return { url, offset: Number(ref.offset), length: Number(ref.length) };
|
|
36
|
+
});
|
|
37
|
+
}
|
|
13
38
|
export class DirectContentPlane {
|
|
14
39
|
/** Key material is stable for a resource's lifetime, so one handoff per
|
|
15
40
|
* process is enough; it lives only in memory, never at rest. */
|
|
16
41
|
keys = new Map();
|
|
17
42
|
brokers = new Map();
|
|
43
|
+
spans;
|
|
18
44
|
wire;
|
|
19
45
|
constructor(wire) {
|
|
20
46
|
this.wire = wire;
|
|
47
|
+
this.spans = createSpanFetcher({ fetchSpan: fetchStorageSpan });
|
|
21
48
|
}
|
|
22
49
|
/** Fetch one sealed storage object and open it. Every attempt asks for a
|
|
23
|
-
* fresh
|
|
24
|
-
* immediately and never reused. */
|
|
50
|
+
* fresh ref — URL expiry is the gateway's revocation lever, so URLs are
|
|
51
|
+
* used immediately and never reused. */
|
|
25
52
|
async fetchObject(resourceId, object) {
|
|
26
|
-
const [{ key, contract },
|
|
53
|
+
const [{ key, contract }, ref] = await Promise.all([
|
|
27
54
|
this.contentKey(resourceId),
|
|
28
|
-
this.broker(resourceId).
|
|
55
|
+
this.broker(resourceId).ref(object),
|
|
29
56
|
]);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
// that are immediately following a successful immutable put may opt
|
|
34
|
-
// into their existing bounded not-found retry; other callers fail.
|
|
35
|
-
throw new WireRequestError({
|
|
36
|
-
type: "shared.error",
|
|
37
|
-
code: "entity_content_not_found",
|
|
38
|
-
message: `content storage has no ${object.kind} ${object.sha256}`,
|
|
39
|
-
status: 404,
|
|
40
|
-
retryable: false,
|
|
41
|
-
});
|
|
57
|
+
let sealed;
|
|
58
|
+
try {
|
|
59
|
+
sealed = await this.spans.fetch(ref);
|
|
42
60
|
}
|
|
43
|
-
|
|
44
|
-
|
|
61
|
+
catch (error) {
|
|
62
|
+
// The span fetch cannot name the object it served; restore the
|
|
63
|
+
// caller-facing identity on the authority's established missing code.
|
|
64
|
+
if (error instanceof WireRequestError && error.code === "entity_content_not_found") {
|
|
65
|
+
throw new WireRequestError({
|
|
66
|
+
type: "shared.error",
|
|
67
|
+
code: "entity_content_not_found",
|
|
68
|
+
message: `content storage has no ${object.kind} ${object.sha256}`,
|
|
69
|
+
status: 404,
|
|
70
|
+
retryable: false,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
throw error;
|
|
45
74
|
}
|
|
46
|
-
const sealed = new Uint8Array(await response.arrayBuffer());
|
|
47
75
|
const opened = await openProtectedEnvelopeBytes(key, sealed, {
|
|
48
76
|
resourceId,
|
|
49
77
|
contract,
|
|
@@ -79,18 +107,14 @@ export class DirectContentPlane {
|
|
|
79
107
|
broker(resourceId) {
|
|
80
108
|
let broker = this.brokers.get(resourceId);
|
|
81
109
|
if (!broker) {
|
|
82
|
-
broker =
|
|
83
|
-
|
|
110
|
+
broker = createRefsBroker({
|
|
111
|
+
requestRefs: async (objects) => {
|
|
84
112
|
const frame = await this.wire.request({
|
|
85
|
-
type: "private.entity-content.
|
|
113
|
+
type: "private.entity-content.refs",
|
|
86
114
|
resource_id: resourceId,
|
|
87
115
|
objects: objects.map((object) => ({ kind: object.kind, sha256: object.sha256 })),
|
|
88
|
-
}, ["private.entity-content.
|
|
89
|
-
|
|
90
|
-
if (!Array.isArray(urls) || !urls.every((url) => typeof url === "string")) {
|
|
91
|
-
throw new Error("content authority answered an invalid presign reply");
|
|
92
|
-
}
|
|
93
|
-
return urls;
|
|
116
|
+
}, ["private.entity-content.refs-result"]);
|
|
117
|
+
return decodeRefs(frame);
|
|
94
118
|
},
|
|
95
119
|
});
|
|
96
120
|
this.brokers.set(resourceId, broker);
|
|
@@ -98,4 +122,29 @@ export class DirectContentPlane {
|
|
|
98
122
|
return broker;
|
|
99
123
|
}
|
|
100
124
|
}
|
|
125
|
+
/** One HTTP GET against content storage: the whole object, or exactly one
|
|
126
|
+
* pack span. A server that ignores the Range header and answers the full
|
|
127
|
+
* object is sliced here — the span fetcher's length law rejects anything
|
|
128
|
+
* short or shifted. */
|
|
129
|
+
async function fetchStorageSpan(url, span) {
|
|
130
|
+
const response = await fetch(url, span ? {
|
|
131
|
+
headers: { range: `bytes=${span.offset}-${span.offset + span.length - 1}` },
|
|
132
|
+
} : undefined);
|
|
133
|
+
if (response.status === 404) {
|
|
134
|
+
throw new WireRequestError({
|
|
135
|
+
type: "shared.error",
|
|
136
|
+
code: "entity_content_not_found",
|
|
137
|
+
message: "content storage has no object at a referenced location",
|
|
138
|
+
status: 404,
|
|
139
|
+
retryable: false,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
if (!response.ok) {
|
|
143
|
+
throw new Error(`content storage answered ${response.status} for a content read`);
|
|
144
|
+
}
|
|
145
|
+
const body = new Uint8Array(await response.arrayBuffer());
|
|
146
|
+
if (!span || response.status === 206)
|
|
147
|
+
return body;
|
|
148
|
+
return body.subarray(span.offset, span.offset + span.length);
|
|
149
|
+
}
|
|
101
150
|
//# sourceMappingURL=content-direct.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-direct.js","sourceRoot":"","sources":["../src/content-direct.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"content-direct.js","sourceRoot":"","sources":["../src/content-direct.ts"],"names":[],"mappings":"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"}
|
package/dist/user-ground-host.js
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, lstatSync, realpathSync, readFileSync, readdirSync, readlin
|
|
|
3
3
|
import { open, readFile } from "node:fs/promises";
|
|
4
4
|
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
5
5
|
import { buildUserHomeManifest, buildUserManifest, liveMachineStateDir, scopedAmalgmDir, shippedUserHomeDeclaration, } from "@amalgm/core/identity";
|
|
6
|
-
import { CHUNK_BYTES, CONTENT_CONTRACT, INLINE_CARGO_MAX_BYTES, ENTITY_CLOUD_CONTRACT, ENTITY_CLOUD_SCHEMA_VERSION, artifactForRecord, canonicalVersion, checkContentManifest, classifyDirectory, classifyFile, classifyRegisteredRoot, createLocalEntityRecord, createEntityRecordAuthorityPort, convergeUserGround, decodeAcceptedEntityRecord, deriveUploadManifest, createUserGroundEnrollmentPolicy, isRepositoryMetadataEntry, indexRepositoryTerritory, downloadAll as downloadAllArtifacts, encodeEntityRecord, EntityApplyRail, EntityRecordRail, membershipHash, pathIsSuspect,
|
|
6
|
+
import { CHUNK_BYTES, CONTENT_CONTRACT, INLINE_CARGO_MAX_BYTES, ENTITY_CLOUD_CONTRACT, ENTITY_CLOUD_SCHEMA_VERSION, artifactForRecord, canonicalVersion, checkContentManifest, classifyDirectory, classifyFile, classifyRegisteredRoot, createLocalEntityRecord, createEntityRecordAuthorityPort, convergeUserGround, decodeAcceptedEntityRecord, deriveUploadManifest, createUserGroundEnrollmentPolicy, isRepositoryMetadataEntry, indexRepositoryTerritory, downloadAll as downloadAllArtifacts, encodeEntityRecord, EntityApplyRail, EntityRecordRail, membershipHash, pathIsSuspect, CONTENT_REFS_BATCH_OBJECTS, privateEntityResourceId, repositoryIdentityHash, sameRecords, snapshotFromRecords, stableJson, streamCargo, travelingRecords, upload as uploadArtifact, userGroundRecords, GRAPH_HEAD_OPERATION_KIND, } from "@amalgm/live";
|
|
7
7
|
import Database from "better-sqlite3";
|
|
8
8
|
import { atomicCopy, atomicWrite, ensurePrivateDir, ensureUserDir } from "./filesystem.js";
|
|
9
9
|
import { emitFilesStage, } from "./files-observability.js";
|
|
@@ -833,10 +833,10 @@ export class UserGroundHost {
|
|
|
833
833
|
throw new Error("entity Record rail already started");
|
|
834
834
|
await this.wire.open();
|
|
835
835
|
// One floor, no per-feature gates: this shell and its gateway release
|
|
836
|
-
// together, and the gateway ships first.
|
|
837
|
-
//
|
|
838
|
-
// resolve
|
|
839
|
-
if (this.wire.protocolVersion <
|
|
836
|
+
// together, and the gateway ships first. 14 = immutable content packs
|
|
837
|
+
// with a refs frame answering locations; an older gateway still speaks
|
|
838
|
+
// presign and cannot resolve a packed object at all.
|
|
839
|
+
if (this.wire.protocolVersion < 14) {
|
|
840
840
|
throw new Error("gateway speaks an older wire protocol than this shell");
|
|
841
841
|
}
|
|
842
842
|
this.adoptCloudDeliveryBaseline(identity, this.cloudState.deliveryWatermark);
|
|
@@ -1637,8 +1637,9 @@ export class UserGroundHost {
|
|
|
1637
1637
|
};
|
|
1638
1638
|
// Every storage object — the manifest and each block — is fetched
|
|
1639
1639
|
// straight from content storage over a presigned URL and opened locally;
|
|
1640
|
-
//
|
|
1641
|
-
//
|
|
1640
|
+
// packed objects arrive as merged byte ranges of their immutable pack.
|
|
1641
|
+
// The wire carries only the key handoff and refs requests. A retry asks
|
|
1642
|
+
// for a fresh ref every attempt.
|
|
1642
1643
|
const fetchObject = async (object) => {
|
|
1643
1644
|
requests += 1;
|
|
1644
1645
|
const bytes = await retryContent(() => this.direct.fetchObject(resourceId, object), true, retryAttempts);
|
|
@@ -2275,8 +2276,8 @@ export class UserGroundHost {
|
|
|
2275
2276
|
* frames; the answer is the only permission to skip an upload. */
|
|
2276
2277
|
async sealedContentHashes(resourceId, hashes) {
|
|
2277
2278
|
const batches = [];
|
|
2278
|
-
for (let start = 0; start < hashes.length; start +=
|
|
2279
|
-
batches.push(hashes.slice(start, start +
|
|
2279
|
+
for (let start = 0; start < hashes.length; start += CONTENT_REFS_BATCH_OBJECTS) {
|
|
2280
|
+
batches.push(hashes.slice(start, start + CONTENT_REFS_BATCH_OBJECTS));
|
|
2280
2281
|
}
|
|
2281
2282
|
const sealed = new Set();
|
|
2282
2283
|
const answers = await Promise.all(batches.map((batch) => retryContent(() => this.wire.request({
|