@anvia/server 1.1.4 → 1.2.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 CHANGED
@@ -1,55 +1,79 @@
1
1
  # @anvia/server
2
2
 
3
- Server response helpers for the Anvia client protocol and explicitly generic event streams.
3
+ Serve Anvia completions and Agent runs over HTTP. These framework-neutral response helpers turn
4
+ async events into streaming `Response` objects for Anvia clients, with JSONL, SSE, and replay support.
4
5
 
5
- ## Bun
6
-
7
- Bun 1.3.14 is the currently tested and supported runtime baseline:
6
+ ## Install
8
7
 
9
8
  ```sh
10
- bun add @anvia/server @anvia/client
9
+ pnpm add @anvia/server @anvia/client @anvia/core @anvia/openai
11
10
  ```
12
11
 
13
- Compatibility tests run these helpers through `Bun.serve`, covering framed JSONL and SSE,
14
- resumable replay, cancellation cleanup, and installation from packed package artifacts.
12
+ The quickstart uses OpenAI; choose another provider adapter if needed.
15
13
 
16
- ## Client protocol responses
14
+ ## Quickstart
17
15
 
18
- Adapt native runtime events at the server boundary, then frame them for the client:
16
+ Set `OPENAI_API_KEY` on your server and mount this handler in a framework that accepts Web
17
+ `Request` and `Response` objects:
19
18
 
20
19
  ```ts
21
20
  import { completionToClientStream, parseClientStreamRequest } from "@anvia/client";
22
21
  import { streamCompletion } from "@anvia/core";
22
+ import { OpenAIClient } from "@anvia/openai";
23
23
  import { createClientStreamResponse } from "@anvia/server";
24
24
 
25
- const body = parseClientStreamRequest(await request.json());
26
- if (body.type !== "messages") throw new Error("This completion endpoint accepts messages only.");
27
- const events = completionToClientStream({
28
- events: streamCompletion({ model, messages: body.messages }),
25
+ const apiKey = process.env.OPENAI_API_KEY;
26
+ if (!apiKey) throw new Error("Set OPENAI_API_KEY.");
27
+ const model = new OpenAIClient({ apiKey }).completionModel({
28
+ modelId: "gpt-5",
29
+ api: "responses",
29
30
  });
30
31
 
31
- return createClientStreamResponse({ events }); // JSONL by default
32
+ export async function POST(request: Request): Promise<Response> {
33
+ const body = parseClientStreamRequest(await request.json());
34
+ if (body.type !== "messages") {
35
+ return new Response("This endpoint accepts messages only.", { status: 400 });
36
+ }
37
+ const events = completionToClientStream({
38
+ events: streamCompletion({ model, messages: body.messages, abortSignal: request.signal }),
39
+ });
40
+ return createClientStreamResponse({ events });
41
+ }
32
42
  ```
33
43
 
34
- `createClientStreamResponse({ events, ...options })` always emits `stream_start`, ordered
35
- `stream_event` frames, and `stream_end`, and sets
36
- `x-anvia-stream-protocol: anvia.client.v3`. Use `format: "sse"` for SSE framing.
44
+ Connect with `createHttpClientTransport` from `@anvia/client`, or use it with the `@anvia/react`
45
+ hooks. Add `format: "sse"` to the response options for SSE instead of the default JSONL.
46
+
47
+ ## Capabilities
48
+
49
+ - Framed client responses with protocol headers and ordered event IDs.
50
+ - Resumable streams backed by a store you provide, with an in-memory store for local use.
51
+ - Separate generic event responses for application-defined protocols.
52
+ - Lower-level JSONL and SSE stream helpers.
53
+
54
+ Your application owns routing, authentication, request error handling, and durable storage.
55
+
56
+ ## Learn more
37
57
 
38
- For resumable streams, pass `{ resumable: { streamId, store } }` when creating the response and
39
- call `resumeClientStreamResponse({ streamId, after, store })` for a resume request.
58
+ - [Server streaming guide](https://github.com/anvia-hq/anvia/blob/main/docs/packages/server.md)
59
+ - [Client protocol](https://github.com/anvia-hq/anvia/tree/main/packages/client#readme)
60
+ - [React hooks](https://github.com/anvia-hq/anvia/tree/main/packages/react#readme)
40
61
 
41
- ## Generic event responses
62
+ ## Durable execution routes
42
63
 
43
- `createEventStreamResponse({ events, ...options })` and `resumeEventStreamResponse(options)` are
44
- separate, generic helpers. They serialize the event type supplied by the application and do not
45
- claim that it is the Anvia client protocol.
64
+ The optional `@anvia/server/durable` entrypoint exports `createDurableHandler` for
65
+ `@anvia/durable` runtimes. It provides submission, session-scoped run listing, snapshots,
66
+ SSE events with persisted IDs, approval responses, retry, cancellation, and reconciliation.
67
+ An `authorize(request, resource)` callback is required for all reads and writes. The host
68
+ owns runtime startup (`resume`) and shutdown (`close`). Client disconnects detach observers.
46
69
 
47
- The lower-level exports are:
70
+ Install `@anvia/durable` when using this subpath. See the
71
+ [durable HTTP guide](../../docs/packages/durable.md#http-server-and-client).
48
72
 
49
- - `createJsonlStream({ events, ...options })`
50
- - `createSseStream({ events, ...options })`
51
- - `createResumableStream({ events, ...options })`
52
- - `resumeStreamEvents(options)`
53
- - `createMemoryResumableStreamStore()`
73
+ Generic `SseStreamOptions` also supports `eventId(event)` for native SSE IDs and
74
+ `onCancel()` to interrupt a pending producer read before its iterator is returned.
54
75
 
55
- There are no compatibility aliases for the removed ambiguous response APIs.
76
+ Durable graph routes under `/durable/graphs` expose submission, paginated discovery, topology
77
+ snapshots, task SSE events, and cancellation. Graph-wide operations authorize every task;
78
+ individual child-run routes authorize against the graph's owning session. See the
79
+ [task graph guide](../../docs/packages/durable.md#task-dependencies-and-exposed-graphs).
@@ -0,0 +1,450 @@
1
+ // src/errors.ts
2
+ import { isJsonValue } from "@anvia/client";
3
+ function errorEvent(error) {
4
+ return {
5
+ type: "error",
6
+ error: serializeError(error)
7
+ };
8
+ }
9
+ function serializeError(error) {
10
+ if (error instanceof Error) {
11
+ const serialized = {
12
+ name: error.name,
13
+ message: error.message
14
+ };
15
+ const code = error.code;
16
+ if (typeof code === "string") {
17
+ serialized.code = code;
18
+ }
19
+ const retryable = error.retryable;
20
+ if (typeof retryable === "boolean") {
21
+ serialized.retryable = retryable;
22
+ }
23
+ if (isJsonValue(error.details)) {
24
+ serialized.details = error.details;
25
+ }
26
+ return serialized;
27
+ }
28
+ if (!isJsonValue(error)) {
29
+ return { message: String(error) };
30
+ }
31
+ return error;
32
+ }
33
+
34
+ // src/jsonl.ts
35
+ function createJsonlStream(options) {
36
+ const encoder = new TextEncoder();
37
+ const iterator = options.events[Symbol.asyncIterator]();
38
+ const serialize = options.serialize ?? serializeJson;
39
+ return new ReadableStream({
40
+ async pull(controller) {
41
+ try {
42
+ const next = await iterator.next();
43
+ if (next.done === true) {
44
+ controller.close();
45
+ return;
46
+ }
47
+ controller.enqueue(encoder.encode(`${serialize(next.value)}
48
+ `));
49
+ } catch (error) {
50
+ controller.enqueue(encoder.encode(`${serialize(errorEvent(error))}
51
+ `));
52
+ controller.close();
53
+ }
54
+ },
55
+ async cancel() {
56
+ await iterator.return?.();
57
+ }
58
+ });
59
+ }
60
+ function serializeJson(value) {
61
+ return JSON.stringify(value);
62
+ }
63
+
64
+ // src/resumable.ts
65
+ function createResumableStream(options) {
66
+ const streamId = options.id;
67
+ let openPromise;
68
+ function start() {
69
+ if (openPromise !== void 0) {
70
+ return openPromise;
71
+ }
72
+ openPromise = options.store.open({ streamId }).then(() => void 0);
73
+ void drainResumableStream(options.events, options, openPromise);
74
+ return openPromise;
75
+ }
76
+ return {
77
+ async *[Symbol.asyncIterator]() {
78
+ await start();
79
+ yield* resumeStreamEvents({ id: streamId, store: options.store });
80
+ }
81
+ };
82
+ }
83
+ async function* resumeStreamEvents(options) {
84
+ const streamId = options.id;
85
+ yield { type: "stream_start", streamId, eventId: 0 };
86
+ const subscribeInput = { streamId };
87
+ if (options.after !== void 0) {
88
+ subscribeInput.after = options.after;
89
+ }
90
+ for await (const record of options.store.subscribe(subscribeInput)) {
91
+ yield recordToEnvelope(record);
92
+ }
93
+ const state = await options.store.status({ streamId });
94
+ yield stateToEndEnvelope(streamId, state);
95
+ }
96
+ function createMemoryResumableStreamStore() {
97
+ const streams = /* @__PURE__ */ new Map();
98
+ function state(stream) {
99
+ if (stream === void 0) {
100
+ return { status: "missing", lastEventId: 0 };
101
+ }
102
+ return {
103
+ status: stream.status,
104
+ lastEventId: stream.records.at(-1)?.eventId ?? 0
105
+ };
106
+ }
107
+ return {
108
+ async open(input) {
109
+ const existing = streams.get(input.streamId);
110
+ if (existing !== void 0) {
111
+ closeSubscribers(existing);
112
+ }
113
+ const stream = {
114
+ records: [],
115
+ status: "running",
116
+ subscribers: /* @__PURE__ */ new Set()
117
+ };
118
+ streams.set(input.streamId, stream);
119
+ return state(stream);
120
+ },
121
+ async append(input) {
122
+ const stream = streams.get(input.streamId);
123
+ if (stream === void 0) {
124
+ throw new Error(`Resumable stream "${input.streamId}" is not open`);
125
+ }
126
+ if (stream.status !== "running") {
127
+ throw new Error(`Resumable stream "${input.streamId}" is already ${stream.status}`);
128
+ }
129
+ const record = {
130
+ streamId: input.streamId,
131
+ eventId: stream.records.length + 1,
132
+ event: input.event,
133
+ createdAt: /* @__PURE__ */ new Date()
134
+ };
135
+ stream.records.push(record);
136
+ for (const subscriber of stream.subscribers) {
137
+ if (record.eventId > subscriber.after) {
138
+ subscriber.queue.enqueue(record);
139
+ }
140
+ }
141
+ return record;
142
+ },
143
+ subscribe(input) {
144
+ const after = input.after ?? 0;
145
+ return {
146
+ [Symbol.asyncIterator]() {
147
+ const stream = streams.get(input.streamId);
148
+ const queue = createAsyncQueue();
149
+ if (stream === void 0) {
150
+ queue.close();
151
+ return queue[Symbol.asyncIterator]();
152
+ }
153
+ for (const record of stream.records) {
154
+ if (record.eventId > after) {
155
+ queue.enqueue(record);
156
+ }
157
+ }
158
+ if (stream.status !== "running") {
159
+ queue.close();
160
+ return queue[Symbol.asyncIterator]();
161
+ }
162
+ const subscriber = { after, queue };
163
+ stream.subscribers.add(subscriber);
164
+ const iterator = queue[Symbol.asyncIterator]();
165
+ return {
166
+ next: () => iterator.next(),
167
+ async return() {
168
+ stream.subscribers.delete(subscriber);
169
+ queue.close();
170
+ return { value: void 0, done: true };
171
+ }
172
+ };
173
+ }
174
+ };
175
+ },
176
+ async status(input) {
177
+ return state(streams.get(input.streamId));
178
+ },
179
+ async close(input) {
180
+ const stream = streams.get(input.streamId);
181
+ if (stream === void 0) {
182
+ return { status: input.status, lastEventId: 0 };
183
+ }
184
+ stream.status = input.status;
185
+ closeSubscribers(stream);
186
+ return state(stream);
187
+ }
188
+ };
189
+ }
190
+ async function drainResumableStream(events, options, openPromise) {
191
+ const streamId = options.id;
192
+ try {
193
+ await openPromise;
194
+ for await (const event of events) {
195
+ await options.store.append({ streamId, event });
196
+ }
197
+ await options.store.close({ streamId, status: "completed" });
198
+ } catch (error) {
199
+ const event = errorEvent(error);
200
+ try {
201
+ await options.store.append({ streamId, event });
202
+ } catch {
203
+ }
204
+ try {
205
+ await options.store.close({ streamId, status: "error" });
206
+ } catch {
207
+ }
208
+ }
209
+ }
210
+ function recordToEnvelope(record) {
211
+ return {
212
+ type: "stream_event",
213
+ streamId: record.streamId,
214
+ eventId: record.eventId,
215
+ event: record.event
216
+ };
217
+ }
218
+ function stateToEndEnvelope(streamId, state) {
219
+ return {
220
+ type: "stream_end",
221
+ streamId,
222
+ eventId: state.lastEventId,
223
+ status: state.status
224
+ };
225
+ }
226
+ function closeSubscribers(stream) {
227
+ for (const subscriber of stream.subscribers) {
228
+ subscriber.queue.close();
229
+ }
230
+ stream.subscribers.clear();
231
+ }
232
+ function createAsyncQueue() {
233
+ const values = [];
234
+ const waiters = [];
235
+ let closed = false;
236
+ let error;
237
+ function flush() {
238
+ while (waiters.length > 0 && values.length > 0) {
239
+ const waiter = waiters.shift();
240
+ const value = values.shift();
241
+ waiter?.resolve({ value, done: false });
242
+ }
243
+ if (values.length > 0 || waiters.length === 0 || !closed) {
244
+ return;
245
+ }
246
+ while (waiters.length > 0) {
247
+ const waiter = waiters.shift();
248
+ if (waiter === void 0) {
249
+ continue;
250
+ }
251
+ if (error !== void 0) {
252
+ waiter.reject(error);
253
+ } else {
254
+ waiter.resolve({ value: void 0, done: true });
255
+ }
256
+ }
257
+ }
258
+ return {
259
+ enqueue(value) {
260
+ if (closed) {
261
+ return;
262
+ }
263
+ values.push(value);
264
+ flush();
265
+ },
266
+ close() {
267
+ closed = true;
268
+ flush();
269
+ },
270
+ throw(thrown) {
271
+ closed = true;
272
+ error = thrown;
273
+ flush();
274
+ },
275
+ [Symbol.asyncIterator]() {
276
+ return {
277
+ next() {
278
+ if (values.length > 0) {
279
+ const value = values.shift();
280
+ return Promise.resolve({ value, done: false });
281
+ }
282
+ if (error !== void 0) {
283
+ return Promise.reject(error);
284
+ }
285
+ if (closed) {
286
+ return Promise.resolve({ value: void 0, done: true });
287
+ }
288
+ return new Promise((resolve, reject) => {
289
+ waiters.push({ resolve, reject });
290
+ });
291
+ }
292
+ };
293
+ }
294
+ };
295
+ }
296
+
297
+ // src/sse.ts
298
+ function createSseStream(options) {
299
+ validateSseOptions(options);
300
+ const encoder = new TextEncoder();
301
+ const iterator = options.events[Symbol.asyncIterator]();
302
+ const serialize = options.serialize ?? serializeJson2;
303
+ let cancelled = false;
304
+ return new ReadableStream({
305
+ start(controller) {
306
+ if (options.retry !== void 0) {
307
+ controller.enqueue(encoder.encode(`retry: ${options.retry}
308
+
309
+ `));
310
+ }
311
+ },
312
+ async pull(controller) {
313
+ try {
314
+ const next = await iterator.next();
315
+ if (cancelled) return;
316
+ if (next.done === true) {
317
+ controller.close();
318
+ return;
319
+ }
320
+ controller.enqueue(
321
+ encoder.encode(formatSseEvent(next.value, serialize, options.eventName, options.eventId))
322
+ );
323
+ } catch (error) {
324
+ if (cancelled) return;
325
+ const event = errorEvent(error);
326
+ controller.enqueue(encoder.encode(formatSseEvent(event, serialize, options.eventName)));
327
+ controller.close();
328
+ }
329
+ },
330
+ async cancel() {
331
+ cancelled = true;
332
+ await options.onCancel?.();
333
+ await iterator.return?.();
334
+ }
335
+ });
336
+ }
337
+ function formatSseEvent(event, serialize, eventName, eventId) {
338
+ const name = typeof eventName === "function" ? eventName(event) : eventName;
339
+ const lines = [];
340
+ const id = eventId?.(event);
341
+ if (id !== void 0) {
342
+ validateSseEventName(id);
343
+ lines.push(`id: ${id}`);
344
+ }
345
+ if (name !== void 0 && name.length > 0) {
346
+ validateSseEventName(name);
347
+ lines.push(`event: ${name}`);
348
+ }
349
+ for (const line of serialize(event).split(/\r?\n/)) {
350
+ lines.push(`data: ${line}`);
351
+ }
352
+ lines.push("", "");
353
+ return lines.join("\n");
354
+ }
355
+ function serializeJson2(value) {
356
+ return JSON.stringify(value);
357
+ }
358
+ function validateSseOptions(options) {
359
+ if (options.retry !== void 0 && !isValidRetry(options.retry)) {
360
+ throw new TypeError("SSE retry must be a finite non-negative integer");
361
+ }
362
+ if (typeof options.eventName === "string") {
363
+ validateSseEventName(options.eventName);
364
+ }
365
+ }
366
+ function isValidRetry(value) {
367
+ return Number.isFinite(value) && Number.isInteger(value) && value >= 0;
368
+ }
369
+ function validateSseEventName(name) {
370
+ for (const character of name) {
371
+ const code = character.charCodeAt(0);
372
+ if (code === 0 || code === 10 || code === 13) {
373
+ throw new TypeError("SSE event names must not contain null bytes or line breaks");
374
+ }
375
+ }
376
+ }
377
+
378
+ // src/response.ts
379
+ function createEventStreamResponse(options) {
380
+ const eventsForResponse = options.resumable === void 0 ? options.events : createResumableStream({ events: options.events, ...options.resumable });
381
+ return encodeEventStreamResponse({
382
+ events: eventsForResponse,
383
+ ...copyResponseOptions(options)
384
+ });
385
+ }
386
+ function resumeEventStreamResponse(options) {
387
+ return encodeEventStreamResponse({
388
+ events: resumeStreamEvents({
389
+ id: options.streamId,
390
+ after: options.after,
391
+ store: options.store
392
+ }),
393
+ ...copyResponseOptions(options)
394
+ });
395
+ }
396
+ function encodeEventStreamResponse(options) {
397
+ const format = options.format ?? "jsonl";
398
+ const headers = new Headers(options.headers);
399
+ if (!headers.has("cache-control")) {
400
+ headers.set("cache-control", "no-cache, no-transform");
401
+ }
402
+ if (!headers.has("connection")) {
403
+ headers.set("connection", "keep-alive");
404
+ }
405
+ if (!headers.has("x-accel-buffering")) {
406
+ headers.set("x-accel-buffering", "no");
407
+ }
408
+ const body = format === "sse" ? createSseStream({ events: options.events, ...options.sse }) : createJsonlStream({ events: options.events, ...options.jsonl });
409
+ if (!headers.has("content-type")) {
410
+ headers.set(
411
+ "content-type",
412
+ format === "sse" ? "text/event-stream; charset=utf-8" : "application/x-ndjson; charset=utf-8"
413
+ );
414
+ }
415
+ const responseInit = { headers };
416
+ if (options.status !== void 0) {
417
+ responseInit.status = options.status;
418
+ }
419
+ if (options.statusText !== void 0) {
420
+ responseInit.statusText = options.statusText;
421
+ }
422
+ return new Response(body, responseInit);
423
+ }
424
+ function copyResponseOptions(options) {
425
+ const next = {};
426
+ if (options.format !== void 0) next.format = options.format;
427
+ if (options.headers !== void 0) next.headers = options.headers;
428
+ if (options.status !== void 0) next.status = options.status;
429
+ if (options.statusText !== void 0) next.statusText = options.statusText;
430
+ if (options.jsonl !== void 0) {
431
+ next.jsonl = options.jsonl;
432
+ }
433
+ if (options.sse !== void 0) {
434
+ next.sse = options.sse;
435
+ }
436
+ return next;
437
+ }
438
+
439
+ export {
440
+ errorEvent,
441
+ createJsonlStream,
442
+ createResumableStream,
443
+ resumeStreamEvents,
444
+ createMemoryResumableStreamStore,
445
+ createSseStream,
446
+ createEventStreamResponse,
447
+ resumeEventStreamResponse,
448
+ encodeEventStreamResponse
449
+ };
450
+ //# sourceMappingURL=chunk-E2M7MXTL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/jsonl.ts","../src/resumable.ts","../src/sse.ts","../src/response.ts"],"sourcesContent":["import { isJsonValue } from \"@anvia/client\";\nimport type { EventStreamErrorEvent } from \"./types\";\n\nexport function errorEvent(error: unknown): EventStreamErrorEvent {\n return {\n type: \"error\",\n error: serializeError(error),\n };\n}\n\nfunction serializeError(error: unknown): unknown {\n if (error instanceof Error) {\n const serialized: {\n name: string;\n message: string;\n code?: string;\n retryable?: boolean;\n details?: unknown;\n } = {\n name: error.name,\n message: error.message,\n };\n // Runtime-specific Error subclasses (for example bun:sqlite's SqliteError)\n // can keep diagnostic fields such as `code` on the prototype, where\n // JSON.stringify drops them. Copy the protocol's diagnostic fields\n // explicitly so the wire payload stays valid and diagnosable.\n const code = (error as { code?: unknown }).code;\n if (typeof code === \"string\") {\n serialized.code = code;\n }\n const retryable = (error as { retryable?: unknown }).retryable;\n if (typeof retryable === \"boolean\") {\n serialized.retryable = retryable;\n }\n if (isJsonValue((error as { details?: unknown }).details)) {\n serialized.details = (error as { details?: unknown }).details;\n }\n return serialized;\n }\n\n if (!isJsonValue(error)) {\n // A thrown non-Error that is not JSON-safe would serialize as `{}` or lose\n // its diagnostics entirely; degrade to a string payload instead.\n return { message: String(error) };\n }\n return error;\n}\n","import { errorEvent } from \"./errors\";\nimport type { JsonlStreamOptions } from \"./types\";\n\nexport function createJsonlStream<TEvent>(\n options: JsonlStreamOptions<TEvent> & { events: AsyncIterable<TEvent> },\n): ReadableStream<Uint8Array> {\n const encoder = new TextEncoder();\n const iterator = options.events[Symbol.asyncIterator]();\n const serialize = options.serialize ?? serializeJson;\n\n return new ReadableStream<Uint8Array>({\n async pull(controller) {\n try {\n const next = await iterator.next();\n if (next.done === true) {\n controller.close();\n return;\n }\n\n controller.enqueue(encoder.encode(`${serialize(next.value)}\\n`));\n } catch (error) {\n controller.enqueue(encoder.encode(`${serialize(errorEvent(error))}\\n`));\n controller.close();\n }\n },\n async cancel() {\n await iterator.return?.();\n },\n });\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n","import { errorEvent } from \"./errors\";\nimport type {\n CreateResumableStreamOptions,\n ResumableStreamEnvelope,\n ResumableStreamRecord,\n ResumableStreamState,\n ResumableStreamStatus,\n ResumableStreamStore,\n ResumableStreamSubscribeInput,\n ResumeStreamEventsOptions,\n} from \"./types\";\n\ntype Subscriber<TEvent> = {\n after: number;\n queue: AsyncQueue<ResumableStreamRecord<TEvent>>;\n};\n\ntype MemoryStream<TEvent> = {\n records: ResumableStreamRecord<TEvent>[];\n status: ResumableStreamStatus;\n subscribers: Set<Subscriber<TEvent>>;\n};\n\ntype AsyncQueue<T> = AsyncIterable<T> & {\n enqueue(value: T): void;\n close(): void;\n throw(error: unknown): void;\n};\n\nexport function createResumableStream<TEvent>(\n options: CreateResumableStreamOptions<TEvent> & { events: AsyncIterable<TEvent> },\n): AsyncIterable<ResumableStreamEnvelope<TEvent>> {\n const streamId = options.id;\n let openPromise: Promise<void> | undefined;\n\n function start(): Promise<void> {\n if (openPromise !== undefined) {\n return openPromise;\n }\n\n openPromise = options.store.open({ streamId }).then(() => undefined);\n void drainResumableStream(options.events, options, openPromise);\n return openPromise;\n }\n\n return {\n async *[Symbol.asyncIterator]() {\n await start();\n yield* resumeStreamEvents({ id: streamId, store: options.store });\n },\n };\n}\n\nexport async function* resumeStreamEvents<TEvent>(\n options: ResumeStreamEventsOptions<TEvent>,\n): AsyncIterable<ResumableStreamEnvelope<TEvent>> {\n const streamId = options.id;\n yield { type: \"stream_start\", streamId, eventId: 0 };\n\n const subscribeInput: ResumableStreamSubscribeInput = { streamId };\n if (options.after !== undefined) {\n subscribeInput.after = options.after;\n }\n for await (const record of options.store.subscribe(subscribeInput)) {\n yield recordToEnvelope(record);\n }\n\n const state = await options.store.status({ streamId });\n yield stateToEndEnvelope<TEvent>(streamId, state);\n}\n\nexport function createMemoryResumableStreamStore<TEvent = unknown>(): ResumableStreamStore<TEvent> {\n const streams = new Map<string, MemoryStream<TEvent>>();\n\n function state(stream: MemoryStream<TEvent> | undefined): ResumableStreamState {\n if (stream === undefined) {\n return { status: \"missing\", lastEventId: 0 };\n }\n return {\n status: stream.status,\n lastEventId: stream.records.at(-1)?.eventId ?? 0,\n };\n }\n\n return {\n async open(input) {\n const existing = streams.get(input.streamId);\n if (existing !== undefined) {\n closeSubscribers(existing);\n }\n\n const stream: MemoryStream<TEvent> = {\n records: [],\n status: \"running\",\n subscribers: new Set(),\n };\n streams.set(input.streamId, stream);\n return state(stream);\n },\n\n async append(input) {\n const stream = streams.get(input.streamId);\n if (stream === undefined) {\n throw new Error(`Resumable stream \"${input.streamId}\" is not open`);\n }\n if (stream.status !== \"running\") {\n throw new Error(`Resumable stream \"${input.streamId}\" is already ${stream.status}`);\n }\n\n const record: ResumableStreamRecord<TEvent> = {\n streamId: input.streamId,\n eventId: stream.records.length + 1,\n event: input.event,\n createdAt: new Date(),\n };\n stream.records.push(record);\n\n for (const subscriber of stream.subscribers) {\n if (record.eventId > subscriber.after) {\n subscriber.queue.enqueue(record);\n }\n }\n\n return record;\n },\n\n subscribe(input) {\n const after = input.after ?? 0;\n return {\n [Symbol.asyncIterator](): AsyncIterator<ResumableStreamRecord<TEvent>> {\n const stream = streams.get(input.streamId);\n const queue = createAsyncQueue<ResumableStreamRecord<TEvent>>();\n if (stream === undefined) {\n queue.close();\n return queue[Symbol.asyncIterator]();\n }\n\n for (const record of stream.records) {\n if (record.eventId > after) {\n queue.enqueue(record);\n }\n }\n\n if (stream.status !== \"running\") {\n queue.close();\n return queue[Symbol.asyncIterator]();\n }\n\n const subscriber: Subscriber<TEvent> = { after, queue };\n stream.subscribers.add(subscriber);\n const iterator = queue[Symbol.asyncIterator]();\n\n return {\n next: () => iterator.next(),\n async return() {\n stream.subscribers.delete(subscriber);\n queue.close();\n return { value: undefined, done: true };\n },\n };\n },\n };\n },\n\n async status(input) {\n return state(streams.get(input.streamId));\n },\n\n async close(input) {\n const stream = streams.get(input.streamId);\n if (stream === undefined) {\n return { status: input.status, lastEventId: 0 };\n }\n stream.status = input.status;\n closeSubscribers(stream);\n return state(stream);\n },\n };\n}\n\nasync function drainResumableStream<TEvent>(\n events: AsyncIterable<TEvent>,\n options: CreateResumableStreamOptions<TEvent>,\n openPromise: Promise<void>,\n): Promise<void> {\n const streamId = options.id;\n try {\n await openPromise;\n for await (const event of events) {\n await options.store.append({ streamId, event });\n }\n await options.store.close({ streamId, status: \"completed\" });\n } catch (error) {\n const event = errorEvent(error);\n try {\n await options.store.append({ streamId, event });\n } catch {\n // The response iterator reports store-open failures; avoid a background rejection.\n }\n try {\n await options.store.close({ streamId, status: \"error\" });\n } catch {\n // The store may not have opened.\n }\n }\n}\n\nfunction recordToEnvelope<TEvent>(\n record: ResumableStreamRecord<TEvent>,\n): ResumableStreamEnvelope<TEvent> {\n return {\n type: \"stream_event\",\n streamId: record.streamId,\n eventId: record.eventId,\n event: record.event,\n };\n}\n\nfunction stateToEndEnvelope<TEvent>(\n streamId: string,\n state: ResumableStreamState,\n): ResumableStreamEnvelope<TEvent> {\n return {\n type: \"stream_end\",\n streamId,\n eventId: state.lastEventId,\n status: state.status,\n };\n}\n\nfunction closeSubscribers<TEvent>(stream: MemoryStream<TEvent>): void {\n for (const subscriber of stream.subscribers) {\n subscriber.queue.close();\n }\n stream.subscribers.clear();\n}\n\nfunction createAsyncQueue<T>(): AsyncQueue<T> {\n const values: T[] = [];\n const waiters: Array<{\n resolve: (result: IteratorResult<T>) => void;\n reject: (error: unknown) => void;\n }> = [];\n let closed = false;\n let error: unknown;\n\n function flush(): void {\n while (waiters.length > 0 && values.length > 0) {\n const waiter = waiters.shift();\n const value = values.shift() as T;\n waiter?.resolve({ value, done: false });\n }\n\n if (values.length > 0 || waiters.length === 0 || !closed) {\n return;\n }\n\n while (waiters.length > 0) {\n const waiter = waiters.shift();\n if (waiter === undefined) {\n continue;\n }\n if (error !== undefined) {\n waiter.reject(error);\n } else {\n waiter.resolve({ value: undefined, done: true });\n }\n }\n }\n\n return {\n enqueue(value) {\n if (closed) {\n return;\n }\n values.push(value);\n flush();\n },\n close() {\n closed = true;\n flush();\n },\n throw(thrown) {\n closed = true;\n error = thrown;\n flush();\n },\n [Symbol.asyncIterator]() {\n return {\n next() {\n if (values.length > 0) {\n const value = values.shift() as T;\n return Promise.resolve({ value, done: false });\n }\n if (error !== undefined) {\n return Promise.reject(error);\n }\n if (closed) {\n return Promise.resolve({ value: undefined, done: true });\n }\n return new Promise((resolve, reject) => {\n waiters.push({ resolve, reject });\n });\n },\n };\n },\n };\n}\n","import { errorEvent } from \"./errors\";\nimport type { EventStreamErrorEvent, SseStreamOptions } from \"./types\";\n\nexport function createSseStream<TEvent>(\n options: SseStreamOptions<TEvent> & { events: AsyncIterable<TEvent> },\n): ReadableStream<Uint8Array> {\n validateSseOptions(options);\n const encoder = new TextEncoder();\n const iterator = options.events[Symbol.asyncIterator]();\n const serialize = options.serialize ?? serializeJson;\n let cancelled = false;\n\n return new ReadableStream<Uint8Array>({\n start(controller) {\n if (options.retry !== undefined) {\n controller.enqueue(encoder.encode(`retry: ${options.retry}\\n\\n`));\n }\n },\n async pull(controller) {\n try {\n const next = await iterator.next();\n if (cancelled) return;\n if (next.done === true) {\n controller.close();\n return;\n }\n\n controller.enqueue(\n encoder.encode(formatSseEvent(next.value, serialize, options.eventName, options.eventId)),\n );\n } catch (error) {\n if (cancelled) return;\n const event = errorEvent(error);\n controller.enqueue(encoder.encode(formatSseEvent(event, serialize, options.eventName)));\n controller.close();\n }\n },\n async cancel() {\n cancelled = true;\n await options.onCancel?.();\n await iterator.return?.();\n },\n });\n}\n\nfunction formatSseEvent<TEvent>(\n event: TEvent | EventStreamErrorEvent,\n serialize: (event: TEvent | EventStreamErrorEvent) => string,\n eventName: SseStreamOptions<TEvent>[\"eventName\"],\n eventId?: SseStreamOptions<TEvent>[\"eventId\"],\n): string {\n const name = typeof eventName === \"function\" ? eventName(event) : eventName;\n const lines: string[] = [];\n const id = eventId?.(event);\n if (id !== undefined) {\n validateSseEventName(id);\n lines.push(`id: ${id}`);\n }\n\n if (name !== undefined && name.length > 0) {\n validateSseEventName(name);\n lines.push(`event: ${name}`);\n }\n\n for (const line of serialize(event).split(/\\r?\\n/)) {\n lines.push(`data: ${line}`);\n }\n\n lines.push(\"\", \"\");\n return lines.join(\"\\n\");\n}\n\nfunction serializeJson(value: unknown): string {\n return JSON.stringify(value);\n}\n\nfunction validateSseOptions<TEvent>(options: SseStreamOptions<TEvent>): void {\n if (options.retry !== undefined && !isValidRetry(options.retry)) {\n throw new TypeError(\"SSE retry must be a finite non-negative integer\");\n }\n if (typeof options.eventName === \"string\") {\n validateSseEventName(options.eventName);\n }\n}\n\nfunction isValidRetry(value: number): boolean {\n return Number.isFinite(value) && Number.isInteger(value) && value >= 0;\n}\n\nfunction validateSseEventName(name: string): void {\n for (const character of name) {\n const code = character.charCodeAt(0);\n if (code === 0 || code === 10 || code === 13) {\n throw new TypeError(\"SSE event names must not contain null bytes or line breaks\");\n }\n }\n}\n","import { createJsonlStream } from \"./jsonl\";\nimport { createResumableStream, resumeStreamEvents } from \"./resumable\";\nimport { createSseStream } from \"./sse\";\nimport type {\n CreateEventStreamResponseOptions,\n EventStreamFormat,\n JsonlStreamOptions,\n ResumableStreamEnvelope,\n ResumeEventStreamResponseOptions,\n SseStreamOptions,\n} from \"./types\";\n\ntype ResponseStreamEvent<TEvent> = TEvent | ResumableStreamEnvelope<TEvent>;\n\ntype EventStreamResponseOptions<TEvent> = {\n format?: EventStreamFormat;\n headers?: HeadersInit;\n status?: number;\n statusText?: string;\n jsonl?: JsonlStreamOptions<ResponseStreamEvent<TEvent>>;\n sse?: SseStreamOptions<ResponseStreamEvent<TEvent>>;\n};\n\nexport function createEventStreamResponse<TEvent>(\n options: CreateEventStreamResponseOptions<TEvent> & { events: AsyncIterable<TEvent> },\n): Response {\n const eventsForResponse: AsyncIterable<ResponseStreamEvent<TEvent>> =\n options.resumable === undefined\n ? (options.events as AsyncIterable<ResponseStreamEvent<TEvent>>)\n : createResumableStream({ events: options.events, ...options.resumable });\n\n return encodeEventStreamResponse({\n events: eventsForResponse,\n ...copyResponseOptions(options),\n });\n}\n\nexport function resumeEventStreamResponse<TEvent>(\n options: ResumeEventStreamResponseOptions<TEvent>,\n): Response {\n return encodeEventStreamResponse({\n events: resumeStreamEvents({\n id: options.streamId,\n after: options.after,\n store: options.store,\n }),\n ...copyResponseOptions(options),\n });\n}\n\nexport function encodeEventStreamResponse<TEvent>(\n options: EventStreamResponseOptions<TEvent> & {\n events: AsyncIterable<ResponseStreamEvent<TEvent>>;\n },\n): Response {\n const format = options.format ?? \"jsonl\";\n const headers = new Headers(options.headers);\n\n if (!headers.has(\"cache-control\")) {\n headers.set(\"cache-control\", \"no-cache, no-transform\");\n }\n if (!headers.has(\"connection\")) {\n headers.set(\"connection\", \"keep-alive\");\n }\n if (!headers.has(\"x-accel-buffering\")) {\n headers.set(\"x-accel-buffering\", \"no\");\n }\n\n const body =\n format === \"sse\"\n ? createSseStream({ events: options.events, ...options.sse })\n : createJsonlStream({ events: options.events, ...options.jsonl });\n\n if (!headers.has(\"content-type\")) {\n headers.set(\n \"content-type\",\n format === \"sse\" ? \"text/event-stream; charset=utf-8\" : \"application/x-ndjson; charset=utf-8\",\n );\n }\n\n const responseInit: ResponseInit = { headers };\n if (options.status !== undefined) {\n responseInit.status = options.status;\n }\n if (options.statusText !== undefined) {\n responseInit.statusText = options.statusText;\n }\n\n return new Response(body, responseInit);\n}\n\nfunction copyResponseOptions<TEvent>(options: {\n format?: EventStreamFormat;\n headers?: HeadersInit;\n status?: number;\n statusText?: string;\n jsonl?: unknown;\n sse?: unknown;\n}): EventStreamResponseOptions<TEvent> {\n const next: EventStreamResponseOptions<TEvent> = {};\n if (options.format !== undefined) next.format = options.format;\n if (options.headers !== undefined) next.headers = options.headers;\n if (options.status !== undefined) next.status = options.status;\n if (options.statusText !== undefined) next.statusText = options.statusText;\n if (options.jsonl !== undefined) {\n next.jsonl = options.jsonl as JsonlStreamOptions<ResponseStreamEvent<TEvent>>;\n }\n if (options.sse !== undefined) {\n next.sse = options.sse as SseStreamOptions<ResponseStreamEvent<TEvent>>;\n }\n return next;\n}\n"],"mappings":"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","names":["serializeJson"]}
@@ -0,0 +1,24 @@
1
+ import { DurableRuntime } from '@anvia/durable';
2
+
3
+ type DurableHttpAction = "list" | "submit" | "inspect" | "events" | "respond" | "resolve-tool" | "retry" | "cancel" | "signal" | "resolve-effect";
4
+ type DurableAuthorization = {
5
+ action: DurableHttpAction;
6
+ sessionId: string;
7
+ runId?: string;
8
+ agentId?: string;
9
+ graphId?: string;
10
+ taskId?: string;
11
+ rootTaskId?: string;
12
+ taskName?: string;
13
+ };
14
+ type DurableHandlerOptions = {
15
+ runtime: DurableRuntime;
16
+ /** Authenticate and authorize every operation, including reads. Deny by returning false. */
17
+ authorize: (request: Request, resource: DurableAuthorization) => boolean | Promise<boolean>;
18
+ basePath?: string;
19
+ maxBodyBytes?: number;
20
+ };
21
+ /** Fetch-compatible routes. The application owns runtime startup, shutdown, and authentication. */
22
+ declare function createDurableHandler(options: DurableHandlerOptions): (request: Request) => Promise<Response>;
23
+
24
+ export { type DurableAuthorization, type DurableHandlerOptions, type DurableHttpAction, createDurableHandler };