@shogo-ai/core 1.9.13 → 2.4.1
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/chunk-H625AGFN.js +466 -0
- package/dist/chunk-MDRCI2CN.js +197 -0
- package/dist/chunk-NTAY4E43.js +72 -0
- package/dist/{chunk-24AL3V6R.js → chunk-VW6ZGCBI.js} +35 -1
- package/dist/{chunk-IDGVRGAL.js → chunk-WRHTXHTH.js} +81 -11
- package/dist/file-types.cjs +79 -5
- package/dist/file-types.d.cts +23 -4
- package/dist/file-types.d.ts +23 -4
- package/dist/file-types.js +7 -1
- package/dist/index.cjs +464 -17
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +35 -7
- package/dist/instrumentation.cjs +95 -10
- package/dist/instrumentation.js +2 -1
- package/dist/logger.cjs +39 -2
- package/dist/logger.d.cts +71 -1
- package/dist/logger.d.ts +71 -1
- package/dist/logger.js +9 -3
- package/dist/stream-buffer.cjs +242 -5
- package/dist/stream-buffer.d.cts +97 -1
- package/dist/stream-buffer.d.ts +97 -1
- package/dist/stream-buffer.js +13 -3
- package/dist/tech-stack-registry.cjs +36 -0
- package/dist/tech-stack-registry.d.cts +48 -1
- package/dist/tech-stack-registry.d.ts +48 -1
- package/dist/tech-stack-registry.js +7 -1
- package/package.json +16 -1
- package/dist/chunk-ELMG6OXT.js +0 -236
- package/dist/chunk-HKX3MEJN.js +0 -126
- package/dist/chunk-KTDDFWXM.js +0 -39
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
// src/stream-compaction.ts
|
|
2
|
+
var TURN_SEQ_EVENT_TYPE = "data-turn-seq";
|
|
3
|
+
var DELTA_PART = {
|
|
4
|
+
"text-delta": "text",
|
|
5
|
+
"reasoning-delta": "reasoning"
|
|
6
|
+
};
|
|
7
|
+
var PART_BOUNDARY = {
|
|
8
|
+
"text-end": "text",
|
|
9
|
+
"reasoning-end": "reasoning",
|
|
10
|
+
"text-start": "text",
|
|
11
|
+
"reasoning-start": "reasoning"
|
|
12
|
+
};
|
|
13
|
+
function compactSseFrames(frames) {
|
|
14
|
+
if (frames.length === 0) return new Uint8Array(0);
|
|
15
|
+
const decoder = new TextDecoder();
|
|
16
|
+
let text = "";
|
|
17
|
+
for (const frame of frames) text += decoder.decode(frame, { stream: true });
|
|
18
|
+
text += decoder.decode();
|
|
19
|
+
const events = text.split("\n\n");
|
|
20
|
+
const tail = events.pop() ?? "";
|
|
21
|
+
const out = [];
|
|
22
|
+
const openParts = /* @__PURE__ */ new Map();
|
|
23
|
+
const openToolInputs = /* @__PURE__ */ new Map();
|
|
24
|
+
const preliminaryOutputs = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const event of events) {
|
|
26
|
+
const chunk = parseEvent(event);
|
|
27
|
+
if (!chunk) {
|
|
28
|
+
out.push({ raw: event });
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const type = chunk.type;
|
|
32
|
+
if (type === TURN_SEQ_EVENT_TYPE) continue;
|
|
33
|
+
if (type in PART_BOUNDARY) {
|
|
34
|
+
openParts.delete(`${PART_BOUNDARY[type]}:${chunk.id}`);
|
|
35
|
+
out.push({ chunk });
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (type in DELTA_PART && typeof chunk.delta === "string") {
|
|
39
|
+
const key = `${DELTA_PART[type]}:${chunk.id}`;
|
|
40
|
+
const merged = openParts.get(key);
|
|
41
|
+
if (merged) {
|
|
42
|
+
merged.delta += chunk.delta;
|
|
43
|
+
if (chunk.providerMetadata !== void 0) merged.providerMetadata = chunk.providerMetadata;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const copy = { ...chunk };
|
|
47
|
+
openParts.set(key, copy);
|
|
48
|
+
out.push({ chunk: copy });
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (type === "tool-input-delta" && typeof chunk.inputTextDelta === "string") {
|
|
52
|
+
const index = openToolInputs.get(chunk.toolCallId);
|
|
53
|
+
const existing = index !== void 0 ? out[index] : null;
|
|
54
|
+
if (existing && "chunk" in existing) {
|
|
55
|
+
existing.chunk.inputTextDelta += chunk.inputTextDelta;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
openToolInputs.set(chunk.toolCallId, out.length);
|
|
59
|
+
out.push({ chunk: { ...chunk } });
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (type === "tool-input-available" || type === "tool-input-error") {
|
|
63
|
+
const index = openToolInputs.get(chunk.toolCallId);
|
|
64
|
+
if (index !== void 0) out[index] = null;
|
|
65
|
+
openToolInputs.delete(chunk.toolCallId);
|
|
66
|
+
} else if (type === "tool-input-start") {
|
|
67
|
+
openToolInputs.delete(chunk.toolCallId);
|
|
68
|
+
} else if (type === "tool-output-available" || type === "tool-output-error") {
|
|
69
|
+
const superseded = preliminaryOutputs.get(chunk.toolCallId);
|
|
70
|
+
if (superseded !== void 0) {
|
|
71
|
+
out[superseded] = null;
|
|
72
|
+
preliminaryOutputs.delete(chunk.toolCallId);
|
|
73
|
+
}
|
|
74
|
+
if (type === "tool-output-available" && chunk.preliminary === true) {
|
|
75
|
+
preliminaryOutputs.set(chunk.toolCallId, out.length);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
out.push({ chunk });
|
|
79
|
+
}
|
|
80
|
+
let result = "";
|
|
81
|
+
for (const entry of out) {
|
|
82
|
+
if (!entry) continue;
|
|
83
|
+
result += "chunk" in entry ? encodeEvent(entry.chunk) : `${entry.raw}
|
|
84
|
+
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
result += tail;
|
|
88
|
+
return new TextEncoder().encode(result);
|
|
89
|
+
}
|
|
90
|
+
function encodeTurnSeqFrame(turnId, seq) {
|
|
91
|
+
return new TextEncoder().encode(
|
|
92
|
+
encodeEvent({ type: TURN_SEQ_EVENT_TYPE, data: { turnId, seq }, transient: true })
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
function encodeEvent(chunk) {
|
|
96
|
+
return `data: ${JSON.stringify(chunk)}
|
|
97
|
+
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
function parseEvent(event) {
|
|
101
|
+
if (!event.startsWith("data: ") || event.includes("\n")) return null;
|
|
102
|
+
const payload = event.slice(6);
|
|
103
|
+
if (!payload.startsWith("{")) return null;
|
|
104
|
+
try {
|
|
105
|
+
const chunk = JSON.parse(payload);
|
|
106
|
+
return chunk && typeof chunk.type === "string" ? chunk : null;
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// src/stream-buffer.ts
|
|
113
|
+
var CLEANUP_INTERVAL_MS = 6e4;
|
|
114
|
+
var MAX_BUFFER_AGE_MS = 30 * 6e4;
|
|
115
|
+
var COMPLETED_GRACE_MS = 3e4;
|
|
116
|
+
var TURN_REPLY_TTL_MS = 60 * 6e4;
|
|
117
|
+
var StreamBufferStore = class {
|
|
118
|
+
constructor() {
|
|
119
|
+
this.buffers = /* @__PURE__ */ new Map();
|
|
120
|
+
this.replies = /* @__PURE__ */ new Map();
|
|
121
|
+
this.cleanupTimer = null;
|
|
122
|
+
this.cleanupTimer = setInterval(() => this.cleanup(), CLEANUP_INTERVAL_MS);
|
|
123
|
+
const handle = this.cleanupTimer;
|
|
124
|
+
if (handle && typeof handle.unref === "function") {
|
|
125
|
+
handle.unref();
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Create (or replace) a buffer for the given key. Any existing active
|
|
130
|
+
* buffer is completed and discarded. Returns a writer bound to this
|
|
131
|
+
* specific buffer instance, including the new `turnId`.
|
|
132
|
+
*/
|
|
133
|
+
create(key, opts) {
|
|
134
|
+
const existing = this.buffers.get(key);
|
|
135
|
+
if (existing && existing.status === "active") {
|
|
136
|
+
this.completeBuffer(existing, "replaced");
|
|
137
|
+
}
|
|
138
|
+
const now = Date.now();
|
|
139
|
+
const turnId = opts?.turnId || generateTurnId();
|
|
140
|
+
const buf = {
|
|
141
|
+
turnId,
|
|
142
|
+
frames: [],
|
|
143
|
+
subscribers: /* @__PURE__ */ new Set(),
|
|
144
|
+
status: "active",
|
|
145
|
+
terminal: null,
|
|
146
|
+
createdAt: now,
|
|
147
|
+
completedAt: null,
|
|
148
|
+
lastEventAt: now,
|
|
149
|
+
nextSeq: 1
|
|
150
|
+
};
|
|
151
|
+
this.buffers.set(key, buf);
|
|
152
|
+
return {
|
|
153
|
+
get turnId() {
|
|
154
|
+
return buf.turnId;
|
|
155
|
+
},
|
|
156
|
+
get lastSeq() {
|
|
157
|
+
return buf.nextSeq - 1;
|
|
158
|
+
},
|
|
159
|
+
append: (chunk) => {
|
|
160
|
+
if (buf.status !== "active") return -1;
|
|
161
|
+
const seq = buf.nextSeq++;
|
|
162
|
+
buf.frames.push({ seq, chunk });
|
|
163
|
+
buf.lastEventAt = Date.now();
|
|
164
|
+
for (const ctrl of buf.subscribers) {
|
|
165
|
+
try {
|
|
166
|
+
ctrl.enqueue(chunk);
|
|
167
|
+
} catch {
|
|
168
|
+
buf.subscribers.delete(ctrl);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return seq;
|
|
172
|
+
},
|
|
173
|
+
complete: (reason) => {
|
|
174
|
+
this.completeBuffer(buf, reason);
|
|
175
|
+
},
|
|
176
|
+
fail: (error) => {
|
|
177
|
+
this.failBuffer(buf, error);
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Append a chunk by key (loose, untyped writer). Returns the seq assigned,
|
|
183
|
+
* or -1 if the buffer is unknown/inactive.
|
|
184
|
+
*/
|
|
185
|
+
append(key, chunk) {
|
|
186
|
+
const buf = this.buffers.get(key);
|
|
187
|
+
if (!buf || buf.status !== "active") return -1;
|
|
188
|
+
const seq = buf.nextSeq++;
|
|
189
|
+
buf.frames.push({ seq, chunk });
|
|
190
|
+
buf.lastEventAt = Date.now();
|
|
191
|
+
for (const ctrl of buf.subscribers) {
|
|
192
|
+
try {
|
|
193
|
+
ctrl.enqueue(chunk);
|
|
194
|
+
} catch {
|
|
195
|
+
buf.subscribers.delete(ctrl);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return seq;
|
|
199
|
+
}
|
|
200
|
+
/** Mark a buffer as completed by key. Optional terminal reason. */
|
|
201
|
+
complete(key, reason) {
|
|
202
|
+
const buf = this.buffers.get(key);
|
|
203
|
+
if (!buf) return;
|
|
204
|
+
this.completeBuffer(buf, reason);
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Abort a stream: complete subscribers and remove the buffer entirely.
|
|
208
|
+
* Future resume/replay requests for this key will return null (→ 204).
|
|
209
|
+
*/
|
|
210
|
+
abort(key) {
|
|
211
|
+
const buf = this.buffers.get(key);
|
|
212
|
+
if (!buf) return;
|
|
213
|
+
this.completeBuffer(buf, "aborted");
|
|
214
|
+
buf.status = "aborted";
|
|
215
|
+
this.buffers.delete(key);
|
|
216
|
+
}
|
|
217
|
+
has(key) {
|
|
218
|
+
return this.buffers.has(key);
|
|
219
|
+
}
|
|
220
|
+
/** Read-only metadata about a buffered turn. Useful for resume responses. */
|
|
221
|
+
snapshot(key) {
|
|
222
|
+
const buf = this.buffers.get(key);
|
|
223
|
+
if (!buf) return null;
|
|
224
|
+
return {
|
|
225
|
+
turnId: buf.turnId,
|
|
226
|
+
status: buf.status,
|
|
227
|
+
lastSeq: buf.nextSeq - 1,
|
|
228
|
+
terminal: buf.terminal,
|
|
229
|
+
createdAt: buf.createdAt,
|
|
230
|
+
completedAt: buf.completedAt,
|
|
231
|
+
lastEventAt: buf.lastEventAt
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Keep the reply a turn finished with, so it can still be read after the
|
|
236
|
+
* buffer is evicted (30 s grace) — e.g. by the API's call follower, or by a
|
|
237
|
+
* reconciliation pass long after the stream is gone. Keyed by the same
|
|
238
|
+
* session key as the buffer.
|
|
239
|
+
*/
|
|
240
|
+
recordTurnReply(key, reply) {
|
|
241
|
+
const trimmed = reply?.trim();
|
|
242
|
+
if (!trimmed) return;
|
|
243
|
+
const now = Date.now();
|
|
244
|
+
this.pruneReplies(now);
|
|
245
|
+
this.replies.set(key, {
|
|
246
|
+
turnId: this.buffers.get(key)?.turnId ?? "",
|
|
247
|
+
reply,
|
|
248
|
+
completedAt: now
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* The terminal reply for a session, or null when none was recorded or it
|
|
253
|
+
* expired. A reply belonging to an older turn of a session that has since
|
|
254
|
+
* started a new one is never returned.
|
|
255
|
+
*/
|
|
256
|
+
turnReply(key) {
|
|
257
|
+
const entry = this.replies.get(key);
|
|
258
|
+
if (!entry) return null;
|
|
259
|
+
if (Date.now() - entry.completedAt > TURN_REPLY_TTL_MS) {
|
|
260
|
+
this.replies.delete(key);
|
|
261
|
+
return null;
|
|
262
|
+
}
|
|
263
|
+
const current = this.buffers.get(key);
|
|
264
|
+
if (current && entry.turnId && current.turnId !== entry.turnId) return null;
|
|
265
|
+
return entry;
|
|
266
|
+
}
|
|
267
|
+
pruneReplies(now) {
|
|
268
|
+
for (const [key, entry] of this.replies) {
|
|
269
|
+
if (now - entry.completedAt > TURN_REPLY_TTL_MS) this.replies.delete(key);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Create a ReadableStream that first replays all buffered chunks past
|
|
274
|
+
* `opts.fromSeq` (default: 0 → replay everything), then subscribes for
|
|
275
|
+
* any further live chunks until the stream completes.
|
|
276
|
+
*
|
|
277
|
+
* Returns null if no buffer exists for the key.
|
|
278
|
+
*/
|
|
279
|
+
createReplayStream(key, opts = {}) {
|
|
280
|
+
const buf = this.buffers.get(key);
|
|
281
|
+
if (!buf) return null;
|
|
282
|
+
const fromSeq = Math.max(0, opts.fromSeq ?? 0);
|
|
283
|
+
let subscribedController = null;
|
|
284
|
+
if (opts.buildReplay) return this.createBuiltReplayStream(buf, fromSeq, opts.buildReplay);
|
|
285
|
+
return new ReadableStream({
|
|
286
|
+
start(controller) {
|
|
287
|
+
if (opts.compact) {
|
|
288
|
+
const pending = buf.frames.filter((frame) => frame.seq > fromSeq);
|
|
289
|
+
const compacted = compactSseFrames(pending.map((frame) => frame.chunk));
|
|
290
|
+
try {
|
|
291
|
+
if (compacted.byteLength > 0) controller.enqueue(compacted);
|
|
292
|
+
if (pending.length > 0 && buf.status === "active") {
|
|
293
|
+
controller.enqueue(encodeTurnSeqFrame(buf.turnId, buf.nextSeq - 1));
|
|
294
|
+
}
|
|
295
|
+
} catch {
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
} else {
|
|
299
|
+
for (const frame of buf.frames) {
|
|
300
|
+
if (frame.seq <= fromSeq) continue;
|
|
301
|
+
try {
|
|
302
|
+
controller.enqueue(frame.chunk);
|
|
303
|
+
} catch {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
if (buf.status !== "active") {
|
|
309
|
+
try {
|
|
310
|
+
controller.close();
|
|
311
|
+
} catch {
|
|
312
|
+
}
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
subscribedController = controller;
|
|
316
|
+
buf.subscribers.add(controller);
|
|
317
|
+
},
|
|
318
|
+
cancel() {
|
|
319
|
+
if (subscribedController) {
|
|
320
|
+
buf.subscribers.delete(subscribedController);
|
|
321
|
+
subscribedController = null;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
createBuiltReplayStream(buf, fromSeq, buildReplay) {
|
|
327
|
+
const pending = buf.frames.filter((frame) => frame.seq > fromSeq).map((frame) => frame.chunk);
|
|
328
|
+
const ctx = { turnId: buf.turnId, lastSeq: buf.nextSeq - 1 };
|
|
329
|
+
const held = [];
|
|
330
|
+
let ended = false;
|
|
331
|
+
let target = null;
|
|
332
|
+
const proxy = {
|
|
333
|
+
enqueue(chunk) {
|
|
334
|
+
if (target) target.enqueue(chunk);
|
|
335
|
+
else held.push(chunk);
|
|
336
|
+
},
|
|
337
|
+
close() {
|
|
338
|
+
if (target) target.close();
|
|
339
|
+
else ended = true;
|
|
340
|
+
},
|
|
341
|
+
error(reason) {
|
|
342
|
+
if (target) target.error(reason);
|
|
343
|
+
else ended = true;
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
const active = buf.status === "active";
|
|
347
|
+
if (active) buf.subscribers.add(proxy);
|
|
348
|
+
return new ReadableStream({
|
|
349
|
+
async start(controller) {
|
|
350
|
+
let replay;
|
|
351
|
+
try {
|
|
352
|
+
replay = await buildReplay(pending, ctx);
|
|
353
|
+
} catch {
|
|
354
|
+
replay = compactSseFrames(pending);
|
|
355
|
+
}
|
|
356
|
+
try {
|
|
357
|
+
if (replay.byteLength > 0) controller.enqueue(replay);
|
|
358
|
+
if (pending.length > 0 && active) controller.enqueue(encodeTurnSeqFrame(ctx.turnId, ctx.lastSeq));
|
|
359
|
+
for (const chunk of held) controller.enqueue(chunk);
|
|
360
|
+
held.length = 0;
|
|
361
|
+
if (!active || ended || buf.status !== "active") {
|
|
362
|
+
controller.close();
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
target = controller;
|
|
366
|
+
} catch {
|
|
367
|
+
buf.subscribers.delete(proxy);
|
|
368
|
+
}
|
|
369
|
+
},
|
|
370
|
+
cancel() {
|
|
371
|
+
buf.subscribers.delete(proxy);
|
|
372
|
+
target = null;
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
cleanup() {
|
|
377
|
+
const now = Date.now();
|
|
378
|
+
this.pruneReplies(now);
|
|
379
|
+
for (const [key, buf] of this.buffers) {
|
|
380
|
+
if (buf.status !== "active" && buf.completedAt && now - buf.completedAt > COMPLETED_GRACE_MS) {
|
|
381
|
+
this.buffers.delete(key);
|
|
382
|
+
} else if (now - buf.createdAt > MAX_BUFFER_AGE_MS && buf.subscribers.size === 0) {
|
|
383
|
+
this.completeBuffer(buf, "expired");
|
|
384
|
+
this.buffers.delete(key);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
dispose() {
|
|
389
|
+
if (this.cleanupTimer) {
|
|
390
|
+
clearInterval(this.cleanupTimer);
|
|
391
|
+
this.cleanupTimer = null;
|
|
392
|
+
}
|
|
393
|
+
for (const buf of this.buffers.values()) {
|
|
394
|
+
this.completeBuffer(buf, "disposed");
|
|
395
|
+
}
|
|
396
|
+
this.buffers.clear();
|
|
397
|
+
this.replies.clear();
|
|
398
|
+
}
|
|
399
|
+
completeBuffer(buf, reason) {
|
|
400
|
+
if (buf.status !== "active") return;
|
|
401
|
+
buf.status = "completed";
|
|
402
|
+
buf.terminal = { reason };
|
|
403
|
+
buf.completedAt = Date.now();
|
|
404
|
+
buf.lastEventAt = buf.completedAt;
|
|
405
|
+
for (const ctrl of buf.subscribers) {
|
|
406
|
+
try {
|
|
407
|
+
ctrl.close();
|
|
408
|
+
} catch {
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
buf.subscribers.clear();
|
|
412
|
+
}
|
|
413
|
+
failBuffer(buf, error) {
|
|
414
|
+
if (buf.status !== "active") return;
|
|
415
|
+
buf.status = "failed";
|
|
416
|
+
buf.terminal = { error };
|
|
417
|
+
buf.completedAt = Date.now();
|
|
418
|
+
buf.lastEventAt = buf.completedAt;
|
|
419
|
+
for (const ctrl of buf.subscribers) {
|
|
420
|
+
try {
|
|
421
|
+
ctrl.close();
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
buf.subscribers.clear();
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
var TURN_COMPLETE_EVENT_TYPE = "data-turn-complete";
|
|
429
|
+
function encodeTurnCompleteFrame(data) {
|
|
430
|
+
return new TextEncoder().encode(
|
|
431
|
+
`data: ${JSON.stringify({ type: TURN_COMPLETE_EVENT_TYPE, data })}
|
|
432
|
+
|
|
433
|
+
`
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
function generateTurnId() {
|
|
437
|
+
try {
|
|
438
|
+
if (typeof globalThis.crypto?.randomUUID === "function") {
|
|
439
|
+
return globalThis.crypto.randomUUID();
|
|
440
|
+
}
|
|
441
|
+
} catch {
|
|
442
|
+
}
|
|
443
|
+
return `turn_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 10)}`;
|
|
444
|
+
}
|
|
445
|
+
function createBufferingTransform(store, key) {
|
|
446
|
+
return new TransformStream({
|
|
447
|
+
transform(chunk, controller) {
|
|
448
|
+
store.append(key, chunk);
|
|
449
|
+
controller.enqueue(chunk);
|
|
450
|
+
},
|
|
451
|
+
flush() {
|
|
452
|
+
store.complete(key);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export {
|
|
458
|
+
TURN_SEQ_EVENT_TYPE,
|
|
459
|
+
compactSseFrames,
|
|
460
|
+
encodeTurnSeqFrame,
|
|
461
|
+
StreamBufferStore,
|
|
462
|
+
TURN_COMPLETE_EVENT_TYPE,
|
|
463
|
+
encodeTurnCompleteFrame,
|
|
464
|
+
createBufferingTransform
|
|
465
|
+
};
|
|
466
|
+
//# sourceMappingURL=chunk-H625AGFN.js.map
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// src/file-types.ts
|
|
2
|
+
var BINARY_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
3
|
+
// Images
|
|
4
|
+
"png",
|
|
5
|
+
"jpg",
|
|
6
|
+
"jpeg",
|
|
7
|
+
"gif",
|
|
8
|
+
"webp",
|
|
9
|
+
"bmp",
|
|
10
|
+
"ico",
|
|
11
|
+
"avif",
|
|
12
|
+
"apng",
|
|
13
|
+
"heic",
|
|
14
|
+
"heif",
|
|
15
|
+
"tiff",
|
|
16
|
+
"tif",
|
|
17
|
+
"jxl",
|
|
18
|
+
"cur",
|
|
19
|
+
// Archives
|
|
20
|
+
"zip",
|
|
21
|
+
"gz",
|
|
22
|
+
"tar",
|
|
23
|
+
"tgz",
|
|
24
|
+
"bz2",
|
|
25
|
+
"xz",
|
|
26
|
+
"7z",
|
|
27
|
+
"rar",
|
|
28
|
+
"zst",
|
|
29
|
+
"lz4",
|
|
30
|
+
// Audio / video / docs
|
|
31
|
+
"mp3",
|
|
32
|
+
"mp4",
|
|
33
|
+
"m4a",
|
|
34
|
+
"m4v",
|
|
35
|
+
"mov",
|
|
36
|
+
"avi",
|
|
37
|
+
"mkv",
|
|
38
|
+
"webm",
|
|
39
|
+
"wav",
|
|
40
|
+
"flac",
|
|
41
|
+
"ogg",
|
|
42
|
+
"oga",
|
|
43
|
+
"ogv",
|
|
44
|
+
"aac",
|
|
45
|
+
"opus",
|
|
46
|
+
"pdf",
|
|
47
|
+
// Office / document containers
|
|
48
|
+
"xls",
|
|
49
|
+
"xlsx",
|
|
50
|
+
"xlsm",
|
|
51
|
+
"xlsb",
|
|
52
|
+
"doc",
|
|
53
|
+
"docx",
|
|
54
|
+
"docm",
|
|
55
|
+
"ppt",
|
|
56
|
+
"pptx",
|
|
57
|
+
"pptm",
|
|
58
|
+
"odt",
|
|
59
|
+
"ods",
|
|
60
|
+
"odp",
|
|
61
|
+
"pages",
|
|
62
|
+
"numbers",
|
|
63
|
+
"key",
|
|
64
|
+
"epub",
|
|
65
|
+
// Fonts
|
|
66
|
+
"woff",
|
|
67
|
+
"woff2",
|
|
68
|
+
"ttf",
|
|
69
|
+
"otf",
|
|
70
|
+
"eot",
|
|
71
|
+
// Native / packed
|
|
72
|
+
"exe",
|
|
73
|
+
"dll",
|
|
74
|
+
"so",
|
|
75
|
+
"dylib",
|
|
76
|
+
"bin",
|
|
77
|
+
"class",
|
|
78
|
+
"jar",
|
|
79
|
+
"wasm",
|
|
80
|
+
// Databases
|
|
81
|
+
"db",
|
|
82
|
+
"sqlite",
|
|
83
|
+
"sqlite3",
|
|
84
|
+
"mdb",
|
|
85
|
+
"lmdb",
|
|
86
|
+
// Misc binary
|
|
87
|
+
"pack",
|
|
88
|
+
"idx",
|
|
89
|
+
"psd",
|
|
90
|
+
"ai",
|
|
91
|
+
"sketch",
|
|
92
|
+
"fig",
|
|
93
|
+
"blend",
|
|
94
|
+
"obj",
|
|
95
|
+
"fbx",
|
|
96
|
+
"pyc",
|
|
97
|
+
"pyo",
|
|
98
|
+
"pyd",
|
|
99
|
+
// 3D / scene / point cloud (binary variants — `.usda` and `.gltf` are
|
|
100
|
+
// text and intentionally NOT listed; users can still edit those)
|
|
101
|
+
"usd",
|
|
102
|
+
"usdc",
|
|
103
|
+
"usdz",
|
|
104
|
+
"glb",
|
|
105
|
+
"stl",
|
|
106
|
+
"ply",
|
|
107
|
+
// Robotics logs
|
|
108
|
+
"bag",
|
|
109
|
+
"mcap",
|
|
110
|
+
// ML weights / saved models / serialized arrays
|
|
111
|
+
"pt",
|
|
112
|
+
"pth",
|
|
113
|
+
"ckpt",
|
|
114
|
+
"safetensors",
|
|
115
|
+
"onnx",
|
|
116
|
+
"pb",
|
|
117
|
+
"tflite",
|
|
118
|
+
"mlmodel",
|
|
119
|
+
"npy",
|
|
120
|
+
"npz",
|
|
121
|
+
"joblib",
|
|
122
|
+
"pkl",
|
|
123
|
+
// Tabular / scientific containers
|
|
124
|
+
"parquet",
|
|
125
|
+
"arrow",
|
|
126
|
+
"feather",
|
|
127
|
+
"h5",
|
|
128
|
+
"hdf5",
|
|
129
|
+
"nc",
|
|
130
|
+
"tfrecord"
|
|
131
|
+
]);
|
|
132
|
+
var BINARY_FILE_TRANSIENT_SUFFIXES = /* @__PURE__ */ new Set([
|
|
133
|
+
"part",
|
|
134
|
+
"partial",
|
|
135
|
+
"crdownload",
|
|
136
|
+
"download"
|
|
137
|
+
]);
|
|
138
|
+
var BINARY_FILE_BASENAMES = /* @__PURE__ */ new Set([
|
|
139
|
+
"aapt",
|
|
140
|
+
"aapt2",
|
|
141
|
+
"adb",
|
|
142
|
+
"apksigner",
|
|
143
|
+
"bcc_compat",
|
|
144
|
+
"dexdump",
|
|
145
|
+
"dmtracedump",
|
|
146
|
+
"etc1tool",
|
|
147
|
+
"fastboot",
|
|
148
|
+
"hprof-conv",
|
|
149
|
+
"llvm-rs-cc",
|
|
150
|
+
"mksdcard",
|
|
151
|
+
"qemu-aarch64-static",
|
|
152
|
+
"qemu-arm-static",
|
|
153
|
+
"qemu-i386-static",
|
|
154
|
+
"qemu-x86_64-static",
|
|
155
|
+
"split-select",
|
|
156
|
+
"sqlite3",
|
|
157
|
+
"zipalign"
|
|
158
|
+
]);
|
|
159
|
+
function basenameOf(path) {
|
|
160
|
+
const slash = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
|
|
161
|
+
return path.slice(slash + 1);
|
|
162
|
+
}
|
|
163
|
+
function extensionOfBasename(basename) {
|
|
164
|
+
const dot = basename.lastIndexOf(".");
|
|
165
|
+
if (dot <= 0 || dot === basename.length - 1) return null;
|
|
166
|
+
return basename.slice(dot + 1).toLowerCase();
|
|
167
|
+
}
|
|
168
|
+
function isBinaryFilePath(path) {
|
|
169
|
+
let basename = basenameOf(path).toLowerCase();
|
|
170
|
+
if (BINARY_FILE_BASENAMES.has(basename)) return true;
|
|
171
|
+
for (let i = 0; i < 2; i++) {
|
|
172
|
+
const ext = extensionOfBasename(basename);
|
|
173
|
+
if (!ext) return false;
|
|
174
|
+
if (BINARY_FILE_EXTENSIONS.has(ext)) return true;
|
|
175
|
+
if (!BINARY_FILE_TRANSIENT_SUFFIXES.has(ext)) return false;
|
|
176
|
+
basename = basename.slice(0, -(ext.length + 1));
|
|
177
|
+
}
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
function isBinaryBuffer(bytes, inspectBytes = 8192) {
|
|
181
|
+
const head = bytes.subarray(0, Math.min(bytes.length, inspectBytes));
|
|
182
|
+
if (head.includes(0)) return true;
|
|
183
|
+
const startsWith = (...signature) => signature.every((value, index) => head[index] === value);
|
|
184
|
+
const ascii = (value) => Array.from(value).every(
|
|
185
|
+
(char, index) => head[index] === char.charCodeAt(0)
|
|
186
|
+
);
|
|
187
|
+
return startsWith(80, 75, 3, 4) || startsWith(80, 75, 5, 6) || startsWith(208, 207, 17, 224, 161, 177, 26, 225) || ascii("%PDF-") || startsWith(137, 80, 78, 71, 13, 10, 26, 10) || startsWith(255, 216, 255) || startsWith(71, 73, 70, 56) || startsWith(82, 73, 70, 70);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export {
|
|
191
|
+
BINARY_FILE_EXTENSIONS,
|
|
192
|
+
BINARY_FILE_TRANSIENT_SUFFIXES,
|
|
193
|
+
BINARY_FILE_BASENAMES,
|
|
194
|
+
isBinaryFilePath,
|
|
195
|
+
isBinaryBuffer
|
|
196
|
+
};
|
|
197
|
+
//# sourceMappingURL=chunk-MDRCI2CN.js.map
|