@tashiscool/stream 0.1.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/README.md +145 -0
- package/dist/aggregator.d.ts +95 -0
- package/dist/aggregator.d.ts.map +1 -0
- package/dist/aggregator.js +127 -0
- package/dist/aggregator.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptor.d.ts +40 -0
- package/dist/interceptor.d.ts.map +1 -0
- package/dist/interceptor.js +94 -0
- package/dist/interceptor.js.map +1 -0
- package/dist/jsonl.d.ts +59 -0
- package/dist/jsonl.d.ts.map +1 -0
- package/dist/jsonl.js +104 -0
- package/dist/jsonl.js.map +1 -0
- package/dist/mux.d.ts +114 -0
- package/dist/mux.d.ts.map +1 -0
- package/dist/mux.js +310 -0
- package/dist/mux.js.map +1 -0
- package/dist/response.d.ts +101 -0
- package/dist/response.d.ts.map +1 -0
- package/dist/response.js +309 -0
- package/dist/response.js.map +1 -0
- package/package.json +51 -0
package/dist/jsonl.js
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL Streaming
|
|
3
|
+
* Parse and serialize JSONL (JSON Lines) streams
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Streams objects as JSONL (JSON Lines) to an HTTP response.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* app.get('/events', (req, res) => {
|
|
11
|
+
* streamJsonLines(res, async function* () {
|
|
12
|
+
* for (const event of events) {
|
|
13
|
+
* yield event;
|
|
14
|
+
* }
|
|
15
|
+
* });
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export function streamJsonLines(res, generator) {
|
|
20
|
+
res.setHeader('Content-Type', 'application/x-ndjson');
|
|
21
|
+
res.setHeader('Transfer-Encoding', 'chunked');
|
|
22
|
+
res.setHeader('Cache-Control', 'no-cache');
|
|
23
|
+
res.setHeader('Connection', 'keep-alive');
|
|
24
|
+
(async () => {
|
|
25
|
+
try {
|
|
26
|
+
for await (const item of generator()) {
|
|
27
|
+
const line = JSON.stringify(item) + '\n';
|
|
28
|
+
res.write(line);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
res.end();
|
|
33
|
+
}
|
|
34
|
+
})();
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Parses a JSONL stream from a fetch Response.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const response = await fetch('/events');
|
|
42
|
+
* for await (const event of parseJsonLines(response)) {
|
|
43
|
+
* handleEvent(event);
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export async function* parseJsonLines(response) {
|
|
48
|
+
if (!response.body) {
|
|
49
|
+
throw new Error('Response body is null');
|
|
50
|
+
}
|
|
51
|
+
const reader = response.body.getReader();
|
|
52
|
+
const decoder = new TextDecoder('utf-8');
|
|
53
|
+
let buffer = '';
|
|
54
|
+
try {
|
|
55
|
+
while (true) {
|
|
56
|
+
const { done, value } = await reader.read();
|
|
57
|
+
if (done) {
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
buffer += decoder.decode(value, { stream: true });
|
|
61
|
+
// Split by newlines and process complete lines
|
|
62
|
+
const lines = buffer.split('\n');
|
|
63
|
+
buffer = lines.pop() || ''; // Keep incomplete line in buffer
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
const trimmed = line.trim();
|
|
66
|
+
if (trimmed) {
|
|
67
|
+
try {
|
|
68
|
+
yield JSON.parse(trimmed);
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
// Skip invalid JSON lines
|
|
72
|
+
console.warn('Invalid JSONL line:', trimmed.slice(0, 100));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Process any remaining content in buffer
|
|
78
|
+
const trimmed = buffer.trim();
|
|
79
|
+
if (trimmed) {
|
|
80
|
+
try {
|
|
81
|
+
yield JSON.parse(trimmed);
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
console.warn('Invalid JSONL line:', trimmed.slice(0, 100));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
reader.releaseLock();
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Serializes an object to a JSONL line
|
|
94
|
+
*/
|
|
95
|
+
export function toJsonLine(obj) {
|
|
96
|
+
return JSON.stringify(obj) + '\n';
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parses a single JSONL line
|
|
100
|
+
*/
|
|
101
|
+
export function fromJsonLine(line) {
|
|
102
|
+
return JSON.parse(line.trim());
|
|
103
|
+
}
|
|
104
|
+
//# sourceMappingURL=jsonl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsonl.js","sourceRoot":"","sources":["../src/jsonl.ts"],"names":[],"mappings":"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"}
|
package/dist/mux.d.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream Multiplexer
|
|
3
|
+
* Merge multiple async streams with stable ordering and cursor support
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Stream event with metadata
|
|
7
|
+
*/
|
|
8
|
+
export interface StreamEvent<T = unknown> {
|
|
9
|
+
/** Event ID for cursor tracking */
|
|
10
|
+
id: string;
|
|
11
|
+
/** Source stream identifier */
|
|
12
|
+
source: string;
|
|
13
|
+
/** Sequence number within source */
|
|
14
|
+
seq: number;
|
|
15
|
+
/** Event timestamp */
|
|
16
|
+
timestamp: number;
|
|
17
|
+
/** Event type */
|
|
18
|
+
type: 'delta' | 'tool_call' | 'tool_result' | 'json' | 'error' | 'done';
|
|
19
|
+
/** Event payload */
|
|
20
|
+
data: T;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Cursor for stream position tracking
|
|
24
|
+
*/
|
|
25
|
+
export interface StreamCursor {
|
|
26
|
+
/** Event ID to resume from */
|
|
27
|
+
eventId: string;
|
|
28
|
+
/** Source positions */
|
|
29
|
+
positions: Record<string, number>;
|
|
30
|
+
/** Timestamp */
|
|
31
|
+
timestamp: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Mux options
|
|
35
|
+
*/
|
|
36
|
+
export interface MuxOptions {
|
|
37
|
+
/** Resume from cursor */
|
|
38
|
+
cursor?: string | StreamCursor | null;
|
|
39
|
+
/** Buffer size for ordering */
|
|
40
|
+
bufferSize?: number;
|
|
41
|
+
/** Timeout for out-of-order events (ms) */
|
|
42
|
+
orderingTimeoutMs?: number;
|
|
43
|
+
/** Generate event IDs */
|
|
44
|
+
generateId?: () => string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Named async iterable
|
|
48
|
+
*/
|
|
49
|
+
export interface NamedStream<T = unknown> {
|
|
50
|
+
name: string;
|
|
51
|
+
stream: AsyncIterable<T>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Parse cursor from string or object
|
|
55
|
+
*/
|
|
56
|
+
export declare function parseCursor(cursor: string | StreamCursor): StreamCursor;
|
|
57
|
+
/**
|
|
58
|
+
* Serialize cursor to string
|
|
59
|
+
*/
|
|
60
|
+
export declare function serializeCursor(cursor: StreamCursor): string;
|
|
61
|
+
/**
|
|
62
|
+
* Create cursor from current state
|
|
63
|
+
*/
|
|
64
|
+
export declare function createCursor(eventId: string, positions: Record<string, number>): StreamCursor;
|
|
65
|
+
/**
|
|
66
|
+
* Multiplex multiple async iterables into a single ordered stream
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const llmStream = getOpenAIStream();
|
|
71
|
+
* const toolStream = getToolResultStream();
|
|
72
|
+
*
|
|
73
|
+
* const combined = mux([
|
|
74
|
+
* { name: 'llm', stream: llmStream },
|
|
75
|
+
* { name: 'tools', stream: toolStream },
|
|
76
|
+
* ], { cursor: request.headers.get('x-cursor') });
|
|
77
|
+
*
|
|
78
|
+
* for await (const event of combined) {
|
|
79
|
+
* console.log(event.source, event.data);
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function mux<T>(streams: NamedStream<T>[], options?: MuxOptions): AsyncGenerator<StreamEvent<T>, void, unknown>;
|
|
84
|
+
/**
|
|
85
|
+
* Simple array-based multiplexer for basic use cases
|
|
86
|
+
*/
|
|
87
|
+
export declare function muxSimple<T>(...streams: AsyncIterable<T>[]): AsyncGenerator<T, void, unknown>;
|
|
88
|
+
/**
|
|
89
|
+
* Create a replayable stream with buffer
|
|
90
|
+
*/
|
|
91
|
+
export declare function createReplayableStream<T>(source: AsyncIterable<T>, bufferSize?: number): {
|
|
92
|
+
stream: () => AsyncGenerator<StreamEvent<T>>;
|
|
93
|
+
replay: (cursor: string | StreamCursor) => AsyncGenerator<StreamEvent<T>>;
|
|
94
|
+
getBuffer: () => StreamEvent<T>[];
|
|
95
|
+
getCursor: () => string;
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Transform stream events
|
|
99
|
+
*/
|
|
100
|
+
export declare function mapEvents<T, U>(stream: AsyncIterable<StreamEvent<T>>, fn: (event: StreamEvent<T>) => StreamEvent<U> | null): AsyncGenerator<StreamEvent<U>>;
|
|
101
|
+
/**
|
|
102
|
+
* Filter stream events
|
|
103
|
+
*/
|
|
104
|
+
export declare function filterEvents<T>(stream: AsyncIterable<StreamEvent<T>>, predicate: (event: StreamEvent<T>) => boolean): AsyncGenerator<StreamEvent<T>>;
|
|
105
|
+
/**
|
|
106
|
+
* Combine delta events into complete messages
|
|
107
|
+
*/
|
|
108
|
+
export declare function accumulateDeltas<T extends {
|
|
109
|
+
delta?: string;
|
|
110
|
+
text?: string;
|
|
111
|
+
}>(stream: AsyncIterable<StreamEvent<T>>): AsyncGenerator<StreamEvent<T & {
|
|
112
|
+
accumulated: string;
|
|
113
|
+
}>>;
|
|
114
|
+
//# sourceMappingURL=mux.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mux.d.ts","sourceRoot":"","sources":["../src/mux.ts"],"names":[],"mappings":"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"}
|
package/dist/mux.js
ADDED
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream Multiplexer
|
|
3
|
+
* Merge multiple async streams with stable ordering and cursor support
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Generate unique event ID
|
|
7
|
+
*/
|
|
8
|
+
function defaultGenerateId() {
|
|
9
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Parse cursor from string or object
|
|
13
|
+
*/
|
|
14
|
+
export function parseCursor(cursor) {
|
|
15
|
+
if (typeof cursor === 'string') {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(atob(cursor));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return {
|
|
21
|
+
eventId: cursor,
|
|
22
|
+
positions: {},
|
|
23
|
+
timestamp: 0,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return cursor;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Serialize cursor to string
|
|
31
|
+
*/
|
|
32
|
+
export function serializeCursor(cursor) {
|
|
33
|
+
return btoa(JSON.stringify(cursor));
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create cursor from current state
|
|
37
|
+
*/
|
|
38
|
+
export function createCursor(eventId, positions) {
|
|
39
|
+
return {
|
|
40
|
+
eventId,
|
|
41
|
+
positions,
|
|
42
|
+
timestamp: Date.now(),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Multiplex multiple async iterables into a single ordered stream
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* const llmStream = getOpenAIStream();
|
|
51
|
+
* const toolStream = getToolResultStream();
|
|
52
|
+
*
|
|
53
|
+
* const combined = mux([
|
|
54
|
+
* { name: 'llm', stream: llmStream },
|
|
55
|
+
* { name: 'tools', stream: toolStream },
|
|
56
|
+
* ], { cursor: request.headers.get('x-cursor') });
|
|
57
|
+
*
|
|
58
|
+
* for await (const event of combined) {
|
|
59
|
+
* console.log(event.source, event.data);
|
|
60
|
+
* }
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export async function* mux(streams, options = {}) {
|
|
64
|
+
const { cursor: cursorInput, bufferSize = 100, generateId = defaultGenerateId, } = options;
|
|
65
|
+
// Parse cursor if provided
|
|
66
|
+
const cursor = cursorInput
|
|
67
|
+
? parseCursor(cursorInput)
|
|
68
|
+
: null;
|
|
69
|
+
const startPositions = cursor?.positions || {};
|
|
70
|
+
// State tracking
|
|
71
|
+
const state = {
|
|
72
|
+
positions: {},
|
|
73
|
+
lastEventId: '',
|
|
74
|
+
buffer: [],
|
|
75
|
+
};
|
|
76
|
+
// Initialize positions
|
|
77
|
+
for (const { name } of streams) {
|
|
78
|
+
state.positions[name] = startPositions[name] || 0;
|
|
79
|
+
}
|
|
80
|
+
// Track active iterators
|
|
81
|
+
const iterators = streams.map(({ name, stream }) => ({
|
|
82
|
+
name,
|
|
83
|
+
iterator: stream[Symbol.asyncIterator](),
|
|
84
|
+
done: false,
|
|
85
|
+
seq: state.positions[name] || 0,
|
|
86
|
+
}));
|
|
87
|
+
const iteratorStates = iterators.map((it) => ({
|
|
88
|
+
...it,
|
|
89
|
+
pending: null,
|
|
90
|
+
}));
|
|
91
|
+
// Start or get pending promise for an iterator
|
|
92
|
+
function getOrStartNext(state) {
|
|
93
|
+
if (state.pending)
|
|
94
|
+
return state.pending;
|
|
95
|
+
state.pending = (async () => {
|
|
96
|
+
try {
|
|
97
|
+
const result = await state.iterator.next();
|
|
98
|
+
if (result.done) {
|
|
99
|
+
state.done = true;
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
state.seq++;
|
|
103
|
+
return { name: state.name, value: result.value, seq: state.seq };
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
state.done = true;
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
})();
|
|
110
|
+
return state.pending;
|
|
111
|
+
}
|
|
112
|
+
// Pull from all streams concurrently
|
|
113
|
+
async function pullNext() {
|
|
114
|
+
while (true) {
|
|
115
|
+
const pending = iteratorStates.filter((it) => !it.done);
|
|
116
|
+
if (pending.length === 0)
|
|
117
|
+
return null;
|
|
118
|
+
// Create wrapper promises that identify which iterator resolved
|
|
119
|
+
const promises = pending.map((state, idx) => getOrStartNext(state).then((result) => ({ idx, state, result })));
|
|
120
|
+
const { idx, state, result } = await Promise.race(promises);
|
|
121
|
+
// Clear the pending promise for the iterator that resolved
|
|
122
|
+
state.pending = null;
|
|
123
|
+
// If this iterator had a value, return it
|
|
124
|
+
if (result !== null) {
|
|
125
|
+
return result;
|
|
126
|
+
}
|
|
127
|
+
// Otherwise, this iterator is done, loop to race remaining iterators
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Check if we should skip (for resume)
|
|
131
|
+
function shouldSkip(name, seq) {
|
|
132
|
+
const startSeq = startPositions[name] || 0;
|
|
133
|
+
return seq <= startSeq;
|
|
134
|
+
}
|
|
135
|
+
// Main loop
|
|
136
|
+
while (true) {
|
|
137
|
+
const result = await pullNext();
|
|
138
|
+
if (!result)
|
|
139
|
+
break;
|
|
140
|
+
const { name, value, seq } = result;
|
|
141
|
+
state.positions[name] = seq;
|
|
142
|
+
// Skip if resuming and before cursor position
|
|
143
|
+
if (shouldSkip(name, seq)) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
// Create event
|
|
147
|
+
const eventId = generateId();
|
|
148
|
+
const event = {
|
|
149
|
+
id: eventId,
|
|
150
|
+
source: name,
|
|
151
|
+
seq,
|
|
152
|
+
timestamp: Date.now(),
|
|
153
|
+
type: detectEventType(value),
|
|
154
|
+
data: value,
|
|
155
|
+
};
|
|
156
|
+
state.lastEventId = eventId;
|
|
157
|
+
// Buffer management
|
|
158
|
+
state.buffer.push(event);
|
|
159
|
+
if (state.buffer.length > bufferSize) {
|
|
160
|
+
state.buffer.shift();
|
|
161
|
+
}
|
|
162
|
+
yield event;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Detect event type from data
|
|
167
|
+
*/
|
|
168
|
+
function detectEventType(data) {
|
|
169
|
+
if (data === null || data === undefined) {
|
|
170
|
+
return 'done';
|
|
171
|
+
}
|
|
172
|
+
if (typeof data === 'object') {
|
|
173
|
+
const obj = data;
|
|
174
|
+
if ('error' in obj)
|
|
175
|
+
return 'error';
|
|
176
|
+
if ('tool_call' in obj || 'function_call' in obj)
|
|
177
|
+
return 'tool_call';
|
|
178
|
+
if ('tool_result' in obj || 'function_result' in obj)
|
|
179
|
+
return 'tool_result';
|
|
180
|
+
if (typeof obj === 'object' && !('delta' in obj) && !('text' in obj)) {
|
|
181
|
+
return 'json';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return 'delta';
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Simple array-based multiplexer for basic use cases
|
|
188
|
+
*/
|
|
189
|
+
export async function* muxSimple(...streams) {
|
|
190
|
+
const iterators = streams.map((s) => ({
|
|
191
|
+
iterator: s[Symbol.asyncIterator](),
|
|
192
|
+
done: false,
|
|
193
|
+
pending: null,
|
|
194
|
+
}));
|
|
195
|
+
function getOrStartNext(state) {
|
|
196
|
+
if (state.pending)
|
|
197
|
+
return state.pending;
|
|
198
|
+
state.pending = (async () => {
|
|
199
|
+
const result = await state.iterator.next();
|
|
200
|
+
if (result.done) {
|
|
201
|
+
state.done = true;
|
|
202
|
+
return null;
|
|
203
|
+
}
|
|
204
|
+
return { value: result.value };
|
|
205
|
+
})();
|
|
206
|
+
return state.pending;
|
|
207
|
+
}
|
|
208
|
+
while (true) {
|
|
209
|
+
const pending = iterators.filter((it) => !it.done);
|
|
210
|
+
if (pending.length === 0)
|
|
211
|
+
break;
|
|
212
|
+
const promises = pending.map((state) => getOrStartNext(state).then((result) => ({ state, result })));
|
|
213
|
+
const { state, result } = await Promise.race(promises);
|
|
214
|
+
state.pending = null;
|
|
215
|
+
if (result !== null) {
|
|
216
|
+
yield result.value;
|
|
217
|
+
}
|
|
218
|
+
// If result is null, the iterator is done, loop continues with remaining
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Create a replayable stream with buffer
|
|
223
|
+
*/
|
|
224
|
+
export function createReplayableStream(source, bufferSize = 1000) {
|
|
225
|
+
const buffer = [];
|
|
226
|
+
let seq = 0;
|
|
227
|
+
let consumed = false;
|
|
228
|
+
async function* stream() {
|
|
229
|
+
if (consumed) {
|
|
230
|
+
throw new Error('Stream already consumed. Use replay() instead.');
|
|
231
|
+
}
|
|
232
|
+
consumed = true;
|
|
233
|
+
for await (const data of source) {
|
|
234
|
+
seq++;
|
|
235
|
+
const event = {
|
|
236
|
+
id: `${Date.now()}-${seq}`,
|
|
237
|
+
source: 'main',
|
|
238
|
+
seq,
|
|
239
|
+
timestamp: Date.now(),
|
|
240
|
+
type: detectEventType(data),
|
|
241
|
+
data,
|
|
242
|
+
};
|
|
243
|
+
buffer.push(event);
|
|
244
|
+
if (buffer.length > bufferSize) {
|
|
245
|
+
buffer.shift();
|
|
246
|
+
}
|
|
247
|
+
yield event;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async function* replay(cursor) {
|
|
251
|
+
const parsed = parseCursor(cursor);
|
|
252
|
+
const startSeq = parsed.positions['main'] || 0;
|
|
253
|
+
for (const event of buffer) {
|
|
254
|
+
if (event.seq > startSeq) {
|
|
255
|
+
yield event;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function getBuffer() {
|
|
260
|
+
return [...buffer];
|
|
261
|
+
}
|
|
262
|
+
function getCursor() {
|
|
263
|
+
if (buffer.length === 0)
|
|
264
|
+
return '';
|
|
265
|
+
const lastEvent = buffer[buffer.length - 1];
|
|
266
|
+
return serializeCursor(createCursor(lastEvent.id, { main: lastEvent.seq }));
|
|
267
|
+
}
|
|
268
|
+
return { stream, replay, getBuffer, getCursor };
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Transform stream events
|
|
272
|
+
*/
|
|
273
|
+
export async function* mapEvents(stream, fn) {
|
|
274
|
+
for await (const event of stream) {
|
|
275
|
+
const mapped = fn(event);
|
|
276
|
+
if (mapped)
|
|
277
|
+
yield mapped;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Filter stream events
|
|
282
|
+
*/
|
|
283
|
+
export async function* filterEvents(stream, predicate) {
|
|
284
|
+
for await (const event of stream) {
|
|
285
|
+
if (predicate(event))
|
|
286
|
+
yield event;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Combine delta events into complete messages
|
|
291
|
+
*/
|
|
292
|
+
export async function* accumulateDeltas(stream) {
|
|
293
|
+
let accumulated = '';
|
|
294
|
+
for await (const event of stream) {
|
|
295
|
+
if (event.type === 'delta') {
|
|
296
|
+
const delta = event.data.delta ||
|
|
297
|
+
event.data.text ||
|
|
298
|
+
'';
|
|
299
|
+
accumulated += delta;
|
|
300
|
+
}
|
|
301
|
+
yield {
|
|
302
|
+
...event,
|
|
303
|
+
data: {
|
|
304
|
+
...event.data,
|
|
305
|
+
accumulated,
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=mux.js.map
|
package/dist/mux.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mux.js","sourceRoot":"","sources":["../src/mux.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Response Utilities
|
|
3
|
+
* Stream to Response helpers for various protocols
|
|
4
|
+
*/
|
|
5
|
+
import type { StreamEvent } from './mux.js';
|
|
6
|
+
/**
|
|
7
|
+
* Stream protocol
|
|
8
|
+
*/
|
|
9
|
+
export type StreamProtocol = 'sse' | 'jsonl' | 'raw';
|
|
10
|
+
/**
|
|
11
|
+
* Response options
|
|
12
|
+
*/
|
|
13
|
+
export interface StreamResponseOptions {
|
|
14
|
+
/** Custom headers */
|
|
15
|
+
headers?: Record<string, string>;
|
|
16
|
+
/** Include cursor in response */
|
|
17
|
+
includeCursor?: boolean;
|
|
18
|
+
/** Cursor header name */
|
|
19
|
+
cursorHeader?: string;
|
|
20
|
+
/** On error callback */
|
|
21
|
+
onError?: (error: Error) => void;
|
|
22
|
+
/** On complete callback */
|
|
23
|
+
onComplete?: () => void;
|
|
24
|
+
/** Signal for abort */
|
|
25
|
+
signal?: AbortSignal;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Protocol encoder
|
|
29
|
+
*/
|
|
30
|
+
export interface ProtocolEncoder<T = unknown> {
|
|
31
|
+
/** Content-Type header */
|
|
32
|
+
contentType: string;
|
|
33
|
+
/** Encode event to string/bytes */
|
|
34
|
+
encode: (event: StreamEvent<T>) => string;
|
|
35
|
+
/** End marker (if any) */
|
|
36
|
+
end?: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Server-Sent Events encoder
|
|
40
|
+
*/
|
|
41
|
+
export declare function sse<T = unknown>(): ProtocolEncoder<T>;
|
|
42
|
+
/**
|
|
43
|
+
* JSON Lines encoder
|
|
44
|
+
*/
|
|
45
|
+
export declare function jsonl<T = unknown>(): ProtocolEncoder<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Raw text encoder (just the data)
|
|
48
|
+
*/
|
|
49
|
+
export declare function raw<T = unknown>(): ProtocolEncoder<T>;
|
|
50
|
+
/**
|
|
51
|
+
* Create a Web API Response from an async stream
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* export async function POST(req: Request) {
|
|
56
|
+
* const stream = getOpenAIStream();
|
|
57
|
+
* return streamToResponse(stream, sse());
|
|
58
|
+
* }
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function streamToResponse<T>(stream: AsyncIterable<StreamEvent<T>>, encoder: ProtocolEncoder<T>, options?: StreamResponseOptions): Response;
|
|
62
|
+
/**
|
|
63
|
+
* Create a simple text streaming response
|
|
64
|
+
*/
|
|
65
|
+
export declare function textStreamResponse(stream: AsyncIterable<string>, options?: Omit<StreamResponseOptions, 'includeCursor'>): Response;
|
|
66
|
+
/**
|
|
67
|
+
* Parse SSE stream from Response
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseSSEResponse<T = unknown>(response: Response): AsyncGenerator<StreamEvent<T>>;
|
|
70
|
+
/**
|
|
71
|
+
* Parse JSONL stream from Response
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseJSONLResponse<T = unknown>(response: Response): AsyncGenerator<StreamEvent<T>>;
|
|
74
|
+
/**
|
|
75
|
+
* Node.js ServerResponse adapter
|
|
76
|
+
*/
|
|
77
|
+
export interface NodeServerResponse {
|
|
78
|
+
writeHead(statusCode: number, headers: Record<string, string>): void;
|
|
79
|
+
write(chunk: string): boolean;
|
|
80
|
+
end(): void;
|
|
81
|
+
on(event: 'close', listener: () => void): void;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Stream to Node.js ServerResponse
|
|
85
|
+
*/
|
|
86
|
+
export declare function streamToNodeResponse<T>(stream: AsyncIterable<StreamEvent<T>>, res: NodeServerResponse, encoder: ProtocolEncoder<T>, options?: StreamResponseOptions): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Create AI-compatible event from various formats
|
|
89
|
+
*/
|
|
90
|
+
export declare function createAIEvent<T>(data: T, options?: {
|
|
91
|
+
source?: string;
|
|
92
|
+
type?: StreamEvent['type'];
|
|
93
|
+
id?: string;
|
|
94
|
+
}): StreamEvent<T>;
|
|
95
|
+
/**
|
|
96
|
+
* Convert simple async string stream to event stream
|
|
97
|
+
*/
|
|
98
|
+
export declare function toEventStream(stream: AsyncIterable<string>, source?: string): AsyncGenerator<StreamEvent<{
|
|
99
|
+
delta: string;
|
|
100
|
+
}>>;
|
|
101
|
+
//# sourceMappingURL=response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"response.d.ts","sourceRoot":"","sources":["../src/response.ts"],"names":[],"mappings":"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"}
|