@awesomate/platform-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/README.md +92 -0
- package/dist/cjs/client.d.ts +128 -0
- package/dist/cjs/client.js +257 -0
- package/dist/cjs/client.js.map +1 -0
- package/dist/cjs/http.d.ts +27 -0
- package/dist/cjs/http.js +127 -0
- package/dist/cjs/http.js.map +1 -0
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.js +35 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/service.d.ts +140 -0
- package/dist/cjs/service.js +216 -0
- package/dist/cjs/service.js.map +1 -0
- package/dist/cjs/sign.d.ts +11 -0
- package/dist/cjs/sign.js +41 -0
- package/dist/cjs/sign.js.map +1 -0
- package/dist/cjs/sse.d.ts +27 -0
- package/dist/cjs/sse.js +130 -0
- package/dist/cjs/sse.js.map +1 -0
- package/dist/cjs/types.d.ts +517 -0
- package/dist/cjs/types.js +4 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/esm/client.d.ts +128 -0
- package/dist/esm/client.js +251 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/http.d.ts +27 -0
- package/dist/esm/http.js +116 -0
- package/dist/esm/http.js.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/service.d.ts +140 -0
- package/dist/esm/service.js +210 -0
- package/dist/esm/service.js.map +1 -0
- package/dist/esm/sign.d.ts +11 -0
- package/dist/esm/sign.js +36 -0
- package/dist/esm/sign.js.map +1 -0
- package/dist/esm/sse.d.ts +27 -0
- package/dist/esm/sse.js +125 -0
- package/dist/esm/sse.js.map +1 -0
- package/dist/esm/types.d.ts +517 -0
- package/dist/esm/types.js +3 -0
- package/dist/esm/types.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { uploadTo } from "./client.js";
|
|
2
|
+
import { deadline, defaultFetch, enc, queryString, resultOf, trimSlash, UNAVAILABLE } from "./http.js";
|
|
3
|
+
import { serviceHeaders } from "./sign.js";
|
|
4
|
+
/**
|
|
5
|
+
* Client for the hub-only service channel (`/v1/admin/*`). Every request carries
|
|
6
|
+
* `Authorization: Bearer amk_s_…`, `X-Awm-Timestamp`, `X-Awm-Signature` (HMAC over
|
|
7
|
+
* `<ts>.<rawBody>`) and, on mutations, `X-Awm-Idempotency-Key` (replays return the stored
|
|
8
|
+
* response). Same error contract as PlatformClient: never throws on the request path.
|
|
9
|
+
*/
|
|
10
|
+
export class ServiceClient {
|
|
11
|
+
adminUrl;
|
|
12
|
+
serviceKey;
|
|
13
|
+
hmacSecret;
|
|
14
|
+
timeoutMs;
|
|
15
|
+
uploadTimeoutMs;
|
|
16
|
+
fetchImpl;
|
|
17
|
+
now;
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.adminUrl = trimSlash(config.adminUrl ?? "");
|
|
20
|
+
this.serviceKey = config.serviceKey ?? "";
|
|
21
|
+
this.hmacSecret = config.hmacSecret ?? "";
|
|
22
|
+
this.timeoutMs = config.timeoutMs ?? 10_000;
|
|
23
|
+
this.uploadTimeoutMs = config.uploadTimeoutMs ?? 10 * 60_000;
|
|
24
|
+
this.fetchImpl = config.fetchImpl ?? defaultFetch();
|
|
25
|
+
this.now = config.now ?? Date.now;
|
|
26
|
+
}
|
|
27
|
+
isConfigured() {
|
|
28
|
+
return Boolean(this.adminUrl && this.serviceKey && this.hmacSecret);
|
|
29
|
+
}
|
|
30
|
+
async request(method, path, body, idempotencyKey) {
|
|
31
|
+
if (!this.isConfigured())
|
|
32
|
+
return UNAVAILABLE;
|
|
33
|
+
const rawBody = body === undefined ? "" : JSON.stringify(body);
|
|
34
|
+
const headers = await serviceHeaders({
|
|
35
|
+
serviceKey: this.serviceKey,
|
|
36
|
+
hmacSecret: this.hmacSecret,
|
|
37
|
+
rawBody,
|
|
38
|
+
idempotencyKey,
|
|
39
|
+
now: this.now,
|
|
40
|
+
});
|
|
41
|
+
if (body !== undefined)
|
|
42
|
+
headers["Content-Type"] = "application/json";
|
|
43
|
+
const d = deadline(this.timeoutMs);
|
|
44
|
+
try {
|
|
45
|
+
const res = await this.fetchImpl(`${this.adminUrl}${path}`, {
|
|
46
|
+
method,
|
|
47
|
+
headers,
|
|
48
|
+
body: body === undefined ? undefined : rawBody,
|
|
49
|
+
signal: d.signal,
|
|
50
|
+
});
|
|
51
|
+
return await resultOf(res);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return UNAVAILABLE;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
d.done();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
tenantPath(tenantId, rest = "") {
|
|
61
|
+
return `/v1/admin/tenants/${enc(tenantId)}${rest}`;
|
|
62
|
+
}
|
|
63
|
+
// --- tenants and keys ------------------------------------------------------------------
|
|
64
|
+
/** `PUT /v1/admin/tenants/:id` — idempotent upsert. */
|
|
65
|
+
upsertTenant(tenantId, body, idempotencyKey) {
|
|
66
|
+
return this.request("PUT", this.tenantPath(tenantId), body, idempotencyKey);
|
|
67
|
+
}
|
|
68
|
+
getTenant(tenantId) {
|
|
69
|
+
return this.request("GET", this.tenantPath(tenantId));
|
|
70
|
+
}
|
|
71
|
+
mintKey(tenantId, body, idempotencyKey) {
|
|
72
|
+
return this.request("POST", this.tenantPath(tenantId, "/keys"), body, idempotencyKey);
|
|
73
|
+
}
|
|
74
|
+
revokeKey(tenantId, keyId, idempotencyKey) {
|
|
75
|
+
return this.request("DELETE", this.tenantPath(tenantId, `/keys/${enc(keyId)}`), undefined, idempotencyKey);
|
|
76
|
+
}
|
|
77
|
+
suspend(tenantId, idempotencyKey) {
|
|
78
|
+
return this.request("POST", this.tenantPath(tenantId, "/suspend"), {}, idempotencyKey);
|
|
79
|
+
}
|
|
80
|
+
resume(tenantId, idempotencyKey) {
|
|
81
|
+
return this.request("POST", this.tenantPath(tenantId, "/resume"), {}, idempotencyKey);
|
|
82
|
+
}
|
|
83
|
+
patchConfig(tenantId, config, idempotencyKey) {
|
|
84
|
+
return this.request("PATCH", this.tenantPath(tenantId, "/config"), config, idempotencyKey);
|
|
85
|
+
}
|
|
86
|
+
/** Short-lived `q` key for a test-chat pane — never persisted. Default TTL 15 min. */
|
|
87
|
+
mintTestChatKey(tenantId, opts = {}) {
|
|
88
|
+
return this.mintKey(tenantId, { class: "q", name: opts.name ?? "hub: test chat", expires_in_s: opts.ttlSeconds ?? 900 }, `kt:${tenantId}:testchat:${this.now()}`);
|
|
89
|
+
}
|
|
90
|
+
// --- purge and usage -------------------------------------------------------------------
|
|
91
|
+
purge(tenantId, idempotencyKey) {
|
|
92
|
+
return this.request("POST", this.tenantPath(tenantId, "/purge"), {}, idempotencyKey);
|
|
93
|
+
}
|
|
94
|
+
getPurgeJob(purgeJobId) {
|
|
95
|
+
return this.request("GET", `/v1/admin/purge-jobs/${enc(purgeJobId)}`);
|
|
96
|
+
}
|
|
97
|
+
/** Absolute daily counters; the range is capped at 62 days. */
|
|
98
|
+
listUsage(params) {
|
|
99
|
+
return this.request("GET", `/v1/admin/usage${queryString({ since_day: params.sinceDay, until_day: params.untilDay })}`);
|
|
100
|
+
}
|
|
101
|
+
// --- content, metadata only ------------------------------------------------------------
|
|
102
|
+
listJobs(tenantId, params = {}) {
|
|
103
|
+
return this.request("GET", this.tenantPath(tenantId, `/jobs${queryString(params)}`));
|
|
104
|
+
}
|
|
105
|
+
retryJob(tenantId, jobId, idempotencyKey) {
|
|
106
|
+
return this.request("POST", this.tenantPath(tenantId, `/jobs/${enc(jobId)}/retry`), {}, idempotencyKey);
|
|
107
|
+
}
|
|
108
|
+
listSources(tenantId, params = {}) {
|
|
109
|
+
return this.request("GET", this.tenantPath(tenantId, `/sources${queryString(params)}`));
|
|
110
|
+
}
|
|
111
|
+
/** Whole-library counts in one call — for "how much is in here", not for browsing.
|
|
112
|
+
* 404 on a platform that predates the route; `liveSourceTotals()` falls back to paging. */
|
|
113
|
+
sourceSummary(tenantId) {
|
|
114
|
+
return this.request("GET", this.tenantPath(tenantId, "/sources/summary"));
|
|
115
|
+
}
|
|
116
|
+
createSource(tenantId, body, idempotencyKey) {
|
|
117
|
+
return this.request("POST", this.tenantPath(tenantId, "/sources"), body, idempotencyKey);
|
|
118
|
+
}
|
|
119
|
+
deleteSource(tenantId, sourceId, idempotencyKey) {
|
|
120
|
+
return this.request("DELETE", this.tenantPath(tenantId, `/sources/${enc(sourceId)}`), undefined, idempotencyKey);
|
|
121
|
+
}
|
|
122
|
+
createUpload(tenantId, body, idempotencyKey) {
|
|
123
|
+
return this.request("POST", this.tenantPath(tenantId, "/uploads"), body, idempotencyKey);
|
|
124
|
+
}
|
|
125
|
+
completeUpload(tenantId, uploadId, body, idempotencyKey) {
|
|
126
|
+
return this.request("POST", this.tenantPath(tenantId, `/uploads/${enc(uploadId)}/complete`), body, idempotencyKey);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* PUT the staged bytes to `put_url` EXACTLY as the platform returned it — presigned S3 or
|
|
130
|
+
* the platform's query-signed dev route. No service headers: the URL is the credential.
|
|
131
|
+
* A relative `put_url` (FsStore deployments) resolves against `adminUrl`.
|
|
132
|
+
*/
|
|
133
|
+
uploadBytes(putUrl, body, sizeBytes) {
|
|
134
|
+
return uploadTo(this.fetchImpl, putUrl.startsWith("/") ? `${this.adminUrl}${putUrl}` : putUrl, body, sizeBytes, this.uploadTimeoutMs);
|
|
135
|
+
}
|
|
136
|
+
// --- people, aliases, entity resolution ------------------------------------------------
|
|
137
|
+
listPeople(tenantId, params = {}) {
|
|
138
|
+
return this.request("GET", this.tenantPath(tenantId, `/people${queryString(params)}`));
|
|
139
|
+
}
|
|
140
|
+
getPerson(tenantId, personId) {
|
|
141
|
+
return this.request("GET", this.tenantPath(tenantId, `/people/${enc(personId)}`));
|
|
142
|
+
}
|
|
143
|
+
/** Rename (`display_name`, 1–80 chars) or hide/unhide (`status`). The platform propagates a
|
|
144
|
+
* rename into its facets and enqueues a resolve. */
|
|
145
|
+
patchPerson(tenantId, personId, body, idempotencyKey) {
|
|
146
|
+
return this.request("PATCH", this.tenantPath(tenantId, `/people/${enc(personId)}`), body, idempotencyKey);
|
|
147
|
+
}
|
|
148
|
+
mergePeople(tenantId, personId, body, idempotencyKey) {
|
|
149
|
+
return this.request("POST", this.tenantPath(tenantId, `/people/${enc(personId)}/merge`), body, idempotencyKey);
|
|
150
|
+
}
|
|
151
|
+
listAliasSuggestions(tenantId, params = {}) {
|
|
152
|
+
return this.request("GET", this.tenantPath(tenantId, `/entities/aliases${queryString(params)}`));
|
|
153
|
+
}
|
|
154
|
+
decideAlias(tenantId, body, idempotencyKey) {
|
|
155
|
+
return this.request("POST", this.tenantPath(tenantId, "/entities/aliases/decide"), body, idempotencyKey);
|
|
156
|
+
}
|
|
157
|
+
/** 202 `{job_id, status:'queued', position}` when a resolve is enqueued; 200 `{job_id, status}`
|
|
158
|
+
* when one is already queued|running for the tenant. */
|
|
159
|
+
resolveEntities(tenantId, idempotencyKey, body = {}) {
|
|
160
|
+
return this.request("POST", this.tenantPath(tenantId, "/entities/resolve"), body, idempotencyKey);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The truthful "what is in this tenant" figure: the platform's summary route (one GROUP BY,
|
|
165
|
+
* exact at any size); on a platform that predates it, the paged count — capped, and flagged.
|
|
166
|
+
*/
|
|
167
|
+
export async function liveSourceTotals(client, tenantId) {
|
|
168
|
+
const summary = await client.sourceSummary(tenantId);
|
|
169
|
+
if (summary.ok) {
|
|
170
|
+
return {
|
|
171
|
+
ok: true,
|
|
172
|
+
status: 200,
|
|
173
|
+
data: {
|
|
174
|
+
total: Number(summary.data.total) || 0,
|
|
175
|
+
failed: Number(summary.data.failed_sources) || 0,
|
|
176
|
+
by_kind: summary.data.by_kind ?? {},
|
|
177
|
+
truncated: false,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (!("status" in summary) || summary.status !== 404)
|
|
182
|
+
return summary;
|
|
183
|
+
const counted = await countTenantSources(client, tenantId);
|
|
184
|
+
if (!counted.ok)
|
|
185
|
+
return counted;
|
|
186
|
+
return { ok: true, status: 200, data: counted.data };
|
|
187
|
+
}
|
|
188
|
+
const SOURCE_COUNT_PAGE = 50;
|
|
189
|
+
const SOURCE_COUNT_MAX_PAGES = 20;
|
|
190
|
+
/**
|
|
191
|
+
* Live source count by paging the metadata list. Prefer `liveSourceTotals`, which uses the
|
|
192
|
+
* summary route when the platform serves it and falls back to this.
|
|
193
|
+
*/
|
|
194
|
+
export async function countTenantSources(client, tenantId) {
|
|
195
|
+
let total = 0;
|
|
196
|
+
let failed = 0;
|
|
197
|
+
let cursor;
|
|
198
|
+
for (let page = 0; page < SOURCE_COUNT_MAX_PAGES; page++) {
|
|
199
|
+
const r = await client.listSources(tenantId, { limit: SOURCE_COUNT_PAGE, cursor });
|
|
200
|
+
if (!r.ok)
|
|
201
|
+
return r;
|
|
202
|
+
total += r.data.sources.length;
|
|
203
|
+
failed += r.data.sources.filter((s) => s.status === "failed").length;
|
|
204
|
+
if (!r.data.next_cursor)
|
|
205
|
+
return { ok: true, status: 200, data: { total, failed, truncated: false } };
|
|
206
|
+
cursor = r.data.next_cursor;
|
|
207
|
+
}
|
|
208
|
+
return { ok: true, status: 200, data: { total, failed, truncated: true } };
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare function hmacSha256Hex(secret: string, message: string | Uint8Array): Promise<string>;
|
|
2
|
+
/** `X-Awm-Signature` value for an outbound service-channel request. Empty body signs `"<ts>."`. */
|
|
3
|
+
export declare function signServiceRequest(secret: string, timestamp: string, rawBody: string): Promise<string>;
|
|
4
|
+
/** Headers the service channel requires on every request; mutations add the idempotency key. */
|
|
5
|
+
export declare function serviceHeaders(opts: {
|
|
6
|
+
serviceKey: string;
|
|
7
|
+
hmacSecret: string;
|
|
8
|
+
rawBody: string;
|
|
9
|
+
idempotencyKey?: string;
|
|
10
|
+
now?: () => number;
|
|
11
|
+
}): Promise<Record<string, string>>;
|
package/dist/esm/sign.js
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Service-channel HMAC (docs/api-v1.md § Service channel): the platform verifies
|
|
2
|
+
// hex(hmac_sha256(secret, `${timestamp}.${rawBody}`)) wrapped as `v1=<hex>`, ±5 min skew.
|
|
3
|
+
// WebCrypto so the same code signs in Node ≥ 20 and in browsers; the hub's
|
|
4
|
+
// fleet/lib/ingest-auth.ts computes the identical value with node:crypto.
|
|
5
|
+
const textEncoder = new TextEncoder();
|
|
6
|
+
function subtle() {
|
|
7
|
+
const s = globalThis.crypto?.subtle;
|
|
8
|
+
if (!s)
|
|
9
|
+
throw new Error("@awesomate/platform-sdk: WebCrypto (crypto.subtle) is not available");
|
|
10
|
+
return s;
|
|
11
|
+
}
|
|
12
|
+
const toHex = (buf) => Array.from(new Uint8Array(buf), (b) => b.toString(16).padStart(2, "0")).join("");
|
|
13
|
+
export async function hmacSha256Hex(secret, message) {
|
|
14
|
+
const key = await subtle().importKey("raw", textEncoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, [
|
|
15
|
+
"sign",
|
|
16
|
+
]);
|
|
17
|
+
const bytes = typeof message === "string" ? textEncoder.encode(message) : message;
|
|
18
|
+
return toHex(await subtle().sign("HMAC", key, bytes));
|
|
19
|
+
}
|
|
20
|
+
/** `X-Awm-Signature` value for an outbound service-channel request. Empty body signs `"<ts>."`. */
|
|
21
|
+
export async function signServiceRequest(secret, timestamp, rawBody) {
|
|
22
|
+
return `v1=${await hmacSha256Hex(secret, `${timestamp}.${rawBody}`)}`;
|
|
23
|
+
}
|
|
24
|
+
/** Headers the service channel requires on every request; mutations add the idempotency key. */
|
|
25
|
+
export async function serviceHeaders(opts) {
|
|
26
|
+
const timestamp = String((opts.now ?? Date.now)());
|
|
27
|
+
const headers = {
|
|
28
|
+
Authorization: `Bearer ${opts.serviceKey}`,
|
|
29
|
+
"X-Awm-Timestamp": timestamp,
|
|
30
|
+
"X-Awm-Signature": await signServiceRequest(opts.hmacSecret, timestamp, opts.rawBody),
|
|
31
|
+
};
|
|
32
|
+
if (opts.idempotencyKey)
|
|
33
|
+
headers["X-Awm-Idempotency-Key"] = opts.idempotencyKey.slice(0, 96);
|
|
34
|
+
return headers;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=sign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../../src/sign.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,0FAA0F;AAC1F,2EAA2E;AAC3E,0EAA0E;AAE1E,MAAM,WAAW,GAAG,IAAI,WAAW,EAAE,CAAC;AAEtC,SAAS,MAAM;IACb,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,MAAM,CAAC;IACpC,IAAI,CAAC,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qEAAqE,CAAC,CAAC;IAC/F,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,GAAgB,EAAU,EAAE,CACzC,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAEnF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAc,EAAE,OAA4B;IAC9E,MAAM,GAAG,GAAG,MAAM,MAAM,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,KAAK,EAAE;QAChH,MAAM;KACP,CAAC,CAAC;IACH,MAAM,KAAK,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAClF,OAAO,KAAK,CAAC,MAAM,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,KAAqB,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,mGAAmG;AACnG,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAAc,EAAE,SAAiB,EAAE,OAAe;IACzF,OAAO,MAAM,MAAM,aAAa,CAAC,MAAM,EAAE,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,EAAE,CAAC;AACxE,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAMpC;IACC,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,OAAO,GAA2B;QACtC,aAAa,EAAE,UAAU,IAAI,CAAC,UAAU,EAAE;QAC1C,iBAAiB,EAAE,SAAS;QAC5B,iBAAiB,EAAE,MAAM,kBAAkB,CAAC,IAAI,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC;KACtF,CAAC;IACF,IAAI,IAAI,CAAC,cAAc;QAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7F,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { AnswerMeta, AnswerStreamEvent } from "./types.js";
|
|
2
|
+
export interface SSEMessage {
|
|
3
|
+
event: string;
|
|
4
|
+
data: string;
|
|
5
|
+
id?: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Parses a text/event-stream body into messages. Follows the WHATWG grammar: fields split on
|
|
9
|
+
* the first ":", one optional leading space stripped, multi-line `data:` joined with "\n",
|
|
10
|
+
* a blank line dispatches. `event` defaults to "message". Comments (":" lines) are dropped.
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseSSE(body: ReadableStream<Uint8Array>): AsyncGenerator<SSEMessage>;
|
|
13
|
+
/**
|
|
14
|
+
* Typed view of the platform's answer stream (`POST /v1/answer` or `/v1/agents/:id/chat` with
|
|
15
|
+
* `Accept: text/event-stream`): `sources` (candidates, before any text), `answer`/`reply`
|
|
16
|
+
* chunks that already passed the citation gate, `meta`, `done`. Unknown events are skipped so
|
|
17
|
+
* a client that only knows these keeps working when the platform adds more.
|
|
18
|
+
*/
|
|
19
|
+
export declare function answerEvents(body: ReadableStream<Uint8Array>): AsyncGenerator<AnswerStreamEvent>;
|
|
20
|
+
export interface CollectedAnswer {
|
|
21
|
+
text: string;
|
|
22
|
+
sources: Array<Record<string, unknown>>;
|
|
23
|
+
meta: AnswerMeta | null;
|
|
24
|
+
error: string | null;
|
|
25
|
+
}
|
|
26
|
+
/** Drains an answer stream into its final text + meta, for callers that stream to nobody. */
|
|
27
|
+
export declare function collectAnswer(body: ReadableStream<Uint8Array>): Promise<CollectedAnswer>;
|
package/dist/esm/sse.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parses a text/event-stream body into messages. Follows the WHATWG grammar: fields split on
|
|
3
|
+
* the first ":", one optional leading space stripped, multi-line `data:` joined with "\n",
|
|
4
|
+
* a blank line dispatches. `event` defaults to "message". Comments (":" lines) are dropped.
|
|
5
|
+
*/
|
|
6
|
+
export async function* parseSSE(body) {
|
|
7
|
+
const reader = body.getReader();
|
|
8
|
+
const decoder = new TextDecoder();
|
|
9
|
+
let buffer = "";
|
|
10
|
+
let event = "";
|
|
11
|
+
let data = [];
|
|
12
|
+
let id;
|
|
13
|
+
const dispatch = () => {
|
|
14
|
+
if (data.length === 0 && !event)
|
|
15
|
+
return null;
|
|
16
|
+
const msg = { event: event || "message", data: data.join("\n") };
|
|
17
|
+
if (id !== undefined)
|
|
18
|
+
msg.id = id;
|
|
19
|
+
event = "";
|
|
20
|
+
data = [];
|
|
21
|
+
return msg;
|
|
22
|
+
};
|
|
23
|
+
const handleLine = (line) => {
|
|
24
|
+
if (line === "")
|
|
25
|
+
return dispatch();
|
|
26
|
+
if (line.startsWith(":"))
|
|
27
|
+
return null;
|
|
28
|
+
const colon = line.indexOf(":");
|
|
29
|
+
const field = colon === -1 ? line : line.slice(0, colon);
|
|
30
|
+
let value = colon === -1 ? "" : line.slice(colon + 1);
|
|
31
|
+
if (value.startsWith(" "))
|
|
32
|
+
value = value.slice(1);
|
|
33
|
+
if (field === "event")
|
|
34
|
+
event = value;
|
|
35
|
+
else if (field === "data")
|
|
36
|
+
data.push(value);
|
|
37
|
+
else if (field === "id")
|
|
38
|
+
id = value;
|
|
39
|
+
return null;
|
|
40
|
+
};
|
|
41
|
+
let eof = false;
|
|
42
|
+
try {
|
|
43
|
+
for (;;) {
|
|
44
|
+
const { value, done } = await reader.read();
|
|
45
|
+
buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
|
|
46
|
+
const lines = buffer.split(/\r\n|\r|\n/);
|
|
47
|
+
buffer = done ? "" : (lines.pop() ?? "");
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const msg = handleLine(line);
|
|
50
|
+
if (msg)
|
|
51
|
+
yield msg;
|
|
52
|
+
}
|
|
53
|
+
if (done) {
|
|
54
|
+
eof = true;
|
|
55
|
+
const tail = dispatch();
|
|
56
|
+
if (tail)
|
|
57
|
+
yield tail;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
// A consumer that stops early (the platform's `done` event, a `break`) must release the
|
|
64
|
+
// connection, not just the lock — otherwise the body, and everything wired to it, stays open.
|
|
65
|
+
if (!eof)
|
|
66
|
+
await reader.cancel().catch(() => undefined);
|
|
67
|
+
reader.releaseLock();
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const parseJson = (text, fallback) => {
|
|
71
|
+
try {
|
|
72
|
+
return JSON.parse(text);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return fallback;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* Typed view of the platform's answer stream (`POST /v1/answer` or `/v1/agents/:id/chat` with
|
|
80
|
+
* `Accept: text/event-stream`): `sources` (candidates, before any text), `answer`/`reply`
|
|
81
|
+
* chunks that already passed the citation gate, `meta`, `done`. Unknown events are skipped so
|
|
82
|
+
* a client that only knows these keeps working when the platform adds more.
|
|
83
|
+
*/
|
|
84
|
+
export async function* answerEvents(body) {
|
|
85
|
+
for await (const msg of parseSSE(body)) {
|
|
86
|
+
switch (msg.event) {
|
|
87
|
+
case "sources":
|
|
88
|
+
yield { event: "sources", sources: parseJson(msg.data, []) };
|
|
89
|
+
break;
|
|
90
|
+
case "answer":
|
|
91
|
+
yield { event: "answer", text: msg.data };
|
|
92
|
+
break;
|
|
93
|
+
case "reply":
|
|
94
|
+
yield { event: "reply", text: msg.data };
|
|
95
|
+
break;
|
|
96
|
+
case "meta":
|
|
97
|
+
yield { event: "meta", meta: parseJson(msg.data, { status: "error" }) };
|
|
98
|
+
break;
|
|
99
|
+
case "done":
|
|
100
|
+
yield { event: "done" };
|
|
101
|
+
return;
|
|
102
|
+
case "error":
|
|
103
|
+
yield { event: "error", message: parseJson(msg.data, {}).message ?? msg.data };
|
|
104
|
+
return;
|
|
105
|
+
default:
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/** Drains an answer stream into its final text + meta, for callers that stream to nobody. */
|
|
111
|
+
export async function collectAnswer(body) {
|
|
112
|
+
const out = { text: "", sources: [], meta: null, error: null };
|
|
113
|
+
for await (const e of answerEvents(body)) {
|
|
114
|
+
if (e.event === "sources")
|
|
115
|
+
out.sources = e.sources;
|
|
116
|
+
else if (e.event === "answer" || e.event === "reply")
|
|
117
|
+
out.text += e.text;
|
|
118
|
+
else if (e.event === "meta")
|
|
119
|
+
out.meta = e.meta;
|
|
120
|
+
else if (e.event === "error")
|
|
121
|
+
out.error = e.message;
|
|
122
|
+
}
|
|
123
|
+
return out;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../../src/sse.ts"],"names":[],"mappings":"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"}
|