@amalgm/live 0.2.47 → 0.2.48

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.
@@ -1,10 +1,14 @@
1
1
  /**
2
- * Download one immutable artifact into a machine cache.
2
+ * Download a set of immutable artifacts into a machine cache.
3
3
  *
4
- * The operation asks the cache which verified chunks it already owns, fetches
5
- * only the gaps, verifies every fetched chunk, and then asks the cache to seal
6
- * the complete artifact. Sealing must verify the whole byte count and content
7
- * hash before returning a local handle.
4
+ * The set is the primitive: one plan wave proves every manifest and asks the
5
+ * cache which chunks are gaps, one chunk wave fetches every gap across the
6
+ * whole set under a single bound, and one seal wave verifies each complete
7
+ * artifact. A lone artifact is a set of one — there is no second path. This
8
+ * shape removes per-artifact serialization: no artifact waits behind
9
+ * another's plan or seal, only behind the shared fetch bound. Each chunk is
10
+ * still its own storage request — the set changes scheduling, not the
11
+ * request count.
8
12
  *
9
13
  * Every chunk is one content-addressed storage object, so the host's ports
10
14
  * fetch chunks independently — parallelism, transport, and decryption are the
@@ -38,6 +42,10 @@ export interface DownloadReceipt<LocalArtifact> {
38
42
  readonly downloadedChunks: number;
39
43
  readonly reusedChunks: number;
40
44
  }
41
- /** Download one immutable artifact, fetching only machine-cache gaps. */
45
+ /** Download a set of immutable artifacts, fetching only machine-cache gaps.
46
+ * Receipts return in input order; any failure fails the whole set after
47
+ * letting in-flight effects settle. */
48
+ export declare function downloadAll<LocalArtifact>(artifacts: readonly TransferArtifact[], ports: DownloadPorts<LocalArtifact>, options?: DownloadOptions): Promise<readonly DownloadReceipt<LocalArtifact>[]>;
49
+ /** Download one immutable artifact — a set of one. */
42
50
  export declare function download<LocalArtifact>(artifact: TransferArtifact, ports: DownloadPorts<LocalArtifact>, options?: DownloadOptions): Promise<DownloadReceipt<LocalArtifact>>;
43
51
  //# sourceMappingURL=download.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG/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;CAC/B;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;AAED,yEAAyE;AACzE,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,CAqCzC"}
1
+ {"version":3,"file":"download.d.ts","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAwB,KAAK,eAAe,EAAE,MAAM,yBAAyB,CAAC;AACrF,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAA0B,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAG/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;CAC/B;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,CAuDpD;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,10 +1,14 @@
1
1
  /**
2
- * Download one immutable artifact into a machine cache.
2
+ * Download a set of immutable artifacts into a machine cache.
3
3
  *
4
- * The operation asks the cache which verified chunks it already owns, fetches
5
- * only the gaps, verifies every fetched chunk, and then asks the cache to seal
6
- * the complete artifact. Sealing must verify the whole byte count and content
7
- * hash before returning a local handle.
4
+ * The set is the primitive: one plan wave proves every manifest and asks the
5
+ * cache which chunks are gaps, one chunk wave fetches every gap across the
6
+ * whole set under a single bound, and one seal wave verifies each complete
7
+ * artifact. A lone artifact is a set of one — there is no second path. This
8
+ * shape removes per-artifact serialization: no artifact waits behind
9
+ * another's plan or seal, only behind the shared fetch bound. Each chunk is
10
+ * still its own storage request — the set changes scheduling, not the
11
+ * request count.
8
12
  *
9
13
  * Every chunk is one content-addressed storage object, so the host's ports
10
14
  * fetch chunks independently — parallelism, transport, and decryption are the
@@ -13,40 +17,70 @@
13
17
  import { checkContentManifest } from '../contracts/content.js';
14
18
  import { assertTransferArtifact } from './artifacts.js';
15
19
  import { DEFAULT_TRANSFER_CONCURRENCY, parallelForEach } from './parallel.js';
16
- /** Download one immutable artifact, fetching only machine-cache gaps. */
17
- export async function download(artifact, ports, options = {}) {
18
- assertTransferArtifact(artifact);
19
- const checked = checkContentManifest(await ports.getManifest(artifact), artifact.contentHash);
20
- if (!checked.ok)
21
- throw new Error(checked.error);
22
- const manifest = checked.value;
23
- const missing = [];
24
- for (const [index, chunk] of manifest.chunks.entries()) {
25
- if (!await ports.hasChunk(artifact, manifest, index))
26
- missing.push(index);
27
- }
28
- await parallelForEach(missing, options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY, async (index) => {
29
- const expected = manifest.chunks[index];
20
+ /** Download a set of immutable artifacts, fetching only machine-cache gaps.
21
+ * Receipts return in input order; any failure fails the whole set after
22
+ * letting in-flight effects settle. */
23
+ export async function downloadAll(artifacts, ports, options = {}) {
24
+ const concurrency = options.concurrency ?? DEFAULT_TRANSFER_CONCURRENCY;
25
+ for (const artifact of artifacts)
26
+ assertTransferArtifact(artifact);
27
+ const plans = new Array(artifacts.length);
28
+ await parallelForEach([...artifacts.keys()], concurrency, async (slot) => {
29
+ const artifact = artifacts[slot];
30
+ if (artifact === undefined)
31
+ return;
32
+ const checked = checkContentManifest(await ports.getManifest(artifact), artifact.contentHash);
33
+ if (!checked.ok)
34
+ throw new Error(checked.error);
35
+ const manifest = checked.value;
36
+ const missing = [];
37
+ for (const index of manifest.chunks.keys()) {
38
+ if (!await ports.hasChunk(artifact, manifest, index))
39
+ missing.push(index);
40
+ }
41
+ plans[slot] = { artifact, manifest, missing };
42
+ });
43
+ const gaps = plans.flatMap((plan) => plan === undefined ? [] : plan.missing.map((index) => ({ plan, index })));
44
+ await parallelForEach(gaps, concurrency, async ({ plan, index }) => {
45
+ const expected = plan.manifest.chunks[index];
30
46
  if (expected === undefined)
31
47
  throw new Error('download manifest named an unknown chunk index');
32
- const bytes = await ports.getChunk(artifact, manifest, index);
48
+ const bytes = await ports.getChunk(plan.artifact, plan.manifest, index);
33
49
  if (!(bytes instanceof Uint8Array)
34
50
  || bytes.byteLength !== expected.bytes
35
51
  || ports.sha256Hex(bytes) !== expected.sha256) {
36
52
  throw new Error(`downloaded content chunk ${index} failed verification`);
37
53
  }
38
- await ports.putChunk(artifact, manifest, index, bytes);
54
+ await ports.putChunk(plan.artifact, plan.manifest, index, bytes);
55
+ });
56
+ const receipts = new Array(artifacts.length);
57
+ await parallelForEach([...plans.keys()], concurrency, async (slot) => {
58
+ const plan = plans[slot];
59
+ if (plan === undefined)
60
+ return;
61
+ const sealed = await ports.sealArtifact(plan.artifact, plan.manifest);
62
+ if (sealed.bytes !== plan.manifest.bytes || sealed.contentHash !== plan.manifest.contentHash) {
63
+ throw new Error(`downloaded artifact ${plan.artifact.contentHash} failed verification`);
64
+ }
65
+ receipts[slot] = {
66
+ artifact: plan.artifact,
67
+ manifest: plan.manifest,
68
+ local: sealed.local,
69
+ downloadedChunks: plan.missing.length,
70
+ reusedChunks: plan.manifest.chunks.length - plan.missing.length,
71
+ };
72
+ });
73
+ return receipts.map((receipt) => {
74
+ if (receipt === undefined)
75
+ throw new Error('download set lost an artifact receipt');
76
+ return receipt;
39
77
  });
40
- const sealed = await ports.sealArtifact(artifact, manifest);
41
- if (sealed.bytes !== manifest.bytes || sealed.contentHash !== manifest.contentHash) {
42
- throw new Error(`downloaded artifact ${artifact.contentHash} failed verification`);
43
- }
44
- return {
45
- artifact,
46
- manifest,
47
- local: sealed.local,
48
- downloadedChunks: missing.length,
49
- reusedChunks: manifest.chunks.length - missing.length,
50
- };
78
+ }
79
+ /** Download one immutable artifact a set of one. */
80
+ export async function download(artifact, ports, options = {}) {
81
+ const [receipt] = await downloadAll([artifact], ports, options);
82
+ if (receipt === undefined)
83
+ throw new Error('download set lost an artifact receipt');
84
+ return receipt;
51
85
  }
52
86
  //# sourceMappingURL=download.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,oBAAoB,EAAwB,MAAM,yBAAyB,CAAC;AAErF,OAAO,EAAE,sBAAsB,EAAyB,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AA+C9E,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,QAA0B,EAC1B,KAAmC,EACnC,UAA2B,EAAE;IAE7B,sBAAsB,CAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,oBAAoB,CAClC,MAAM,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EACjC,QAAQ,CAAC,WAAW,CACrB,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;IAE/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,IAAI,4BAA4B,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QAClG,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC9D,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,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,CAAC,WAAW,sBAAsB,CAAC,CAAC;IACrF,CAAC;IACD,OAAO;QACL,QAAQ;QACR,QAAQ;QACR,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,gBAAgB,EAAE,OAAO,CAAC,MAAM;QAChC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM;KACtD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":"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"}
@@ -1,55 +1,90 @@
1
1
  "use strict";
2
2
  /**
3
- * Download one immutable artifact into a machine cache.
3
+ * Download a set of immutable artifacts into a machine cache.
4
4
  *
5
- * The operation asks the cache which verified chunks it already owns, fetches
6
- * only the gaps, verifies every fetched chunk, and then asks the cache to seal
7
- * the complete artifact. Sealing must verify the whole byte count and content
8
- * hash before returning a local handle.
5
+ * The set is the primitive: one plan wave proves every manifest and asks the
6
+ * cache which chunks are gaps, one chunk wave fetches every gap across the
7
+ * whole set under a single bound, and one seal wave verifies each complete
8
+ * artifact. A lone artifact is a set of one — there is no second path. This
9
+ * shape removes per-artifact serialization: no artifact waits behind
10
+ * another's plan or seal, only behind the shared fetch bound. Each chunk is
11
+ * still its own storage request — the set changes scheduling, not the
12
+ * request count.
9
13
  *
10
14
  * Every chunk is one content-addressed storage object, so the host's ports
11
15
  * fetch chunks independently — parallelism, transport, and decryption are the
12
16
  * host's concern; the verification laws here are not.
13
17
  */
14
18
  Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.downloadAll = downloadAll;
15
20
  exports.download = download;
16
21
  const content_js_1 = require("../contracts/content.js");
17
22
  const artifacts_js_1 = require("./artifacts.js");
18
23
  const parallel_js_1 = require("./parallel.js");
19
- /** Download one immutable artifact, fetching only machine-cache gaps. */
20
- async function download(artifact, ports, options = {}) {
21
- (0, artifacts_js_1.assertTransferArtifact)(artifact);
22
- const checked = (0, content_js_1.checkContentManifest)(await ports.getManifest(artifact), artifact.contentHash);
23
- if (!checked.ok)
24
- throw new Error(checked.error);
25
- const manifest = checked.value;
26
- const missing = [];
27
- for (const [index, chunk] of manifest.chunks.entries()) {
28
- if (!await ports.hasChunk(artifact, manifest, index))
29
- missing.push(index);
30
- }
31
- await (0, parallel_js_1.parallelForEach)(missing, options.concurrency ?? parallel_js_1.DEFAULT_TRANSFER_CONCURRENCY, async (index) => {
32
- const expected = manifest.chunks[index];
24
+ /** Download a set of immutable artifacts, fetching only machine-cache gaps.
25
+ * Receipts return in input order; any failure fails the whole set after
26
+ * letting in-flight effects settle. */
27
+ async function downloadAll(artifacts, ports, options = {}) {
28
+ const concurrency = options.concurrency ?? parallel_js_1.DEFAULT_TRANSFER_CONCURRENCY;
29
+ for (const artifact of artifacts)
30
+ (0, artifacts_js_1.assertTransferArtifact)(artifact);
31
+ const plans = new Array(artifacts.length);
32
+ await (0, parallel_js_1.parallelForEach)([...artifacts.keys()], concurrency, async (slot) => {
33
+ const artifact = artifacts[slot];
34
+ if (artifact === undefined)
35
+ return;
36
+ const checked = (0, content_js_1.checkContentManifest)(await ports.getManifest(artifact), artifact.contentHash);
37
+ if (!checked.ok)
38
+ throw new Error(checked.error);
39
+ const manifest = checked.value;
40
+ const missing = [];
41
+ for (const index of manifest.chunks.keys()) {
42
+ if (!await ports.hasChunk(artifact, manifest, index))
43
+ missing.push(index);
44
+ }
45
+ plans[slot] = { artifact, manifest, missing };
46
+ });
47
+ const gaps = plans.flatMap((plan) => plan === undefined ? [] : plan.missing.map((index) => ({ plan, index })));
48
+ await (0, parallel_js_1.parallelForEach)(gaps, concurrency, async ({ plan, index }) => {
49
+ const expected = plan.manifest.chunks[index];
33
50
  if (expected === undefined)
34
51
  throw new Error('download manifest named an unknown chunk index');
35
- const bytes = await ports.getChunk(artifact, manifest, index);
52
+ const bytes = await ports.getChunk(plan.artifact, plan.manifest, index);
36
53
  if (!(bytes instanceof Uint8Array)
37
54
  || bytes.byteLength !== expected.bytes
38
55
  || ports.sha256Hex(bytes) !== expected.sha256) {
39
56
  throw new Error(`downloaded content chunk ${index} failed verification`);
40
57
  }
41
- await ports.putChunk(artifact, manifest, index, bytes);
58
+ await ports.putChunk(plan.artifact, plan.manifest, index, bytes);
59
+ });
60
+ const receipts = new Array(artifacts.length);
61
+ await (0, parallel_js_1.parallelForEach)([...plans.keys()], concurrency, async (slot) => {
62
+ const plan = plans[slot];
63
+ if (plan === undefined)
64
+ return;
65
+ const sealed = await ports.sealArtifact(plan.artifact, plan.manifest);
66
+ if (sealed.bytes !== plan.manifest.bytes || sealed.contentHash !== plan.manifest.contentHash) {
67
+ throw new Error(`downloaded artifact ${plan.artifact.contentHash} failed verification`);
68
+ }
69
+ receipts[slot] = {
70
+ artifact: plan.artifact,
71
+ manifest: plan.manifest,
72
+ local: sealed.local,
73
+ downloadedChunks: plan.missing.length,
74
+ reusedChunks: plan.manifest.chunks.length - plan.missing.length,
75
+ };
76
+ });
77
+ return receipts.map((receipt) => {
78
+ if (receipt === undefined)
79
+ throw new Error('download set lost an artifact receipt');
80
+ return receipt;
42
81
  });
43
- const sealed = await ports.sealArtifact(artifact, manifest);
44
- if (sealed.bytes !== manifest.bytes || sealed.contentHash !== manifest.contentHash) {
45
- throw new Error(`downloaded artifact ${artifact.contentHash} failed verification`);
46
- }
47
- return {
48
- artifact,
49
- manifest,
50
- local: sealed.local,
51
- downloadedChunks: missing.length,
52
- reusedChunks: manifest.chunks.length - missing.length,
53
- };
82
+ }
83
+ /** Download one immutable artifact a set of one. */
84
+ async function download(artifact, ports, options = {}) {
85
+ const [receipt] = await downloadAll([artifact], ports, options);
86
+ if (receipt === undefined)
87
+ throw new Error('download set lost an artifact receipt');
88
+ return receipt;
54
89
  }
55
90
  //# sourceMappingURL=download.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;AAqDH,4BAyCC;AA5FD,wDAAqF;AAErF,iDAA+E;AAC/E,+CAA8E;AA+C9E,yEAAyE;AAClE,KAAK,UAAU,QAAQ,CAC5B,QAA0B,EAC1B,KAAmC,EACnC,UAA2B,EAAE;IAE7B,IAAA,qCAAsB,EAAC,QAAQ,CAAC,CAAC;IACjC,MAAM,OAAO,GAAG,IAAA,iCAAoB,EAClC,MAAM,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,EACjC,QAAQ,CAAC,WAAW,CACrB,CAAC;IACF,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC;IAE/B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,KAAK,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;YAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,IAAA,6BAAe,EAAC,OAAO,EAAE,OAAO,CAAC,WAAW,IAAI,0CAA4B,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QAClG,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxC,IAAI,QAAQ,KAAK,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAC9F,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAC9D,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,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC5D,IAAI,MAAM,CAAC,KAAK,KAAK,QAAQ,CAAC,KAAK,IAAI,MAAM,CAAC,WAAW,KAAK,QAAQ,CAAC,WAAW,EAAE,CAAC;QACnF,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,CAAC,WAAW,sBAAsB,CAAC,CAAC;IACrF,CAAC;IACD,OAAO;QACL,QAAQ;QACR,QAAQ;QACR,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,gBAAgB,EAAE,OAAO,CAAC,MAAM;QAChC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM;KACtD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"download.js","sourceRoot":"","sources":["../../src/transfer/download.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.47",
3
+ "version": "0.2.48",
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",