deepline 0.1.291 → 0.1.293
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/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/app-runtime-api.ts +81 -3
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +4 -46
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +0 -14
- package/dist/bundling-sources/shared_libs/play-runtime/gateway-postgres-admission.ts +159 -0
- package/dist/bundling-sources/shared_libs/play-runtime/governor/app-runtime-rate-state-backend.ts +50 -29
- package/dist/bundling-sources/shared_libs/play-runtime/persistence-latch.ts +3 -0
- package/dist/bundling-sources/shared_libs/play-runtime/protocol.ts +6 -14
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +5 -2
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-capacity-policy.ts +76 -11
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-store-adapter.ts +410 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-receipt-writer.ts +494 -0
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-completion-sink.ts +0 -343
- package/dist/bundling-sources/shared_libs/play-runtime/receipt-state-sink.ts +0 -69
- package/dist/bundling-sources/shared_libs/plays/legacy-webhook-drain.ts +0 -110
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
type RetryableReceiptError = {
|
|
2
|
+
retryAfterMs: number;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
type PendingWrite<Input, Output> = {
|
|
6
|
+
input: Input;
|
|
7
|
+
bytes: number;
|
|
8
|
+
signal: AbortSignal | null;
|
|
9
|
+
state: 'blocked' | 'queued' | 'active' | 'settled';
|
|
10
|
+
aborted: unknown;
|
|
11
|
+
onAbort: (() => void) | null;
|
|
12
|
+
resolve: (output: Output) => void;
|
|
13
|
+
reject: (error: unknown) => void;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type RuntimeReceiptWriterStats = {
|
|
17
|
+
active: boolean;
|
|
18
|
+
queued: number;
|
|
19
|
+
blocked: number;
|
|
20
|
+
bufferedBytes: number;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export class RuntimeReceiptWriterBufferLimitError extends Error {
|
|
24
|
+
constructor(
|
|
25
|
+
readonly inputBytes: number,
|
|
26
|
+
readonly maxBufferedBytes: number,
|
|
27
|
+
) {
|
|
28
|
+
super(
|
|
29
|
+
`Runtime receipt input is ${inputBytes} bytes, exceeding the ` +
|
|
30
|
+
`${maxBufferedBytes}-byte writer limit.`,
|
|
31
|
+
);
|
|
32
|
+
this.name = 'RuntimeReceiptWriterBufferLimitError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class RuntimeReceiptWriterResultCountError extends Error {
|
|
37
|
+
constructor(
|
|
38
|
+
readonly inputCount: number,
|
|
39
|
+
readonly outputCount: number,
|
|
40
|
+
) {
|
|
41
|
+
super(
|
|
42
|
+
`Runtime receipt transport returned ${outputCount} results for ` +
|
|
43
|
+
`${inputCount} inputs.`,
|
|
44
|
+
);
|
|
45
|
+
this.name = 'RuntimeReceiptWriterResultCountError';
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export class RuntimeReceiptWriterClosedError extends Error {
|
|
50
|
+
constructor() {
|
|
51
|
+
super('Runtime receipt writer is closed.');
|
|
52
|
+
this.name = 'RuntimeReceiptWriterClosedError';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Private batching implementation used by a Play Durability Store Adapter.
|
|
58
|
+
*
|
|
59
|
+
* The writer deliberately exposes no receipt-domain operations. The Adapter
|
|
60
|
+
* translates claim, settle, read, and heartbeat calls into commands while this
|
|
61
|
+
* Module owns serialization, bounded buffering, and transport redelivery.
|
|
62
|
+
*/
|
|
63
|
+
export class RuntimeReceiptWriter<Input, Output> {
|
|
64
|
+
readonly #batchKey: (input: Input) => unknown;
|
|
65
|
+
readonly #send: (
|
|
66
|
+
inputs: readonly Input[],
|
|
67
|
+
options: { signal: AbortSignal },
|
|
68
|
+
) => Promise<readonly Output[]>;
|
|
69
|
+
readonly #classifyRetryableError: (
|
|
70
|
+
error: unknown,
|
|
71
|
+
) => RetryableReceiptError | null;
|
|
72
|
+
readonly #estimateBytes: (input: Input) => number;
|
|
73
|
+
readonly #maxBatchSize: number;
|
|
74
|
+
readonly #maxBatchBytes: number;
|
|
75
|
+
readonly #maxBufferedBytes: number;
|
|
76
|
+
readonly #maxFlushMs: number;
|
|
77
|
+
readonly #queued: Array<PendingWrite<Input, Output>> = [];
|
|
78
|
+
readonly #blocked: Array<PendingWrite<Input, Output>> = [];
|
|
79
|
+
readonly #closeController = new AbortController();
|
|
80
|
+
|
|
81
|
+
#bufferedBytes = 0;
|
|
82
|
+
#activeBatch: Array<PendingWrite<Input, Output>> | null = null;
|
|
83
|
+
#pump: Promise<void> | null = null;
|
|
84
|
+
#flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
85
|
+
#closed = false;
|
|
86
|
+
#closeReason: unknown = null;
|
|
87
|
+
#drainWaiters: Array<{
|
|
88
|
+
resolve: () => void;
|
|
89
|
+
reject: (error: unknown) => void;
|
|
90
|
+
}> = [];
|
|
91
|
+
|
|
92
|
+
constructor(options: {
|
|
93
|
+
batchKey: (input: Input) => unknown;
|
|
94
|
+
send: (
|
|
95
|
+
inputs: readonly Input[],
|
|
96
|
+
options: { signal: AbortSignal },
|
|
97
|
+
) => Promise<readonly Output[]>;
|
|
98
|
+
classifyRetryableError?: (error: unknown) => RetryableReceiptError | null;
|
|
99
|
+
estimateBytes?: (input: Input) => number;
|
|
100
|
+
maxBatchSize?: number;
|
|
101
|
+
maxBatchBytes?: number;
|
|
102
|
+
maxBufferedBytes?: number;
|
|
103
|
+
maxFlushMs?: number;
|
|
104
|
+
}) {
|
|
105
|
+
this.#batchKey = options.batchKey;
|
|
106
|
+
this.#send = options.send;
|
|
107
|
+
this.#classifyRetryableError =
|
|
108
|
+
options.classifyRetryableError ?? (() => null);
|
|
109
|
+
this.#estimateBytes = options.estimateBytes ?? estimateJsonBytes;
|
|
110
|
+
this.#maxBatchSize = normalizePositiveInteger(options.maxBatchSize, 100);
|
|
111
|
+
this.#maxBufferedBytes = normalizePositiveInteger(
|
|
112
|
+
options.maxBufferedBytes,
|
|
113
|
+
32 * 1024 * 1024,
|
|
114
|
+
);
|
|
115
|
+
this.#maxBatchBytes = Math.min(
|
|
116
|
+
normalizePositiveInteger(options.maxBatchBytes, this.#maxBufferedBytes),
|
|
117
|
+
this.#maxBufferedBytes,
|
|
118
|
+
);
|
|
119
|
+
this.#maxFlushMs = Math.max(0, Math.floor(options.maxFlushMs ?? 5));
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
write(input: Input, options: { signal?: AbortSignal } = {}): Promise<Output> {
|
|
123
|
+
if (this.#closed) {
|
|
124
|
+
return Promise.reject(
|
|
125
|
+
this.#closeReason ?? new RuntimeReceiptWriterClosedError(),
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const bytes = Math.max(0, Math.ceil(this.#estimateBytes(input)));
|
|
130
|
+
if (bytes > this.#maxBufferedBytes || bytes > this.#maxBatchBytes) {
|
|
131
|
+
return Promise.reject(
|
|
132
|
+
new RuntimeReceiptWriterBufferLimitError(
|
|
133
|
+
bytes,
|
|
134
|
+
Math.min(this.#maxBufferedBytes, this.#maxBatchBytes),
|
|
135
|
+
),
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
if (options.signal?.aborted) {
|
|
139
|
+
return Promise.reject(abortReason(options.signal));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return new Promise<Output>((resolve, reject) => {
|
|
143
|
+
const pending: PendingWrite<Input, Output> = {
|
|
144
|
+
input,
|
|
145
|
+
bytes,
|
|
146
|
+
signal: options.signal ?? null,
|
|
147
|
+
state: 'blocked',
|
|
148
|
+
aborted: null,
|
|
149
|
+
onAbort: null,
|
|
150
|
+
resolve,
|
|
151
|
+
reject,
|
|
152
|
+
};
|
|
153
|
+
pending.onAbort = () => this.#abortPending(pending);
|
|
154
|
+
pending.signal?.addEventListener('abort', pending.onAbort, {
|
|
155
|
+
once: true,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
if (this.#canBuffer(bytes)) {
|
|
159
|
+
this.#accept(pending);
|
|
160
|
+
} else {
|
|
161
|
+
this.#blocked.push(pending);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async flush(): Promise<void> {
|
|
167
|
+
this.#clearFlushTimer();
|
|
168
|
+
this.#startPump();
|
|
169
|
+
if (this.#isDrained()) return;
|
|
170
|
+
await new Promise<void>((resolve, reject) => {
|
|
171
|
+
this.#drainWaiters.push({ resolve, reject });
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async close(reason?: unknown): Promise<void> {
|
|
176
|
+
if (!this.#closed) {
|
|
177
|
+
this.#closed = true;
|
|
178
|
+
this.#closeReason =
|
|
179
|
+
reason === undefined ? new RuntimeReceiptWriterClosedError() : reason;
|
|
180
|
+
if (reason !== undefined) {
|
|
181
|
+
this.#closeController.abort(reason);
|
|
182
|
+
this.#rejectWaiting(reason);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (reason === undefined) {
|
|
186
|
+
await this.flush();
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (this.#pump) await this.#pump;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
getStats(): RuntimeReceiptWriterStats {
|
|
193
|
+
return {
|
|
194
|
+
active: this.#activeBatch !== null,
|
|
195
|
+
queued: this.#queued.length,
|
|
196
|
+
blocked: this.#blocked.length,
|
|
197
|
+
bufferedBytes: this.#bufferedBytes,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
#canBuffer(bytes: number): boolean {
|
|
202
|
+
return this.#bufferedBytes + bytes <= this.#maxBufferedBytes;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
#accept(pending: PendingWrite<Input, Output>): void {
|
|
206
|
+
pending.state = 'queued';
|
|
207
|
+
this.#queued.push(pending);
|
|
208
|
+
this.#bufferedBytes += pending.bytes;
|
|
209
|
+
if (
|
|
210
|
+
this.#queued.length >= this.#maxBatchSize ||
|
|
211
|
+
this.#queuedBytesAtHead() >= this.#maxBatchBytes
|
|
212
|
+
) {
|
|
213
|
+
this.#clearFlushTimer();
|
|
214
|
+
this.#startPump();
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
this.#scheduleFlush();
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
#scheduleFlush(): void {
|
|
221
|
+
if (this.#pump || this.#flushTimer || this.#queued.length === 0) return;
|
|
222
|
+
this.#flushTimer = setTimeout(() => {
|
|
223
|
+
this.#flushTimer = null;
|
|
224
|
+
this.#startPump();
|
|
225
|
+
}, this.#maxFlushMs);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
#startPump(): void {
|
|
229
|
+
if (this.#pump || this.#queued.length === 0) {
|
|
230
|
+
this.#notifyDrained();
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
this.#pump = this.#runPump().finally(() => {
|
|
234
|
+
this.#pump = null;
|
|
235
|
+
if (this.#queued.length > 0) this.#startPump();
|
|
236
|
+
else this.#notifyDrained();
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
async #runPump(): Promise<void> {
|
|
241
|
+
while (this.#queued.length > 0) {
|
|
242
|
+
const batch = this.#takeBatch();
|
|
243
|
+
if (batch.length === 0) continue;
|
|
244
|
+
this.#activeBatch = batch;
|
|
245
|
+
try {
|
|
246
|
+
const outputs = await this.#sendWithRetry(batch);
|
|
247
|
+
if (outputs.length !== batch.length) {
|
|
248
|
+
throw new RuntimeReceiptWriterResultCountError(
|
|
249
|
+
batch.length,
|
|
250
|
+
outputs.length,
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
batch.forEach((pending, index) => {
|
|
254
|
+
if (pending.aborted !== null) {
|
|
255
|
+
this.#settleRejected(pending, pending.aborted);
|
|
256
|
+
} else {
|
|
257
|
+
this.#settleResolved(pending, outputs[index]!);
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
} catch (error) {
|
|
261
|
+
batch.forEach((pending) => {
|
|
262
|
+
this.#settleRejected(
|
|
263
|
+
pending,
|
|
264
|
+
pending.aborted !== null ? pending.aborted : error,
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
} finally {
|
|
268
|
+
this.#activeBatch = null;
|
|
269
|
+
for (const pending of batch) {
|
|
270
|
+
this.#bufferedBytes -= pending.bytes;
|
|
271
|
+
}
|
|
272
|
+
this.#admitBlocked();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
#takeBatch(): Array<PendingWrite<Input, Output>> {
|
|
278
|
+
while (this.#queued[0]?.aborted !== null) {
|
|
279
|
+
const aborted = this.#queued.shift()!;
|
|
280
|
+
this.#bufferedBytes -= aborted.bytes;
|
|
281
|
+
this.#settleRejected(aborted, aborted.aborted);
|
|
282
|
+
this.#admitBlocked();
|
|
283
|
+
}
|
|
284
|
+
const first = this.#queued[0];
|
|
285
|
+
if (!first) return [];
|
|
286
|
+
|
|
287
|
+
const key = this.#batchKey(first.input);
|
|
288
|
+
const batch: Array<PendingWrite<Input, Output>> = [];
|
|
289
|
+
let batchBytes = 0;
|
|
290
|
+
while (batch.length < this.#maxBatchSize) {
|
|
291
|
+
const next = this.#queued[0];
|
|
292
|
+
if (!next || !Object.is(this.#batchKey(next.input), key)) break;
|
|
293
|
+
if (batch.length > 0 && batchBytes + next.bytes > this.#maxBatchBytes) {
|
|
294
|
+
break;
|
|
295
|
+
}
|
|
296
|
+
this.#queued.shift();
|
|
297
|
+
next.state = 'active';
|
|
298
|
+
batch.push(next);
|
|
299
|
+
batchBytes += next.bytes;
|
|
300
|
+
}
|
|
301
|
+
return batch;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async #sendWithRetry(
|
|
305
|
+
batch: readonly PendingWrite<Input, Output>[],
|
|
306
|
+
): Promise<readonly Output[]> {
|
|
307
|
+
const inputs = batch.map((pending) => pending.input);
|
|
308
|
+
while (true) {
|
|
309
|
+
if (this.#closeController.signal.aborted) {
|
|
310
|
+
throw this.#closeReason;
|
|
311
|
+
}
|
|
312
|
+
if (batch.every((pending) => pending.aborted !== null)) {
|
|
313
|
+
throw batch[0]?.aborted;
|
|
314
|
+
}
|
|
315
|
+
try {
|
|
316
|
+
return await this.#send(inputs, {
|
|
317
|
+
signal: this.#closeController.signal,
|
|
318
|
+
});
|
|
319
|
+
} catch (error) {
|
|
320
|
+
const retry = this.#classifyRetryableError(error);
|
|
321
|
+
if (!retry) throw error;
|
|
322
|
+
await this.#waitForRetry(
|
|
323
|
+
Math.max(0, Math.floor(retry.retryAfterMs)),
|
|
324
|
+
batch,
|
|
325
|
+
);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async #waitForRetry(
|
|
331
|
+
delayMs: number,
|
|
332
|
+
batch: readonly PendingWrite<Input, Output>[],
|
|
333
|
+
): Promise<void> {
|
|
334
|
+
if (delayMs === 0) {
|
|
335
|
+
await Promise.resolve();
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
await new Promise<void>((resolve, reject) => {
|
|
339
|
+
const signals = batch
|
|
340
|
+
.map((pending) => pending.signal)
|
|
341
|
+
.filter((signal): signal is AbortSignal => signal !== null);
|
|
342
|
+
let settled = false;
|
|
343
|
+
const finish = (error?: unknown): void => {
|
|
344
|
+
if (settled) return;
|
|
345
|
+
settled = true;
|
|
346
|
+
clearTimeout(timer);
|
|
347
|
+
this.#closeController.signal.removeEventListener('abort', onClose);
|
|
348
|
+
for (const signal of signals) {
|
|
349
|
+
signal.removeEventListener('abort', onCommandAbort);
|
|
350
|
+
}
|
|
351
|
+
if (error !== undefined) reject(error);
|
|
352
|
+
else resolve();
|
|
353
|
+
};
|
|
354
|
+
const onClose = (): void => finish(this.#closeReason);
|
|
355
|
+
const onCommandAbort = (): void => {
|
|
356
|
+
if (batch.every((pending) => pending.aborted !== null)) {
|
|
357
|
+
finish(batch[0]?.aborted);
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
const timer = setTimeout(() => finish(), delayMs);
|
|
361
|
+
this.#closeController.signal.addEventListener('abort', onClose, {
|
|
362
|
+
once: true,
|
|
363
|
+
});
|
|
364
|
+
for (const signal of signals) {
|
|
365
|
+
signal.addEventListener('abort', onCommandAbort, { once: true });
|
|
366
|
+
}
|
|
367
|
+
if (this.#closeController.signal.aborted) onClose();
|
|
368
|
+
else onCommandAbort();
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
#abortPending(pending: PendingWrite<Input, Output>): void {
|
|
373
|
+
if (pending.state === 'settled') return;
|
|
374
|
+
pending.aborted = abortReason(pending.signal);
|
|
375
|
+
if (pending.state === 'active') return;
|
|
376
|
+
|
|
377
|
+
const collection =
|
|
378
|
+
pending.state === 'queued' ? this.#queued : this.#blocked;
|
|
379
|
+
const index = collection.indexOf(pending);
|
|
380
|
+
if (index >= 0) collection.splice(index, 1);
|
|
381
|
+
if (pending.state === 'queued') {
|
|
382
|
+
this.#bufferedBytes -= pending.bytes;
|
|
383
|
+
this.#admitBlocked();
|
|
384
|
+
}
|
|
385
|
+
this.#settleRejected(pending, pending.aborted);
|
|
386
|
+
this.#notifyDrained();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
#admitBlocked(): void {
|
|
390
|
+
while (this.#blocked.length > 0) {
|
|
391
|
+
const pending = this.#blocked[0]!;
|
|
392
|
+
if (pending.aborted !== null) {
|
|
393
|
+
this.#blocked.shift();
|
|
394
|
+
this.#settleRejected(pending, pending.aborted);
|
|
395
|
+
continue;
|
|
396
|
+
}
|
|
397
|
+
if (!this.#canBuffer(pending.bytes)) break;
|
|
398
|
+
this.#blocked.shift();
|
|
399
|
+
this.#accept(pending);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
#settleResolved(pending: PendingWrite<Input, Output>, output: Output): void {
|
|
404
|
+
if (pending.state === 'settled') return;
|
|
405
|
+
this.#detachAbort(pending);
|
|
406
|
+
pending.state = 'settled';
|
|
407
|
+
pending.resolve(output);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
#settleRejected(pending: PendingWrite<Input, Output>, error: unknown): void {
|
|
411
|
+
if (pending.state === 'settled') return;
|
|
412
|
+
this.#detachAbort(pending);
|
|
413
|
+
pending.state = 'settled';
|
|
414
|
+
pending.reject(error);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
#detachAbort(pending: PendingWrite<Input, Output>): void {
|
|
418
|
+
if (pending.signal && pending.onAbort) {
|
|
419
|
+
pending.signal.removeEventListener('abort', pending.onAbort);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
#rejectWaiting(reason: unknown): void {
|
|
424
|
+
this.#clearFlushTimer();
|
|
425
|
+
for (const pending of this.#queued.splice(0)) {
|
|
426
|
+
this.#bufferedBytes -= pending.bytes;
|
|
427
|
+
this.#settleRejected(pending, reason);
|
|
428
|
+
}
|
|
429
|
+
for (const pending of this.#blocked.splice(0)) {
|
|
430
|
+
this.#settleRejected(pending, reason);
|
|
431
|
+
}
|
|
432
|
+
this.#notifyDrained(reason);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
#queuedBytesAtHead(): number {
|
|
436
|
+
const first = this.#queued[0];
|
|
437
|
+
if (!first) return 0;
|
|
438
|
+
const key = this.#batchKey(first.input);
|
|
439
|
+
let bytes = 0;
|
|
440
|
+
let count = 0;
|
|
441
|
+
for (const pending of this.#queued) {
|
|
442
|
+
if (
|
|
443
|
+
count >= this.#maxBatchSize ||
|
|
444
|
+
!Object.is(this.#batchKey(pending.input), key)
|
|
445
|
+
) {
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
bytes += pending.bytes;
|
|
449
|
+
count += 1;
|
|
450
|
+
}
|
|
451
|
+
return bytes;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
#isDrained(): boolean {
|
|
455
|
+
return (
|
|
456
|
+
this.#activeBatch === null &&
|
|
457
|
+
this.#queued.length === 0 &&
|
|
458
|
+
this.#blocked.length === 0
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
#notifyDrained(error?: unknown): void {
|
|
463
|
+
if (!this.#isDrained() && error === undefined) return;
|
|
464
|
+
const waiters = this.#drainWaiters.splice(0);
|
|
465
|
+
for (const waiter of waiters) {
|
|
466
|
+
if (error !== undefined) waiter.reject(error);
|
|
467
|
+
else waiter.resolve();
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
#clearFlushTimer(): void {
|
|
472
|
+
if (!this.#flushTimer) return;
|
|
473
|
+
clearTimeout(this.#flushTimer);
|
|
474
|
+
this.#flushTimer = null;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const textEncoder = new TextEncoder();
|
|
479
|
+
|
|
480
|
+
function estimateJsonBytes(input: unknown): number {
|
|
481
|
+
const encoded = JSON.stringify(input);
|
|
482
|
+
return textEncoder.encode(encoded ?? String(input)).byteLength;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function normalizePositiveInteger(
|
|
486
|
+
value: number | undefined,
|
|
487
|
+
fallback: number,
|
|
488
|
+
): number {
|
|
489
|
+
return Math.max(1, Math.floor(value ?? fallback));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
function abortReason(signal: AbortSignal | null): unknown {
|
|
493
|
+
return signal?.reason ?? new Error('Runtime receipt write was aborted.');
|
|
494
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -718,7 +718,7 @@ var SDK_RELEASE = {
|
|
|
718
718
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
719
719
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
720
720
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
721
|
-
version: "0.1.
|
|
721
|
+
version: "0.1.293",
|
|
722
722
|
contracts: {
|
|
723
723
|
api: {
|
|
724
724
|
name: "sdk-http-api",
|
package/dist/cli/index.mjs
CHANGED
|
@@ -703,7 +703,7 @@ var SDK_RELEASE = {
|
|
|
703
703
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
704
704
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
705
705
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
706
|
-
version: "0.1.
|
|
706
|
+
version: "0.1.293",
|
|
707
707
|
contracts: {
|
|
708
708
|
api: {
|
|
709
709
|
name: "sdk-http-api",
|
package/dist/index.js
CHANGED
|
@@ -438,7 +438,7 @@ var SDK_RELEASE = {
|
|
|
438
438
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
439
439
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
440
440
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
441
|
-
version: "0.1.
|
|
441
|
+
version: "0.1.293",
|
|
442
442
|
contracts: {
|
|
443
443
|
api: {
|
|
444
444
|
name: "sdk-http-api",
|
package/dist/index.mjs
CHANGED
|
@@ -367,7 +367,7 @@ var SDK_RELEASE = {
|
|
|
367
367
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
368
368
|
// 0.1.254 removes the internal operations tree from the published SDK CLI.
|
|
369
369
|
// Operators use the checkout-local deepline-admin binary instead.
|
|
370
|
-
version: "0.1.
|
|
370
|
+
version: "0.1.293",
|
|
371
371
|
contracts: {
|
|
372
372
|
api: {
|
|
373
373
|
name: "sdk-http-api",
|