@amalgm/live 0.2.59 → 0.2.60

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,150 +1,63 @@
1
1
  "use strict";
2
2
  /**
3
- * Ranged pack reading.
3
+ * Pack span planning.
4
4
  *
5
- * Sealed envelopes of many small objects live inside one immutable pack.
6
- * Requests for ranges of the same pack URL made in the same event-loop turn
7
- * merge into minimal byte spans one ranged GET per spanand every
8
- * requester receives exactly its envelope slice. A small hole between wanted
9
- * ranges is cheaper to read through than to split a request over, so spans
10
- * merge across gaps up to RANGE_MERGE_GAP_BYTES. Wrong or shifted bytes can
11
- * never leak: every dispensed slice is still an authenticated envelope the
12
- * caller opens and hash-verifies.
5
+ * Sealed envelopes of many small objects live inside one immutable pack. A
6
+ * download wave knows every member it needs before any byte moves, so the
7
+ * members of one pack are planned into a few broad byte spans one ranged
8
+ * GET per span instead of a request per member. A small hole between
9
+ * wanted ranges is cheaper to read through than to split a request over, so
10
+ * spans merge across gaps up to RANGE_MERGE_GAP_BYTES; a span never grows
11
+ * past the caller's byte cap, so one planned read always fits the wave's
12
+ * in-flight memory bound. Wrong or shifted bytes can never leak: every
13
+ * dispensed slice is still an authenticated envelope the reader opens and
14
+ * hash-verifies.
13
15
  */
14
16
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.SPAN_FETCH_MAX_IN_FLIGHT_BYTES = exports.RANGE_MERGE_GAP_BYTES = void 0;
16
- exports.planSpans = planSpans;
17
- exports.createSpanFetcher = createSpanFetcher;
17
+ exports.RANGE_MERGE_GAP_BYTES = void 0;
18
+ exports.planPackSpans = planPackSpans;
18
19
  /** Read through holes up to this size rather than splitting a range request. */
19
20
  exports.RANGE_MERGE_GAP_BYTES = 64 * 1024;
20
- /** Merged span bytes one fetcher may hold in flight at once. Admission of
21
- * spans — not just of the objects above them — is byte-bounded, so a wide
22
- * same-turn fan-out can never hold every pack's sealed bytes at once. */
23
- exports.SPAN_FETCH_MAX_IN_FLIGHT_BYTES = 64 * 1024 * 1024;
24
21
  function invalidSpan(span) {
25
22
  return !Number.isSafeInteger(span.offset) || span.offset < 0
26
23
  || !Number.isSafeInteger(span.length) || span.length < 1
27
24
  || !Number.isSafeInteger(span.offset + span.length);
28
25
  }
29
- /** Merge wanted ranges into minimal fetch spans. Pure planning — no IO. */
30
- function planSpans(requests, mergeGap) {
31
- if (requests.length === 0)
32
- return { spans: [], slices: [] };
26
+ /** Plan one pack's wanted member ranges into broad fetch spans. Pure
27
+ * planning — no IO. Members merge across holes up to `mergeGap`; a span
28
+ * stops growing at `maxSpanBytes`, except that a single member larger than
29
+ * the cap still gets exactly one span of its own. */
30
+ function planPackSpans(members, mergeGap, maxSpanBytes) {
31
+ if (members.length === 0)
32
+ return { spans: [], memberSpan: [] };
33
33
  if (!Number.isSafeInteger(mergeGap) || mergeGap < 0) {
34
- throw new Error('range plan received an invalid merge gap');
34
+ throw new Error('pack span plan received an invalid merge gap');
35
35
  }
36
- if (requests.some(invalidSpan))
37
- throw new Error('range plan received an invalid byte span');
38
- const order = requests.map((request, index) => ({ request, index }))
39
- .sort((a, b) => a.request.offset - b.request.offset || a.request.length - b.request.length);
36
+ if (!Number.isSafeInteger(maxSpanBytes) || maxSpanBytes < 1) {
37
+ throw new Error('pack span plan received an invalid span byte cap');
38
+ }
39
+ if (members.some(invalidSpan))
40
+ throw new Error('pack span plan received an invalid byte span');
41
+ const order = members.map((member, index) => ({ member, index }))
42
+ .sort((a, b) => a.member.offset - b.member.offset || a.member.length - b.member.length);
40
43
  const spans = [];
41
- const slices = new Array(requests.length);
42
- for (const { request, index } of order) {
43
- const end = request.offset + request.length;
44
+ const memberSpan = new Array(members.length);
45
+ for (const { member, index } of order) {
46
+ const end = member.offset + member.length;
44
47
  const current = spans[spans.length - 1];
45
- if (current && request.offset <= current.end + mergeGap) {
48
+ if (current
49
+ && member.offset <= current.end + mergeGap
50
+ && (Math.max(current.end, end) - current.offset <= maxSpanBytes || end <= current.end)) {
46
51
  current.end = Math.max(current.end, end);
47
52
  }
48
53
  else {
49
- spans.push({ offset: request.offset, end });
54
+ spans.push({ offset: member.offset, end });
50
55
  }
51
- slices[index] = { span: spans.length - 1, start: request.offset - spans[spans.length - 1].offset };
56
+ memberSpan[index] = spans.length - 1;
52
57
  }
53
58
  return {
54
59
  spans: spans.map((span) => ({ offset: span.offset, length: span.end - span.offset })),
55
- slices,
56
- };
57
- }
58
- function createSpanFetcher(ports) {
59
- const pending = new Map();
60
- let scheduled = false;
61
- // The memory law: merged span bytes in flight are admission-bounded. A
62
- // span above the cap admits alone rather than deadlocking.
63
- let inFlightSpanBytes = 0;
64
- const waitingSpans = [];
65
- const spanWeight = (length) => Math.min(length, exports.SPAN_FETCH_MAX_IN_FLIGHT_BYTES);
66
- const admitSpan = (length) => new Promise((admit) => {
67
- const weight = spanWeight(length);
68
- if (inFlightSpanBytes === 0 || inFlightSpanBytes + weight <= exports.SPAN_FETCH_MAX_IN_FLIGHT_BYTES) {
69
- inFlightSpanBytes += weight;
70
- admit();
71
- return;
72
- }
73
- waitingSpans.push({ weight, admit });
74
- });
75
- const releaseSpan = (length) => {
76
- inFlightSpanBytes -= spanWeight(length);
77
- while (waitingSpans.length > 0) {
78
- const next = waitingSpans[0];
79
- if (inFlightSpanBytes !== 0
80
- && inFlightSpanBytes + next.weight > exports.SPAN_FETCH_MAX_IN_FLIGHT_BYTES)
81
- return;
82
- waitingSpans.shift();
83
- inFlightSpanBytes += next.weight;
84
- next.admit();
85
- }
86
- };
87
- const flushUrl = async (url, waiters) => {
88
- let plan;
89
- try {
90
- plan = planSpans(waiters.map((waiter) => waiter.range), exports.RANGE_MERGE_GAP_BYTES);
91
- }
92
- catch (error) {
93
- waiters.forEach((waiter) => waiter.reject(error));
94
- return;
95
- }
96
- await Promise.all(plan.spans.map(async (span, spanIndex) => {
97
- const served = [];
98
- plan.slices.forEach((slice, index) => {
99
- if (slice.span === spanIndex)
100
- served.push({ waiter: waiters[index], start: slice.start });
101
- });
102
- await admitSpan(span.length);
103
- try {
104
- const bytes = await ports.fetchSpan(url, span);
105
- if (bytes.length !== span.length) {
106
- throw new Error(`pack range answered ${bytes.length} bytes where ${span.length} were requested`);
107
- }
108
- // Copies, not views: a dispensed slice must never pin the whole
109
- // merged span buffer for as long as its consumer holds it.
110
- served.forEach(({ waiter, start }) => waiter.resolve(bytes.slice(start, start + waiter.range.length)));
111
- }
112
- catch (error) {
113
- served.forEach(({ waiter }) => waiter.reject(error));
114
- }
115
- finally {
116
- releaseSpan(span.length);
117
- }
118
- }));
119
- };
120
- const flush = () => {
121
- scheduled = false;
122
- const batches = [...pending.entries()];
123
- pending.clear();
124
- for (const [url, waiters] of batches)
125
- void flushUrl(url, waiters);
126
- };
127
- return {
128
- fetch(ref) {
129
- if (ref.offset == null && ref.length == null) {
130
- return ports.fetchSpan(ref.url, null);
131
- }
132
- const range = { offset: ref.offset ?? -1, length: ref.length ?? -1 };
133
- if (invalidSpan(range)) {
134
- return Promise.reject(new Error('content ref carries an invalid pack range'));
135
- }
136
- return new Promise((resolve, reject) => {
137
- const waiters = pending.get(ref.url);
138
- if (waiters)
139
- waiters.push({ range, resolve, reject });
140
- else
141
- pending.set(ref.url, [{ range, resolve, reject }]);
142
- if (!scheduled) {
143
- scheduled = true;
144
- setTimeout(flush, 0);
145
- }
146
- });
147
- },
60
+ memberSpan,
148
61
  };
149
62
  }
150
63
  //# sourceMappingURL=ranges.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ranges.js","sourceRoot":"","sources":["../../src/transfer/ranges.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ranges.js","sourceRoot":"","sources":["../../src/transfer/ranges.ts"],"names":[],"mappings":"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"}
@@ -1,49 +1,45 @@
1
1
  "use strict";
2
2
  /**
3
- * Content-ref brokering for direct content-storage fetches.
3
+ * Content-ref resolution for direct content-storage fetches.
4
4
  *
5
- * Downloads fetch every storage object straight from content storage. Callers
6
- * ask where one object lives at a time; the broker coalesces every request
7
- * made in the same event-loop turn into one batched refs call. The authority
8
- * answers each object with a short-lived URL and, when the object's sealed
9
- * envelope rides inside an immutable pack, the exact byte range holding it.
10
- * URLs are used immediately and never cached their expiry is the gateway's
11
- * revocation lever.
5
+ * Downloads fetch every storage object straight from content storage. A
6
+ * planned wave resolves the locations of its entire want-list up front a
7
+ * handful of batched refs calls, never one per object so pack members can
8
+ * be fetched as a few broad spans instead of a request per member. The
9
+ * authority answers each object with a short-lived URL and, when the
10
+ * object's sealed envelope rides inside an immutable pack, the exact byte
11
+ * range holding it. URLs are used immediately and never cached — their
12
+ * expiry is the gateway's revocation lever.
12
13
  */
13
14
  Object.defineProperty(exports, "__esModule", { value: true });
14
15
  exports.CONTENT_REFS_BATCH_OBJECTS = void 0;
15
- exports.createRefsBroker = createRefsBroker;
16
+ exports.resolveContentRefs = resolveContentRefs;
17
+ const parallel_js_1 = require("./parallel.js");
16
18
  /** One law shared with the gateway: the most objects one refs call may name. */
17
19
  exports.CONTENT_REFS_BATCH_OBJECTS = 2048;
18
- function createRefsBroker(ports) {
19
- let pending = [];
20
- let scheduled = false;
21
- const flush = async () => {
22
- scheduled = false;
23
- while (pending.length > 0) {
24
- const batch = pending.splice(0, exports.CONTENT_REFS_BATCH_OBJECTS);
25
- try {
26
- const refs = await ports.requestRefs(batch.map((waiter) => waiter.object));
27
- if (refs.length !== batch.length) {
28
- throw new Error('content refs answered the wrong number of objects');
29
- }
30
- batch.forEach((waiter, index) => waiter.resolve(refs[index]));
31
- }
32
- catch (error) {
33
- batch.forEach((waiter) => waiter.reject(error));
34
- }
20
+ /** Refs batches a wave resolves concurrently. Batches are control frames —
21
+ * small either way — so this only bounds simultaneous authority questions. */
22
+ const REFS_RESOLVE_CONCURRENCY = 4;
23
+ /** Resolve every named object's location, batching by the shared wire law.
24
+ * Answers align with the input. */
25
+ async function resolveContentRefs(ports, objects) {
26
+ if (objects.length === 0)
27
+ return [];
28
+ const refs = new Array(objects.length);
29
+ const starts = [];
30
+ for (let start = 0; start < objects.length; start += exports.CONTENT_REFS_BATCH_OBJECTS) {
31
+ starts.push(start);
32
+ }
33
+ await (0, parallel_js_1.parallelForEach)(starts, REFS_RESOLVE_CONCURRENCY, async (start) => {
34
+ const batch = objects.slice(start, start + exports.CONTENT_REFS_BATCH_OBJECTS);
35
+ const answered = await ports.requestRefs(batch);
36
+ if (answered.length !== batch.length) {
37
+ throw new Error('content refs answered the wrong number of objects');
35
38
  }
36
- };
37
- return {
38
- ref(object) {
39
- return new Promise((resolve, reject) => {
40
- pending.push({ object, resolve, reject });
41
- if (!scheduled) {
42
- scheduled = true;
43
- setTimeout(() => { void flush(); }, 0);
44
- }
45
- });
46
- },
47
- };
39
+ answered.forEach((ref, index) => {
40
+ refs[start + index] = ref;
41
+ });
42
+ });
43
+ return refs;
48
44
  }
49
45
  //# sourceMappingURL=refs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/transfer/refs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAmCH,4CA+BC;AAhED,gFAAgF;AACnE,QAAA,0BAA0B,GAAG,IAAI,CAAC;AAgC/C,SAAgB,gBAAgB,CAAC,KAAsB;IACrD,IAAI,OAAO,GAAa,EAAE,CAAC;IAC3B,IAAI,SAAS,GAAG,KAAK,CAAC;IAEtB,MAAM,KAAK,GAAG,KAAK,IAAmB,EAAE;QACtC,SAAS,GAAG,KAAK,CAAC;QAClB,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1B,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,kCAA0B,CAAC,CAAC;YAC5D,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC3E,IAAI,IAAI,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;oBACjC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;gBACvE,CAAC;gBACD,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC,CAAC;YACjE,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAClD,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,GAAG,CAAC,MAAyB;YAC3B,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACjD,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gBAC1C,IAAI,CAAC,SAAS,EAAE,CAAC;oBACf,SAAS,GAAG,IAAI,CAAC;oBACjB,UAAU,CAAC,GAAG,EAAE,GAAG,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"refs.js","sourceRoot":"","sources":["../../src/transfer/refs.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAkCH,gDAqBC;AArDD,+CAAgD;AAEhD,gFAAgF;AACnE,QAAA,0BAA0B,GAAG,IAAI,CAAC;AAE/C;8EAC8E;AAC9E,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAuBnC;mCACmC;AAC5B,KAAK,UAAU,kBAAkB,CACtC,KAAuB,EACvB,OAAqC;IAErC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,KAAK,CAAa,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC,MAAM,EAAE,KAAK,IAAI,kCAA0B,EAAE,CAAC;QAChF,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,IAAA,6BAAe,EAAC,MAAM,EAAE,wBAAwB,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACtE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,kCAA0B,CAAC,CAAC;QACvE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,QAAQ,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QACvE,CAAC;QACD,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YAC9B,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amalgm/live",
3
- "version": "0.2.59",
3
+ "version": "0.2.60",
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",