@anvia/server 1.1.5 → 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 +19 -0
- package/dist/chunk-E2M7MXTL.js +450 -0
- package/dist/chunk-E2M7MXTL.js.map +1 -0
- package/dist/durable.d.ts +24 -0
- package/dist/durable.js +330 -0
- package/dist/durable.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +12 -430
- package/dist/index.js.map +1 -1
- package/package.json +15 -4
package/dist/durable.js
ADDED
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createEventStreamResponse
|
|
3
|
+
} from "./chunk-E2M7MXTL.js";
|
|
4
|
+
|
|
5
|
+
// src/durable-task.ts
|
|
6
|
+
import {
|
|
7
|
+
parseTaskSubmission,
|
|
8
|
+
parseTaskListOptions,
|
|
9
|
+
parseTaskSignal,
|
|
10
|
+
parseTaskResolution
|
|
11
|
+
} from "@anvia/durable/protocol";
|
|
12
|
+
|
|
13
|
+
// src/durable-http.ts
|
|
14
|
+
function jsonResponse(value, status = 200) {
|
|
15
|
+
return Response.json(value, { status, headers: { "cache-control": "no-store" } });
|
|
16
|
+
}
|
|
17
|
+
function listQuery(url) {
|
|
18
|
+
const query = {};
|
|
19
|
+
for (const [key, value] of url.searchParams) {
|
|
20
|
+
if (Object.hasOwn(query, key)) throw new TypeError("Duplicate query parameter.");
|
|
21
|
+
if (key === "after" || key === "limit") {
|
|
22
|
+
if (!/^\d+$/.test(value)) throw new TypeError("Invalid pagination.");
|
|
23
|
+
query[key] = Number(value);
|
|
24
|
+
} else query[key] = value;
|
|
25
|
+
}
|
|
26
|
+
return query;
|
|
27
|
+
}
|
|
28
|
+
function durableEventsResponse(request, cursor, stream) {
|
|
29
|
+
const url = new URL(request.url);
|
|
30
|
+
const rawCursor = url.searchParams.get("after") ?? request.headers.get("last-event-id") ?? "0";
|
|
31
|
+
if (!/^\d+$/.test(rawCursor)) throw new TypeError("Invalid event cursor.");
|
|
32
|
+
const after = Number(rawCursor);
|
|
33
|
+
if (!Number.isSafeInteger(after) || after > cursor) throw new TypeError("Invalid event cursor.");
|
|
34
|
+
const detached = new AbortController();
|
|
35
|
+
const signal = AbortSignal.any([request.signal, detached.signal]);
|
|
36
|
+
return createEventStreamResponse({
|
|
37
|
+
events: stream({ after, abortSignal: signal }),
|
|
38
|
+
format: "sse",
|
|
39
|
+
headers: { "cache-control": "no-store, no-transform" },
|
|
40
|
+
sse: {
|
|
41
|
+
eventName: "durable",
|
|
42
|
+
eventId: (event) => "sequence" in event ? String(event.sequence) : void 0,
|
|
43
|
+
serialize: (event) => JSON.stringify(
|
|
44
|
+
"sequence" in event ? event : { type: "error", error: "Durable stream interrupted." }
|
|
45
|
+
),
|
|
46
|
+
onCancel: () => {
|
|
47
|
+
detached.abort(new Error("Durable subscriber disconnected."));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
var HttpInputError = class extends Error {
|
|
53
|
+
constructor(status, message) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.status = status;
|
|
56
|
+
}
|
|
57
|
+
status;
|
|
58
|
+
};
|
|
59
|
+
async function readJson(request, maxBytes) {
|
|
60
|
+
if (request.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() !== "application/json")
|
|
61
|
+
throw new HttpInputError(415, "Expected application/json");
|
|
62
|
+
if (request.body === null) throw new HttpInputError(400, "Expected a JSON body");
|
|
63
|
+
const reader = request.body.getReader();
|
|
64
|
+
const decoder = new TextDecoder();
|
|
65
|
+
let bytes = 0;
|
|
66
|
+
let text = "";
|
|
67
|
+
try {
|
|
68
|
+
while (true) {
|
|
69
|
+
const next = await reader.read();
|
|
70
|
+
if (next.done) break;
|
|
71
|
+
bytes += next.value.byteLength;
|
|
72
|
+
if (bytes > maxBytes) {
|
|
73
|
+
await reader.cancel();
|
|
74
|
+
throw new HttpInputError(413, "Durable request body is too large");
|
|
75
|
+
}
|
|
76
|
+
text += decoder.decode(next.value, { stream: true });
|
|
77
|
+
}
|
|
78
|
+
text += decoder.decode();
|
|
79
|
+
return JSON.parse(text);
|
|
80
|
+
} finally {
|
|
81
|
+
reader.releaseLock();
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// src/durable-task.ts
|
|
86
|
+
async function handleDurableTaskRequest(options, request, base, maxBytes) {
|
|
87
|
+
const url = new URL(request.url);
|
|
88
|
+
const path = `${base}/tasks`;
|
|
89
|
+
if (url.pathname !== path && !url.pathname.startsWith(`${path}/`)) return void 0;
|
|
90
|
+
const parts = url.pathname.slice(path.length).split("/").filter(Boolean).map(decodeURIComponent);
|
|
91
|
+
const runtime = options.runtime;
|
|
92
|
+
const authorize = async (task, action2) => {
|
|
93
|
+
const agent = task.agentRunId === void 0 ? void 0 : runtime.runScope(task.agentRunId).agentId;
|
|
94
|
+
if (!await options.authorize(request, {
|
|
95
|
+
action: action2,
|
|
96
|
+
sessionId: task.sessionId,
|
|
97
|
+
taskId: task.id,
|
|
98
|
+
rootTaskId: task.rootId,
|
|
99
|
+
taskName: task.name,
|
|
100
|
+
...agent === void 0 ? {} : { agentId: agent, runId: task.agentRunId }
|
|
101
|
+
}))
|
|
102
|
+
throw new HttpInputError(403, "Forbidden");
|
|
103
|
+
};
|
|
104
|
+
if (parts.length === 0) {
|
|
105
|
+
if (request.method === "POST") {
|
|
106
|
+
const input = parseTaskSubmission(await readJson(request, maxBytes));
|
|
107
|
+
if (!await options.authorize(request, {
|
|
108
|
+
action: "submit",
|
|
109
|
+
sessionId: input.sessionId,
|
|
110
|
+
taskName: input.name
|
|
111
|
+
}))
|
|
112
|
+
throw new HttpInputError(403, "Forbidden");
|
|
113
|
+
return jsonResponse(await (await runtime.submitRegisteredTask(input)).snapshot(), 202);
|
|
114
|
+
}
|
|
115
|
+
if (request.method === "GET") {
|
|
116
|
+
const filter = parseTaskListOptions(listQuery(url));
|
|
117
|
+
if (filter.sessionId === void 0) throw new TypeError("Listing requires sessionId.");
|
|
118
|
+
if (!await options.authorize(request, { action: "list", sessionId: filter.sessionId }))
|
|
119
|
+
throw new HttpInputError(403, "Forbidden");
|
|
120
|
+
const page = await runtime.listTasks(filter);
|
|
121
|
+
for (const task of page.tasks) await authorize(task, "list");
|
|
122
|
+
return jsonResponse(page);
|
|
123
|
+
}
|
|
124
|
+
return jsonResponse({ error: "Method not allowed" }, 405);
|
|
125
|
+
}
|
|
126
|
+
const suffix = parts[1];
|
|
127
|
+
if (parts.length > 2 || suffix !== void 0 && !["graph", "events", "signal", "resolve-effect", "retry", "cancel"].includes(suffix))
|
|
128
|
+
return jsonResponse({ error: "Not found" }, 404);
|
|
129
|
+
const action = suffix === void 0 || suffix === "graph" ? "inspect" : suffix;
|
|
130
|
+
if (request.method !== (["inspect", "events"].includes(action) ? "GET" : "POST"))
|
|
131
|
+
return jsonResponse({ error: "Method not allowed" }, 405);
|
|
132
|
+
const handle = await runtime.getTask(parts[0]);
|
|
133
|
+
const snapshot = await handle.snapshot();
|
|
134
|
+
await authorize(snapshot.task, action);
|
|
135
|
+
if (suffix === void 0) return jsonResponse(snapshot);
|
|
136
|
+
if (suffix === "graph" || suffix === "events" || suffix === "cancel") {
|
|
137
|
+
const graph = await handle.graph();
|
|
138
|
+
for (const task of graph.nodes) await authorize(task, action);
|
|
139
|
+
if (suffix === "graph") return jsonResponse(graph);
|
|
140
|
+
if (suffix === "cancel") {
|
|
141
|
+
await handle.cancel({ expectedTreeIds: graph.nodes.map((task) => task.id) });
|
|
142
|
+
return new Response(null, { status: 204, headers: { "cache-control": "no-store" } });
|
|
143
|
+
}
|
|
144
|
+
if (suffix === "events")
|
|
145
|
+
return durableEventsResponse(request, graph.cursor, async function* (streamOptions) {
|
|
146
|
+
for await (const event of handle.stream(streamOptions)) {
|
|
147
|
+
const task = (await (await runtime.getTask(event.taskId)).snapshot()).task;
|
|
148
|
+
await authorize(task, "events");
|
|
149
|
+
yield event;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
if (suffix === "signal") {
|
|
154
|
+
const body = parseTaskSignal(await readJson(request, maxBytes));
|
|
155
|
+
await handle.signal(body.name, body.requestId, body.value);
|
|
156
|
+
} else if (suffix === "resolve-effect") {
|
|
157
|
+
const body = parseTaskResolution(await readJson(request, maxBytes));
|
|
158
|
+
await handle.resolveEffect(body.key, body.value);
|
|
159
|
+
} else if (suffix === "retry") await handle.retry();
|
|
160
|
+
return new Response(null, { status: 204, headers: { "cache-control": "no-store" } });
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// src/durable.ts
|
|
164
|
+
import {
|
|
165
|
+
DurableConflictError,
|
|
166
|
+
DurableNotFoundError,
|
|
167
|
+
DurableLimitError,
|
|
168
|
+
DurableStorageError
|
|
169
|
+
} from "@anvia/durable";
|
|
170
|
+
import {
|
|
171
|
+
parseDurableListOptions,
|
|
172
|
+
parseDurableResolution,
|
|
173
|
+
parseDurableResponse,
|
|
174
|
+
parseDurableSubmission
|
|
175
|
+
} from "@anvia/durable/protocol";
|
|
176
|
+
|
|
177
|
+
// src/durable-graph.ts
|
|
178
|
+
import { parseDurableGraphSubmission, parseDurableGraphListOptions } from "@anvia/durable/protocol";
|
|
179
|
+
async function handleDurableGraphRequest(options, request, basePath, maxBodyBytes) {
|
|
180
|
+
const url = new URL(request.url);
|
|
181
|
+
const root = `${basePath}/graphs`;
|
|
182
|
+
if (url.pathname !== root && !url.pathname.startsWith(`${root}/`)) return void 0;
|
|
183
|
+
const parts = url.pathname.slice(root.length).split("/").filter(Boolean).map(decodeURIComponent);
|
|
184
|
+
if (parts.length === 0) {
|
|
185
|
+
if (request.method === "GET") {
|
|
186
|
+
const filter = parseDurableGraphListOptions(listQuery(url));
|
|
187
|
+
if (filter.sessionId === void 0) throw new TypeError("Listing graphs requires sessionId.");
|
|
188
|
+
if (!await options.authorize(request, { action: "list", sessionId: filter.sessionId }))
|
|
189
|
+
return jsonResponse({ error: "Forbidden" }, 403);
|
|
190
|
+
return jsonResponse(await options.runtime.listGraphs(filter));
|
|
191
|
+
}
|
|
192
|
+
if (request.method === "POST") {
|
|
193
|
+
const input = parseDurableGraphSubmission(await readJson(request, maxBodyBytes));
|
|
194
|
+
for (const task of input.tasks) {
|
|
195
|
+
if (!await options.authorize(request, {
|
|
196
|
+
action: "submit",
|
|
197
|
+
sessionId: input.sessionId,
|
|
198
|
+
taskId: task.id,
|
|
199
|
+
agentId: task.agentId
|
|
200
|
+
}))
|
|
201
|
+
return jsonResponse({ error: "Forbidden" }, 403);
|
|
202
|
+
}
|
|
203
|
+
const graph2 = await options.runtime.submitGraph(input);
|
|
204
|
+
return jsonResponse(await graph2.snapshot(), 202);
|
|
205
|
+
}
|
|
206
|
+
return jsonResponse({ error: "Method not allowed" }, 405);
|
|
207
|
+
}
|
|
208
|
+
if (parts.length > 2 || parts[1] !== void 0 && parts[1] !== "events" && parts[1] !== "cancel")
|
|
209
|
+
return jsonResponse({ error: "Not found" }, 404);
|
|
210
|
+
const action = parts[1] ?? "inspect";
|
|
211
|
+
if (request.method !== (action === "cancel" ? "POST" : "GET"))
|
|
212
|
+
return jsonResponse({ error: "Method not allowed" }, 405);
|
|
213
|
+
const graph = await options.runtime.getGraph(parts[0]);
|
|
214
|
+
const snapshot = await graph.snapshot();
|
|
215
|
+
for (const node of snapshot.nodes) {
|
|
216
|
+
if (!await options.authorize(request, {
|
|
217
|
+
action,
|
|
218
|
+
sessionId: snapshot.sessionId,
|
|
219
|
+
graphId: snapshot.id,
|
|
220
|
+
runId: node.runId,
|
|
221
|
+
taskId: node.id,
|
|
222
|
+
agentId: node.agentId
|
|
223
|
+
}))
|
|
224
|
+
return jsonResponse({ error: "Forbidden" }, 403);
|
|
225
|
+
}
|
|
226
|
+
if (action === "inspect") return jsonResponse(snapshot);
|
|
227
|
+
if (action === "events")
|
|
228
|
+
return durableEventsResponse(request, snapshot.cursor, (options2) => graph.stream(options2));
|
|
229
|
+
await graph.cancel();
|
|
230
|
+
return new Response(null, { status: 204, headers: { "cache-control": "no-store" } });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// src/durable.ts
|
|
234
|
+
function createDurableHandler(options) {
|
|
235
|
+
const basePath = options.basePath ?? "/durable";
|
|
236
|
+
if (!basePath.startsWith("/") || basePath.endsWith("/") || /[?#]/.test(basePath))
|
|
237
|
+
throw new TypeError("basePath must be an absolute path without a trailing slash.");
|
|
238
|
+
if (typeof options.authorize !== "function")
|
|
239
|
+
throw new TypeError("Durable routes require authorize.");
|
|
240
|
+
const maxBodyBytes = options.maxBodyBytes ?? 65536;
|
|
241
|
+
if (!Number.isSafeInteger(maxBodyBytes) || maxBodyBytes < 1)
|
|
242
|
+
throw new TypeError("Invalid body limit.");
|
|
243
|
+
const runtime = options.runtime;
|
|
244
|
+
const json = jsonResponse;
|
|
245
|
+
const denied = () => json({ error: "Forbidden" }, 403);
|
|
246
|
+
return async (request) => {
|
|
247
|
+
try {
|
|
248
|
+
const url = new URL(request.url);
|
|
249
|
+
const taskResponse = await handleDurableTaskRequest(options, request, basePath, maxBodyBytes);
|
|
250
|
+
if (taskResponse !== void 0) return taskResponse;
|
|
251
|
+
const graphResponse = await handleDurableGraphRequest(
|
|
252
|
+
options,
|
|
253
|
+
request,
|
|
254
|
+
basePath,
|
|
255
|
+
maxBodyBytes
|
|
256
|
+
);
|
|
257
|
+
if (graphResponse !== void 0) return graphResponse;
|
|
258
|
+
if (url.pathname !== `${basePath}/runs` && !url.pathname.startsWith(`${basePath}/runs/`))
|
|
259
|
+
return json({ error: "Not found" }, 404);
|
|
260
|
+
const parts = url.pathname.slice(`${basePath}/runs`.length).split("/").filter(Boolean).map(decodeURIComponent);
|
|
261
|
+
if (parts.length === 0) {
|
|
262
|
+
if (request.method === "GET") {
|
|
263
|
+
const filter = parseDurableListOptions(listQuery(url));
|
|
264
|
+
if (filter.sessionId === void 0) throw new TypeError("Listing requires sessionId.");
|
|
265
|
+
if (!await options.authorize(request, { action: "list", sessionId: filter.sessionId }))
|
|
266
|
+
return denied();
|
|
267
|
+
const page = await runtime.listRuns(filter);
|
|
268
|
+
for (const run2 of page.runs)
|
|
269
|
+
if (!await options.authorize(request, { action: "list", ...runtime.runScope(run2.id) }))
|
|
270
|
+
return denied();
|
|
271
|
+
return json(page);
|
|
272
|
+
}
|
|
273
|
+
if (request.method === "POST") {
|
|
274
|
+
const { enqueue, ...submission } = parseDurableSubmission(
|
|
275
|
+
await readJson(request, maxBodyBytes)
|
|
276
|
+
);
|
|
277
|
+
if (!await options.authorize(request, {
|
|
278
|
+
action: "submit",
|
|
279
|
+
sessionId: submission.sessionId,
|
|
280
|
+
agentId: submission.agentId
|
|
281
|
+
}))
|
|
282
|
+
return denied();
|
|
283
|
+
const run2 = await runtime.submit(submission, enqueue === void 0 ? {} : { enqueue });
|
|
284
|
+
return json(await run2.snapshot(), 202);
|
|
285
|
+
}
|
|
286
|
+
return json({ error: "Method not allowed" }, 405);
|
|
287
|
+
}
|
|
288
|
+
const id = parts[0];
|
|
289
|
+
const suffix = parts[1];
|
|
290
|
+
if (parts.length > 2 || suffix !== void 0 && !["events", "respond", "resolve-tool", "retry", "cancel"].includes(suffix))
|
|
291
|
+
return json({ error: "Not found" }, 404);
|
|
292
|
+
const action = suffix === void 0 ? "inspect" : suffix;
|
|
293
|
+
const method = action === "inspect" || action === "events" ? "GET" : "POST";
|
|
294
|
+
if (request.method !== method) return json({ error: "Method not allowed" }, 405);
|
|
295
|
+
const run = await runtime.getRun(id);
|
|
296
|
+
const snapshot = await run.snapshot();
|
|
297
|
+
if (!await options.authorize(request, { action, ...runtime.runScope(id) })) return denied();
|
|
298
|
+
if (action === "inspect") return json(snapshot);
|
|
299
|
+
if (action === "events")
|
|
300
|
+
return durableEventsResponse(request, snapshot.cursor, (options2) => run.stream(options2));
|
|
301
|
+
if (action === "respond") {
|
|
302
|
+
const body = parseDurableResponse(await readJson(request, maxBodyBytes));
|
|
303
|
+
await run.respond(body.interactionId, body.response);
|
|
304
|
+
} else if (action === "resolve-tool") {
|
|
305
|
+
const body = parseDurableResolution(await readJson(request, maxBodyBytes));
|
|
306
|
+
await run.resolveTool(body.operationId, body.output);
|
|
307
|
+
} else if (action === "retry") {
|
|
308
|
+
await run.retry();
|
|
309
|
+
} else if (action === "cancel") {
|
|
310
|
+
await run.cancel();
|
|
311
|
+
}
|
|
312
|
+
return new Response(null, { status: 204, headers: { "cache-control": "no-store" } });
|
|
313
|
+
} catch (error) {
|
|
314
|
+
if (error instanceof HttpInputError) return json({ error: error.message }, error.status);
|
|
315
|
+
if (error instanceof DurableNotFoundError)
|
|
316
|
+
return json({ error: "Durable resource not found" }, 404);
|
|
317
|
+
if (error instanceof DurableLimitError) return json({ error: error.message }, 429);
|
|
318
|
+
if (error instanceof DurableStorageError)
|
|
319
|
+
return json({ error: "Durable runtime unavailable" }, 503);
|
|
320
|
+
if (error instanceof DurableConflictError) return json({ error: error.message }, 409);
|
|
321
|
+
if (error instanceof TypeError || error instanceof SyntaxError || error instanceof URIError)
|
|
322
|
+
return json({ error: "Invalid durable request" }, 400);
|
|
323
|
+
return json({ error: "Durable request failed" }, 500);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
export {
|
|
328
|
+
createDurableHandler
|
|
329
|
+
};
|
|
330
|
+
//# sourceMappingURL=durable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/durable-task.ts","../src/durable-http.ts","../src/durable.ts","../src/durable-graph.ts"],"sourcesContent":["import {\n parseTaskSubmission,\n parseTaskListOptions,\n parseTaskSignal,\n parseTaskResolution,\n} from \"@anvia/durable/protocol\";\nimport type { TaskRecord } from \"@anvia/durable\";\nimport type { DurableHandlerOptions, DurableHttpAction } from \"./durable\";\nimport {\n durableEventsResponse,\n HttpInputError,\n jsonResponse,\n listQuery,\n readJson,\n} from \"./durable-http\";\n\nexport async function handleDurableTaskRequest(\n options: DurableHandlerOptions,\n request: Request,\n base: string,\n maxBytes: number,\n): Promise<Response | undefined> {\n const url = new URL(request.url);\n const path = `${base}/tasks`;\n if (url.pathname !== path && !url.pathname.startsWith(`${path}/`)) return undefined;\n const parts = url.pathname.slice(path.length).split(\"/\").filter(Boolean).map(decodeURIComponent);\n const runtime = options.runtime;\n const authorize = async (task: TaskRecord, action: DurableHttpAction) => {\n const agent =\n task.agentRunId === undefined ? undefined : runtime.runScope(task.agentRunId).agentId;\n if (\n !(await options.authorize(request, {\n action,\n sessionId: task.sessionId,\n taskId: task.id,\n rootTaskId: task.rootId,\n taskName: task.name,\n ...(agent === undefined ? {} : { agentId: agent, runId: task.agentRunId! }),\n }))\n )\n throw new HttpInputError(403, \"Forbidden\");\n };\n if (parts.length === 0) {\n if (request.method === \"POST\") {\n const input = parseTaskSubmission(await readJson(request, maxBytes));\n if (\n !(await options.authorize(request, {\n action: \"submit\",\n sessionId: input.sessionId,\n taskName: input.name,\n }))\n )\n throw new HttpInputError(403, \"Forbidden\");\n return jsonResponse(await (await runtime.submitRegisteredTask(input)).snapshot(), 202);\n }\n if (request.method === \"GET\") {\n const filter = parseTaskListOptions(listQuery(url));\n if (filter.sessionId === undefined) throw new TypeError(\"Listing requires sessionId.\");\n if (!(await options.authorize(request, { action: \"list\", sessionId: filter.sessionId })))\n throw new HttpInputError(403, \"Forbidden\");\n const page = await runtime.listTasks(filter);\n for (const task of page.tasks) await authorize(task, \"list\");\n return jsonResponse(page);\n }\n return jsonResponse({ error: \"Method not allowed\" }, 405);\n }\n const suffix = parts[1];\n if (\n parts.length > 2 ||\n (suffix !== undefined &&\n ![\"graph\", \"events\", \"signal\", \"resolve-effect\", \"retry\", \"cancel\"].includes(suffix))\n )\n return jsonResponse({ error: \"Not found\" }, 404);\n const action =\n suffix === undefined || suffix === \"graph\" ? \"inspect\" : (suffix as DurableHttpAction);\n if (request.method !== ([\"inspect\", \"events\"].includes(action) ? \"GET\" : \"POST\"))\n return jsonResponse({ error: \"Method not allowed\" }, 405);\n const handle = await runtime.getTask(parts[0]!);\n const snapshot = await handle.snapshot();\n await authorize(snapshot.task, action);\n if (suffix === undefined) return jsonResponse(snapshot);\n if (suffix === \"graph\" || suffix === \"events\" || suffix === \"cancel\") {\n const graph = await handle.graph();\n for (const task of graph.nodes) await authorize(task, action);\n if (suffix === \"graph\") return jsonResponse(graph);\n if (suffix === \"cancel\") {\n await handle.cancel({ expectedTreeIds: graph.nodes.map((task) => task.id) });\n return new Response(null, { status: 204, headers: { \"cache-control\": \"no-store\" } });\n }\n if (suffix === \"events\")\n return durableEventsResponse(request, graph.cursor, async function* (streamOptions) {\n for await (const event of handle.stream(streamOptions)) {\n // Children may be created after attachment; authorize each record before exposing its event.\n const task = (await (await runtime.getTask(event.taskId)).snapshot()).task;\n await authorize(task, \"events\");\n yield event;\n }\n });\n }\n if (suffix === \"signal\") {\n const body = parseTaskSignal(await readJson(request, maxBytes));\n await handle.signal(body.name, body.requestId, body.value);\n } else if (suffix === \"resolve-effect\") {\n const body = parseTaskResolution(await readJson(request, maxBytes));\n await handle.resolveEffect(body.key, body.value);\n } else if (suffix === \"retry\") await handle.retry();\n return new Response(null, { status: 204, headers: { \"cache-control\": \"no-store\" } });\n}\n","import { createEventStreamResponse } from \"./response\";\n\nexport function jsonResponse(value: unknown, status = 200): Response {\n return Response.json(value, { status, headers: { \"cache-control\": \"no-store\" } });\n}\nexport function listQuery(url: URL): Record<string, unknown> {\n const query: Record<string, unknown> = {};\n for (const [key, value] of url.searchParams) {\n if (Object.hasOwn(query, key)) throw new TypeError(\"Duplicate query parameter.\");\n if (key === \"after\" || key === \"limit\") {\n if (!/^\\d+$/.test(value)) throw new TypeError(\"Invalid pagination.\");\n query[key] = Number(value);\n } else query[key] = value;\n }\n return query;\n}\nexport function durableEventsResponse<T extends { sequence: number }>(\n request: Request,\n cursor: number,\n stream: (options: { after: number; abortSignal: AbortSignal }) => AsyncIterable<T>,\n): Response {\n const url = new URL(request.url);\n const rawCursor = url.searchParams.get(\"after\") ?? request.headers.get(\"last-event-id\") ?? \"0\";\n if (!/^\\d+$/.test(rawCursor)) throw new TypeError(\"Invalid event cursor.\");\n const after = Number(rawCursor);\n if (!Number.isSafeInteger(after) || after > cursor) throw new TypeError(\"Invalid event cursor.\");\n const detached = new AbortController();\n const signal = AbortSignal.any([request.signal, detached.signal]);\n return createEventStreamResponse({\n events: stream({ after, abortSignal: signal }),\n format: \"sse\",\n headers: { \"cache-control\": \"no-store, no-transform\" },\n sse: {\n eventName: \"durable\",\n eventId: (event) => (\"sequence\" in event ? String(event.sequence) : undefined),\n serialize: (event) =>\n JSON.stringify(\n \"sequence\" in event ? event : { type: \"error\", error: \"Durable stream interrupted.\" },\n ),\n onCancel: () => {\n detached.abort(new Error(\"Durable subscriber disconnected.\"));\n },\n },\n });\n}\n\nexport class HttpInputError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nexport async function readJson(request: Request, maxBytes: number): Promise<unknown> {\n if (\n request.headers.get(\"content-type\")?.split(\";\")[0]?.trim().toLowerCase() !== \"application/json\"\n )\n throw new HttpInputError(415, \"Expected application/json\");\n if (request.body === null) throw new HttpInputError(400, \"Expected a JSON body\");\n const reader = request.body.getReader();\n const decoder = new TextDecoder();\n let bytes = 0;\n let text = \"\";\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) break;\n bytes += next.value.byteLength;\n if (bytes > maxBytes) {\n await reader.cancel();\n throw new HttpInputError(413, \"Durable request body is too large\");\n }\n text += decoder.decode(next.value, { stream: true });\n }\n text += decoder.decode();\n return JSON.parse(text) as unknown;\n } finally {\n reader.releaseLock();\n }\n}\n","import { handleDurableTaskRequest } from \"./durable-task\";\nimport {\n DurableConflictError,\n DurableNotFoundError,\n DurableLimitError,\n DurableStorageError,\n type DurableRuntime,\n} from \"@anvia/durable\";\nimport {\n parseDurableListOptions,\n parseDurableResolution,\n parseDurableResponse,\n parseDurableSubmission,\n} from \"@anvia/durable/protocol\";\nimport {\n durableEventsResponse,\n HttpInputError,\n jsonResponse,\n listQuery,\n readJson,\n} from \"./durable-http\";\nimport { handleDurableGraphRequest } from \"./durable-graph\";\n\nexport type DurableHttpAction =\n | \"list\"\n | \"submit\"\n | \"inspect\"\n | \"events\"\n | \"respond\"\n | \"resolve-tool\"\n | \"retry\"\n | \"cancel\"\n | \"signal\"\n | \"resolve-effect\";\nexport type DurableAuthorization = {\n action: DurableHttpAction;\n sessionId: string;\n runId?: string;\n agentId?: string;\n graphId?: string;\n taskId?: string;\n rootTaskId?: string;\n taskName?: string;\n};\nexport type DurableHandlerOptions = {\n runtime: DurableRuntime;\n /** Authenticate and authorize every operation, including reads. Deny by returning false. */\n authorize: (request: Request, resource: DurableAuthorization) => boolean | Promise<boolean>;\n basePath?: string;\n maxBodyBytes?: number;\n};\n\n/** Fetch-compatible routes. The application owns runtime startup, shutdown, and authentication. */\nexport function createDurableHandler(\n options: DurableHandlerOptions,\n): (request: Request) => Promise<Response> {\n const basePath = options.basePath ?? \"/durable\";\n if (!basePath.startsWith(\"/\") || basePath.endsWith(\"/\") || /[?#]/.test(basePath))\n throw new TypeError(\"basePath must be an absolute path without a trailing slash.\");\n if (typeof options.authorize !== \"function\")\n throw new TypeError(\"Durable routes require authorize.\");\n const maxBodyBytes = options.maxBodyBytes ?? 65_536;\n if (!Number.isSafeInteger(maxBodyBytes) || maxBodyBytes < 1)\n throw new TypeError(\"Invalid body limit.\");\n const runtime = options.runtime;\n const json = jsonResponse;\n const denied = () => json({ error: \"Forbidden\" }, 403);\n\n return async (request) => {\n try {\n const url = new URL(request.url);\n const taskResponse = await handleDurableTaskRequest(options, request, basePath, maxBodyBytes);\n if (taskResponse !== undefined) return taskResponse;\n const graphResponse = await handleDurableGraphRequest(\n options,\n request,\n basePath,\n maxBodyBytes,\n );\n if (graphResponse !== undefined) return graphResponse;\n if (url.pathname !== `${basePath}/runs` && !url.pathname.startsWith(`${basePath}/runs/`))\n return json({ error: \"Not found\" }, 404);\n const parts = url.pathname\n .slice(`${basePath}/runs`.length)\n .split(\"/\")\n .filter(Boolean)\n .map(decodeURIComponent);\n if (parts.length === 0) {\n if (request.method === \"GET\") {\n const filter = parseDurableListOptions(listQuery(url));\n if (filter.sessionId === undefined) throw new TypeError(\"Listing requires sessionId.\");\n if (!(await options.authorize(request, { action: \"list\", sessionId: filter.sessionId })))\n return denied();\n const page = await runtime.listRuns(filter);\n for (const run of page.runs)\n if (\n !(await options.authorize(request, { action: \"list\", ...runtime.runScope(run.id) }))\n )\n return denied();\n return json(page);\n }\n if (request.method === \"POST\") {\n const { enqueue, ...submission } = parseDurableSubmission(\n await readJson(request, maxBodyBytes),\n );\n if (\n !(await options.authorize(request, {\n action: \"submit\",\n sessionId: submission.sessionId,\n agentId: submission.agentId,\n }))\n )\n return denied();\n const run = await runtime.submit(submission, enqueue === undefined ? {} : { enqueue });\n return json(await run.snapshot(), 202);\n }\n return json({ error: \"Method not allowed\" }, 405);\n }\n const id = parts[0]!;\n const suffix = parts[1];\n if (\n parts.length > 2 ||\n (suffix !== undefined &&\n ![\"events\", \"respond\", \"resolve-tool\", \"retry\", \"cancel\"].includes(suffix))\n )\n return json({ error: \"Not found\" }, 404);\n const action: DurableHttpAction =\n suffix === undefined ? \"inspect\" : (suffix as DurableHttpAction);\n const method = action === \"inspect\" || action === \"events\" ? \"GET\" : \"POST\";\n if (request.method !== method) return json({ error: \"Method not allowed\" }, 405);\n const run = await runtime.getRun(id);\n const snapshot = await run.snapshot();\n if (!(await options.authorize(request, { action, ...runtime.runScope(id) }))) return denied();\n if (action === \"inspect\") return json(snapshot);\n if (action === \"events\")\n return durableEventsResponse(request, snapshot.cursor, (options) => run.stream(options));\n if (action === \"respond\") {\n const body = parseDurableResponse(await readJson(request, maxBodyBytes));\n await run.respond(body.interactionId, body.response);\n } else if (action === \"resolve-tool\") {\n const body = parseDurableResolution(await readJson(request, maxBodyBytes));\n await run.resolveTool(body.operationId, body.output);\n } else if (action === \"retry\") {\n await run.retry();\n } else if (action === \"cancel\") {\n await run.cancel();\n }\n return new Response(null, { status: 204, headers: { \"cache-control\": \"no-store\" } });\n } catch (error) {\n if (error instanceof HttpInputError) return json({ error: error.message }, error.status);\n if (error instanceof DurableNotFoundError)\n return json({ error: \"Durable resource not found\" }, 404);\n if (error instanceof DurableLimitError) return json({ error: error.message }, 429);\n if (error instanceof DurableStorageError)\n return json({ error: \"Durable runtime unavailable\" }, 503);\n if (error instanceof DurableConflictError) return json({ error: error.message }, 409);\n if (error instanceof TypeError || error instanceof SyntaxError || error instanceof URIError)\n return json({ error: \"Invalid durable request\" }, 400);\n return json({ error: \"Durable request failed\" }, 500);\n }\n };\n}\n","import { parseDurableGraphSubmission, parseDurableGraphListOptions } from \"@anvia/durable/protocol\";\nimport type { DurableHandlerOptions, DurableHttpAction } from \"./durable\";\nimport { durableEventsResponse, jsonResponse as json, listQuery, readJson } from \"./durable-http\";\n\n/** Graph reads and mutations require access to every node they expose or affect. */\nexport async function handleDurableGraphRequest(\n options: DurableHandlerOptions,\n request: Request,\n basePath: string,\n maxBodyBytes: number,\n): Promise<Response | undefined> {\n const url = new URL(request.url);\n const root = `${basePath}/graphs`;\n if (url.pathname !== root && !url.pathname.startsWith(`${root}/`)) return undefined;\n const parts = url.pathname.slice(root.length).split(\"/\").filter(Boolean).map(decodeURIComponent);\n if (parts.length === 0) {\n if (request.method === \"GET\") {\n const filter = parseDurableGraphListOptions(listQuery(url));\n if (filter.sessionId === undefined) throw new TypeError(\"Listing graphs requires sessionId.\");\n if (!(await options.authorize(request, { action: \"list\", sessionId: filter.sessionId })))\n return json({ error: \"Forbidden\" }, 403);\n return json(await options.runtime.listGraphs(filter));\n }\n if (request.method === \"POST\") {\n const input = parseDurableGraphSubmission(await readJson(request, maxBodyBytes));\n for (const task of input.tasks) {\n if (\n !(await options.authorize(request, {\n action: \"submit\",\n sessionId: input.sessionId,\n taskId: task.id,\n agentId: task.agentId,\n }))\n )\n return json({ error: \"Forbidden\" }, 403);\n }\n const graph = await options.runtime.submitGraph(input);\n return json(await graph.snapshot(), 202);\n }\n return json({ error: \"Method not allowed\" }, 405);\n }\n if (\n parts.length > 2 ||\n (parts[1] !== undefined && parts[1] !== \"events\" && parts[1] !== \"cancel\")\n )\n return json({ error: \"Not found\" }, 404);\n const action: DurableHttpAction = parts[1] ?? \"inspect\";\n if (request.method !== (action === \"cancel\" ? \"POST\" : \"GET\"))\n return json({ error: \"Method not allowed\" }, 405);\n const graph = await options.runtime.getGraph(parts[0]!);\n const snapshot = await graph.snapshot();\n for (const node of snapshot.nodes) {\n if (\n !(await options.authorize(request, {\n action,\n sessionId: snapshot.sessionId,\n graphId: snapshot.id,\n runId: node.runId,\n taskId: node.id,\n agentId: node.agentId,\n }))\n )\n return json({ error: \"Forbidden\" }, 403);\n }\n if (action === \"inspect\") return json(snapshot);\n if (action === \"events\")\n return durableEventsResponse(request, snapshot.cursor, (options) => graph.stream(options));\n await graph.cancel();\n return new Response(null, { status: 204, headers: { \"cache-control\": \"no-store\" } });\n}\n"],"mappings":"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","names":["action","graph","options","run","options"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -29,6 +29,9 @@ type JsonlStreamOptions<TEvent> = {
|
|
|
29
29
|
serialize?: (event: TEvent | EventStreamErrorEvent) => string;
|
|
30
30
|
};
|
|
31
31
|
type SseStreamOptions<TEvent> = {
|
|
32
|
+
eventId?: (event: TEvent | EventStreamErrorEvent) => string | undefined;
|
|
33
|
+
/** Interrupt a pending producer read before returning its iterator on disconnect. */
|
|
34
|
+
onCancel?: () => void | Promise<void>;
|
|
32
35
|
eventName?: string | ((event: TEvent | EventStreamErrorEvent) => string | undefined);
|
|
33
36
|
serialize?: (event: TEvent | EventStreamErrorEvent) => string;
|
|
34
37
|
retry?: number;
|