@earendil-works/chord 1.1.0 → 1.3.0
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/CHANGELOG.md +78 -0
- package/README.md +79 -195
- package/dist/cell.d.ts +122 -0
- package/dist/cell.d.ts.map +1 -0
- package/dist/cell.js +356 -0
- package/dist/cell.js.map +1 -0
- package/dist/cluster.d.ts +27 -0
- package/dist/cluster.d.ts.map +1 -0
- package/dist/cluster.js +230 -0
- package/dist/cluster.js.map +1 -0
- package/dist/connection.d.ts +270 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +1216 -0
- package/dist/connection.js.map +1 -0
- package/dist/context/index.d.ts +12 -1
- package/dist/context/index.d.ts.map +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/contract.d.ts +208 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +246 -0
- package/dist/contract.js.map +1 -0
- package/dist/declare.d.ts +33 -0
- package/dist/declare.d.ts.map +1 -0
- package/dist/declare.js +2 -0
- package/dist/declare.js.map +1 -0
- package/dist/delta/apply-immutable-trusted.js.map +1 -1
- package/dist/delta/diff.d.ts +1 -1
- package/dist/delta/diff.d.ts.map +1 -1
- package/dist/delta/diff.js.map +1 -1
- package/dist/delta/index.d.ts +4 -3
- package/dist/delta/index.d.ts.map +1 -1
- package/dist/delta/index.js +45 -0
- package/dist/delta/index.js.map +1 -1
- package/dist/delta/revision-validator.d.ts +1 -1
- package/dist/delta/revision-validator.d.ts.map +1 -1
- package/dist/delta/revision-validator.js.map +1 -1
- package/dist/delta/tracker.d.ts +1 -1
- package/dist/delta/tracker.d.ts.map +1 -1
- package/dist/delta/tracker.js +40 -4
- package/dist/delta/tracker.js.map +1 -1
- package/dist/errors.d.ts +28 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +59 -0
- package/dist/errors.js.map +1 -0
- package/dist/host.d.ts +348 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +1000 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +17 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/json.d.ts +9 -1
- package/dist/json.d.ts.map +1 -1
- package/dist/json.js.map +1 -1
- package/dist/link.d.ts +107 -0
- package/dist/link.d.ts.map +1 -0
- package/dist/link.js +355 -0
- package/dist/link.js.map +1 -0
- package/dist/loader.d.ts +4 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +73 -0
- package/dist/loader.js.map +1 -0
- package/dist/manager.d.ts +115 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +345 -0
- package/dist/manager.js.map +1 -0
- package/dist/node.d.ts +3 -4
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +3 -2
- package/dist/node.js.map +1 -1
- package/dist/object.d.ts +438 -0
- package/dist/object.d.ts.map +1 -0
- package/dist/object.js +1571 -0
- package/dist/object.js.map +1 -0
- package/dist/output.d.ts +85 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +350 -0
- package/dist/output.js.map +1 -0
- package/dist/publish.d.ts +5 -0
- package/dist/publish.d.ts.map +1 -0
- package/dist/publish.js +40 -0
- package/dist/publish.js.map +1 -0
- package/dist/registry.d.ts +25 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +6 -0
- package/dist/registry.js.map +1 -0
- package/dist/reload.d.ts +126 -0
- package/dist/reload.d.ts.map +1 -0
- package/dist/reload.js +653 -0
- package/dist/reload.js.map +1 -0
- package/dist/remote.d.ts +165 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +612 -0
- package/dist/remote.js.map +1 -0
- package/dist/schema.d.ts +21 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +228 -0
- package/dist/schema.js.map +1 -0
- package/dist/state.d.ts +92 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/{services/state.js → state.js} +28 -138
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +69 -258
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/websocket.d.ts +15 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +16 -0
- package/dist/websocket.js.map +1 -0
- package/dist/wire.d.ts +216 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +165 -0
- package/dist/wire.js.map +1 -0
- package/docs/guide.md +814 -0
- package/docs/spec.md +288 -0
- package/docs/tutorial.md +931 -0
- package/package.json +14 -10
- package/src/delta/README.md +5 -3
- package/dist/api.d.ts +0 -20
- package/dist/api.d.ts.map +0 -1
- package/dist/api.js +0 -77
- package/dist/api.js.map +0 -1
- package/dist/bundler.d.ts +0 -6
- package/dist/bundler.d.ts.map +0 -1
- package/dist/bundler.js +0 -3
- package/dist/bundler.js.map +0 -1
- package/dist/facets/host.d.ts +0 -12
- package/dist/facets/host.d.ts.map +0 -1
- package/dist/facets/host.js +0 -763
- package/dist/facets/host.js.map +0 -1
- package/dist/facets/loader.d.ts +0 -3
- package/dist/facets/loader.d.ts.map +0 -1
- package/dist/facets/loader.js +0 -5
- package/dist/facets/loader.js.map +0 -1
- package/dist/node/bundle-loader.d.ts +0 -30
- package/dist/node/bundle-loader.d.ts.map +0 -1
- package/dist/node/bundle-loader.js +0 -377
- package/dist/node/bundle-loader.js.map +0 -1
- package/dist/node/bundle.d.ts +0 -26
- package/dist/node/bundle.d.ts.map +0 -1
- package/dist/node/bundle.js +0 -183
- package/dist/node/bundle.js.map +0 -1
- package/dist/node/manifest.d.ts +0 -36
- package/dist/node/manifest.d.ts.map +0 -1
- package/dist/node/manifest.js +0 -6
- package/dist/node/manifest.js.map +0 -1
- package/dist/node/package.d.ts +0 -15
- package/dist/node/package.d.ts.map +0 -1
- package/dist/node/package.js +0 -199
- package/dist/node/package.js.map +0 -1
- package/dist/services/consumer.d.ts +0 -11
- package/dist/services/consumer.d.ts.map +0 -1
- package/dist/services/consumer.js +0 -585
- package/dist/services/consumer.js.map +0 -1
- package/dist/services/errors.d.ts +0 -8
- package/dist/services/errors.d.ts.map +0 -1
- package/dist/services/errors.js +0 -22
- package/dist/services/errors.js.map +0 -1
- package/dist/services/handle.d.ts +0 -15
- package/dist/services/handle.d.ts.map +0 -1
- package/dist/services/handle.js +0 -101
- package/dist/services/handle.js.map +0 -1
- package/dist/services/instances.d.ts +0 -26
- package/dist/services/instances.d.ts.map +0 -1
- package/dist/services/instances.js +0 -140
- package/dist/services/instances.js.map +0 -1
- package/dist/services/loopback.d.ts +0 -5
- package/dist/services/loopback.d.ts.map +0 -1
- package/dist/services/loopback.js +0 -15
- package/dist/services/loopback.js.map +0 -1
- package/dist/services/provider.d.ts +0 -37
- package/dist/services/provider.d.ts.map +0 -1
- package/dist/services/provider.js +0 -521
- package/dist/services/provider.js.map +0 -1
- package/dist/services/state-codec.d.ts +0 -15
- package/dist/services/state-codec.d.ts.map +0 -1
- package/dist/services/state-codec.js +0 -133
- package/dist/services/state-codec.js.map +0 -1
- package/dist/services/state-internals.d.ts +0 -13
- package/dist/services/state-internals.d.ts.map +0 -1
- package/dist/services/state-internals.js +0 -10
- package/dist/services/state-internals.js.map +0 -1
- package/dist/services/state.d.ts +0 -28
- package/dist/services/state.d.ts.map +0 -1
- package/dist/services/state.js.map +0 -1
- package/dist/services/wire.d.ts +0 -63
- package/dist/services/wire.d.ts.map +0 -1
- package/dist/services/wire.js +0 -186
- package/dist/services/wire.js.map +0 -1
package/dist/output.js
ADDED
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded output streams and adaptive progress commits: `OutputBuffer` keeps a head or tail window of a stream at a cost
|
|
3
|
+
* proportional to each chunk, and `Progress` paces commits of a changing value by their size.
|
|
4
|
+
*/
|
|
5
|
+
const NEWLINE = 0x0a;
|
|
6
|
+
const INVALID_OUTPUT = /[\x00-\x08\x0b-\x1f\ufff9-\ufffb]/g;
|
|
7
|
+
const encoder = new TextEncoder();
|
|
8
|
+
/** Slices decode exactly: a U+FEFF at a slice's start is text, not a byte-order mark. */
|
|
9
|
+
const decoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
10
|
+
/** Remove control characters that break display and transcripts; tabs and newlines stay. */
|
|
11
|
+
export function sanitizeOutput(text) {
|
|
12
|
+
return text.replace(INVALID_OUTPUT, "");
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Bound `text` to whole lines within the limits: the first lines for `head`, the last lines for `tail`. The result is an
|
|
16
|
+
* exact slice, trailing newline included. A single line longer than `maxBytes` is cut at the byte limit on a character
|
|
17
|
+
* boundary.
|
|
18
|
+
*/
|
|
19
|
+
export function boundOutput(text, limits) {
|
|
20
|
+
const bytes = encoder.encode(text);
|
|
21
|
+
const [from, to] = limits.retain === "head" ? headRange(bytes, limits) : tailRange(bytes, limits);
|
|
22
|
+
const kept = bytes.subarray(from, to);
|
|
23
|
+
return {
|
|
24
|
+
text: kept.length === bytes.length ? text : decoder.decode(kept),
|
|
25
|
+
bytes: kept.length,
|
|
26
|
+
droppedBytes: bytes.length - kept.length,
|
|
27
|
+
droppedLines: lineCount(bytes) - lineCount(kept),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function headRange(bytes, limits) {
|
|
31
|
+
if (limits.maxLines === 0 || limits.maxBytes === 0)
|
|
32
|
+
return [0, 0];
|
|
33
|
+
let end = bytes.length;
|
|
34
|
+
let lines = 0;
|
|
35
|
+
for (let index = bytes.indexOf(NEWLINE); index !== -1; index = bytes.indexOf(NEWLINE, index + 1)) {
|
|
36
|
+
if (++lines === limits.maxLines) {
|
|
37
|
+
end = index + 1;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (end > limits.maxBytes) {
|
|
42
|
+
const newline = bytes.lastIndexOf(NEWLINE, limits.maxBytes - 1);
|
|
43
|
+
end = newline === -1 ? characterEnd(bytes, limits.maxBytes) : newline + 1;
|
|
44
|
+
}
|
|
45
|
+
return [0, end];
|
|
46
|
+
}
|
|
47
|
+
function tailRange(bytes, limits) {
|
|
48
|
+
if (limits.maxLines === 0 || limits.maxBytes === 0)
|
|
49
|
+
return [bytes.length, bytes.length];
|
|
50
|
+
// A trailing newline ends the last line rather than starting another.
|
|
51
|
+
const last = bytes[bytes.length - 1] === NEWLINE ? bytes.length - 2 : bytes.length - 1;
|
|
52
|
+
let start = 0;
|
|
53
|
+
let lines = 1;
|
|
54
|
+
for (let index = last < 0 ? -1 : bytes.lastIndexOf(NEWLINE, last); index !== -1;) {
|
|
55
|
+
if (lines === limits.maxLines) {
|
|
56
|
+
start = index + 1;
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
lines++;
|
|
60
|
+
index = index === 0 ? -1 : bytes.lastIndexOf(NEWLINE, index - 1);
|
|
61
|
+
}
|
|
62
|
+
if (bytes.length - start > limits.maxBytes) {
|
|
63
|
+
const from = bytes.length - limits.maxBytes;
|
|
64
|
+
const newline = bytes.indexOf(NEWLINE, from - 1);
|
|
65
|
+
// The first line starting inside the byte window, or a cut of the last line when it alone is too long.
|
|
66
|
+
start = newline !== -1 && newline + 1 < bytes.length ? newline + 1 : characterStart(bytes, from);
|
|
67
|
+
}
|
|
68
|
+
return [start, bytes.length];
|
|
69
|
+
}
|
|
70
|
+
/** The last character boundary at or before `index`. */
|
|
71
|
+
export function characterEnd(bytes, index) {
|
|
72
|
+
let end = index;
|
|
73
|
+
while (end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80)
|
|
74
|
+
end--;
|
|
75
|
+
return end;
|
|
76
|
+
}
|
|
77
|
+
/** The first character boundary at or after `index`. */
|
|
78
|
+
function characterStart(bytes, index) {
|
|
79
|
+
let start = index;
|
|
80
|
+
while (start < bytes.length && ((bytes[start] ?? 0) & 0xc0) === 0x80)
|
|
81
|
+
start++;
|
|
82
|
+
return start;
|
|
83
|
+
}
|
|
84
|
+
function lineCount(bytes) {
|
|
85
|
+
if (bytes.length === 0)
|
|
86
|
+
return 0;
|
|
87
|
+
let newlines = 0;
|
|
88
|
+
for (let index = bytes.indexOf(NEWLINE); index !== -1; index = bytes.indexOf(NEWLINE, index + 1))
|
|
89
|
+
newlines++;
|
|
90
|
+
return newlines + (bytes[bytes.length - 1] === NEWLINE ? 0 : 1);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Bounded running output of one stream, such as a tool call's or a process's. Accepting a chunk costs time proportional to the chunk: head retention stops
|
|
94
|
+
* storing once the window is full, and tail retention drops stored text the window no longer needs when it snapshots.
|
|
95
|
+
* Counts of the whole stream are kept so the dropped totals stay exact.
|
|
96
|
+
*/
|
|
97
|
+
export class OutputBuffer {
|
|
98
|
+
#limits;
|
|
99
|
+
/**
|
|
100
|
+
* Decoder of byte chunks. A string chunk or a skip ends an incomplete character of earlier bytes (it becomes U+FFFD);
|
|
101
|
+
* the next byte chunk then starts a new character. As in `StreamDecoder`, only a byte-order mark at the very start of
|
|
102
|
+
* the output is dropped, never a U+FEFF later in it.
|
|
103
|
+
*/
|
|
104
|
+
#decoder = new TextDecoder("utf-8", { ignoreBOM: true });
|
|
105
|
+
#started = false;
|
|
106
|
+
/** Stored chunks: for head the start of the stream, for tail a suffix that still contains the next window. */
|
|
107
|
+
#chunks = [];
|
|
108
|
+
#storedBytes = 0;
|
|
109
|
+
#storedNewlines = 0;
|
|
110
|
+
#full = false;
|
|
111
|
+
#totalBytes = 0;
|
|
112
|
+
#totalNewlines = 0;
|
|
113
|
+
#endsWithNewline = true;
|
|
114
|
+
constructor(limits) {
|
|
115
|
+
this.#limits = limits;
|
|
116
|
+
}
|
|
117
|
+
/** Bytes currently held; bounded by the limits plus one chunk. */
|
|
118
|
+
get storedBytes() {
|
|
119
|
+
return this.#storedBytes;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Accept a chunk; returns whether anything was accepted. `skipped` is output omitted right before the chunk, which
|
|
123
|
+
* must be more than the tail window by at least one byte or line; only tail retention accepts it.
|
|
124
|
+
*/
|
|
125
|
+
push(chunk, skipped) {
|
|
126
|
+
// Bytes of an incomplete character from an earlier byte chunk come first.
|
|
127
|
+
const pending = typeof chunk === "string" || skipped !== undefined ? this.#decoder.decode() : "";
|
|
128
|
+
let text = typeof chunk === "string" ? chunk : this.#decoder.decode(chunk, { stream: true });
|
|
129
|
+
const first = !this.#started && pending === "" && skipped === undefined;
|
|
130
|
+
if (pending !== "" || text !== "" || skipped !== undefined)
|
|
131
|
+
this.#started = true;
|
|
132
|
+
if (first && typeof chunk !== "string" && text.startsWith("\ufeff"))
|
|
133
|
+
text = text.slice(1);
|
|
134
|
+
if (skipped === undefined)
|
|
135
|
+
return this.#accept(pending + text);
|
|
136
|
+
if (this.#limits.retain !== "tail")
|
|
137
|
+
throw new Error("Skipped output requires tail retention");
|
|
138
|
+
this.#accept(pending);
|
|
139
|
+
this.#skip(skipped);
|
|
140
|
+
this.#accept(text);
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
/** Count omitted output; nothing stored before it can be in the window once the text after it arrives. */
|
|
144
|
+
#skip(skipped) {
|
|
145
|
+
if (skipped.bytes === 0)
|
|
146
|
+
return;
|
|
147
|
+
this.#totalBytes += skipped.bytes;
|
|
148
|
+
this.#totalNewlines += skipped.newlines;
|
|
149
|
+
this.#endsWithNewline = skipped.endsWithNewline;
|
|
150
|
+
this.#chunks = [];
|
|
151
|
+
this.#storedBytes = 0;
|
|
152
|
+
this.#storedNewlines = 0;
|
|
153
|
+
}
|
|
154
|
+
/** Flush an incomplete trailing character as a replacement character; call when the stream ends. */
|
|
155
|
+
end() {
|
|
156
|
+
this.#accept(this.#decoder.decode());
|
|
157
|
+
}
|
|
158
|
+
#accept(text) {
|
|
159
|
+
if (text.length === 0)
|
|
160
|
+
return false;
|
|
161
|
+
const bytes = utf8ByteLength(text);
|
|
162
|
+
const newlines = countNewlines(text);
|
|
163
|
+
this.#totalBytes += bytes;
|
|
164
|
+
this.#totalNewlines += newlines;
|
|
165
|
+
this.#endsWithNewline = text.endsWith("\n");
|
|
166
|
+
if (this.#full)
|
|
167
|
+
return true;
|
|
168
|
+
this.#chunks.push({ text, bytes, newlines });
|
|
169
|
+
this.#storedBytes += bytes;
|
|
170
|
+
this.#storedNewlines += newlines;
|
|
171
|
+
if (this.#limits.retain === "head") {
|
|
172
|
+
// Nothing past a full window is ever needed.
|
|
173
|
+
this.#full = this.#storedBytes > this.#limits.maxBytes || this.#storedNewlines >= this.#limits.maxLines;
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
// Drop leading chunks while the rest still holds more than a window: more than `maxBytes` bytes or `maxLines`
|
|
177
|
+
// newlines, plus one, so the window's line start can still be found. Each chunk is dropped once.
|
|
178
|
+
while (this.#chunks.length > 1) {
|
|
179
|
+
const first = this.#chunks[0];
|
|
180
|
+
const bytesAfter = this.#storedBytes - first.bytes;
|
|
181
|
+
const newlinesAfter = this.#storedNewlines - first.newlines;
|
|
182
|
+
if (bytesAfter <= this.#limits.maxBytes + 1 && newlinesAfter <= this.#limits.maxLines + 1)
|
|
183
|
+
break;
|
|
184
|
+
this.#chunks.shift();
|
|
185
|
+
this.#storedBytes = bytesAfter;
|
|
186
|
+
this.#storedNewlines = newlinesAfter;
|
|
187
|
+
}
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
/** Retained, sanitized output and what the limits dropped from the whole stream. */
|
|
191
|
+
snapshot() {
|
|
192
|
+
const stored = this.#chunks.length === 1 ? this.#chunks[0].text : this.#chunks.map((chunk) => chunk.text).join("");
|
|
193
|
+
const kept = boundOutput(stored, this.#limits);
|
|
194
|
+
const storedLines = lines(this.#storedNewlines, stored === "" || stored.endsWith("\n"));
|
|
195
|
+
const keptLines = storedLines - kept.droppedLines;
|
|
196
|
+
// Tail windows never reach back before this one, but finding a later window's first line needs what precedes it:
|
|
197
|
+
// keep the shortest suffix longer than the window by a byte or a line, as `#accept` does.
|
|
198
|
+
if (this.#limits.retain === "tail" || this.#chunks.length > 1) {
|
|
199
|
+
const text = this.#limits.retain === "tail" ? tailMargin(stored, this.#limits) : stored;
|
|
200
|
+
const bytes = this.#limits.retain === "tail" ? utf8ByteLength(text) : this.#storedBytes;
|
|
201
|
+
this.#chunks = text === "" ? [] : [{ text, bytes, newlines: countNewlines(text) }];
|
|
202
|
+
this.#storedBytes = bytes;
|
|
203
|
+
this.#storedNewlines = this.#chunks[0]?.newlines ?? 0;
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
text: sanitizeOutput(kept.text),
|
|
207
|
+
droppedBytes: this.#totalBytes - kept.bytes,
|
|
208
|
+
droppedLines: lines(this.#totalNewlines, this.#endsWithNewline) - keptLines,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* The shortest suffix of `text` with more than `maxBytes` bytes or more than `maxLines` newlines, or all of it. The
|
|
214
|
+
* tail window of any text that ends with this suffix, followed by anything, is the same as of `text` followed by it.
|
|
215
|
+
*/
|
|
216
|
+
function tailMargin(text, limits) {
|
|
217
|
+
const bytes = encoder.encode(text);
|
|
218
|
+
const byteStart = bytes.length > limits.maxBytes ? characterEnd(bytes, bytes.length - limits.maxBytes - 1) : 0;
|
|
219
|
+
let lineStart = 0;
|
|
220
|
+
let newlines = 0;
|
|
221
|
+
for (let index = bytes.lastIndexOf(NEWLINE); index !== -1; index = bytes.lastIndexOf(NEWLINE, index - 1)) {
|
|
222
|
+
if (++newlines > limits.maxLines) {
|
|
223
|
+
lineStart = index;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
if (index === 0)
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
const start = Math.max(byteStart, lineStart);
|
|
230
|
+
return start === 0 ? text : decoder.decode(bytes.subarray(start));
|
|
231
|
+
}
|
|
232
|
+
/** Lines of text with `newlines` newlines; a final unterminated line counts. */
|
|
233
|
+
function lines(newlines, terminated) {
|
|
234
|
+
return newlines + (terminated ? 0 : 1);
|
|
235
|
+
}
|
|
236
|
+
const runtimeBuffer = globalThis.Buffer;
|
|
237
|
+
const nonAsciiPattern = /[^\x00-\x7f]/;
|
|
238
|
+
/** UTF-8 byte length of `content`; a lone surrogate counts as U+FFFD, three bytes. */
|
|
239
|
+
export function utf8ByteLength(content) {
|
|
240
|
+
if (runtimeBuffer)
|
|
241
|
+
return runtimeBuffer.byteLength(content, "utf8");
|
|
242
|
+
const firstNonAscii = content.search(nonAsciiPattern);
|
|
243
|
+
if (firstNonAscii === -1)
|
|
244
|
+
return content.length;
|
|
245
|
+
let bytes = firstNonAscii;
|
|
246
|
+
for (let i = firstNonAscii; i < content.length; i++) {
|
|
247
|
+
const code = content.charCodeAt(i);
|
|
248
|
+
if (code <= 0x7f)
|
|
249
|
+
bytes += 1;
|
|
250
|
+
else if (code <= 0x7ff)
|
|
251
|
+
bytes += 2;
|
|
252
|
+
else if (code >= 0xd800 && code <= 0xdbff && i + 1 < content.length) {
|
|
253
|
+
const next = content.charCodeAt(i + 1);
|
|
254
|
+
if (next >= 0xdc00 && next <= 0xdfff) {
|
|
255
|
+
bytes += 4;
|
|
256
|
+
i++;
|
|
257
|
+
}
|
|
258
|
+
else
|
|
259
|
+
bytes += 3;
|
|
260
|
+
}
|
|
261
|
+
else
|
|
262
|
+
bytes += 3;
|
|
263
|
+
}
|
|
264
|
+
return bytes;
|
|
265
|
+
}
|
|
266
|
+
function countNewlines(text) {
|
|
267
|
+
let count = 0;
|
|
268
|
+
for (let index = text.indexOf("\n"); index !== -1; index = text.indexOf("\n", index + 1))
|
|
269
|
+
count++;
|
|
270
|
+
return count;
|
|
271
|
+
}
|
|
272
|
+
/** Each progress commit also buys a pause proportional to what it wrote. */
|
|
273
|
+
export const PROGRESS_BYTES_PER_SECOND = 100 * 1024;
|
|
274
|
+
/**
|
|
275
|
+
* Adaptive progress commits: the first change after an idle period commits at once; each commit then delays the next
|
|
276
|
+
* by at least `minIntervalMs` and by its written size at 100 KiB/s. At most one commit is in flight; changes made
|
|
277
|
+
* meanwhile coalesce into the next one.
|
|
278
|
+
*/
|
|
279
|
+
export class Progress {
|
|
280
|
+
#write;
|
|
281
|
+
#onError;
|
|
282
|
+
#minIntervalMs;
|
|
283
|
+
#waiters = [];
|
|
284
|
+
#timer;
|
|
285
|
+
#inFlight;
|
|
286
|
+
#nextAt = 0;
|
|
287
|
+
#dirty = false;
|
|
288
|
+
#stopped = false;
|
|
289
|
+
constructor(write, onError, minIntervalMs) {
|
|
290
|
+
this.#write = write;
|
|
291
|
+
this.#onError = onError;
|
|
292
|
+
this.#minIntervalMs = minIntervalMs;
|
|
293
|
+
}
|
|
294
|
+
/** Schedule a commit. */
|
|
295
|
+
mark() {
|
|
296
|
+
this.#dirty = true;
|
|
297
|
+
this.#schedule();
|
|
298
|
+
}
|
|
299
|
+
/** Schedule a commit; the promise settles with the commit that includes this change. */
|
|
300
|
+
markAndWait() {
|
|
301
|
+
const waiter = Promise.withResolvers();
|
|
302
|
+
this.#waiters.push(waiter);
|
|
303
|
+
this.mark();
|
|
304
|
+
return waiter.promise;
|
|
305
|
+
}
|
|
306
|
+
/** Stop committing and wait for the commit in flight; returns the waiters the final commit must settle. */
|
|
307
|
+
async stop() {
|
|
308
|
+
this.#stopped = true;
|
|
309
|
+
clearTimeout(this.#timer);
|
|
310
|
+
this.#timer = undefined;
|
|
311
|
+
await this.#inFlight;
|
|
312
|
+
return this.#waiters.splice(0);
|
|
313
|
+
}
|
|
314
|
+
#schedule() {
|
|
315
|
+
if (this.#stopped || this.#timer !== undefined || this.#inFlight !== undefined)
|
|
316
|
+
return;
|
|
317
|
+
const wait = this.#nextAt - Date.now();
|
|
318
|
+
if (wait <= 0)
|
|
319
|
+
this.#flush();
|
|
320
|
+
else
|
|
321
|
+
this.#timer = setTimeout(() => {
|
|
322
|
+
this.#timer = undefined;
|
|
323
|
+
this.#flush();
|
|
324
|
+
}, wait);
|
|
325
|
+
}
|
|
326
|
+
#flush() {
|
|
327
|
+
if (this.#stopped || !this.#dirty)
|
|
328
|
+
return;
|
|
329
|
+
this.#dirty = false;
|
|
330
|
+
const waiters = this.#waiters.splice(0);
|
|
331
|
+
const started = Date.now();
|
|
332
|
+
this.#inFlight = this.#write()
|
|
333
|
+
.then((bytes) => {
|
|
334
|
+
this.#nextAt = started + Math.max(this.#minIntervalMs, (bytes * 1000) / PROGRESS_BYTES_PER_SECOND);
|
|
335
|
+
for (const waiter of waiters)
|
|
336
|
+
waiter.resolve();
|
|
337
|
+
}, (error) => {
|
|
338
|
+
this.#nextAt = started + this.#minIntervalMs;
|
|
339
|
+
for (const waiter of waiters)
|
|
340
|
+
waiter.reject(error);
|
|
341
|
+
this.#onError(error);
|
|
342
|
+
})
|
|
343
|
+
.finally(() => {
|
|
344
|
+
this.#inFlight = undefined;
|
|
345
|
+
if (this.#dirty)
|
|
346
|
+
this.#schedule();
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Bounded output streams and adaptive progress commits: `OutputBuffer` keeps a head or tail window of a stream at a cost\n * proportional to each chunk, and `Progress` paces commits of a changing value by their size.\n */\n\n/** Retention limits of one output stream. */\nexport type OutputLimits = { readonly maxBytes: number; readonly maxLines: number; readonly retain: \"head\" | \"tail\" };\n\n/** Retained output and what the limits dropped. */\nexport type BoundedOutput = { readonly text: string; readonly droppedBytes: number; readonly droppedLines: number };\n\n/** An exact slice of the input within the limits, and what it left out. */\nexport type OutputSlice = {\n\treadonly text: string;\n\treadonly bytes: number;\n\treadonly droppedBytes: number;\n\treadonly droppedLines: number;\n};\n\n/**\n * Output a producer omitted before a chunk, measured on the decoded text: every U+FFFD counts as three bytes, and no\n * sanitizing is applied.\n */\nexport interface OutputSkip {\n\t/** UTF-8 byte length of the omitted text. */\n\treadonly bytes: number;\n\t/** Newlines (U+000A) in the omitted text. */\n\treadonly newlines: number;\n\t/** Whether the omitted text ends with a newline. */\n\treadonly endsWithNewline: boolean;\n}\n\nconst NEWLINE = 0x0a;\nconst INVALID_OUTPUT = /[\\x00-\\x08\\x0b-\\x1f\\ufff9-\\ufffb]/g;\nconst encoder = new TextEncoder();\n/** Slices decode exactly: a U+FEFF at a slice's start is text, not a byte-order mark. */\nconst decoder = new TextDecoder(\"utf-8\", { ignoreBOM: true });\n\n/** Remove control characters that break display and transcripts; tabs and newlines stay. */\nexport function sanitizeOutput(text: string): string {\n\treturn text.replace(INVALID_OUTPUT, \"\");\n}\n\n/**\n * Bound `text` to whole lines within the limits: the first lines for `head`, the last lines for `tail`. The result is an\n * exact slice, trailing newline included. A single line longer than `maxBytes` is cut at the byte limit on a character\n * boundary.\n */\nexport function boundOutput(text: string, limits: OutputLimits): OutputSlice {\n\tconst bytes = encoder.encode(text);\n\tconst [from, to] = limits.retain === \"head\" ? headRange(bytes, limits) : tailRange(bytes, limits);\n\tconst kept = bytes.subarray(from, to);\n\treturn {\n\t\ttext: kept.length === bytes.length ? text : decoder.decode(kept),\n\t\tbytes: kept.length,\n\t\tdroppedBytes: bytes.length - kept.length,\n\t\tdroppedLines: lineCount(bytes) - lineCount(kept),\n\t};\n}\n\nfunction headRange(bytes: Uint8Array, limits: OutputLimits): [number, number] {\n\tif (limits.maxLines === 0 || limits.maxBytes === 0) return [0, 0];\n\tlet end = bytes.length;\n\tlet lines = 0;\n\tfor (let index = bytes.indexOf(NEWLINE); index !== -1; index = bytes.indexOf(NEWLINE, index + 1)) {\n\t\tif (++lines === limits.maxLines) {\n\t\t\tend = index + 1;\n\t\t\tbreak;\n\t\t}\n\t}\n\tif (end > limits.maxBytes) {\n\t\tconst newline = bytes.lastIndexOf(NEWLINE, limits.maxBytes - 1);\n\t\tend = newline === -1 ? characterEnd(bytes, limits.maxBytes) : newline + 1;\n\t}\n\treturn [0, end];\n}\n\nfunction tailRange(bytes: Uint8Array, limits: OutputLimits): [number, number] {\n\tif (limits.maxLines === 0 || limits.maxBytes === 0) return [bytes.length, bytes.length];\n\t// A trailing newline ends the last line rather than starting another.\n\tconst last = bytes[bytes.length - 1] === NEWLINE ? bytes.length - 2 : bytes.length - 1;\n\tlet start = 0;\n\tlet lines = 1;\n\tfor (let index = last < 0 ? -1 : bytes.lastIndexOf(NEWLINE, last); index !== -1; ) {\n\t\tif (lines === limits.maxLines) {\n\t\t\tstart = index + 1;\n\t\t\tbreak;\n\t\t}\n\t\tlines++;\n\t\tindex = index === 0 ? -1 : bytes.lastIndexOf(NEWLINE, index - 1);\n\t}\n\tif (bytes.length - start > limits.maxBytes) {\n\t\tconst from = bytes.length - limits.maxBytes;\n\t\tconst newline = bytes.indexOf(NEWLINE, from - 1);\n\t\t// The first line starting inside the byte window, or a cut of the last line when it alone is too long.\n\t\tstart = newline !== -1 && newline + 1 < bytes.length ? newline + 1 : characterStart(bytes, from);\n\t}\n\treturn [start, bytes.length];\n}\n\n/** The last character boundary at or before `index`. */\nexport function characterEnd(bytes: Uint8Array, index: number): number {\n\tlet end = index;\n\twhile (end > 0 && ((bytes[end] ?? 0) & 0xc0) === 0x80) end--;\n\treturn end;\n}\n\n/** The first character boundary at or after `index`. */\nfunction characterStart(bytes: Uint8Array, index: number): number {\n\tlet start = index;\n\twhile (start < bytes.length && ((bytes[start] ?? 0) & 0xc0) === 0x80) start++;\n\treturn start;\n}\n\nfunction lineCount(bytes: Uint8Array): number {\n\tif (bytes.length === 0) return 0;\n\tlet newlines = 0;\n\tfor (let index = bytes.indexOf(NEWLINE); index !== -1; index = bytes.indexOf(NEWLINE, index + 1)) newlines++;\n\treturn newlines + (bytes[bytes.length - 1] === NEWLINE ? 0 : 1);\n}\n\n/**\n * Bounded running output of one stream, such as a tool call's or a process's. Accepting a chunk costs time proportional to the chunk: head retention stops\n * storing once the window is full, and tail retention drops stored text the window no longer needs when it snapshots.\n * Counts of the whole stream are kept so the dropped totals stay exact.\n */\nexport class OutputBuffer {\n\treadonly #limits: OutputLimits;\n\t/**\n\t * Decoder of byte chunks. A string chunk or a skip ends an incomplete character of earlier bytes (it becomes U+FFFD);\n\t * the next byte chunk then starts a new character. As in `StreamDecoder`, only a byte-order mark at the very start of\n\t * the output is dropped, never a U+FEFF later in it.\n\t */\n\treadonly #decoder = new TextDecoder(\"utf-8\", { ignoreBOM: true });\n\t#started = false;\n\t/** Stored chunks: for head the start of the stream, for tail a suffix that still contains the next window. */\n\t#chunks: { readonly text: string; readonly bytes: number; readonly newlines: number }[] = [];\n\t#storedBytes = 0;\n\t#storedNewlines = 0;\n\t#full = false;\n\t#totalBytes = 0;\n\t#totalNewlines = 0;\n\t#endsWithNewline = true;\n\n\tconstructor(limits: OutputLimits) {\n\t\tthis.#limits = limits;\n\t}\n\n\t/** Bytes currently held; bounded by the limits plus one chunk. */\n\tget storedBytes(): number {\n\t\treturn this.#storedBytes;\n\t}\n\n\t/**\n\t * Accept a chunk; returns whether anything was accepted. `skipped` is output omitted right before the chunk, which\n\t * must be more than the tail window by at least one byte or line; only tail retention accepts it.\n\t */\n\tpush(chunk: string | Uint8Array, skipped?: OutputSkip): boolean {\n\t\t// Bytes of an incomplete character from an earlier byte chunk come first.\n\t\tconst pending = typeof chunk === \"string\" || skipped !== undefined ? this.#decoder.decode() : \"\";\n\t\tlet text = typeof chunk === \"string\" ? chunk : this.#decoder.decode(chunk, { stream: true });\n\t\tconst first = !this.#started && pending === \"\" && skipped === undefined;\n\t\tif (pending !== \"\" || text !== \"\" || skipped !== undefined) this.#started = true;\n\t\tif (first && typeof chunk !== \"string\" && text.startsWith(\"\\ufeff\")) text = text.slice(1);\n\t\tif (skipped === undefined) return this.#accept(pending + text);\n\t\tif (this.#limits.retain !== \"tail\") throw new Error(\"Skipped output requires tail retention\");\n\t\tthis.#accept(pending);\n\t\tthis.#skip(skipped);\n\t\tthis.#accept(text);\n\t\treturn true;\n\t}\n\n\t/** Count omitted output; nothing stored before it can be in the window once the text after it arrives. */\n\t#skip(skipped: OutputSkip): void {\n\t\tif (skipped.bytes === 0) return;\n\t\tthis.#totalBytes += skipped.bytes;\n\t\tthis.#totalNewlines += skipped.newlines;\n\t\tthis.#endsWithNewline = skipped.endsWithNewline;\n\t\tthis.#chunks = [];\n\t\tthis.#storedBytes = 0;\n\t\tthis.#storedNewlines = 0;\n\t}\n\n\t/** Flush an incomplete trailing character as a replacement character; call when the stream ends. */\n\tend(): void {\n\t\tthis.#accept(this.#decoder.decode());\n\t}\n\n\t#accept(text: string): boolean {\n\t\tif (text.length === 0) return false;\n\t\tconst bytes = utf8ByteLength(text);\n\t\tconst newlines = countNewlines(text);\n\t\tthis.#totalBytes += bytes;\n\t\tthis.#totalNewlines += newlines;\n\t\tthis.#endsWithNewline = text.endsWith(\"\\n\");\n\t\tif (this.#full) return true;\n\t\tthis.#chunks.push({ text, bytes, newlines });\n\t\tthis.#storedBytes += bytes;\n\t\tthis.#storedNewlines += newlines;\n\t\tif (this.#limits.retain === \"head\") {\n\t\t\t// Nothing past a full window is ever needed.\n\t\t\tthis.#full = this.#storedBytes > this.#limits.maxBytes || this.#storedNewlines >= this.#limits.maxLines;\n\t\t\treturn true;\n\t\t}\n\t\t// Drop leading chunks while the rest still holds more than a window: more than `maxBytes` bytes or `maxLines`\n\t\t// newlines, plus one, so the window's line start can still be found. Each chunk is dropped once.\n\t\twhile (this.#chunks.length > 1) {\n\t\t\tconst first = this.#chunks[0]!;\n\t\t\tconst bytesAfter = this.#storedBytes - first.bytes;\n\t\t\tconst newlinesAfter = this.#storedNewlines - first.newlines;\n\t\t\tif (bytesAfter <= this.#limits.maxBytes + 1 && newlinesAfter <= this.#limits.maxLines + 1) break;\n\t\t\tthis.#chunks.shift();\n\t\t\tthis.#storedBytes = bytesAfter;\n\t\t\tthis.#storedNewlines = newlinesAfter;\n\t\t}\n\t\treturn true;\n\t}\n\n\t/** Retained, sanitized output and what the limits dropped from the whole stream. */\n\tsnapshot(): BoundedOutput {\n\t\tconst stored =\n\t\t\tthis.#chunks.length === 1 ? this.#chunks[0]!.text : this.#chunks.map((chunk) => chunk.text).join(\"\");\n\t\tconst kept = boundOutput(stored, this.#limits);\n\t\tconst storedLines = lines(this.#storedNewlines, stored === \"\" || stored.endsWith(\"\\n\"));\n\t\tconst keptLines = storedLines - kept.droppedLines;\n\t\t// Tail windows never reach back before this one, but finding a later window's first line needs what precedes it:\n\t\t// keep the shortest suffix longer than the window by a byte or a line, as `#accept` does.\n\t\tif (this.#limits.retain === \"tail\" || this.#chunks.length > 1) {\n\t\t\tconst text = this.#limits.retain === \"tail\" ? tailMargin(stored, this.#limits) : stored;\n\t\t\tconst bytes = this.#limits.retain === \"tail\" ? utf8ByteLength(text) : this.#storedBytes;\n\t\t\tthis.#chunks = text === \"\" ? [] : [{ text, bytes, newlines: countNewlines(text) }];\n\t\t\tthis.#storedBytes = bytes;\n\t\t\tthis.#storedNewlines = this.#chunks[0]?.newlines ?? 0;\n\t\t}\n\t\treturn {\n\t\t\ttext: sanitizeOutput(kept.text),\n\t\t\tdroppedBytes: this.#totalBytes - kept.bytes,\n\t\t\tdroppedLines: lines(this.#totalNewlines, this.#endsWithNewline) - keptLines,\n\t\t};\n\t}\n}\n\n/**\n * The shortest suffix of `text` with more than `maxBytes` bytes or more than `maxLines` newlines, or all of it. The\n * tail window of any text that ends with this suffix, followed by anything, is the same as of `text` followed by it.\n */\nfunction tailMargin(text: string, limits: OutputLimits): string {\n\tconst bytes = encoder.encode(text);\n\tconst byteStart = bytes.length > limits.maxBytes ? characterEnd(bytes, bytes.length - limits.maxBytes - 1) : 0;\n\tlet lineStart = 0;\n\tlet newlines = 0;\n\tfor (let index = bytes.lastIndexOf(NEWLINE); index !== -1; index = bytes.lastIndexOf(NEWLINE, index - 1)) {\n\t\tif (++newlines > limits.maxLines) {\n\t\t\tlineStart = index;\n\t\t\tbreak;\n\t\t}\n\t\tif (index === 0) break;\n\t}\n\tconst start = Math.max(byteStart, lineStart);\n\treturn start === 0 ? text : decoder.decode(bytes.subarray(start));\n}\n\n/** Lines of text with `newlines` newlines; a final unterminated line counts. */\nfunction lines(newlines: number, terminated: boolean): number {\n\treturn newlines + (terminated ? 0 : 1);\n}\n\ninterface RuntimeBuffer {\n\tbyteLength(content: string, encoding: \"utf8\"): number;\n}\n\nconst runtimeBuffer = (globalThis as { Buffer?: RuntimeBuffer }).Buffer;\nconst nonAsciiPattern = /[^\\x00-\\x7f]/;\n\n/** UTF-8 byte length of `content`; a lone surrogate counts as U+FFFD, three bytes. */\nexport function utf8ByteLength(content: string): number {\n\tif (runtimeBuffer) return runtimeBuffer.byteLength(content, \"utf8\");\n\tconst firstNonAscii = content.search(nonAsciiPattern);\n\tif (firstNonAscii === -1) return content.length;\n\tlet bytes = firstNonAscii;\n\tfor (let i = firstNonAscii; i < content.length; i++) {\n\t\tconst code = content.charCodeAt(i);\n\t\tif (code <= 0x7f) bytes += 1;\n\t\telse if (code <= 0x7ff) bytes += 2;\n\t\telse if (code >= 0xd800 && code <= 0xdbff && i + 1 < content.length) {\n\t\t\tconst next = content.charCodeAt(i + 1);\n\t\t\tif (next >= 0xdc00 && next <= 0xdfff) {\n\t\t\t\tbytes += 4;\n\t\t\t\ti++;\n\t\t\t} else bytes += 3;\n\t\t} else bytes += 3;\n\t}\n\treturn bytes;\n}\n\nfunction countNewlines(text: string): number {\n\tlet count = 0;\n\tfor (let index = text.indexOf(\"\\n\"); index !== -1; index = text.indexOf(\"\\n\", index + 1)) count++;\n\treturn count;\n}\n\n/** Each progress commit also buys a pause proportional to what it wrote. */\nexport const PROGRESS_BYTES_PER_SECOND = 100 * 1024;\n\n/**\n * Adaptive progress commits: the first change after an idle period commits at once; each commit then delays the next\n * by at least `minIntervalMs` and by its written size at 100 KiB/s. At most one commit is in flight; changes made\n * meanwhile coalesce into the next one.\n */\nexport class Progress {\n\treadonly #write: () => Promise<number>;\n\treadonly #onError: (error: unknown) => void;\n\treadonly #minIntervalMs: number;\n\t#waiters: PromiseWithResolvers<void>[] = [];\n\t#timer: ReturnType<typeof setTimeout> | undefined;\n\t#inFlight: Promise<void> | undefined;\n\t#nextAt = 0;\n\t#dirty = false;\n\t#stopped = false;\n\n\tconstructor(write: () => Promise<number>, onError: (error: unknown) => void, minIntervalMs: number) {\n\t\tthis.#write = write;\n\t\tthis.#onError = onError;\n\t\tthis.#minIntervalMs = minIntervalMs;\n\t}\n\n\t/** Schedule a commit. */\n\tmark(): void {\n\t\tthis.#dirty = true;\n\t\tthis.#schedule();\n\t}\n\n\t/** Schedule a commit; the promise settles with the commit that includes this change. */\n\tmarkAndWait(): Promise<void> {\n\t\tconst waiter = Promise.withResolvers<void>();\n\t\tthis.#waiters.push(waiter);\n\t\tthis.mark();\n\t\treturn waiter.promise;\n\t}\n\n\t/** Stop committing and wait for the commit in flight; returns the waiters the final commit must settle. */\n\tasync stop(): Promise<PromiseWithResolvers<void>[]> {\n\t\tthis.#stopped = true;\n\t\tclearTimeout(this.#timer);\n\t\tthis.#timer = undefined;\n\t\tawait this.#inFlight;\n\t\treturn this.#waiters.splice(0);\n\t}\n\n\t#schedule(): void {\n\t\tif (this.#stopped || this.#timer !== undefined || this.#inFlight !== undefined) return;\n\t\tconst wait = this.#nextAt - Date.now();\n\t\tif (wait <= 0) this.#flush();\n\t\telse\n\t\t\tthis.#timer = setTimeout(() => {\n\t\t\t\tthis.#timer = undefined;\n\t\t\t\tthis.#flush();\n\t\t\t}, wait);\n\t}\n\n\t#flush(): void {\n\t\tif (this.#stopped || !this.#dirty) return;\n\t\tthis.#dirty = false;\n\t\tconst waiters = this.#waiters.splice(0);\n\t\tconst started = Date.now();\n\t\tthis.#inFlight = this.#write()\n\t\t\t.then(\n\t\t\t\t(bytes) => {\n\t\t\t\t\tthis.#nextAt = started + Math.max(this.#minIntervalMs, (bytes * 1000) / PROGRESS_BYTES_PER_SECOND);\n\t\t\t\t\tfor (const waiter of waiters) waiter.resolve();\n\t\t\t\t},\n\t\t\t\t(error: unknown) => {\n\t\t\t\t\tthis.#nextAt = started + this.#minIntervalMs;\n\t\t\t\t\tfor (const waiter of waiters) waiter.reject(error);\n\t\t\t\t\tthis.#onError(error);\n\t\t\t\t},\n\t\t\t)\n\t\t\t.finally(() => {\n\t\t\t\tthis.#inFlight = undefined;\n\t\t\t\tif (this.#dirty) this.#schedule();\n\t\t\t});\n\t}\n}\n"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Runs `task` after everything enqueued before it. Tasks must not throw (report instead). */
|
|
2
|
+
export declare function enqueue(task: () => void): void;
|
|
3
|
+
/** Delivers nothing until `fn` returns, then everything it enqueued, in order. */
|
|
4
|
+
export declare function holdPublications<T>(fn: () => T): T;
|
|
5
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAaA,8FAA8F;AAC9F,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG,IAAI,CAG9C;AAED,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAQlD"}
|
package/dist/publish.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// One FIFO queue for every observer notification (state events, shape pushes, registry tables, listener
|
|
2
|
+
// invocations).
|
|
3
|
+
//
|
|
4
|
+
// Problem: notifying observers synchronously from inside a write lets a re-entrant write overtake the write being
|
|
5
|
+
// published. Example: subscriber A reacts to n = 1 by writing n = 2; subscriber B then sees 2 before 1.
|
|
6
|
+
// Solution: a publication first adopts every revision it makes (cells and derivations), then enqueues its
|
|
7
|
+
// notifications. Notifications run in enqueue order, so every observer sees revisions in adoption order.
|
|
8
|
+
// `holdPublications` defers delivery until a multi-step change (a reload commit) is complete.
|
|
9
|
+
const queue = [];
|
|
10
|
+
let held = 0;
|
|
11
|
+
let draining = false;
|
|
12
|
+
/** Runs `task` after everything enqueued before it. Tasks must not throw (report instead). */
|
|
13
|
+
export function enqueue(task) {
|
|
14
|
+
queue.push(task);
|
|
15
|
+
drain();
|
|
16
|
+
}
|
|
17
|
+
/** Delivers nothing until `fn` returns, then everything it enqueued, in order. */
|
|
18
|
+
export function holdPublications(fn) {
|
|
19
|
+
held++;
|
|
20
|
+
try {
|
|
21
|
+
return fn();
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
held--;
|
|
25
|
+
drain();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function drain() {
|
|
29
|
+
if (draining || held > 0)
|
|
30
|
+
return;
|
|
31
|
+
draining = true;
|
|
32
|
+
try {
|
|
33
|
+
for (let task = queue.shift(); task !== undefined; task = queue.shift())
|
|
34
|
+
task();
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
draining = false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../src/publish.ts"],"names":[],"mappings":"AAAA,wGAAwG;AACxG,gBAAgB;AAChB,EAAE;AACF,kHAAkH;AAClH,wGAAwG;AACxG,0GAA0G;AAC1G,yGAAyG;AACzG,8FAA8F;AAE9F,MAAM,KAAK,GAAmB,EAAE,CAAC;AACjC,IAAI,IAAI,GAAG,CAAC,CAAC;AACb,IAAI,QAAQ,GAAG,KAAK,CAAC;AAErB,8FAA8F;AAC9F,MAAM,UAAU,OAAO,CAAC,IAAgB;IACvC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACjB,KAAK,EAAE,CAAC;AACT,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,gBAAgB,CAAI,EAAW;IAC9C,IAAI,EAAE,CAAC;IACP,IAAI,CAAC;QACJ,OAAO,EAAE,EAAE,CAAC;IACb,CAAC;YAAS,CAAC;QACV,IAAI,EAAE,CAAC;QACP,KAAK,EAAE,CAAC;IACT,CAAC;AACF,CAAC;AAED,SAAS,KAAK;IACb,IAAI,QAAQ,IAAI,IAAI,GAAG,CAAC;QAAE,OAAO;IACjC,QAAQ,GAAG,IAAI,CAAC;IAChB,IAAI,CAAC;QACJ,KAAK,IAAI,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,IAAI,KAAK,SAAS,EAAE,IAAI,GAAG,KAAK,CAAC,KAAK,EAAE;YAAE,IAAI,EAAE,CAAC;IACjF,CAAC;YAAS,CAAC;QACV,QAAQ,GAAG,KAAK,CAAC;IAClB,CAAC;AACF,CAAC","sourcesContent":["// One FIFO queue for every observer notification (state events, shape pushes, registry tables, listener\n// invocations).\n//\n// Problem: notifying observers synchronously from inside a write lets a re-entrant write overtake the write being\n// published. Example: subscriber A reacts to n = 1 by writing n = 2; subscriber B then sees 2 before 1.\n// Solution: a publication first adopts every revision it makes (cells and derivations), then enqueues its\n// notifications. Notifications run in enqueue order, so every observer sees revisions in adoption order.\n// `holdPublications` defers delivery until a multi-step change (a reload commit) is complete.\n\nconst queue: (() => void)[] = [];\nlet held = 0;\nlet draining = false;\n\n/** Runs `task` after everything enqueued before it. Tasks must not throw (report instead). */\nexport function enqueue(task: () => void): void {\n\tqueue.push(task);\n\tdrain();\n}\n\n/** Delivers nothing until `fn` returns, then everything it enqueued, in order. */\nexport function holdPublications<T>(fn: () => T): T {\n\theld++;\n\ttry {\n\t\treturn fn();\n\t} finally {\n\t\theld--;\n\t\tdrain();\n\t}\n}\n\nfunction drain(): void {\n\tif (draining || held > 0) return;\n\tdraining = true;\n\ttry {\n\t\tfor (let task = queue.shift(); task !== undefined; task = queue.shift()) task();\n\t} finally {\n\t\tdraining = false;\n\t}\n}\n"]}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Ctx } from "./types.ts";
|
|
2
|
+
export interface Registry<V> {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly conflict: "error" | "last";
|
|
5
|
+
/** Type carrier only; never set. */
|
|
6
|
+
readonly value?: V;
|
|
7
|
+
}
|
|
8
|
+
/** `conflict: "error"` rejects two objects registering one key; `"last"` keeps the later registration. */
|
|
9
|
+
export declare const defineRegistry: <V>(name: string, options?: {
|
|
10
|
+
conflict?: "error" | "last";
|
|
11
|
+
}) => Registry<V>;
|
|
12
|
+
export type RegistryTable<V> = ReadonlyMap<string, V>;
|
|
13
|
+
export interface RegistryView<V> {
|
|
14
|
+
/** Table of `ctx.codeVersion`, or of the current code version without ctx. */
|
|
15
|
+
table(ctx?: Ctx): RegistryTable<V>;
|
|
16
|
+
get(key: string, ctx?: Ctx): V | undefined;
|
|
17
|
+
/** Called with the current table immediately and whenever a new table is installed. */
|
|
18
|
+
subscribe(listener: (table: RegistryTable<V>, codeVersion: number) => void): () => void;
|
|
19
|
+
}
|
|
20
|
+
export interface Registration {
|
|
21
|
+
readonly registry: Registry<unknown>;
|
|
22
|
+
readonly key: string;
|
|
23
|
+
readonly value: unknown;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,YAAY,CAAC;AAEtC,MAAM,WAAW,QAAQ,CAAC,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,CAAC;IACpC,oCAAoC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;CACnB;AAED,0GAA0G;AAC1G,eAAO,MAAM,cAAc,GAAI,CAAC,QAAQ,MAAM,YAAW;IAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;CAAE,KAAQ,QAAQ,CAAC,CAAC,CAGxG,CAAC;AAEH,MAAM,MAAM,aAAa,CAAC,CAAC,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAEtD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC9B,8EAA8E;IAC9E,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;IACnC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC;IAC3C,uFAAuF;IACvF,SAAS,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACxF;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACxB"}
|
package/dist/registry.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AASA,0GAA0G;AAC1G,MAAM,CAAC,MAAM,cAAc,GAAG,CAAI,IAAY,EAAE,OAAO,GAAoC,EAAE,EAAe,EAAE,CAAC,CAAC;IAC/G,IAAI;IACJ,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO;CACrC,CAAC,CAAC","sourcesContent":["import type { Ctx } from \"./types.ts\";\n\nexport interface Registry<V> {\n\treadonly name: string;\n\treadonly conflict: \"error\" | \"last\";\n\t/** Type carrier only; never set. */\n\treadonly value?: V;\n}\n\n/** `conflict: \"error\"` rejects two objects registering one key; `\"last\"` keeps the later registration. */\nexport const defineRegistry = <V>(name: string, options: { conflict?: \"error\" | \"last\" } = {}): Registry<V> => ({\n\tname,\n\tconflict: options.conflict ?? \"error\",\n});\n\nexport type RegistryTable<V> = ReadonlyMap<string, V>;\n\nexport interface RegistryView<V> {\n\t/** Table of `ctx.codeVersion`, or of the current code version without ctx. */\n\ttable(ctx?: Ctx): RegistryTable<V>;\n\tget(key: string, ctx?: Ctx): V | undefined;\n\t/** Called with the current table immediately and whenever a new table is installed. */\n\tsubscribe(listener: (table: RegistryTable<V>, codeVersion: number) => void): () => void;\n}\n\nexport interface Registration {\n\treadonly registry: Registry<unknown>;\n\treadonly key: string;\n\treadonly value: unknown;\n}\n"]}
|
package/dist/reload.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import type { Cell } from "./cell.ts";
|
|
2
|
+
import { ChordError } from "./errors.ts";
|
|
3
|
+
import type { Facet, HostImpl, PluginRef } from "./host.ts";
|
|
4
|
+
import { type ObjectImpl, type ResourceImpl, type Run, type Service, type StagedListeners } from "./object.ts";
|
|
5
|
+
import type { RegistryTable } from "./registry.ts";
|
|
6
|
+
export interface ReloadOptions {
|
|
7
|
+
/** Facet names to remove. */
|
|
8
|
+
readonly remove?: readonly string[];
|
|
9
|
+
/** Milliseconds the gate waits for grandfathered roots (default 5000). Missed: the reload aborts. */
|
|
10
|
+
readonly gateDeadline?: number;
|
|
11
|
+
/** Milliseconds to wait for the previous code version to retire first (default 5000). Missed: it is retired anyway. */
|
|
12
|
+
readonly retireDeadline?: number;
|
|
13
|
+
/** Server: facet modules for child hosts by host-name prefix (longest wins). Every connected host participates. */
|
|
14
|
+
readonly remote?: Readonly<Record<string, readonly string[]>>;
|
|
15
|
+
/** Server: facet names to remove on child hosts, by the same host-name prefix rules. */
|
|
16
|
+
readonly remoteRemove?: Readonly<Record<string, readonly string[]>>;
|
|
17
|
+
/** Server: milliseconds to wait for every child's vote (default: gate + retire deadlines + 5000). */
|
|
18
|
+
readonly voteDeadline?: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ReloadReport {
|
|
21
|
+
readonly codeVersion: number;
|
|
22
|
+
readonly previous: number;
|
|
23
|
+
readonly changed: readonly string[];
|
|
24
|
+
readonly removed: readonly string[];
|
|
25
|
+
/** Addresses of objects whose new factory was installed. */
|
|
26
|
+
readonly prepared: readonly string[];
|
|
27
|
+
/** Addresses of objects that went through the gate. */
|
|
28
|
+
readonly gated: readonly string[];
|
|
29
|
+
/**
|
|
30
|
+
* Cluster reloads: what each participating child host prepared, by host name (its vote; the child commits it after
|
|
31
|
+
* the server). Absent for local reloads.
|
|
32
|
+
*/
|
|
33
|
+
readonly children?: Readonly<Record<string, ReloadReport>>;
|
|
34
|
+
}
|
|
35
|
+
interface Candidate {
|
|
36
|
+
readonly object: ObjectImpl;
|
|
37
|
+
readonly service: Service;
|
|
38
|
+
readonly run: Run;
|
|
39
|
+
/** Why the object needs the gate (empty: compatible). */
|
|
40
|
+
readonly reasons: string[];
|
|
41
|
+
/** New exclusive resources and their new dependents, opened at the gate. */
|
|
42
|
+
readonly atGate: ResourceImpl[];
|
|
43
|
+
/** Old exclusive resources closed at the gate. */
|
|
44
|
+
readonly replaced: ResourceImpl[];
|
|
45
|
+
readonly migrated: Map<Cell<unknown>, unknown>;
|
|
46
|
+
/** Values of the run's derivations over the candidate (migrated) values, validated. */
|
|
47
|
+
derived: Map<unknown, unknown>;
|
|
48
|
+
/** Listener subscriptions made at the end of prepare, activated by the commit. */
|
|
49
|
+
staged: StagedListeners | undefined;
|
|
50
|
+
}
|
|
51
|
+
/** A reload error keeps the underlying code (`contract_mismatch`, `invalid`, ...) and says it aborted the reload. */
|
|
52
|
+
export declare function reloadError(error: unknown): ChordError;
|
|
53
|
+
/** Serialized: a second reload while one runs is rejected. */
|
|
54
|
+
export declare function runReload(host: HostImpl, plugins: readonly PluginRef[], options: ReloadOptions): Promise<ReloadReport>;
|
|
55
|
+
/** Takes the host's reload slot and loads the plugin modules. Pair with `endReload`. */
|
|
56
|
+
export declare function beginReload(host: HostImpl, plugins: readonly PluginRef[], options: ReloadOptions, codeVersion?: number): Promise<Reload>;
|
|
57
|
+
export declare function endReload(host: HostImpl): void;
|
|
58
|
+
/** One reload on one host: `prepare` (load, prepare, gate), then `commit` or `rollback`. */
|
|
59
|
+
export declare class Reload {
|
|
60
|
+
#private;
|
|
61
|
+
readonly host: HostImpl;
|
|
62
|
+
readonly facets: readonly Facet[];
|
|
63
|
+
readonly options: ReloadOptions;
|
|
64
|
+
/** Code version id to commit (issued by the coordinating server); a local reload allocates one. */
|
|
65
|
+
readonly codeVersion: number | undefined;
|
|
66
|
+
readonly candidates: Map<ObjectImpl, Candidate>;
|
|
67
|
+
readonly abort: AbortController;
|
|
68
|
+
readonly closed: [ObjectImpl, ResourceImpl][];
|
|
69
|
+
services: Map<string, Service>;
|
|
70
|
+
changed: Set<string>;
|
|
71
|
+
removed: Set<string>;
|
|
72
|
+
tables: Map<string, RegistryTable<unknown>>;
|
|
73
|
+
gated: Candidate[];
|
|
74
|
+
rolledBack: boolean;
|
|
75
|
+
/** Objects of types this reload adds, with their staged listeners: their runtime starts at commit. */
|
|
76
|
+
readonly deferred: Map<ObjectImpl, StagedListeners>;
|
|
77
|
+
/** This reload's run of each facet it loads (`FacetApi.signal`): installed at commit, aborted at rollback. */
|
|
78
|
+
readonly facetRuns: Map<string, AbortController>;
|
|
79
|
+
constructor(host: HostImpl, facets: readonly Facet[], options: ReloadOptions, codeVersion?: number);
|
|
80
|
+
/** Everything up to the commit. On failure the host is rolled back and the underlying error is thrown. */
|
|
81
|
+
prepare(): Promise<void>;
|
|
82
|
+
/** What a successful prepare will commit (a child sends it with its vote). */
|
|
83
|
+
summary(): ReloadReport;
|
|
84
|
+
/**
|
|
85
|
+
* Retires the previous code version before loading the next one (a host keeps two). Waits until its roots ended and,
|
|
86
|
+
* on a child host, its parent retired it too (`retire` frame), at most `retireDeadline`. Past the deadline it is
|
|
87
|
+
* retired anyway: its remaining roots are aborted first and get a short grace to stop, so they see cancellation
|
|
88
|
+
* before the resources only that code version used are closed; their next call is `superseded`.
|
|
89
|
+
*/
|
|
90
|
+
waitForRetirement(): Promise<void>;
|
|
91
|
+
/** Builds the candidate service table: unchanged services plus everything the given facets serve. */
|
|
92
|
+
load(): void;
|
|
93
|
+
withDeadline<T>(promise: Promise<T>, what: string): Promise<T>;
|
|
94
|
+
/** Same contract version must cover the old description (forgotten bump); facets' `uses` must bind. */
|
|
95
|
+
checkProviders(): void;
|
|
96
|
+
/**
|
|
97
|
+
* Prepares every live object of a changed type, including objects that activate meanwhile, to a fixpoint. Objects
|
|
98
|
+
* already running the new code (types this reload adds) are skipped.
|
|
99
|
+
*/
|
|
100
|
+
prepareAll(): Promise<void>;
|
|
101
|
+
/** Runs the new factory in recording mode and opens what can be opened without the gate. */
|
|
102
|
+
prepareObject(object: ObjectImpl): Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* Every reference that survives into the new code version must bind to the new provider. Browser references don't block a
|
|
105
|
+
* reload: after the commit they get `upgrade_required` instead.
|
|
106
|
+
*/
|
|
107
|
+
checkRefs(): void;
|
|
108
|
+
entries(): [ObjectImpl, Run["decls"]][];
|
|
109
|
+
/**
|
|
110
|
+
* Admission cut, wait for grandfathered roots (deadline), replace exclusive resources, migrate into private
|
|
111
|
+
* copies. Old tasks of gated objects are stopped at the cut; listener events are queued until commit or abort.
|
|
112
|
+
*/
|
|
113
|
+
gate(): Promise<void>;
|
|
114
|
+
migrate(candidate: Candidate): void;
|
|
115
|
+
rollback(): Promise<void>;
|
|
116
|
+
/**
|
|
117
|
+
* Publishes the new code version in one synchronous step. Everything fallible ran in prepare (factories, opens,
|
|
118
|
+
* migration and derivation checks against the prospective schemas, listener subscriptions), so this only installs.
|
|
119
|
+
* Observers (state, shapes, registries, listener roots) are notified after the whole step. If an install still
|
|
120
|
+
* throws, the code version is half-published: the host fails terminally and admits no more work.
|
|
121
|
+
*/
|
|
122
|
+
commit(beforeStart?: () => void): ReloadReport;
|
|
123
|
+
install(candidate: Candidate, codeVersion: number): void;
|
|
124
|
+
}
|
|
125
|
+
export {};
|
|
126
|
+
//# sourceMappingURL=reload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reload.d.ts","sourceRoot":"","sources":["../src/reload.ts"],"names":[],"mappings":"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"}
|