@anureo/sdk 0.2.0 → 0.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.
Files changed (90) hide show
  1. package/README.md +162 -65
  2. package/package.json +29 -24
  3. package/src/adapter/identity.d.ts +41 -0
  4. package/src/adapter/identity.js +71 -0
  5. package/src/client-options.d.ts +71 -0
  6. package/src/client-options.js +0 -0
  7. package/src/client.d.ts +106 -0
  8. package/src/client.js +254 -0
  9. package/src/diagnostics/errors.d.ts +15 -0
  10. package/src/diagnostics/errors.js +59 -0
  11. package/src/diagnostics/events.d.ts +46 -0
  12. package/src/diagnostics/events.js +47 -0
  13. package/src/diagnostics.d.ts +20 -0
  14. package/src/diagnostics.js +56 -0
  15. package/src/errors.d.ts +48 -0
  16. package/src/errors.js +63 -0
  17. package/src/index.d.ts +27 -0
  18. package/src/index.js +23 -0
  19. package/src/lifecycle/approval.d.ts +16 -0
  20. package/src/lifecycle/approval.js +18 -0
  21. package/src/lifecycle/deferred.d.ts +10 -0
  22. package/src/lifecycle/deferred.js +12 -0
  23. package/src/lifecycle/errors.d.ts +18 -0
  24. package/src/lifecycle/errors.js +45 -0
  25. package/src/lifecycle/events.d.ts +35 -0
  26. package/src/lifecycle/events.js +141 -0
  27. package/src/lifecycle/execution-observation.d.ts +33 -0
  28. package/src/lifecycle/execution-observation.js +0 -0
  29. package/src/lifecycle/immutable.d.ts +12 -0
  30. package/src/lifecycle/immutable.js +28 -0
  31. package/src/lifecycle/input.d.ts +9 -0
  32. package/src/lifecycle/input.js +19 -0
  33. package/src/lifecycle/interactions.d.ts +129 -0
  34. package/src/lifecycle/interactions.js +282 -0
  35. package/src/lifecycle/limits.d.ts +7 -0
  36. package/src/lifecycle/limits.js +13 -0
  37. package/src/lifecycle/result.d.ts +77 -0
  38. package/src/lifecycle/result.js +213 -0
  39. package/src/lifecycle/value.d.ts +4 -0
  40. package/src/lifecycle/value.js +5 -0
  41. package/src/ports.d.ts +224 -0
  42. package/src/ports.js +0 -0
  43. package/src/privacy/file-change-limits.d.ts +20 -0
  44. package/src/privacy/file-change-limits.js +124 -0
  45. package/src/privacy/secrets.d.ts +205 -0
  46. package/src/privacy/secrets.js +564 -0
  47. package/src/process.d.ts +92 -0
  48. package/src/process.js +331 -0
  49. package/src/queue.d.ts +143 -0
  50. package/src/queue.js +266 -0
  51. package/src/request.d.ts +28 -0
  52. package/src/request.js +81 -0
  53. package/src/requests/guard.d.ts +15 -0
  54. package/src/requests/guard.js +93 -0
  55. package/src/session.d.ts +459 -0
  56. package/src/session.js +1135 -0
  57. package/src/structured-output/adapter.d.ts +8 -0
  58. package/src/structured-output/adapter.js +54 -0
  59. package/src/structured-output/bridge.d.ts +81 -0
  60. package/src/structured-output/bridge.js +274 -0
  61. package/src/structured-output/errors.d.ts +17 -0
  62. package/src/structured-output/errors.js +31 -0
  63. package/src/structured-output/limits.d.ts +19 -0
  64. package/src/structured-output/limits.js +0 -0
  65. package/src/structured-output/schema.d.ts +20 -0
  66. package/src/structured-output/schema.js +122 -0
  67. package/src/structured-output/session.d.ts +329 -0
  68. package/src/structured-output/session.js +846 -0
  69. package/src/structured-output/stdio.mjs +83 -0
  70. package/src/structured-output/tool.d.ts +38 -0
  71. package/src/structured-output/tool.js +34 -0
  72. package/src/turn.d.ts +75 -0
  73. package/src/turn.js +95 -0
  74. package/src/types.d.ts +62 -0
  75. package/src/types.js +0 -0
  76. package/dist/diagnostics.d.ts +0 -15
  77. package/dist/diagnostics.js +0 -34
  78. package/dist/errors.d.ts +0 -15
  79. package/dist/file-change-limits.d.ts +0 -5
  80. package/dist/identity.d.ts +0 -13
  81. package/dist/index.d.ts +0 -8
  82. package/dist/index.js +0 -1474
  83. package/dist/interactions.d.ts +0 -20
  84. package/dist/ports.d.ts +0 -66
  85. package/dist/process.d.ts +0 -34
  86. package/dist/process.js +0 -191
  87. package/dist/queue.d.ts +0 -36
  88. package/dist/queue.js +0 -166
  89. package/dist/runtime.d.ts +0 -85
  90. package/dist/secrets.d.ts +0 -28
package/src/process.js ADDED
@@ -0,0 +1,331 @@
1
+ // Owns harness subprocess I/O, exit observation, and process-tree cleanup.
2
+ import { spawn } from 'node:child_process';
3
+ import { setTimeout as delay } from 'node:timers/promises';
4
+ /** Process failure category for adapters; native causes are reduced to a format-checked code. */
5
+ export class ProcessPortError extends Error {
6
+ /**
7
+ * Construct a failure using caller-supplied safe message text, which is retained verbatim.
8
+ * Supply a native cause to retain only its format-checked error code.
9
+ */
10
+ constructor(code, message, options) {
11
+ // Native spawn errors contain spawnargs. Never retain their raw cause in a public error.
12
+ super(message);
13
+ this.name = 'ProcessPortError';
14
+ this.code = code;
15
+ const nativeCode = readNativeErrorCode(options?.cause);
16
+ if (nativeCode !== undefined)
17
+ this.nativeCode = nativeCode;
18
+ }
19
+ /** Stable category for adapter startup, input, or disposal failures. */
20
+ code;
21
+ /**
22
+ * Native code of 1 to 64 characters, beginning with an uppercase letter and containing only
23
+ * uppercase letters, digits, and underscores.
24
+ */
25
+ nativeCode;
26
+ }
27
+ /**
28
+ * Launch a harness executable directly with piped I/O and literal arguments, without a shell.
29
+ * Resolve after the spawn event provides a process handle. The caller handles protocol readiness.
30
+ * Invalid inputs or launch failures reject with HARNESS_UNAVAILABLE. Failed startup releases any
31
+ * local pipes it acquired. Drain output and await disposal even after child exit.
32
+ *
33
+ * ACP's processStream awaits launch to wire the pipes into its channel, propagates launch
34
+ * rejection, and delegates channel disposal to the handle.
35
+ */
36
+ export async function spawnHarnessProcess(options) {
37
+ const timeoutMs = validateProcessOptions(options);
38
+ const owned = options.owned ?? true;
39
+ const child = launchProcess({ options, owned });
40
+ const initialPid = child.pid;
41
+ const exit = observeProcessExit(child);
42
+ // Prevent an unhandled pipe error if a peer closes while the caller isn't writing.
43
+ child.stdin.on('error', () => { });
44
+ const pid = await waitForSpawn(child, initialPid);
45
+ return createProcessHandle({ child, pid, owned, timeoutMs, ...exit });
46
+ }
47
+ /**
48
+ * Return the validated grace period for disposal. Throw HARNESS_UNAVAILABLE for an empty
49
+ * executable, NUL bytes in the executable or arguments, or an invalid timeout. spawnHarnessProcess
50
+ * calls this before launching the child.
51
+ */
52
+ function validateProcessOptions(options) {
53
+ if (!options.command || options.command.includes('\0') || options.args?.some((arg) => arg.includes('\0'))) {
54
+ throw new ProcessPortError('HARNESS_UNAVAILABLE', 'Invalid harness executable or argument');
55
+ }
56
+ const timeoutMs = options.shutdownTimeoutMs ?? 1000;
57
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 0 || timeoutMs > 60_000) {
58
+ throw new ProcessPortError('HARNESS_UNAVAILABLE', 'Invalid process shutdown timeout');
59
+ }
60
+ return timeoutMs;
61
+ }
62
+ /**
63
+ * Open piped stdio for a shell-free launch. Detach owned POSIX children so teardown can signal
64
+ * their whole group. Convert synchronous spawn failures to HARNESS_UNAVAILABLE. spawnHarnessProcess
65
+ * installs the event observers after this returns.
66
+ */
67
+ function launchProcess({ options, owned }) {
68
+ try {
69
+ return spawn(options.command, [...(options.args ?? [])], {
70
+ cwd: options.cwd, env: options.env, stdio: ['pipe', 'pipe', 'pipe'],
71
+ detached: owned && process.platform !== 'win32', shell: false, windowsHide: true,
72
+ });
73
+ }
74
+ catch (cause) {
75
+ throw new ProcessPortError('HARNESS_UNAVAILABLE', 'Unable to start harness executable', { cause });
76
+ }
77
+ }
78
+ /**
79
+ * Register child exit and error listeners before spawnHarnessProcess awaits startup. Update the exit
80
+ * flag before resolving so writes and teardown can consult the observation immediately.
81
+ */
82
+ function observeProcessExit(child) {
83
+ let didExit = false;
84
+ const exited = new Promise((resolve) => {
85
+ child.once('exit', (code, signal) => {
86
+ didExit = true;
87
+ resolve({ code, signal });
88
+ });
89
+ child.once('error', (error) => {
90
+ if (!child.pid) {
91
+ didExit = true;
92
+ resolve({ code: null, signal: null, errorCode: error.code });
93
+ }
94
+ });
95
+ });
96
+ return { exited, didExit: () => didExit };
97
+ }
98
+ /**
99
+ * Wait for the spawn event and retain its PID before the runtime can clear it on exit. Fall back
100
+ * to the initial PID if the event provides no usable PID. On failure, release the pipes and
101
+ * reject with HARNESS_UNAVAILABLE so spawnHarnessProcess never publishes a partial handle.
102
+ */
103
+ async function waitForSpawn(child, initialPid) {
104
+ let pid = initialPid;
105
+ try {
106
+ await new Promise((resolve, reject) => {
107
+ child.once('spawn', () => {
108
+ const spawnPid = child.pid;
109
+ if (spawnPid !== undefined && spawnPid > 1)
110
+ pid = spawnPid;
111
+ resolve();
112
+ });
113
+ child.once('error', reject);
114
+ });
115
+ }
116
+ catch (cause) {
117
+ return failProcessStartup(child, cause);
118
+ }
119
+ if (pid === undefined || pid <= 1)
120
+ return failProcessStartup(child);
121
+ return pid;
122
+ }
123
+ /** Release startup's local pipes before rejecting launch with a privacy-safe error. */
124
+ function failProcessStartup(child, cause) {
125
+ destroyProcessStreams(child);
126
+ throw new ProcessPortError('HARNESS_UNAVAILABLE', 'Unable to start harness executable', { cause });
127
+ }
128
+ /** Close all three local pipes after failed startup or after disposal, even if termination failed. */
129
+ function destroyProcessStreams(child) {
130
+ child.stdin.destroy();
131
+ child.stdout.destroy();
132
+ child.stderr.destroy();
133
+ }
134
+ /**
135
+ * Give spawnHarnessProcess's callers the pipes and exit observation. Keep stdin write admission
136
+ * and the teardown promise together so disposing closes admission and shares the cleanup outcome.
137
+ */
138
+ function createProcessHandle(resources) {
139
+ const { child, pid, owned, didExit, exited } = resources;
140
+ const { stdin, stdout, stderr } = child;
141
+ let disposePromise;
142
+ return {
143
+ pid, owned, stdout, stderr, exited,
144
+ write(chunk) {
145
+ if (disposePromise || isInputClosed(stdin) || didExit()) {
146
+ return Promise.reject(new ProcessPortError('PROCESS_WRITE_FAILED', 'Harness process input is closed'));
147
+ }
148
+ return runInputOperation('Unable to write harness input', (complete) => {
149
+ stdin.write(chunk, complete);
150
+ });
151
+ },
152
+ closeInput() {
153
+ return runInputOperation('Unable to close harness input', (complete) => {
154
+ if (isInputClosed(stdin))
155
+ complete();
156
+ else
157
+ stdin.end(complete);
158
+ });
159
+ },
160
+ dispose() {
161
+ return disposePromise ??= disposeProcess(resources);
162
+ },
163
+ };
164
+ }
165
+ /** Treat ending as closed for writes and redundant close requests. */
166
+ function isInputClosed(stdin) {
167
+ return stdin.destroyed || stdin.writableEnded;
168
+ }
169
+ /**
170
+ * Settle the handle's write or close promise from the callback passed to stdin. Convert callback
171
+ * errors to PROCESS_WRITE_FAILED and let synchronous exceptions reject through the promise executor.
172
+ */
173
+ function runInputOperation(failureMessage, start) {
174
+ return new Promise((resolve, reject) => {
175
+ start((error) => {
176
+ if (error)
177
+ reject(new ProcessPortError('PROCESS_WRITE_FAILED', failureMessage, { cause: error }));
178
+ else
179
+ resolve();
180
+ });
181
+ });
182
+ }
183
+ /**
184
+ * createProcessHandle's dispose method caches this promise. Terminate owned trees or unref
185
+ * external processes, then destroy local pipes even on failure. Convert native termination or
186
+ * unref errors to a ProcessPortError containing only safe error details.
187
+ */
188
+ async function disposeProcess({ child, pid, owned, timeoutMs, didExit, exited }) {
189
+ try {
190
+ if (owned) {
191
+ await terminateTree(pid, timeoutMs, didExit);
192
+ if (!didExit())
193
+ await waitForTerminatedProcessExit(didExit, exited);
194
+ }
195
+ else {
196
+ child.unref();
197
+ }
198
+ }
199
+ catch (cause) {
200
+ if (cause instanceof ProcessPortError)
201
+ throw cause;
202
+ throw new ProcessPortError('PROCESS_DISPOSE_FAILED', 'Unable to dispose harness process', { cause });
203
+ }
204
+ finally {
205
+ destroyProcessStreams(child);
206
+ }
207
+ }
208
+ /**
209
+ * After tree termination, disposeProcess allows 1000 ms for any pending child exit observation.
210
+ * A vanished group can precede the child exit event. Reject PROCESS_DISPOSE_FAILED if exit still
211
+ * has not been observed.
212
+ */
213
+ async function waitForTerminatedProcessExit(didExit, exited) {
214
+ await Promise.race([exited, delay(1000)]);
215
+ if (!didExit())
216
+ throw new ProcessPortError('PROCESS_DISPOSE_FAILED', 'Harness process did not exit after termination');
217
+ }
218
+ /**
219
+ * disposeProcess awaits this only for owned children and sanitizes failures before rejecting its
220
+ * public dispose promise. Validate the retained PID, then delegate platform cleanup; callers retain
221
+ * ownership of exit observation and pipe destruction.
222
+ */
223
+ async function terminateTree(pid, timeoutMs, didExit) {
224
+ // Bun may clear/change ChildProcess.pid after exit. Only use the original positive PID.
225
+ if (!Number.isSafeInteger(pid) || pid <= 1)
226
+ throw new ProcessPortError('PROCESS_DISPOSE_FAILED', 'Invalid original harness PID');
227
+ if (process.platform === 'win32')
228
+ return terminateWindowsTree(pid, timeoutMs, didExit);
229
+ return terminatePosixTree(pid, timeoutMs);
230
+ }
231
+ /**
232
+ * terminateTree delegates here on POSIX; exit observation and pipe destruction remain in
233
+ * disposeProcess. Stop the detached POSIX group and force remaining descendants after the grace
234
+ * period.
235
+ */
236
+ async function terminatePosixTree(pid, timeoutMs) {
237
+ // Descendants can keep inherited pipes open after the direct child has exited.
238
+ const group = -pid;
239
+ await signalGroupWithExitRace(group, 'SIGTERM');
240
+ const deadline = Date.now() + timeoutMs;
241
+ while (processOrGroupExists(group) && Date.now() < deadline)
242
+ await delay(10);
243
+ if (processOrGroupExists(group))
244
+ await signalGroupWithExitRace(group, 'SIGKILL');
245
+ }
246
+ /**
247
+ * Signal the negative group PID for terminatePosixTree. A vanished group completes the attempt.
248
+ * Retry a short exit-time EPERM race up to four times, then propagate the failure to disposal.
249
+ */
250
+ async function signalGroupWithExitRace(group, signal) {
251
+ for (let attempt = 0;; attempt++) {
252
+ try {
253
+ process.kill(group, signal);
254
+ return;
255
+ }
256
+ catch (error) {
257
+ const { code } = error;
258
+ if (code === 'ESRCH')
259
+ return;
260
+ if (code !== 'EPERM' || attempt >= 4)
261
+ throw error;
262
+ await delay(10);
263
+ }
264
+ }
265
+ }
266
+ /**
267
+ * Stop the Windows tree for terminateTree. Attempt graceful taskkill while the child is still
268
+ * running. Escalate immediately if that attempt fails and exit is still pending, or after the
269
+ * grace period if the child remains alive. Forced taskkill failures reject teardown.
270
+ */
271
+ async function terminateWindowsTree(pid, timeoutMs, didExit) {
272
+ if (!didExit()) {
273
+ try {
274
+ await windowsKillTree(pid, 'graceful');
275
+ }
276
+ catch {
277
+ // Console-less Windows children may reject non-forced taskkill, so retry while alive.
278
+ if (!didExit())
279
+ await windowsKillTree(pid, 'force');
280
+ }
281
+ }
282
+ const deadline = Date.now() + timeoutMs;
283
+ while (!didExit() && Date.now() < deadline)
284
+ await delay(10);
285
+ if (!didExit())
286
+ await windowsKillTree(pid, 'force');
287
+ }
288
+ /**
289
+ * Run shell-free taskkill for terminateWindowsTree. Reject if the tool fails to start or exits
290
+ * unsuccessfully while the original PID is still present.
291
+ */
292
+ async function windowsKillTree(pid, mode) {
293
+ await new Promise((resolve, reject) => {
294
+ const killer = spawn('taskkill.exe', ['/PID', String(pid), '/T', ...(mode === 'force' ? ['/F'] : [])], {
295
+ stdio: 'ignore', windowsHide: true, shell: false,
296
+ });
297
+ killer.once('error', reject);
298
+ killer.once('exit', (code) => {
299
+ // taskkill reports a nonzero result if the process exited during the call.
300
+ if (code === 0 || !processOrGroupExists(pid))
301
+ resolve();
302
+ else
303
+ reject(new ProcessPortError('PROCESS_DISPOSE_FAILED', 'Unable to terminate harness process tree'));
304
+ });
305
+ });
306
+ }
307
+ /**
308
+ * terminatePosixTree uses this for POSIX polling; windowsKillTree uses it to distinguish a taskkill
309
+ * failure from concurrent child exit. Probe a PID or negative POSIX group without signalling it; EPERM
310
+ * counts as existing so cleanup still escalates.
311
+ */
312
+ function processOrGroupExists(pid) {
313
+ try {
314
+ process.kill(pid, 0);
315
+ return true;
316
+ }
317
+ catch (error) {
318
+ return error.code === 'EPERM';
319
+ }
320
+ }
321
+ /**
322
+ * Extract only a bounded uppercase code for ProcessPortError; a native cause may contain private
323
+ * spawn arguments and must never become part of the public error.
324
+ */
325
+ function readNativeErrorCode(cause) {
326
+ if (!cause || typeof cause !== 'object' || !('code' in cause))
327
+ return undefined;
328
+ if (typeof cause.code !== 'string' || !/^[A-Z][A-Z0-9_]{0,63}$/.test(cause.code))
329
+ return undefined;
330
+ return cause.code;
331
+ }
package/src/queue.d.ts ADDED
@@ -0,0 +1,143 @@
1
+ /** Queue budgets for producers and event subscriptions. Each resolved budget must be a positive safe integer. */
2
+ export interface QueueLimits {
3
+ /** Maximum buffered regular events; defaults to 2048. Direct delivery to a waiting reader consumes no slot. */
4
+ maxEvents?: number;
5
+ /** Maximum bytes buffered by regular events; defaults to 16 MiB. Controls have a separate count budget. */
6
+ maxBytes?: number;
7
+ /** Maximum bytes per regular or control event; defaults to 8 MiB. Each event must also fit maxBytes. */
8
+ maxFrameBytes?: number;
9
+ /** Maximum suspended write calls. Defaults to 32. */
10
+ maxWaitingWriters?: number;
11
+ /** Maximum buffered controls; defaults to 33. They drain after regular events and use separate capacity. */
12
+ maxControlEvents?: number;
13
+ }
14
+ /**
15
+ * Buffer a producer stream within event and byte budgets, or await capacity with write.
16
+ * One iterator owns reads at a time. Returning it releases ownership while the producer stays open.
17
+ * Producers own closure and consumers own iterator release. Buffered regular events drain before
18
+ * buffered controls, then readers observe completion or failure. Values are retained by reference;
19
+ * keep their measured size stable while queued. EventHub uses a private queue per observer to
20
+ * isolate overflow, while adapter transports use queues for incoming frames or native input.
21
+ */
22
+ export declare class BoundedEventQueue<T> implements AsyncIterable<T> {
23
+ private readonly sizeOf;
24
+ /**
25
+ * Configure storage without claiming a reader. Invalid resolved budgets throw INVALID_PARAMS.
26
+ * Omitted or nullish budget fields select the QueueLimits defaults. The queue calls sizeOf during
27
+ * admission and propagates measurement failures. It defaults to measuring the UTF-8 byte length
28
+ * of the JSON serialization. A custom measurement must return a consistent, nonnegative byte
29
+ * count because a value can be measured more than once.
30
+ */
31
+ constructor(limits?: QueueLimits, sizeOf?: (value: T) => number);
32
+ /** Resolved construction-time budgets exposed for producers; callers must treat this object as read-only. */
33
+ readonly limits: Required<QueueLimits>;
34
+ /** Count regular events and controls currently in the buffer. */
35
+ get bufferedEvents(): number;
36
+ /** Count bytes reserved by buffered regular events. Controls consume their own event budget. */
37
+ get bufferedBytes(): number;
38
+ /**
39
+ * Check regular-event admission without reserving capacity. A later push can still fail.
40
+ * Throw the stored non-nullish closure cause (or STREAM_CLOSED), FRAME_TOO_LARGE, a measurement
41
+ * failure, or BACKPRESSURE_EXCEEDED for a full regular buffer.
42
+ */
43
+ assertWritable(value: T): void;
44
+ /**
45
+ * Deliver to a waiting read or buffer synchronously, throwing on closure, capacity or
46
+ * size/measurement failure without evicting data. Producers handle failures and own closure.
47
+ * EventHub.publish ends only the affected observer on failure. The message listener in
48
+ * createSocketTransport also closes the native socket.
49
+ */
50
+ push(value: T): void;
51
+ /**
52
+ * Await capacity and resolve once delivered or buffered, without waiting for consumption.
53
+ * Reject on closure, size/measurement failure or exhausted writer capacity.
54
+ * Waking writers compete for capacity and recheck it before admitting a value. Pass accepted
55
+ * to run a synchronous callback after admission. If it throws, the promise rejects and the value
56
+ * remains admitted. Producers can end the queue to wake all blocked writers and reject admission.
57
+ */
58
+ write(value: T, accepted?: () => void): Promise<void>;
59
+ /**
60
+ * Admit a control event even when the regular buffer is full. Each event still obeys
61
+ * maxFrameBytes and maxBytes; buffered controls have a separate maxControlEvents limit
62
+ * and do not contribute to bufferedBytes.
63
+ * Buffered regular events are delivered before buffered control events. Throws on closure,
64
+ * measurement/size failure or exhausted control capacity; callers still own producer closure.
65
+ */
66
+ pushControl(value: T): void;
67
+ /**
68
+ * Admit a final control under the usual control budget, then close admission. Readers can
69
+ * receive the control before completion. Already-ended queues ignore the value. If admission
70
+ * throws, the producer still owns recovery or closure.
71
+ */
72
+ endWithControl(value: T): void;
73
+ /**
74
+ * Idempotently close admission, wake blocked writers so they can reject, and settle any pending read.
75
+ * Buffered values drain before a truthy cause rejects reads; falsy causes complete reads normally.
76
+ * Closure checks throw a non-nullish stored cause, otherwise STREAM_CLOSED.
77
+ * Reader ownership remains until next observes drained closure or the consumer calls return or
78
+ * throw on the iterator. The caller still owns stopping any native producer.
79
+ */
80
+ end(cause?: unknown): void;
81
+ /**
82
+ * Claim exclusive reader ownership, throwing EVENT_STREAM_ALREADY_OWNED until the prior reader
83
+ * releases it. next drains regular values then controls before terminal completion or rejection.
84
+ * A second next while a read is blocked rejects with CONCURRENT_EVENT_READ. return and throw
85
+ * release ownership and complete a blocked read while leaving the producer open. throw also
86
+ * rejects its own promise with the supplied cause. A pending read settled by end still needs
87
+ * a subsequent next, return or throw to release ownership.
88
+ */
89
+ [Symbol.asyncIterator](): AsyncIterator<T>;
90
+ private readonly entries;
91
+ private bytes;
92
+ private activeReaderToken?;
93
+ private pendingRead?;
94
+ private controls;
95
+ private ended;
96
+ private failure?;
97
+ private waitingWriterResumes;
98
+ /**
99
+ * end, readBuffered and readNext wake blocked writers when they close the queue, free capacity
100
+ * or register a reader for direct delivery. Writers recheck admission on resumption.
101
+ */
102
+ private resumeWaitingWriters;
103
+ /**
104
+ * assertWritable and write share this admission rule. A pending read permits direct delivery even
105
+ * at the buffer budget; checking capacity neither reserves a slot nor wakes a producer.
106
+ */
107
+ private isRegularBufferFull;
108
+ /**
109
+ * push and pushControl try direct delivery after checking size. Report whether this settled
110
+ * a pending read so the caller can skip buffering.
111
+ */
112
+ private deliverToWaitingReader;
113
+ /** Remove the pending read before its caller delivers a value, completes it or rejects it. */
114
+ private takePendingRead;
115
+ /**
116
+ * Producer admission uses this to check for closure. A closed queue throws the stored
117
+ * non-nullish cause or STREAM_CLOSED and keeps the reader attached.
118
+ */
119
+ private assertOpen;
120
+ /**
121
+ * assertWritable, push, write and pushControl call before admission. Measure without reserving
122
+ * capacity; throw FRAME_TOO_LARGE above either single-frame or regular-byte limits, including for
123
+ * controls. Propagate sizeOf failures unchanged so the producer can handle admission failure.
124
+ */
125
+ private checkedSize;
126
+ /**
127
+ * Settle the iterator's next call from buffered data or drained closure. Otherwise register a
128
+ * pending read and wake writers because they can now deliver directly. A detached reader
129
+ * completes immediately, and an overlapping blocked read rejects without replacing the first.
130
+ */
131
+ private readNext;
132
+ /**
133
+ * readNext on drained closure and the iterator's return and throw release ownership here.
134
+ * createSubscription also calls return when cancelled. Only the active reader can have a pending
135
+ * read, so checking its token protects a replacement reader from stale calls.
136
+ */
137
+ private detachReader;
138
+ /**
139
+ * Give readNext regular values before controls and release regular bytes before waking writers.
140
+ * Return undefined only when neither buffer has data, leaving terminal settlement to readNext.
141
+ */
142
+ private readBuffered;
143
+ }