@amalgm/live 0.2.57 → 0.2.59

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 CHANGED
@@ -111,8 +111,11 @@ its cutover.
111
111
  binding to Watch. The intent clears only after coverage is healthy. Entity
112
112
  rows therefore never mean pending download, and visible Add ground is never
113
113
  left without its durable identity. Hidden staging that crosses a restart is
114
- rebuilt from verified immutable content; revealed ground that crosses that
115
- blind interval remains completely suspect until Detect settles it. The
114
+ untrusted resume substrate: ordinary retained chunks are reread and
115
+ re-hashed against the pinned manifest, missing or corrupt chunks are
116
+ fetched again, and the ordered whole artifact is proven before rows or
117
+ reveal are trusted. Revealed ground that crosses that blind interval
118
+ remains completely suspect until Detect settles it. The
116
119
  local SQLite table contains workspace rows only for boundaries materialized
117
120
  on that machine, while cloud reconciliation preserves every unmaterialized
118
121
  boundary. A fresh verified install may be Watch's initial baseline so the
@@ -183,21 +186,27 @@ its cutover.
183
186
  neither act may weaken the other's result.
184
187
  30. **Proof travels forward; disposable bytes need not.** Registration reads
185
188
  every ordinary text or binary file through one bounded stream to classify
186
- it, derive its content head, and retain any block-manifest evidence needed
187
- by the later Upload stage. A graph-only Register capture does not copy
188
- those same bytes into the machine cache merely to preserve them for
189
- Upload. Upload receives one seekable source selected by the host an
190
- already-sealed cache object when one exists, otherwise the registered
191
- ground itself and verifies every byte it sends against the captured
192
- content head. A typed source mismatch returns control to Register so it
193
- can recapture current ground; stale bytes can never be sealed or
194
- published. Download still writes received bytes once before their
195
- registered adapter consumes them. No file type or size permits a
189
+ it and derive its content head. When cloud cargo is missing, that same
190
+ capture stream carries the verified bytes forward: bounded complete small
191
+ artifacts enter the cargo stream, while large-file blocks become durable
192
+ under their own digests as they are read and the authority seals the
193
+ manifest only after every named block exists. A graph-only Register
194
+ capture never copies or rereads ground merely to preserve bytes for a
195
+ later Upload stage. A typed source mismatch returns control to Register so
196
+ it can recapture current ground; stale bytes can never be sealed or
197
+ published. A final missing-cargo inventory remains the publication
198
+ guarantor and may reread ground only when fused transport was unavailable
199
+ or refused. During Add, ordinary text and binary bytes land directly in
200
+ their hidden staged destinations in manifest order while set-wide fetches
201
+ remain bounded and concurrent, so their whole-artifact proof advances from
202
+ arriving bytes without rereading staging; links and repository transports
203
+ keep their dedicated adapter/cache rails. No file type or size permits a
196
204
  complete-file allocation in the bounded transfer path.
197
205
  31. **A content block is not a round trip.** Text and binary retain independent
198
- content-addressed block identities. Cold upload may move complete small
199
- artifacts in bounded cargo waves, while cold upload and download move
200
- adjacent missing blocks in bounded binary batches. Packing may reduce
206
+ content-addressed block identities. Cold upload moves complete small
207
+ artifacts in bounded cargo segments and adjacent missing large-file
208
+ blocks in bounded binary batches, while cold download merges packed spans.
209
+ Packing may reduce
201
210
  transport work but can never weaken per-block verification, durable sealing,
202
211
  or commit order.
203
212
  32. **A content layout owns a cloud namespace.** A writer change that derives
@@ -52,6 +52,17 @@ export interface CargoStreamReceipt {
52
52
  }
53
53
  /** Pack items in order into segments within the byte and artifact bounds. */
54
54
  export declare function planCargoSegments<T extends CargoItem>(items: readonly T[]): readonly CargoSegment<T>[];
55
+ /** A cargo stream whose items arrive while a walk is still discovering
56
+ * them. Full segments ship as they close; `add` applies backpressure when
57
+ * the shared window is full, and `flush` ships the final partial segment
58
+ * and settles every acknowledgement. After any rejection, `flush` still
59
+ * settles in-flight segments before rethrowing the first failure, so their
60
+ * sealed work stays durable for the resuming rerun. */
61
+ export interface CargoStream<T extends CargoItem> {
62
+ add(item: T): Promise<void>;
63
+ flush(): Promise<CargoStreamReceipt>;
64
+ }
65
+ export declare function openCargoStream<T extends CargoItem>(ports: CargoStreamPorts<T>, options?: CargoStreamOptions): CargoStream<T>;
55
66
  /** Stream one cold set of small artifacts as bounded pipelined segments.
56
67
  * Every item must come back sealed or the stream fails; a failure stops new
57
68
  * admission, lets in-flight segments settle, and leaves their sealed work
@@ -1 +1 @@
1
- {"version":3,"file":"cargo.d.ts","sourceRoot":"","sources":["../../src/transfer/cargo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,eAAO,MAAM,mBAAmB,QAA4B,CAAC;AAC7D;;;uDAGuD;AACvD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C;;;2EAG2E;AAC3E,eAAO,MAAM,4BAA4B,QAA0B,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,SAAS;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,SAAS;IACnD;;;uEAGmE;IACnE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,SAAS,EACnD,KAAK,EAAE,SAAS,CAAC,EAAE,GAClB,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,CAyB5B;AAED;;;qCAGqC;AACrC,wBAAsB,WAAW,CAAC,CAAC,SAAS,SAAS,EACnD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC1B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAqB7B"}
1
+ {"version":3,"file":"cargo.d.ts","sourceRoot":"","sources":["../../src/transfer/cargo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,eAAO,MAAM,mBAAmB,QAA4B,CAAC;AAC7D;;;uDAGuD;AACvD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C;;;2EAG2E;AAC3E,eAAO,MAAM,4BAA4B,QAA0B,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,gEAAgE;IAChE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY,CAAC,CAAC,SAAS,SAAS;IAC/C,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,SAAS;IACnD;;;uEAGmE;IACnE,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,SAAS,MAAM,EAAE,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAcD,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,SAAS,EACnD,KAAK,EAAE,SAAS,CAAC,EAAE,GAClB,SAAS,YAAY,CAAC,CAAC,CAAC,EAAE,CAiB5B;AAED;;;;;uDAKuD;AACvD,MAAM,WAAW,WAAW,CAAC,CAAC,SAAS,SAAS;IAC9C,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,KAAK,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAC;CACtC;AAED,wBAAgB,eAAe,CAAC,CAAC,SAAS,SAAS,EACjD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC1B,OAAO,GAAE,kBAAuB,GAC/B,WAAW,CAAC,CAAC,CAAC,CAuEhB;AAED;;;qCAGqC;AACrC,wBAAsB,WAAW,CAAC,CAAC,SAAS,SAAS,EACnD,KAAK,EAAE,SAAS,CAAC,EAAE,EACnB,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC1B,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAS7B"}
@@ -26,21 +26,24 @@ export const CARGO_SEGMENT_ARTIFACTS = 256;
26
26
  * fan-out, and worst-case payload residency (plaintext plus one encoded
27
27
  * copy per in-flight segment) stays comfortably inside a 1-GiB runtime. */
28
28
  export const CARGO_STREAM_IN_FLIGHT_BYTES = 4 * CARGO_SEGMENT_BYTES;
29
+ const assertCargoItem = (item) => {
30
+ if (typeof item.contentHash !== 'string' || item.contentHash.length === 0) {
31
+ throw new Error('cargo item is missing its content identity');
32
+ }
33
+ if (!Number.isSafeInteger(item.bytes) || item.bytes < 0) {
34
+ throw new Error('cargo item byte count is invalid');
35
+ }
36
+ if (item.bytes > CARGO_SEGMENT_BYTES) {
37
+ throw new Error('cargo item exceeds the segment byte bound');
38
+ }
39
+ };
29
40
  /** Pack items in order into segments within the byte and artifact bounds. */
30
41
  export function planCargoSegments(items) {
31
42
  const segments = [];
32
43
  let current = [];
33
44
  let bytes = 0;
34
45
  for (const item of items) {
35
- if (typeof item.contentHash !== 'string' || item.contentHash.length === 0) {
36
- throw new Error('cargo item is missing its content identity');
37
- }
38
- if (!Number.isSafeInteger(item.bytes) || item.bytes < 0) {
39
- throw new Error('cargo item byte count is invalid');
40
- }
41
- if (item.bytes > CARGO_SEGMENT_BYTES) {
42
- throw new Error('cargo item exceeds the segment byte bound');
43
- }
46
+ assertCargoItem(item);
44
47
  if (current.length > 0
45
48
  && (bytes + item.bytes > CARGO_SEGMENT_BYTES || current.length >= CARGO_SEGMENT_ARTIFACTS)) {
46
49
  segments.push({ items: current, bytes });
@@ -54,24 +57,95 @@ export function planCargoSegments(items) {
54
57
  segments.push({ items: current, bytes });
55
58
  return segments;
56
59
  }
60
+ export function openCargoStream(ports, options = {}) {
61
+ const lanes = options.lanes ?? DEFAULT_TRANSFER_CONCURRENCY;
62
+ const maxInFlightBytes = options.maxInFlightBytes ?? CARGO_STREAM_IN_FLIGHT_BYTES;
63
+ const inFlight = new Set();
64
+ let inFlightBytes = 0;
65
+ let failure;
66
+ let current = [];
67
+ let currentBytes = 0;
68
+ let segments = 0;
69
+ let artifacts = 0;
70
+ let bytes = 0;
71
+ const dispatch = async (segment) => {
72
+ const weight = Math.max(segment.bytes, 1);
73
+ while (failure === undefined
74
+ && (inFlight.size >= lanes
75
+ || (inFlight.size > 0 && inFlightBytes + weight > maxInFlightBytes))) {
76
+ await Promise.race(inFlight);
77
+ }
78
+ if (failure !== undefined)
79
+ throw failure.error;
80
+ inFlightBytes += weight;
81
+ const settled = (async () => {
82
+ const sealed = new Set(await ports.send(segment));
83
+ for (const item of segment.items) {
84
+ if (!sealed.has(item.contentHash)) {
85
+ throw new Error(`cargo authority did not seal ${item.contentHash}`);
86
+ }
87
+ }
88
+ segments += 1;
89
+ artifacts += segment.items.length;
90
+ bytes += segment.bytes;
91
+ })().then(() => { inFlight.delete(settled); inFlightBytes -= weight; }, (error) => {
92
+ inFlight.delete(settled);
93
+ inFlightBytes -= weight;
94
+ failure ??= { error };
95
+ });
96
+ inFlight.add(settled);
97
+ };
98
+ const closeCurrent = () => {
99
+ const segment = { items: current, bytes: currentBytes };
100
+ current = [];
101
+ currentBytes = 0;
102
+ return segment;
103
+ };
104
+ return {
105
+ async add(item) {
106
+ assertCargoItem(item);
107
+ if (failure !== undefined)
108
+ throw failure.error;
109
+ if (current.length > 0
110
+ && (currentBytes + item.bytes > CARGO_SEGMENT_BYTES
111
+ || current.length >= CARGO_SEGMENT_ARTIFACTS)) {
112
+ await dispatch(closeCurrent());
113
+ }
114
+ current.push(item);
115
+ currentBytes += item.bytes;
116
+ },
117
+ async flush() {
118
+ if (failure === undefined && current.length > 0) {
119
+ try {
120
+ await dispatch(closeCurrent());
121
+ }
122
+ catch {
123
+ // The failure is recorded; settle the window before rethrowing.
124
+ }
125
+ }
126
+ while (inFlight.size > 0)
127
+ await Promise.race(inFlight);
128
+ if (failure !== undefined)
129
+ throw failure.error;
130
+ return { segments, artifacts, bytes };
131
+ },
132
+ };
133
+ }
57
134
  /** Stream one cold set of small artifacts as bounded pipelined segments.
58
135
  * Every item must come back sealed or the stream fails; a failure stops new
59
136
  * admission, lets in-flight segments settle, and leaves their sealed work
60
137
  * durable for the resuming rerun. */
61
138
  export async function streamCargo(items, ports, options = {}) {
62
- const segments = planCargoSegments(items);
63
- let artifacts = 0;
64
- let bytes = 0;
65
- await weightedParallelForEach(segments, options.lanes ?? DEFAULT_TRANSFER_CONCURRENCY, options.maxInFlightBytes ?? CARGO_STREAM_IN_FLIGHT_BYTES, (segment) => Math.max(segment.bytes, 1), async (segment) => {
66
- const sealed = new Set(await ports.send(segment));
67
- for (const item of segment.items) {
68
- if (!sealed.has(item.contentHash)) {
69
- throw new Error(`cargo authority did not seal ${item.contentHash}`);
70
- }
71
- }
72
- artifacts += segment.items.length;
73
- bytes += segment.bytes;
74
- });
75
- return { segments: segments.length, artifacts, bytes };
139
+ for (const item of items)
140
+ assertCargoItem(item);
141
+ const stream = openCargoStream(ports, options);
142
+ try {
143
+ for (const item of items)
144
+ await stream.add(item);
145
+ }
146
+ catch {
147
+ // add() already recorded the failure; flush settles and rethrows it.
148
+ }
149
+ return stream.flush();
76
150
  }
77
151
  //# sourceMappingURL=cargo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cargo.js","sourceRoot":"","sources":["../../src/transfer/cargo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cargo.js","sourceRoot":"","sources":["../../src/transfer/cargo.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,13 @@
10
10
  * still its own storage request — the set changes scheduling, not the
11
11
  * request count.
12
12
  *
13
+ * Fetches complete in whatever order the network answers, but each artifact
14
+ * stores its chunks in chunk order: a verified chunk waits until every
15
+ * earlier gap of the same artifact has been stored. Gaps are admitted round
16
+ * robin across artifacts, so one large artifact cannot occupy the whole
17
+ * window while unrelated work waits. Held bytes stay inside the in-flight
18
+ * byte bound.
19
+ *
13
20
  * Every chunk keeps one content-addressed identity, whether its sealed
14
21
  * envelope lives alone or as a byte range inside an immutable pack. The
15
22
  * host's ports resolve and fetch those identities; parallelism, storage
@@ -1 +1 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAqC,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAO/E,MAAM,WAAW,aAAa,CAAC,aAAa;IAC1C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,6EAA6E;IAC7E,QAAQ,CACN,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CACN,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,QAAQ,CACN,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,8EAA8E;IAC9E,YAAY,CACV,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,cAAc,CAAC,aAAa;IAC3C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;sEACkE;IAClE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,eAAe,CAAC,aAAa;IAC5C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAQD;;uCAEuC;AACvC,wBAAsB,WAAW,CAAC,aAAa,EAC7C,SAAS,EAAE,SAAS,gBAAgB,EAAE,EACtC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,EACnC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,SAAS,eAAe,CAAC,aAAa,CAAC,EAAE,CAAC,CA+DpD;AAED,sDAAsD;AACtD,wBAAsB,QAAQ,CAAC,aAAa,EAC1C,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,EACnC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAIzC"}
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAqC,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAO/E,MAAM,WAAW,aAAa,CAAC,aAAa;IAC1C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,WAAW,CAAC,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1D,6EAA6E;IAC7E,QAAQ,CACN,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAAC;IACpB,QAAQ,CACN,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC,CAAC;IACvB,QAAQ,CACN,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,EACzB,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,8EAA8E;IAC9E,YAAY,CACV,QAAQ,EAAE,gBAAgB,EAC1B,QAAQ,EAAE,eAAe,GACxB,OAAO,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,cAAc,CAAC,aAAa;IAC3C,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;sEACkE;IAClE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,eAAe,CAAC,aAAa;IAC5C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AAmBD;;uCAEuC;AACvC,wBAAsB,WAAW,CAAC,aAAa,EAC7C,SAAS,EAAE,SAAS,gBAAgB,EAAE,EACtC,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,EACnC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,SAAS,eAAe,CAAC,aAAa,CAAC,EAAE,CAAC,CA0FpD;AAED,sDAAsD;AACtD,wBAAsB,QAAQ,CAAC,aAAa,EAC1C,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,aAAa,CAAC,aAAa,CAAC,EACnC,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,eAAe,CAAC,aAAa,CAAC,CAAC,CAIzC"}
@@ -10,6 +10,13 @@
10
10
  * still its own storage request — the set changes scheduling, not the
11
11
  * request count.
12
12
  *
13
+ * Fetches complete in whatever order the network answers, but each artifact
14
+ * stores its chunks in chunk order: a verified chunk waits until every
15
+ * earlier gap of the same artifact has been stored. Gaps are admitted round
16
+ * robin across artifacts, so one large artifact cannot occupy the whole
17
+ * window while unrelated work waits. Held bytes stay inside the in-flight
18
+ * byte bound.
19
+ *
13
20
  * Every chunk keeps one content-addressed identity, whether its sealed
14
21
  * envelope lives alone or as a byte range inside an immutable pack. The
15
22
  * host's ports resolve and fetch those identities; parallelism, storage
@@ -44,18 +51,49 @@ export async function downloadAll(artifacts, ports, options = {}) {
44
51
  }
45
52
  plans[slot] = { artifact, manifest, missing };
46
53
  });
47
- const gaps = plans.flatMap((plan) => plan === undefined ? [] : plan.missing.map((index) => ({ plan, index })));
48
- await weightedParallelForEach(gaps, concurrency, maxInFlightBytes, ({ plan, index }) => plan.manifest.chunks[index]?.bytes ?? 0, async ({ plan, index }) => {
49
- const expected = plan.manifest.chunks[index];
50
- if (expected === undefined)
51
- throw new Error('download manifest named an unknown chunk index');
52
- const bytes = await ports.getChunk(plan.artifact, plan.manifest, index);
53
- if (!(bytes instanceof Uint8Array)
54
- || bytes.byteLength !== expected.bytes
55
- || ports.sha256Hex(bytes) !== expected.sha256) {
56
- throw new Error(`downloaded content chunk ${index} failed verification`);
54
+ const gaps = [];
55
+ const priorByPlan = new Map();
56
+ const maxGaps = plans.reduce((maximum, plan) => Math.max(maximum, plan?.missing.length ?? 0), 0);
57
+ for (let depth = 0; depth < maxGaps; depth += 1) {
58
+ for (const plan of plans) {
59
+ if (plan === undefined)
60
+ continue;
61
+ const index = plan.missing[depth];
62
+ if (index === undefined)
63
+ continue;
64
+ let stored;
65
+ let failed;
66
+ const delivered = new Promise((resolve, reject) => {
67
+ stored = resolve;
68
+ failed = reject;
69
+ });
70
+ // A failed effect may leave no later chunk admitted to observe the
71
+ // rejection; the set still fails through the effect's own throw.
72
+ delivered.catch(() => { });
73
+ gaps.push({ plan, index, priorStored: priorByPlan.get(plan), stored, failed });
74
+ priorByPlan.set(plan, delivered);
75
+ }
76
+ }
77
+ await weightedParallelForEach(gaps, concurrency, maxInFlightBytes, ({ plan, index }) => plan.manifest.chunks[index]?.bytes ?? 0, async ({ plan, index, priorStored, stored, failed }) => {
78
+ try {
79
+ const expected = plan.manifest.chunks[index];
80
+ if (expected === undefined)
81
+ throw new Error('download manifest named an unknown chunk index');
82
+ const bytes = await ports.getChunk(plan.artifact, plan.manifest, index);
83
+ if (!(bytes instanceof Uint8Array)
84
+ || bytes.byteLength !== expected.bytes
85
+ || ports.sha256Hex(bytes) !== expected.sha256) {
86
+ throw new Error(`downloaded content chunk ${index} failed verification`);
87
+ }
88
+ if (priorStored !== undefined)
89
+ await priorStored;
90
+ await ports.putChunk(plan.artifact, plan.manifest, index, bytes);
91
+ stored();
92
+ }
93
+ catch (error) {
94
+ failed(error);
95
+ throw error;
57
96
  }
58
- await ports.putChunk(plan.artifact, plan.manifest, index, bytes);
59
97
  });
60
98
  const receipts = new Array(artifacts.length);
61
99
  await parallelForEach([...plans.keys()], concurrency, async (slot) => {
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  /** Type-aware immutable content transfer operations. */
2
2
  export * from './artifacts.js';
3
3
  export * from './cargo.js';
4
+ export * from './stream.js';
4
5
  export * from './upload.js';
5
6
  export * from './download.js';
6
7
  export * from './refs.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transfer/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/transfer/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
@@ -1,6 +1,7 @@
1
1
  /** Type-aware immutable content transfer operations. */
2
2
  export * from './artifacts.js';
3
3
  export * from './cargo.js';
4
+ export * from './stream.js';
4
5
  export * from './upload.js';
5
6
  export * from './download.js';
6
7
  export * from './refs.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transfer/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transfer/index.ts"],"names":[],"mappings":"AAAA,wDAAwD;AAExD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * One-read upload — capture and transport fused.
3
+ *
4
+ * The classic upload (`upload.ts`) needs the whole-file identity up front
5
+ * and a seekable source it may reread. This primitive serves the moment the
6
+ * bytes are first read: the identity is DISCOVERED while one sequential
7
+ * read proceeds. Each full transfer batch of verified blocks — addressed by
8
+ * their own digests, bound to no whole-file identity yet — rides the wire
9
+ * while the next batch is read, and only after the last byte proves the
10
+ * whole-file digest is the manifest sealed. An interrupted or torn stream
11
+ * leaves unreferenced blocks the authority already tolerates, never a
12
+ * sealed artifact; whether the streamed digest matches current ground is
13
+ * the host's stat law, exactly as for the classic capture. Registration
14
+ * owns entity identity — this primitive knows only content.
15
+ *
16
+ * Memory is bounded by construction: one batch on the wire while one batch
17
+ * is read, so a stream holds at most two transfer batches at once.
18
+ */
19
+ import { type ContentChunk, type ContentManifest } from '../contracts/content.js';
20
+ import type { Sha256Hex } from '../entities/types.js';
21
+ export interface StreamSource {
22
+ /** Exact byte count the source will produce; a short read is refused. */
23
+ readonly bytes: number;
24
+ /** Return exactly `bytes` bytes beginning at `offset`. Called strictly in
25
+ * ascending offset order, never twice for the same span. */
26
+ read(offset: number, bytes: number): Promise<Uint8Array>;
27
+ }
28
+ /** Incremental whole-file digest, since the identity outlives any one call. */
29
+ export interface Sha256Stream {
30
+ update(bytes: Uint8Array): void;
31
+ digestHex(): string;
32
+ }
33
+ export interface StreamUploadPorts {
34
+ readonly sha256Hex: Sha256Hex;
35
+ createSha256(): Sha256Stream;
36
+ /** Store adjacent verified blocks addressed by their own digests. The
37
+ * blocks bind to no artifact yet; resolving means they are durable. */
38
+ putBlocks(chunks: readonly ContentChunk[], bytes: Uint8Array): Promise<void>;
39
+ /** Bind the discovered identity to its block list. The authority seals
40
+ * only when it holds every named block. */
41
+ sealManifest(manifest: ContentManifest): Promise<void>;
42
+ }
43
+ export interface StreamUploadReceipt {
44
+ readonly manifest: ContentManifest;
45
+ readonly uploadedChunks: number;
46
+ }
47
+ /** Upload one file's content from a single sequential read, discovering its
48
+ * identity along the way and sealing the manifest last. */
49
+ export declare function uploadStream(source: StreamSource, ports: StreamUploadPorts): Promise<StreamUploadReceipt>;
50
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/transfer/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAGL,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,MAAM,WAAW,YAAY;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;gEAC4D;IAC5D,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1D;AAED,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,SAAS,IAAI,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,YAAY,IAAI,YAAY,CAAC;IAC7B;2EACuE;IACvE,SAAS,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7E;+CAC2C;IAC3C,YAAY,CAAC,QAAQ,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACjC;AAwBD;2DAC2D;AAC3D,wBAAsB,YAAY,CAChC,MAAM,EAAE,YAAY,EACpB,KAAK,EAAE,iBAAiB,GACvB,OAAO,CAAC,mBAAmB,CAAC,CAoC9B"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * One-read upload — capture and transport fused.
3
+ *
4
+ * The classic upload (`upload.ts`) needs the whole-file identity up front
5
+ * and a seekable source it may reread. This primitive serves the moment the
6
+ * bytes are first read: the identity is DISCOVERED while one sequential
7
+ * read proceeds. Each full transfer batch of verified blocks — addressed by
8
+ * their own digests, bound to no whole-file identity yet — rides the wire
9
+ * while the next batch is read, and only after the last byte proves the
10
+ * whole-file digest is the manifest sealed. An interrupted or torn stream
11
+ * leaves unreferenced blocks the authority already tolerates, never a
12
+ * sealed artifact; whether the streamed digest matches current ground is
13
+ * the host's stat law, exactly as for the classic capture. Registration
14
+ * owns entity identity — this primitive knows only content.
15
+ *
16
+ * Memory is bounded by construction: one batch on the wire while one batch
17
+ * is read, so a stream holds at most two transfer batches at once.
18
+ */
19
+ import { chunkSizes, manifestFromChunks, } from '../contracts/content.js';
20
+ import { FILE_TRANSFER_BATCH_BYTES } from './batches.js';
21
+ const planStreamBatches = (totalBytes) => {
22
+ const batches = [];
23
+ let offset = 0;
24
+ for (const size of chunkSizes(totalBytes)) {
25
+ const prior = batches.at(-1);
26
+ if (prior && prior.bytes + size <= FILE_TRANSFER_BATCH_BYTES) {
27
+ prior.bytes += size;
28
+ prior.sizes.push(size);
29
+ }
30
+ else {
31
+ batches.push({ offset, bytes: size, sizes: [size] });
32
+ }
33
+ offset += size;
34
+ }
35
+ return batches;
36
+ };
37
+ /** Upload one file's content from a single sequential read, discovering its
38
+ * identity along the way and sealing the manifest last. */
39
+ export async function uploadStream(source, ports) {
40
+ if (!Number.isSafeInteger(source.bytes) || source.bytes <= 0) {
41
+ throw new Error('stream upload source byte count is invalid');
42
+ }
43
+ const whole = ports.createSha256();
44
+ const chunks = [];
45
+ let inFlight;
46
+ try {
47
+ for (const batch of planStreamBatches(source.bytes)) {
48
+ const bytes = await source.read(batch.offset, batch.bytes);
49
+ if (!(bytes instanceof Uint8Array) || bytes.byteLength !== batch.bytes) {
50
+ throw new Error(`stream upload source returned the wrong byte count at offset ${batch.offset}`);
51
+ }
52
+ whole.update(bytes);
53
+ const batchChunks = [];
54
+ let within = 0;
55
+ for (const size of batch.sizes) {
56
+ batchChunks.push({ sha256: ports.sha256Hex(bytes.subarray(within, within + size)), bytes: size });
57
+ within += size;
58
+ }
59
+ chunks.push(...batchChunks);
60
+ await inFlight;
61
+ inFlight = ports.putBlocks(batchChunks, bytes);
62
+ }
63
+ await inFlight;
64
+ inFlight = undefined;
65
+ const checked = manifestFromChunks(whole.digestHex(), chunks);
66
+ if (!checked.ok)
67
+ throw new Error(checked.error);
68
+ await ports.sealManifest(checked.value);
69
+ return { manifest: checked.value, uploadedChunks: chunks.length };
70
+ }
71
+ catch (error) {
72
+ // In-flight blocks settle before control returns, so the host may
73
+ // safely close file and network handles after rejection.
74
+ await inFlight?.catch(() => { });
75
+ throw error;
76
+ }
77
+ }
78
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/transfer/stream.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.CARGO_STREAM_IN_FLIGHT_BYTES = exports.CARGO_SEGMENT_ARTIFACTS = exports.CARGO_SEGMENT_BYTES = void 0;
19
19
  exports.planCargoSegments = planCargoSegments;
20
+ exports.openCargoStream = openCargoStream;
20
21
  exports.streamCargo = streamCargo;
21
22
  const batches_js_1 = require("./batches.js");
22
23
  const parallel_js_1 = require("./parallel.js");
@@ -31,21 +32,24 @@ exports.CARGO_SEGMENT_ARTIFACTS = 256;
31
32
  * fan-out, and worst-case payload residency (plaintext plus one encoded
32
33
  * copy per in-flight segment) stays comfortably inside a 1-GiB runtime. */
33
34
  exports.CARGO_STREAM_IN_FLIGHT_BYTES = 4 * exports.CARGO_SEGMENT_BYTES;
35
+ const assertCargoItem = (item) => {
36
+ if (typeof item.contentHash !== 'string' || item.contentHash.length === 0) {
37
+ throw new Error('cargo item is missing its content identity');
38
+ }
39
+ if (!Number.isSafeInteger(item.bytes) || item.bytes < 0) {
40
+ throw new Error('cargo item byte count is invalid');
41
+ }
42
+ if (item.bytes > exports.CARGO_SEGMENT_BYTES) {
43
+ throw new Error('cargo item exceeds the segment byte bound');
44
+ }
45
+ };
34
46
  /** Pack items in order into segments within the byte and artifact bounds. */
35
47
  function planCargoSegments(items) {
36
48
  const segments = [];
37
49
  let current = [];
38
50
  let bytes = 0;
39
51
  for (const item of items) {
40
- if (typeof item.contentHash !== 'string' || item.contentHash.length === 0) {
41
- throw new Error('cargo item is missing its content identity');
42
- }
43
- if (!Number.isSafeInteger(item.bytes) || item.bytes < 0) {
44
- throw new Error('cargo item byte count is invalid');
45
- }
46
- if (item.bytes > exports.CARGO_SEGMENT_BYTES) {
47
- throw new Error('cargo item exceeds the segment byte bound');
48
- }
52
+ assertCargoItem(item);
49
53
  if (current.length > 0
50
54
  && (bytes + item.bytes > exports.CARGO_SEGMENT_BYTES || current.length >= exports.CARGO_SEGMENT_ARTIFACTS)) {
51
55
  segments.push({ items: current, bytes });
@@ -59,24 +63,95 @@ function planCargoSegments(items) {
59
63
  segments.push({ items: current, bytes });
60
64
  return segments;
61
65
  }
66
+ function openCargoStream(ports, options = {}) {
67
+ const lanes = options.lanes ?? parallel_js_1.DEFAULT_TRANSFER_CONCURRENCY;
68
+ const maxInFlightBytes = options.maxInFlightBytes ?? exports.CARGO_STREAM_IN_FLIGHT_BYTES;
69
+ const inFlight = new Set();
70
+ let inFlightBytes = 0;
71
+ let failure;
72
+ let current = [];
73
+ let currentBytes = 0;
74
+ let segments = 0;
75
+ let artifacts = 0;
76
+ let bytes = 0;
77
+ const dispatch = async (segment) => {
78
+ const weight = Math.max(segment.bytes, 1);
79
+ while (failure === undefined
80
+ && (inFlight.size >= lanes
81
+ || (inFlight.size > 0 && inFlightBytes + weight > maxInFlightBytes))) {
82
+ await Promise.race(inFlight);
83
+ }
84
+ if (failure !== undefined)
85
+ throw failure.error;
86
+ inFlightBytes += weight;
87
+ const settled = (async () => {
88
+ const sealed = new Set(await ports.send(segment));
89
+ for (const item of segment.items) {
90
+ if (!sealed.has(item.contentHash)) {
91
+ throw new Error(`cargo authority did not seal ${item.contentHash}`);
92
+ }
93
+ }
94
+ segments += 1;
95
+ artifacts += segment.items.length;
96
+ bytes += segment.bytes;
97
+ })().then(() => { inFlight.delete(settled); inFlightBytes -= weight; }, (error) => {
98
+ inFlight.delete(settled);
99
+ inFlightBytes -= weight;
100
+ failure ??= { error };
101
+ });
102
+ inFlight.add(settled);
103
+ };
104
+ const closeCurrent = () => {
105
+ const segment = { items: current, bytes: currentBytes };
106
+ current = [];
107
+ currentBytes = 0;
108
+ return segment;
109
+ };
110
+ return {
111
+ async add(item) {
112
+ assertCargoItem(item);
113
+ if (failure !== undefined)
114
+ throw failure.error;
115
+ if (current.length > 0
116
+ && (currentBytes + item.bytes > exports.CARGO_SEGMENT_BYTES
117
+ || current.length >= exports.CARGO_SEGMENT_ARTIFACTS)) {
118
+ await dispatch(closeCurrent());
119
+ }
120
+ current.push(item);
121
+ currentBytes += item.bytes;
122
+ },
123
+ async flush() {
124
+ if (failure === undefined && current.length > 0) {
125
+ try {
126
+ await dispatch(closeCurrent());
127
+ }
128
+ catch {
129
+ // The failure is recorded; settle the window before rethrowing.
130
+ }
131
+ }
132
+ while (inFlight.size > 0)
133
+ await Promise.race(inFlight);
134
+ if (failure !== undefined)
135
+ throw failure.error;
136
+ return { segments, artifacts, bytes };
137
+ },
138
+ };
139
+ }
62
140
  /** Stream one cold set of small artifacts as bounded pipelined segments.
63
141
  * Every item must come back sealed or the stream fails; a failure stops new
64
142
  * admission, lets in-flight segments settle, and leaves their sealed work
65
143
  * durable for the resuming rerun. */
66
144
  async function streamCargo(items, ports, options = {}) {
67
- const segments = planCargoSegments(items);
68
- let artifacts = 0;
69
- let bytes = 0;
70
- await (0, parallel_js_1.weightedParallelForEach)(segments, options.lanes ?? parallel_js_1.DEFAULT_TRANSFER_CONCURRENCY, options.maxInFlightBytes ?? exports.CARGO_STREAM_IN_FLIGHT_BYTES, (segment) => Math.max(segment.bytes, 1), async (segment) => {
71
- const sealed = new Set(await ports.send(segment));
72
- for (const item of segment.items) {
73
- if (!sealed.has(item.contentHash)) {
74
- throw new Error(`cargo authority did not seal ${item.contentHash}`);
75
- }
76
- }
77
- artifacts += segment.items.length;
78
- bytes += segment.bytes;
79
- });
80
- return { segments: segments.length, artifacts, bytes };
145
+ for (const item of items)
146
+ assertCargoItem(item);
147
+ const stream = openCargoStream(ports, options);
148
+ try {
149
+ for (const item of items)
150
+ await stream.add(item);
151
+ }
152
+ catch {
153
+ // add() already recorded the failure; flush settles and rethrows it.
154
+ }
155
+ return stream.flush();
81
156
  }
82
157
  //# sourceMappingURL=cargo.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cargo.js","sourceRoot":"","sources":["../../src/transfer/cargo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cargo.js","sourceRoot":"","sources":["../../src/transfer/cargo.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,13 @@
11
11
  * still its own storage request — the set changes scheduling, not the
12
12
  * request count.
13
13
  *
14
+ * Fetches complete in whatever order the network answers, but each artifact
15
+ * stores its chunks in chunk order: a verified chunk waits until every
16
+ * earlier gap of the same artifact has been stored. Gaps are admitted round
17
+ * robin across artifacts, so one large artifact cannot occupy the whole
18
+ * window while unrelated work waits. Held bytes stay inside the in-flight
19
+ * byte bound.
20
+ *
14
21
  * Every chunk keeps one content-addressed identity, whether its sealed
15
22
  * envelope lives alone or as a byte range inside an immutable pack. The
16
23
  * host's ports resolve and fetch those identities; parallelism, storage
@@ -48,18 +55,49 @@ async function downloadAll(artifacts, ports, options = {}) {
48
55
  }
49
56
  plans[slot] = { artifact, manifest, missing };
50
57
  });
51
- const gaps = plans.flatMap((plan) => plan === undefined ? [] : plan.missing.map((index) => ({ plan, index })));
52
- await (0, parallel_js_1.weightedParallelForEach)(gaps, concurrency, maxInFlightBytes, ({ plan, index }) => plan.manifest.chunks[index]?.bytes ?? 0, async ({ plan, index }) => {
53
- const expected = plan.manifest.chunks[index];
54
- if (expected === undefined)
55
- throw new Error('download manifest named an unknown chunk index');
56
- const bytes = await ports.getChunk(plan.artifact, plan.manifest, index);
57
- if (!(bytes instanceof Uint8Array)
58
- || bytes.byteLength !== expected.bytes
59
- || ports.sha256Hex(bytes) !== expected.sha256) {
60
- throw new Error(`downloaded content chunk ${index} failed verification`);
58
+ const gaps = [];
59
+ const priorByPlan = new Map();
60
+ const maxGaps = plans.reduce((maximum, plan) => Math.max(maximum, plan?.missing.length ?? 0), 0);
61
+ for (let depth = 0; depth < maxGaps; depth += 1) {
62
+ for (const plan of plans) {
63
+ if (plan === undefined)
64
+ continue;
65
+ const index = plan.missing[depth];
66
+ if (index === undefined)
67
+ continue;
68
+ let stored;
69
+ let failed;
70
+ const delivered = new Promise((resolve, reject) => {
71
+ stored = resolve;
72
+ failed = reject;
73
+ });
74
+ // A failed effect may leave no later chunk admitted to observe the
75
+ // rejection; the set still fails through the effect's own throw.
76
+ delivered.catch(() => { });
77
+ gaps.push({ plan, index, priorStored: priorByPlan.get(plan), stored, failed });
78
+ priorByPlan.set(plan, delivered);
79
+ }
80
+ }
81
+ await (0, parallel_js_1.weightedParallelForEach)(gaps, concurrency, maxInFlightBytes, ({ plan, index }) => plan.manifest.chunks[index]?.bytes ?? 0, async ({ plan, index, priorStored, stored, failed }) => {
82
+ try {
83
+ const expected = plan.manifest.chunks[index];
84
+ if (expected === undefined)
85
+ throw new Error('download manifest named an unknown chunk index');
86
+ const bytes = await ports.getChunk(plan.artifact, plan.manifest, index);
87
+ if (!(bytes instanceof Uint8Array)
88
+ || bytes.byteLength !== expected.bytes
89
+ || ports.sha256Hex(bytes) !== expected.sha256) {
90
+ throw new Error(`downloaded content chunk ${index} failed verification`);
91
+ }
92
+ if (priorStored !== undefined)
93
+ await priorStored;
94
+ await ports.putChunk(plan.artifact, plan.manifest, index, bytes);
95
+ stored();
96
+ }
97
+ catch (error) {
98
+ failed(error);
99
+ throw error;
61
100
  }
62
- await ports.putChunk(plan.artifact, plan.manifest, index, bytes);
63
101
  });
64
102
  const receipts = new Array(artifacts.length);
65
103
  await (0, parallel_js_1.parallelForEach)([...plans.keys()], concurrency, async (slot) => {
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;GAiBG;;AAoEH,kCAmEC;AAGD,4BAQC;AAhJD,wDAAkG;AAElG,iDAA+E;AAC/E,+CAIuB;AAwDvB;;uCAEuC;AAChC,KAAK,UAAU,WAAW,CAC/B,SAAsC,EACtC,KAAmC,EACnC,UAA2B,EAAE;IAE7B,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,0CAA4B,CAAC;IACxE,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB;WAC5C,0CAA4B,GAAG,wBAAW,CAAC;IAChD,KAAK,MAAM,QAAQ,IAAI,SAAS;QAAE,IAAA,qCAAsB,EAAC,QAAQ,CAAC,CAAC;IAEnE,MAAM,KAAK,GAAiC,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACxE,MAAM,IAAA,6BAAe,EAAC,CAAC,GAAG,SAAS,CAAC,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACvE,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,QAAQ,KAAK,SAAS;YAAE,OAAO;QACnC,MAAM,OAAO,GAAG,IAAA,iCAAoB,EAClC,MAAM,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EACjC,QAAQ,CAAC,WAAW,CACrB,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;QAC/B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3C,IAAI,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC5E,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAClC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5E,MAAM,IAAA,qCAAuB,EAC3B,IAAI,EACJ,WAAW,EACX,gBAAgB,EAChB,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC,EAC5D,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE;QACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7C,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACxE,IAAI,CAAC,CAAC,KAAK,YAAY,UAAU,CAAC;eAC7B,KAAK,CAAC,UAAU,KAAK,QAAQ,CAAC,KAAK;eACnC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,sBAAsB,CAAC,CAAC;QAC3E,CAAC;QACD,MAAM,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACnE,CAAC,CACF,CAAC;IAEF,MAAM,QAAQ,GAAmD,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7F,MAAM,IAAA,6BAAe,EAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QACnE,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,IAAI,KAAK,SAAS;YAAE,OAAO;QAC/B,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtE,IAAI,MAAM,CAAC,KAAK,KAAK,IAAI,CAAC,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;YAC7F,MAAM,IAAI,KAAK,CAAC,uBAAuB,IAAI,CAAC,QAAQ,CAAC,WAAW,sBAAsB,CAAC,CAAC;QAC1F,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,GAAG;YACf,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,gBAAgB,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YACrC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM;SAChE,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC9B,IAAI,OAAO,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;QACpF,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,sDAAsD;AAC/C,KAAK,UAAU,QAAQ,CAC5B,QAA0B,EAC1B,KAAmC,EACnC,UAA2B,EAAE;IAE7B,MAAM,CAAC,OAAO,CAAC,GAAG,MAAM,WAAW,CAAC,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;IAChE,IAAI,OAAO,KAAK,SAAS;QAAE,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;IACpF,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  __exportStar(require("./artifacts.js"), exports);
19
19
  __exportStar(require("./cargo.js"), exports);
20
+ __exportStar(require("./stream.js"), exports);
20
21
  __exportStar(require("./upload.js"), exports);
21
22
  __exportStar(require("./download.js"), exports);
22
23
  __exportStar(require("./refs.js"), exports);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transfer/index.ts"],"names":[],"mappings":";AAAA,wDAAwD;;;;;;;;;;;;;;;;AAExD,iDAA+B;AAC/B,6CAA2B;AAC3B,8CAA4B;AAC5B,gDAA8B;AAC9B,4CAA0B;AAC1B,8CAA4B"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/transfer/index.ts"],"names":[],"mappings":";AAAA,wDAAwD;;;;;;;;;;;;;;;;AAExD,iDAA+B;AAC/B,6CAA2B;AAC3B,8CAA4B;AAC5B,8CAA4B;AAC5B,gDAA8B;AAC9B,4CAA0B;AAC1B,8CAA4B"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * One-read upload — capture and transport fused.
4
+ *
5
+ * The classic upload (`upload.ts`) needs the whole-file identity up front
6
+ * and a seekable source it may reread. This primitive serves the moment the
7
+ * bytes are first read: the identity is DISCOVERED while one sequential
8
+ * read proceeds. Each full transfer batch of verified blocks — addressed by
9
+ * their own digests, bound to no whole-file identity yet — rides the wire
10
+ * while the next batch is read, and only after the last byte proves the
11
+ * whole-file digest is the manifest sealed. An interrupted or torn stream
12
+ * leaves unreferenced blocks the authority already tolerates, never a
13
+ * sealed artifact; whether the streamed digest matches current ground is
14
+ * the host's stat law, exactly as for the classic capture. Registration
15
+ * owns entity identity — this primitive knows only content.
16
+ *
17
+ * Memory is bounded by construction: one batch on the wire while one batch
18
+ * is read, so a stream holds at most two transfer batches at once.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.uploadStream = uploadStream;
22
+ const content_js_1 = require("../contracts/content.js");
23
+ const batches_js_1 = require("./batches.js");
24
+ const planStreamBatches = (totalBytes) => {
25
+ const batches = [];
26
+ let offset = 0;
27
+ for (const size of (0, content_js_1.chunkSizes)(totalBytes)) {
28
+ const prior = batches.at(-1);
29
+ if (prior && prior.bytes + size <= batches_js_1.FILE_TRANSFER_BATCH_BYTES) {
30
+ prior.bytes += size;
31
+ prior.sizes.push(size);
32
+ }
33
+ else {
34
+ batches.push({ offset, bytes: size, sizes: [size] });
35
+ }
36
+ offset += size;
37
+ }
38
+ return batches;
39
+ };
40
+ /** Upload one file's content from a single sequential read, discovering its
41
+ * identity along the way and sealing the manifest last. */
42
+ async function uploadStream(source, ports) {
43
+ if (!Number.isSafeInteger(source.bytes) || source.bytes <= 0) {
44
+ throw new Error('stream upload source byte count is invalid');
45
+ }
46
+ const whole = ports.createSha256();
47
+ const chunks = [];
48
+ let inFlight;
49
+ try {
50
+ for (const batch of planStreamBatches(source.bytes)) {
51
+ const bytes = await source.read(batch.offset, batch.bytes);
52
+ if (!(bytes instanceof Uint8Array) || bytes.byteLength !== batch.bytes) {
53
+ throw new Error(`stream upload source returned the wrong byte count at offset ${batch.offset}`);
54
+ }
55
+ whole.update(bytes);
56
+ const batchChunks = [];
57
+ let within = 0;
58
+ for (const size of batch.sizes) {
59
+ batchChunks.push({ sha256: ports.sha256Hex(bytes.subarray(within, within + size)), bytes: size });
60
+ within += size;
61
+ }
62
+ chunks.push(...batchChunks);
63
+ await inFlight;
64
+ inFlight = ports.putBlocks(batchChunks, bytes);
65
+ }
66
+ await inFlight;
67
+ inFlight = undefined;
68
+ const checked = (0, content_js_1.manifestFromChunks)(whole.digestHex(), chunks);
69
+ if (!checked.ok)
70
+ throw new Error(checked.error);
71
+ await ports.sealManifest(checked.value);
72
+ return { manifest: checked.value, uploadedChunks: chunks.length };
73
+ }
74
+ catch (error) {
75
+ // In-flight blocks settle before control returns, so the host may
76
+ // safely close file and network handles after rejection.
77
+ await inFlight?.catch(() => { });
78
+ throw error;
79
+ }
80
+ }
81
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/transfer/stream.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/live",
3
- "version": "0.2.57",
3
+ "version": "0.2.59",
4
4
  "description": "Portable realtime SDK for Amalgm — wire contracts, mutation discipline, and delivery state machines behind host-injected adapters.",
5
5
  "type": "module",
6
6
  "main": "./dist-cjs/index.js",