@darqlabs/curator-sdk 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/LICENSE +21 -0
- package/README.md +313 -0
- package/dist/cjs/client.d.ts +174 -0
- package/dist/cjs/client.d.ts.map +1 -0
- package/dist/cjs/client.js +417 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/errors.d.ts +91 -0
- package/dist/cjs/errors.d.ts.map +1 -0
- package/dist/cjs/errors.js +131 -0
- package/dist/cjs/errors.js.map +1 -0
- package/dist/cjs/files.d.ts +66 -0
- package/dist/cjs/files.d.ts.map +1 -0
- package/dist/cjs/files.js +86 -0
- package/dist/cjs/files.js.map +1 -0
- package/dist/cjs/http.d.ts +92 -0
- package/dist/cjs/http.d.ts.map +1 -0
- package/dist/cjs/http.js +232 -0
- package/dist/cjs/http.js.map +1 -0
- package/dist/cjs/index.d.ts +10 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +22 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/sse.d.ts +20 -0
- package/dist/cjs/sse.d.ts.map +1 -0
- package/dist/cjs/sse.js +89 -0
- package/dist/cjs/sse.js.map +1 -0
- package/dist/cjs/streamEventParse.d.ts +13 -0
- package/dist/cjs/streamEventParse.d.ts.map +1 -0
- package/dist/cjs/streamEventParse.js +81 -0
- package/dist/cjs/streamEventParse.js.map +1 -0
- package/dist/cjs/streamEvents.d.ts +58 -0
- package/dist/cjs/streamEvents.d.ts.map +1 -0
- package/dist/cjs/streamEvents.js +22 -0
- package/dist/cjs/streamEvents.js.map +1 -0
- package/dist/cjs/types.d.ts +93 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +10 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/client.d.ts +174 -0
- package/dist/esm/client.d.ts.map +1 -0
- package/dist/esm/client.js +411 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/errors.d.ts +91 -0
- package/dist/esm/errors.d.ts.map +1 -0
- package/dist/esm/errors.js +119 -0
- package/dist/esm/errors.js.map +1 -0
- package/dist/esm/files.d.ts +66 -0
- package/dist/esm/files.d.ts.map +1 -0
- package/dist/esm/files.js +82 -0
- package/dist/esm/files.js.map +1 -0
- package/dist/esm/http.d.ts +92 -0
- package/dist/esm/http.d.ts.map +1 -0
- package/dist/esm/http.js +228 -0
- package/dist/esm/http.js.map +1 -0
- package/dist/esm/index.d.ts +10 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/sse.d.ts +20 -0
- package/dist/esm/sse.d.ts.map +1 -0
- package/dist/esm/sse.js +86 -0
- package/dist/esm/sse.js.map +1 -0
- package/dist/esm/streamEventParse.d.ts +13 -0
- package/dist/esm/streamEventParse.d.ts.map +1 -0
- package/dist/esm/streamEventParse.js +78 -0
- package/dist/esm/streamEventParse.js.map +1 -0
- package/dist/esm/streamEvents.d.ts +58 -0
- package/dist/esm/streamEvents.d.ts.map +1 -0
- package/dist/esm/streamEvents.js +19 -0
- package/dist/esm/streamEvents.js.map +1 -0
- package/dist/esm/types.d.ts +93 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +9 -0
- package/dist/esm/types.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-upload surface for the Curator SDK.
|
|
3
|
+
*
|
|
4
|
+
* curator.files.createUpload({ filename, mimeType, size })
|
|
5
|
+
* // → { uploadUrl, headers, fileReference, expiresAt }
|
|
6
|
+
* // caller PUTs bytes to `uploadUrl`, then passes `fileReference`
|
|
7
|
+
* // into chat.send(..., { files: [fileReference] })
|
|
8
|
+
*
|
|
9
|
+
* curator.files.upload({ filename, mimeType, data })
|
|
10
|
+
* // one-shot convenience: presign + PUT + return fileReference
|
|
11
|
+
*
|
|
12
|
+
* Both helpers go through `POST /api/files/presign-upload`. The
|
|
13
|
+
* resulting upload URL is a short-lived V4 signed URL straight to the
|
|
14
|
+
* underlying object store — file bytes never round-trip through the
|
|
15
|
+
* Curator API.
|
|
16
|
+
*/
|
|
17
|
+
import type { HttpClient } from "./http.js";
|
|
18
|
+
import type { FileAttachment } from "./types.js";
|
|
19
|
+
export interface PresignUploadInput {
|
|
20
|
+
filename: string;
|
|
21
|
+
mimeType: string;
|
|
22
|
+
/** File size in bytes. Required by the server for validation. */
|
|
23
|
+
size: number;
|
|
24
|
+
}
|
|
25
|
+
export interface PresignUploadResult {
|
|
26
|
+
/** PUT bytes here. Single header to set: see `headers`. */
|
|
27
|
+
uploadUrl: string;
|
|
28
|
+
method: "PUT";
|
|
29
|
+
/** Headers the upload MUST include verbatim. The signature binds them. */
|
|
30
|
+
headers: Record<string, string>;
|
|
31
|
+
/** ISO timestamp the signed URL stops working. */
|
|
32
|
+
expiresAt: string;
|
|
33
|
+
/** Pass into `chat.send(..., { files: [...] })` after the upload completes. */
|
|
34
|
+
fileReference: FileAttachment;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Anything we can stuff into a `fetch` PUT body. Browsers prefer Blob /
|
|
38
|
+
* File; Node accepts Buffer / Uint8Array (Node 18+ fetch).
|
|
39
|
+
*/
|
|
40
|
+
export type UploadData = Blob | ArrayBuffer | ArrayBufferView | Uint8Array;
|
|
41
|
+
export interface OneShotUploadInput {
|
|
42
|
+
filename: string;
|
|
43
|
+
mimeType: string;
|
|
44
|
+
data: UploadData;
|
|
45
|
+
/** Optional — inferred from `data` when omitted. */
|
|
46
|
+
size?: number;
|
|
47
|
+
}
|
|
48
|
+
export declare class Files {
|
|
49
|
+
private readonly http;
|
|
50
|
+
private readonly baseUrl;
|
|
51
|
+
private readonly fetchImpl;
|
|
52
|
+
constructor(http: HttpClient, baseUrl: string, fetchImpl: typeof fetch);
|
|
53
|
+
/**
|
|
54
|
+
* Two-step flow. Returns the signed PUT URL plus the `fileReference`
|
|
55
|
+
* you'll later hand to `chat.send`. The caller is responsible for
|
|
56
|
+
* doing the actual upload.
|
|
57
|
+
*/
|
|
58
|
+
createUpload(input: PresignUploadInput): Promise<PresignUploadResult>;
|
|
59
|
+
/**
|
|
60
|
+
* One-shot helper: presign, PUT the bytes, return the file reference
|
|
61
|
+
* ready to attach to a message. Use this when you have the file
|
|
62
|
+
* bytes in hand and don't need progress tracking.
|
|
63
|
+
*/
|
|
64
|
+
upload(input: OneShotUploadInput): Promise<FileAttachment>;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,mBAAmB;IAClC,2DAA2D;IAC3D,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,KAAK,CAAA;IACb,0EAA0E;IAC1E,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAA;IACjB,+EAA+E;IAC/E,aAAa,EAAE,cAAc,CAAA;CAC9B;AAED;;;GAGG;AACH,MAAM,MAAM,UAAU,GAClB,IAAI,GACJ,WAAW,GACX,eAAe,GACf,UAAU,CAAA;AAEd,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,UAAU,CAAA;IAChB,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,qBAAa,KAAK;IAEd,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,SAAS;gBAFT,IAAI,EAAE,UAAU,EAChB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,OAAO,KAAK;IAG1C;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiB3E;;;;OAIG;IACG,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC;CAsBjE"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-upload surface for the Curator SDK.
|
|
3
|
+
*
|
|
4
|
+
* curator.files.createUpload({ filename, mimeType, size })
|
|
5
|
+
* // → { uploadUrl, headers, fileReference, expiresAt }
|
|
6
|
+
* // caller PUTs bytes to `uploadUrl`, then passes `fileReference`
|
|
7
|
+
* // into chat.send(..., { files: [fileReference] })
|
|
8
|
+
*
|
|
9
|
+
* curator.files.upload({ filename, mimeType, data })
|
|
10
|
+
* // one-shot convenience: presign + PUT + return fileReference
|
|
11
|
+
*
|
|
12
|
+
* Both helpers go through `POST /api/files/presign-upload`. The
|
|
13
|
+
* resulting upload URL is a short-lived V4 signed URL straight to the
|
|
14
|
+
* underlying object store — file bytes never round-trip through the
|
|
15
|
+
* Curator API.
|
|
16
|
+
*/
|
|
17
|
+
import { CuratorError } from "./errors.js";
|
|
18
|
+
export class Files {
|
|
19
|
+
http;
|
|
20
|
+
baseUrl;
|
|
21
|
+
fetchImpl;
|
|
22
|
+
constructor(http, baseUrl, fetchImpl) {
|
|
23
|
+
this.http = http;
|
|
24
|
+
this.baseUrl = baseUrl;
|
|
25
|
+
this.fetchImpl = fetchImpl;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Two-step flow. Returns the signed PUT URL plus the `fileReference`
|
|
29
|
+
* you'll later hand to `chat.send`. The caller is responsible for
|
|
30
|
+
* doing the actual upload.
|
|
31
|
+
*/
|
|
32
|
+
async createUpload(input) {
|
|
33
|
+
if (!input.filename)
|
|
34
|
+
throw new CuratorError("`filename` is required.");
|
|
35
|
+
if (!input.mimeType)
|
|
36
|
+
throw new CuratorError("`mimeType` is required.");
|
|
37
|
+
if (!Number.isFinite(input.size) || input.size <= 0) {
|
|
38
|
+
throw new CuratorError("`size` must be a positive number of bytes.");
|
|
39
|
+
}
|
|
40
|
+
return this.http.request(`${this.baseUrl}/api/files/presign-upload`, {
|
|
41
|
+
method: "POST",
|
|
42
|
+
body: {
|
|
43
|
+
filename: input.filename,
|
|
44
|
+
mimeType: input.mimeType,
|
|
45
|
+
size: input.size,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* One-shot helper: presign, PUT the bytes, return the file reference
|
|
51
|
+
* ready to attach to a message. Use this when you have the file
|
|
52
|
+
* bytes in hand and don't need progress tracking.
|
|
53
|
+
*/
|
|
54
|
+
async upload(input) {
|
|
55
|
+
const size = input.size ?? sizeOf(input.data);
|
|
56
|
+
const presigned = await this.createUpload({
|
|
57
|
+
filename: input.filename,
|
|
58
|
+
mimeType: input.mimeType,
|
|
59
|
+
size,
|
|
60
|
+
});
|
|
61
|
+
const putResponse = await this.fetchImpl(presigned.uploadUrl, {
|
|
62
|
+
method: presigned.method,
|
|
63
|
+
headers: presigned.headers,
|
|
64
|
+
body: input.data,
|
|
65
|
+
});
|
|
66
|
+
if (!putResponse.ok) {
|
|
67
|
+
const text = await putResponse.text().catch(() => "");
|
|
68
|
+
throw new CuratorError(`Upload failed with status ${putResponse.status}${text ? `: ${text}` : ""}`);
|
|
69
|
+
}
|
|
70
|
+
return presigned.fileReference;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function sizeOf(data) {
|
|
74
|
+
if (typeof Blob !== "undefined" && data instanceof Blob)
|
|
75
|
+
return data.size;
|
|
76
|
+
if (data instanceof ArrayBuffer)
|
|
77
|
+
return data.byteLength;
|
|
78
|
+
if (ArrayBuffer.isView(data))
|
|
79
|
+
return data.byteLength;
|
|
80
|
+
throw new CuratorError("Could not determine `size` from data — pass `size` explicitly.");
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/files.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAyC1C,MAAM,OAAO,KAAK;IAEG;IACA;IACA;IAHnB,YACmB,IAAgB,EAChB,OAAe,EACf,SAAuB;QAFvB,SAAI,GAAJ,IAAI,CAAY;QAChB,YAAO,GAAP,OAAO,CAAQ;QACf,cAAS,GAAT,SAAS,CAAc;IACvC,CAAC;IAEJ;;;;OAIG;IACH,KAAK,CAAC,YAAY,CAAC,KAAyB;QAC1C,IAAI,CAAC,KAAK,CAAC,QAAQ;YAAE,MAAM,IAAI,YAAY,CAAC,yBAAyB,CAAC,CAAA;QACtE,IAAI,CAAC,KAAK,CAAC,QAAQ;YAAE,MAAM,IAAI,YAAY,CAAC,yBAAyB,CAAC,CAAA;QACtE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,IAAI,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,YAAY,CAAC,4CAA4C,CAAC,CAAA;QACtE,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAsB,GAAG,IAAI,CAAC,OAAO,2BAA2B,EAAE;YACxF,MAAM,EAAE,MAAM;YACd,IAAI,EAAE;gBACJ,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,IAAI,EAAE,KAAK,CAAC,IAAI;aACjB;SACF,CAAC,CAAA;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,MAAM,CAAC,KAAyB;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC7C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC;YACxC,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,IAAI;SACL,CAAC,CAAA;QAEF,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,SAAS,EAAE;YAC5D,MAAM,EAAE,SAAS,CAAC,MAAM;YACxB,OAAO,EAAE,SAAS,CAAC,OAAO;YAC1B,IAAI,EAAE,KAAK,CAAC,IAAgB;SAC7B,CAAC,CAAA;QACF,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YACpB,MAAM,IAAI,GAAG,MAAM,WAAW,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAA;YACrD,MAAM,IAAI,YAAY,CACpB,6BAA6B,WAAW,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAC5E,CAAA;QACH,CAAC;QAED,OAAO,SAAS,CAAC,aAAa,CAAA;IAChC,CAAC;CACF;AAED,SAAS,MAAM,CAAC,IAAgB;IAC9B,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,YAAY,IAAI;QAAE,OAAO,IAAI,CAAC,IAAI,CAAA;IACzE,IAAI,IAAI,YAAY,WAAW;QAAE,OAAO,IAAI,CAAC,UAAU,CAAA;IACvD,IAAI,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,UAAU,CAAA;IACpD,MAAM,IAAI,YAAY,CAAC,gEAAgE,CAAC,CAAA;AAC1F,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin HTTP layer the SDK uses to talk to the Curator API.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Attach the `Authorization: Bearer curator_<live|test>_*` header.
|
|
6
|
+
* - Resolve the right URL family for project-scoped vs system-scoped
|
|
7
|
+
* deployments.
|
|
8
|
+
* - Translate HTTP failures into typed SDK errors so callers don't
|
|
9
|
+
* branch on status codes.
|
|
10
|
+
*
|
|
11
|
+
* Everything else (retries, conversation state, waiting) lives in the
|
|
12
|
+
* higher-level classes that consume this transport.
|
|
13
|
+
*/
|
|
14
|
+
import type { Environment } from "./types.js";
|
|
15
|
+
/**
|
|
16
|
+
* Per-deployment routing. The SDK supports the two URL families the
|
|
17
|
+
* backend exposes:
|
|
18
|
+
* - project-scoped, env-aware: /api/projects/<slug>/environments/<env>/deployments/<slug>
|
|
19
|
+
* - system-scoped: /api/deployments/<slug>
|
|
20
|
+
*/
|
|
21
|
+
export interface DeploymentRoute {
|
|
22
|
+
kind: "project" | "system";
|
|
23
|
+
/** Required for `kind === 'project'`. */
|
|
24
|
+
project?: string;
|
|
25
|
+
/** Required for `kind === 'project'`. */
|
|
26
|
+
environment?: Environment;
|
|
27
|
+
deployment: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* End-user JWT — a short-lived token minted by the customer's backend that
|
|
31
|
+
* proves which user on their platform is currently driving the agent. The
|
|
32
|
+
* SDK passes it through as `X-Curator-End-User-JWT` and the Curator backend
|
|
33
|
+
* verifies it against the org's configured JWKS. See the end-user JWT plan.
|
|
34
|
+
*
|
|
35
|
+
* Accepts either:
|
|
36
|
+
* - a static string (caller refreshes by re-creating the client), or
|
|
37
|
+
* - a sync/async function the SDK calls per-request (typical for browsers
|
|
38
|
+
* that mint a fresh short-lived JWT via their backend on each turn).
|
|
39
|
+
*/
|
|
40
|
+
export type EndUserJwtProvider = string | (() => string | Promise<string> | null | undefined);
|
|
41
|
+
export interface HttpClientOptions {
|
|
42
|
+
apiKey: string;
|
|
43
|
+
baseUrl: string;
|
|
44
|
+
/** Custom fetch implementation — defaults to global `fetch`. */
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
/** Extra headers attached to every request (e.g. tracing). */
|
|
47
|
+
defaultHeaders?: Record<string, string>;
|
|
48
|
+
/**
|
|
49
|
+
* End-user JWT — see {@link EndUserJwtProvider}. Optional. When set and
|
|
50
|
+
* resolved to a non-empty string, the SDK attaches the
|
|
51
|
+
* `X-Curator-End-User-JWT` header to every request.
|
|
52
|
+
*/
|
|
53
|
+
endUserJwt?: EndUserJwtProvider;
|
|
54
|
+
}
|
|
55
|
+
export interface RequestOptions {
|
|
56
|
+
method?: "GET" | "POST" | "DELETE";
|
|
57
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
58
|
+
body?: unknown;
|
|
59
|
+
/** Per-request fetch timeout, in ms. Aborts via AbortController. */
|
|
60
|
+
signalTimeoutMs?: number;
|
|
61
|
+
}
|
|
62
|
+
export declare class HttpClient {
|
|
63
|
+
private readonly apiKey;
|
|
64
|
+
private readonly baseUrl;
|
|
65
|
+
private readonly fetchImpl;
|
|
66
|
+
private readonly defaultHeaders;
|
|
67
|
+
private readonly endUserJwtProvider?;
|
|
68
|
+
constructor(opts: HttpClientOptions);
|
|
69
|
+
/** Build the URL prefix for a given deployment route. */
|
|
70
|
+
deploymentBase(route: DeploymentRoute): string;
|
|
71
|
+
/**
|
|
72
|
+
* Resolve the end-user JWT for this request. Resolves to `undefined`
|
|
73
|
+
* when no provider was configured or the provider returns falsy — the
|
|
74
|
+
* caller skips attaching the header in that case. Wraps function
|
|
75
|
+
* provider exceptions in a `CuratorError` so callers see a single
|
|
76
|
+
* error type regardless of whether the failure was network or token-mint.
|
|
77
|
+
*/
|
|
78
|
+
private resolveEndUserJwt;
|
|
79
|
+
/**
|
|
80
|
+
* Issue a streaming POST and return the open response. Throws typed
|
|
81
|
+
* errors on a non-2xx status (consuming the error body for the
|
|
82
|
+
* message); on 2xx, hands back the live `Response` so the caller can
|
|
83
|
+
* read `response.body` as a `ReadableStream`.
|
|
84
|
+
*/
|
|
85
|
+
streamPost(url: string, opts?: {
|
|
86
|
+
body?: unknown;
|
|
87
|
+
query?: RequestOptions["query"];
|
|
88
|
+
signal?: AbortSignal;
|
|
89
|
+
}): Promise<Response>;
|
|
90
|
+
request<T>(url: string, opts?: RequestOptions): Promise<T>;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AAE7C;;;;;GAKG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC1B,yCAAyC;IACzC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yCAAyC;IACzC,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;;;;;;;GAUG;AACH,MAAM,MAAM,kBAAkB,GAC1B,MAAM,GACN,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAEvD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,gEAAgE;IAChE,KAAK,CAAC,EAAE,OAAO,KAAK,CAAA;IACpB,8DAA8D;IAC9D,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC;;;;OAIG;IACH,UAAU,CAAC,EAAE,kBAAkB,CAAA;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAA;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAA;IAC7D,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,oEAAoE;IACpE,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAC/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAc;IACxC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAoB;gBAE5C,IAAI,EAAE,iBAAiB;IAsBnC,yDAAyD;IACzD,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM;IAgB9C;;;;;;OAMG;YACW,iBAAiB;IAe/B;;;;;OAKG;IACG,UAAU,CACd,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,WAAW,CAAA;KAAO,GACnF,OAAO,CAAC,QAAQ,CAAC;IAyCd,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,CAAC,CAAC;CAmDrE"}
|
package/dist/esm/http.js
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin HTTP layer the SDK uses to talk to the Curator API.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Attach the `Authorization: Bearer curator_<live|test>_*` header.
|
|
6
|
+
* - Resolve the right URL family for project-scoped vs system-scoped
|
|
7
|
+
* deployments.
|
|
8
|
+
* - Translate HTTP failures into typed SDK errors so callers don't
|
|
9
|
+
* branch on status codes.
|
|
10
|
+
*
|
|
11
|
+
* Everything else (retries, conversation state, waiting) lives in the
|
|
12
|
+
* higher-level classes that consume this transport.
|
|
13
|
+
*/
|
|
14
|
+
import { CuratorAuthError, CuratorDeploymentRetiredError, CuratorError, CuratorForbiddenError, CuratorNotFoundError, CuratorRateLimitError, } from "./errors.js";
|
|
15
|
+
export class HttpClient {
|
|
16
|
+
apiKey;
|
|
17
|
+
baseUrl;
|
|
18
|
+
fetchImpl;
|
|
19
|
+
defaultHeaders;
|
|
20
|
+
endUserJwtProvider;
|
|
21
|
+
constructor(opts) {
|
|
22
|
+
if (!opts.apiKey) {
|
|
23
|
+
throw new CuratorError("`apiKey` is required to construct the Curator client.");
|
|
24
|
+
}
|
|
25
|
+
this.apiKey = opts.apiKey;
|
|
26
|
+
this.baseUrl = stripTrailingSlash(opts.baseUrl);
|
|
27
|
+
this.endUserJwtProvider = opts.endUserJwt;
|
|
28
|
+
// Bind the global fetch to its host (`window` in browsers, `globalThis`
|
|
29
|
+
// in Node). Without this, browsers throw "Illegal invocation" because
|
|
30
|
+
// the unbound fetch reference is later called via `this.fetchImpl(...)`
|
|
31
|
+
// with the HttpClient instance as `this`. Caller-supplied fetches are
|
|
32
|
+
// assumed to already be bound (or to be arrow-style wrappers).
|
|
33
|
+
const globalFetch = globalThis.fetch;
|
|
34
|
+
this.fetchImpl = opts.fetch ?? (globalFetch ? globalFetch.bind(globalThis) : undefined);
|
|
35
|
+
if (!this.fetchImpl) {
|
|
36
|
+
throw new CuratorError("No global fetch found. Pass `fetch` explicitly in the SDK options on Node < 18 or in a runtime that lacks it.");
|
|
37
|
+
}
|
|
38
|
+
this.defaultHeaders = { ...opts.defaultHeaders };
|
|
39
|
+
}
|
|
40
|
+
/** Build the URL prefix for a given deployment route. */
|
|
41
|
+
deploymentBase(route) {
|
|
42
|
+
if (route.kind === "project") {
|
|
43
|
+
if (!route.project || !route.environment) {
|
|
44
|
+
throw new CuratorError("Project-scoped deployment requires both `project` and `environment`.");
|
|
45
|
+
}
|
|
46
|
+
const project = encodeURIComponent(route.project);
|
|
47
|
+
const env = encodeURIComponent(route.environment);
|
|
48
|
+
const slug = encodeURIComponent(route.deployment);
|
|
49
|
+
return `${this.baseUrl}/api/projects/${project}/environments/${env}/deployments/${slug}`;
|
|
50
|
+
}
|
|
51
|
+
const slug = encodeURIComponent(route.deployment);
|
|
52
|
+
return `${this.baseUrl}/api/deployments/${slug}`;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Resolve the end-user JWT for this request. Resolves to `undefined`
|
|
56
|
+
* when no provider was configured or the provider returns falsy — the
|
|
57
|
+
* caller skips attaching the header in that case. Wraps function
|
|
58
|
+
* provider exceptions in a `CuratorError` so callers see a single
|
|
59
|
+
* error type regardless of whether the failure was network or token-mint.
|
|
60
|
+
*/
|
|
61
|
+
async resolveEndUserJwt() {
|
|
62
|
+
const p = this.endUserJwtProvider;
|
|
63
|
+
if (!p)
|
|
64
|
+
return undefined;
|
|
65
|
+
if (typeof p === "string")
|
|
66
|
+
return p || undefined;
|
|
67
|
+
try {
|
|
68
|
+
const value = await p();
|
|
69
|
+
return value || undefined;
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
throw new CuratorError(`Failed to obtain end-user JWT: ${err.message}`, { cause: err });
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Issue a streaming POST and return the open response. Throws typed
|
|
77
|
+
* errors on a non-2xx status (consuming the error body for the
|
|
78
|
+
* message); on 2xx, hands back the live `Response` so the caller can
|
|
79
|
+
* read `response.body` as a `ReadableStream`.
|
|
80
|
+
*/
|
|
81
|
+
async streamPost(url, opts = {}) {
|
|
82
|
+
const finalUrl = appendQuery(url, opts.query);
|
|
83
|
+
const headers = {
|
|
84
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
85
|
+
Accept: "text/event-stream",
|
|
86
|
+
...this.defaultHeaders,
|
|
87
|
+
};
|
|
88
|
+
if (opts.body !== undefined) {
|
|
89
|
+
headers["Content-Type"] = "application/json";
|
|
90
|
+
}
|
|
91
|
+
const endUserJwt = await this.resolveEndUserJwt();
|
|
92
|
+
if (endUserJwt) {
|
|
93
|
+
headers["X-Curator-End-User-JWT"] = endUserJwt;
|
|
94
|
+
}
|
|
95
|
+
let response;
|
|
96
|
+
try {
|
|
97
|
+
response = await this.fetchImpl(finalUrl, {
|
|
98
|
+
method: "POST",
|
|
99
|
+
headers,
|
|
100
|
+
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
101
|
+
signal: opts.signal,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (err) {
|
|
105
|
+
throw new CuratorError(`Network error talking to ${finalUrl}: ${err.message}`, { cause: err });
|
|
106
|
+
}
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
const text = await response.text().catch(() => "");
|
|
109
|
+
const body = text ? safeJsonParse(text) : undefined;
|
|
110
|
+
throw httpError(response.status, body, finalUrl);
|
|
111
|
+
}
|
|
112
|
+
if (!response.body) {
|
|
113
|
+
throw new CuratorError(`Streaming response had no body (${finalUrl})`);
|
|
114
|
+
}
|
|
115
|
+
return response;
|
|
116
|
+
}
|
|
117
|
+
async request(url, opts = {}) {
|
|
118
|
+
const finalUrl = appendQuery(url, opts.query);
|
|
119
|
+
const headers = {
|
|
120
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
121
|
+
Accept: "application/json",
|
|
122
|
+
...this.defaultHeaders,
|
|
123
|
+
};
|
|
124
|
+
if (opts.body !== undefined) {
|
|
125
|
+
headers["Content-Type"] = "application/json";
|
|
126
|
+
}
|
|
127
|
+
const endUserJwt = await this.resolveEndUserJwt();
|
|
128
|
+
if (endUserJwt) {
|
|
129
|
+
headers["X-Curator-End-User-JWT"] = endUserJwt;
|
|
130
|
+
}
|
|
131
|
+
const controller = opts.signalTimeoutMs ? new AbortController() : null;
|
|
132
|
+
const timer = controller
|
|
133
|
+
? setTimeout(() => controller.abort(), opts.signalTimeoutMs)
|
|
134
|
+
: null;
|
|
135
|
+
let response;
|
|
136
|
+
try {
|
|
137
|
+
response = await this.fetchImpl(finalUrl, {
|
|
138
|
+
method: opts.method ?? "GET",
|
|
139
|
+
headers,
|
|
140
|
+
body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined,
|
|
141
|
+
signal: controller?.signal,
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
throw new CuratorError(`Network error talking to ${finalUrl}: ${err.message}`, { cause: err });
|
|
146
|
+
}
|
|
147
|
+
finally {
|
|
148
|
+
if (timer)
|
|
149
|
+
clearTimeout(timer);
|
|
150
|
+
}
|
|
151
|
+
if (response.status === 204) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
const text = await response.text();
|
|
155
|
+
const body = text ? safeJsonParse(text) : undefined;
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
throw httpError(response.status, body, finalUrl);
|
|
158
|
+
}
|
|
159
|
+
return body ?? undefined;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function stripTrailingSlash(s) {
|
|
163
|
+
return s.replace(/\/+$/, "");
|
|
164
|
+
}
|
|
165
|
+
function appendQuery(url, query) {
|
|
166
|
+
if (!query)
|
|
167
|
+
return url;
|
|
168
|
+
const params = new URLSearchParams();
|
|
169
|
+
for (const [key, value] of Object.entries(query)) {
|
|
170
|
+
if (value === undefined || value === null)
|
|
171
|
+
continue;
|
|
172
|
+
params.append(key, String(value));
|
|
173
|
+
}
|
|
174
|
+
const qs = params.toString();
|
|
175
|
+
if (!qs)
|
|
176
|
+
return url;
|
|
177
|
+
return url.includes("?") ? `${url}&${qs}` : `${url}?${qs}`;
|
|
178
|
+
}
|
|
179
|
+
function safeJsonParse(text) {
|
|
180
|
+
try {
|
|
181
|
+
return JSON.parse(text);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return text;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function httpError(status, body, url) {
|
|
188
|
+
const detail = readErrorMessage(body);
|
|
189
|
+
switch (status) {
|
|
190
|
+
case 401:
|
|
191
|
+
return new CuratorAuthError(detail ?? "Invalid or revoked API key");
|
|
192
|
+
case 403:
|
|
193
|
+
return new CuratorForbiddenError(detail ?? "Permission denied");
|
|
194
|
+
case 404:
|
|
195
|
+
return new CuratorNotFoundError(detail ?? "Resource not found");
|
|
196
|
+
case 410: {
|
|
197
|
+
const retiredAt = body && typeof body === "object" && "details" in body
|
|
198
|
+
? (body.details
|
|
199
|
+
?.retired_at ?? null)
|
|
200
|
+
: null;
|
|
201
|
+
return new CuratorDeploymentRetiredError(detail ?? "Deployment has been retired", retiredAt);
|
|
202
|
+
}
|
|
203
|
+
case 429: {
|
|
204
|
+
const retry = body && typeof body === "object" && "retryAfter" in body
|
|
205
|
+
? Number(body.retryAfter)
|
|
206
|
+
: null;
|
|
207
|
+
return new CuratorRateLimitError(detail ?? undefined, Number.isFinite(retry) ? retry : null);
|
|
208
|
+
}
|
|
209
|
+
default:
|
|
210
|
+
return new CuratorError(`HTTP ${status} from ${url}${detail ? `: ${detail}` : ""}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function readErrorMessage(body) {
|
|
214
|
+
if (!body || typeof body !== "object")
|
|
215
|
+
return undefined;
|
|
216
|
+
const b = body;
|
|
217
|
+
if (typeof b.error === "string")
|
|
218
|
+
return b.error;
|
|
219
|
+
if (b.error && typeof b.error === "object") {
|
|
220
|
+
const inner = b.error;
|
|
221
|
+
if (typeof inner.message === "string")
|
|
222
|
+
return inner.message;
|
|
223
|
+
}
|
|
224
|
+
if (typeof b.message === "string")
|
|
225
|
+
return b.message;
|
|
226
|
+
return undefined;
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/http.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { Curator, Agent, Chat } from "./client.js";
|
|
2
|
+
export type { CuratorOptions, AgentLocator } from "./client.js";
|
|
3
|
+
export type { EndUserJwtProvider } from "./http.js";
|
|
4
|
+
export { Files } from "./files.js";
|
|
5
|
+
export type { PresignUploadInput, PresignUploadResult, OneShotUploadInput, UploadData, } from "./files.js";
|
|
6
|
+
export { CuratorError, CuratorAuthError, CuratorForbiddenError, CuratorNotFoundError, CuratorDeploymentRetiredError, CuratorRateLimitError, CuratorApprovalRequiredError, CuratorAgentError, CuratorTimeoutError, } from "./errors.js";
|
|
7
|
+
export type { AssistantMessage, UserMessage, ToolMessage, ConversationMessage, Environment, FileAttachment, ApprovalDetails, AgentFailureClass, SendOptions, HistoryOptions, HistoryPage, DeploymentConfig, } from "./types.js";
|
|
8
|
+
export type { StreamEvent, StreamDelta, StreamToolCallStarted, StreamToolCallCompleted, StreamDone, StreamError, StreamPausedForApproval, } from "./streamEvents.js";
|
|
9
|
+
export { isTerminalStreamEvent } from "./streamEvents.js";
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/D,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAA;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAClC,YAAY,EACV,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,GACX,MAAM,YAAY,CAAA;AACnB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,WAAW,EACX,mBAAmB,EACnB,WAAW,EACX,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,WAAW,EACX,gBAAgB,GACjB,MAAM,YAAY,CAAA;AACnB,YAAY,EACV,WAAW,EACX,WAAW,EACX,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,WAAW,EACX,uBAAuB,GACxB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Curator, Agent, Chat } from "./client.js";
|
|
2
|
+
export { Files } from "./files.js";
|
|
3
|
+
export { CuratorError, CuratorAuthError, CuratorForbiddenError, CuratorNotFoundError, CuratorDeploymentRetiredError, CuratorRateLimitError, CuratorApprovalRequiredError, CuratorAgentError, CuratorTimeoutError, } from "./errors.js";
|
|
4
|
+
export { isTerminalStreamEvent } from "./streamEvents.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAGlD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAOlC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACpB,6BAA6B,EAC7B,qBAAqB,EACrB,4BAA4B,EAC5B,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,aAAa,CAAA;AAwBpB,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny SSE parser.
|
|
3
|
+
*
|
|
4
|
+
* Reads a `ReadableStream<Uint8Array>` (the body returned by `fetch`)
|
|
5
|
+
* and yields SSE frames as `{ event, data }`. Spec essentials: lines
|
|
6
|
+
* separated by `\n` (or `\r\n`), blank line terminates a message,
|
|
7
|
+
* `event:` and `data:` fields are accumulated until the terminator,
|
|
8
|
+
* `:` lines are comments and ignored. We don't track ids or retries —
|
|
9
|
+
* not needed for the wait-for-terminal use case.
|
|
10
|
+
*
|
|
11
|
+
* Used by Chat.stream() to turn the backend's SSE response into typed
|
|
12
|
+
* stream events.
|
|
13
|
+
*/
|
|
14
|
+
export interface SseFrame {
|
|
15
|
+
event: string;
|
|
16
|
+
/** Raw JSON string (or empty when the field was absent). */
|
|
17
|
+
data: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function parseSseStream(stream: ReadableStream<Uint8Array>): AsyncIterable<SseFrame>;
|
|
20
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/sse.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAA;CACb;AAED,wBAAuB,cAAc,CACnC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,aAAa,CAAC,QAAQ,CAAC,CAoCzB"}
|
package/dist/esm/sse.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tiny SSE parser.
|
|
3
|
+
*
|
|
4
|
+
* Reads a `ReadableStream<Uint8Array>` (the body returned by `fetch`)
|
|
5
|
+
* and yields SSE frames as `{ event, data }`. Spec essentials: lines
|
|
6
|
+
* separated by `\n` (or `\r\n`), blank line terminates a message,
|
|
7
|
+
* `event:` and `data:` fields are accumulated until the terminator,
|
|
8
|
+
* `:` lines are comments and ignored. We don't track ids or retries —
|
|
9
|
+
* not needed for the wait-for-terminal use case.
|
|
10
|
+
*
|
|
11
|
+
* Used by Chat.stream() to turn the backend's SSE response into typed
|
|
12
|
+
* stream events.
|
|
13
|
+
*/
|
|
14
|
+
export async function* parseSseStream(stream) {
|
|
15
|
+
const reader = stream.getReader();
|
|
16
|
+
const decoder = new TextDecoder("utf-8");
|
|
17
|
+
let buffer = "";
|
|
18
|
+
try {
|
|
19
|
+
while (true) {
|
|
20
|
+
const { value, done } = await reader.read();
|
|
21
|
+
if (done)
|
|
22
|
+
break;
|
|
23
|
+
buffer += decoder.decode(value, { stream: true });
|
|
24
|
+
// Split on blank-line terminators (either \n\n or \r\n\r\n). The
|
|
25
|
+
// last chunk in the buffer may be a partial frame; we keep it for
|
|
26
|
+
// the next read.
|
|
27
|
+
let boundary = findBoundary(buffer);
|
|
28
|
+
while (boundary !== -1) {
|
|
29
|
+
const rawFrame = buffer.slice(0, boundary);
|
|
30
|
+
buffer = buffer.slice(boundary).replace(/^(\r?\n)+/, "");
|
|
31
|
+
const frame = parseFrame(rawFrame);
|
|
32
|
+
if (frame)
|
|
33
|
+
yield frame;
|
|
34
|
+
boundary = findBoundary(buffer);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Flush any trailing complete frame (no blank line, but the stream ended).
|
|
38
|
+
if (buffer.trim().length > 0) {
|
|
39
|
+
const frame = parseFrame(buffer);
|
|
40
|
+
if (frame)
|
|
41
|
+
yield frame;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
try {
|
|
46
|
+
reader.releaseLock();
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
/* ignore */
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function findBoundary(s) {
|
|
54
|
+
const a = s.indexOf("\n\n");
|
|
55
|
+
const b = s.indexOf("\r\n\r\n");
|
|
56
|
+
if (a === -1)
|
|
57
|
+
return b;
|
|
58
|
+
if (b === -1)
|
|
59
|
+
return a;
|
|
60
|
+
return Math.min(a, b);
|
|
61
|
+
}
|
|
62
|
+
function parseFrame(raw) {
|
|
63
|
+
let event = "message";
|
|
64
|
+
const dataLines = [];
|
|
65
|
+
for (const line of raw.split(/\r?\n/)) {
|
|
66
|
+
if (line.length === 0)
|
|
67
|
+
continue;
|
|
68
|
+
if (line.startsWith(":"))
|
|
69
|
+
continue; // comment / heartbeat
|
|
70
|
+
const colon = line.indexOf(":");
|
|
71
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
72
|
+
// Spec: a single leading space after the colon is stripped.
|
|
73
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
74
|
+
if (value.startsWith(" "))
|
|
75
|
+
value = value.slice(1);
|
|
76
|
+
if (field === "event")
|
|
77
|
+
event = value;
|
|
78
|
+
else if (field === "data")
|
|
79
|
+
dataLines.push(value);
|
|
80
|
+
// ignore id / retry
|
|
81
|
+
}
|
|
82
|
+
if (dataLines.length === 0 && event === "message")
|
|
83
|
+
return null;
|
|
84
|
+
return { event, data: dataLines.join("\n") };
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/sse.ts"],"names":[],"mappings":"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"}
|