@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.
Files changed (45) hide show
  1. package/README.md +92 -0
  2. package/dist/cjs/client.d.ts +128 -0
  3. package/dist/cjs/client.js +257 -0
  4. package/dist/cjs/client.js.map +1 -0
  5. package/dist/cjs/http.d.ts +27 -0
  6. package/dist/cjs/http.js +127 -0
  7. package/dist/cjs/http.js.map +1 -0
  8. package/dist/cjs/index.d.ts +9 -0
  9. package/dist/cjs/index.js +35 -0
  10. package/dist/cjs/index.js.map +1 -0
  11. package/dist/cjs/package.json +1 -0
  12. package/dist/cjs/service.d.ts +140 -0
  13. package/dist/cjs/service.js +216 -0
  14. package/dist/cjs/service.js.map +1 -0
  15. package/dist/cjs/sign.d.ts +11 -0
  16. package/dist/cjs/sign.js +41 -0
  17. package/dist/cjs/sign.js.map +1 -0
  18. package/dist/cjs/sse.d.ts +27 -0
  19. package/dist/cjs/sse.js +130 -0
  20. package/dist/cjs/sse.js.map +1 -0
  21. package/dist/cjs/types.d.ts +517 -0
  22. package/dist/cjs/types.js +4 -0
  23. package/dist/cjs/types.js.map +1 -0
  24. package/dist/esm/client.d.ts +128 -0
  25. package/dist/esm/client.js +251 -0
  26. package/dist/esm/client.js.map +1 -0
  27. package/dist/esm/http.d.ts +27 -0
  28. package/dist/esm/http.js +116 -0
  29. package/dist/esm/http.js.map +1 -0
  30. package/dist/esm/index.d.ts +9 -0
  31. package/dist/esm/index.js +6 -0
  32. package/dist/esm/index.js.map +1 -0
  33. package/dist/esm/service.d.ts +140 -0
  34. package/dist/esm/service.js +210 -0
  35. package/dist/esm/service.js.map +1 -0
  36. package/dist/esm/sign.d.ts +11 -0
  37. package/dist/esm/sign.js +36 -0
  38. package/dist/esm/sign.js.map +1 -0
  39. package/dist/esm/sse.d.ts +27 -0
  40. package/dist/esm/sse.js +125 -0
  41. package/dist/esm/sse.js.map +1 -0
  42. package/dist/esm/types.d.ts +517 -0
  43. package/dist/esm/types.js +3 -0
  44. package/dist/esm/types.js.map +1 -0
  45. package/package.json +48 -0
@@ -0,0 +1,9 @@
1
+ export { PlatformClient, keyClass, uploadTo } from "./client.js";
2
+ export type { PlatformClientConfig, AnswerStreamResult } from "./client.js";
3
+ export { ServiceClient, countTenantSources, liveSourceTotals } from "./service.js";
4
+ export type { ServiceClientConfig } from "./service.js";
5
+ export { parseSSE, answerEvents, collectAnswer } from "./sse.js";
6
+ export type { SSEMessage, CollectedAnswer } from "./sse.js";
7
+ export { signServiceRequest, serviceHeaders, hmacSha256Hex } from "./sign.js";
8
+ export type { FetchLike } from "./http.js";
9
+ export * from "./types.js";
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.hmacSha256Hex = exports.serviceHeaders = exports.signServiceRequest = exports.collectAnswer = exports.answerEvents = exports.parseSSE = exports.liveSourceTotals = exports.countTenantSources = exports.ServiceClient = exports.uploadTo = exports.keyClass = exports.PlatformClient = void 0;
18
+ var client_js_1 = require("./client.js");
19
+ Object.defineProperty(exports, "PlatformClient", { enumerable: true, get: function () { return client_js_1.PlatformClient; } });
20
+ Object.defineProperty(exports, "keyClass", { enumerable: true, get: function () { return client_js_1.keyClass; } });
21
+ Object.defineProperty(exports, "uploadTo", { enumerable: true, get: function () { return client_js_1.uploadTo; } });
22
+ var service_js_1 = require("./service.js");
23
+ Object.defineProperty(exports, "ServiceClient", { enumerable: true, get: function () { return service_js_1.ServiceClient; } });
24
+ Object.defineProperty(exports, "countTenantSources", { enumerable: true, get: function () { return service_js_1.countTenantSources; } });
25
+ Object.defineProperty(exports, "liveSourceTotals", { enumerable: true, get: function () { return service_js_1.liveSourceTotals; } });
26
+ var sse_js_1 = require("./sse.js");
27
+ Object.defineProperty(exports, "parseSSE", { enumerable: true, get: function () { return sse_js_1.parseSSE; } });
28
+ Object.defineProperty(exports, "answerEvents", { enumerable: true, get: function () { return sse_js_1.answerEvents; } });
29
+ Object.defineProperty(exports, "collectAnswer", { enumerable: true, get: function () { return sse_js_1.collectAnswer; } });
30
+ var sign_js_1 = require("./sign.js");
31
+ Object.defineProperty(exports, "signServiceRequest", { enumerable: true, get: function () { return sign_js_1.signServiceRequest; } });
32
+ Object.defineProperty(exports, "serviceHeaders", { enumerable: true, get: function () { return sign_js_1.serviceHeaders; } });
33
+ Object.defineProperty(exports, "hmacSha256Hex", { enumerable: true, get: function () { return sign_js_1.hmacSha256Hex; } });
34
+ __exportStar(require("./types.js"), exports);
35
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,yCAAiE;AAAxD,2GAAA,cAAc,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAAE,qGAAA,QAAQ,OAAA;AAE3C,2CAAmF;AAA1E,2GAAA,aAAa,OAAA;AAAE,gHAAA,kBAAkB,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAE5D,mCAAiE;AAAxD,kGAAA,QAAQ,OAAA;AAAE,sGAAA,YAAY,OAAA;AAAE,uGAAA,aAAa,OAAA;AAE9C,qCAA8E;AAArE,6GAAA,kBAAkB,OAAA;AAAE,yGAAA,cAAc,OAAA;AAAE,wGAAA,aAAa,OAAA;AAE1D,6CAA2B"}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,140 @@
1
+ import type { FetchLike } from "./http.js";
2
+ import type { AdminJobsPage, AliasDecisionBody, AliasesPage, CompleteUploadBody, CreateSourceBody, CreateUploadBody, Enqueued, EntityKind, LiveSourceTotals, MergeResult, MintKeyBody, MintedKey, PeoplePage, PersonDetail, PersonMeta, PersonPatchBody, PersonStatus, PlatformResult, PurgeJob, SourceSummary, SourcesPage, Tenant, TenantDetail, UploadTicket, UpsertTenantBody, UsageRow } from "./types.js";
3
+ export interface ServiceClientConfig {
4
+ /** Service-channel base, e.g. `https://knowledge-admin.awesomate.ai`. */
5
+ adminUrl: string;
6
+ /** `amk_s_…` — held by the hub's api and worker only, never handed to a client. */
7
+ serviceKey: string;
8
+ hmacSecret: string;
9
+ timeoutMs?: number;
10
+ uploadTimeoutMs?: number;
11
+ fetchImpl?: FetchLike;
12
+ /** Clock for the signed timestamp (tests). */
13
+ now?: () => number;
14
+ }
15
+ /**
16
+ * Client for the hub-only service channel (`/v1/admin/*`). Every request carries
17
+ * `Authorization: Bearer amk_s_…`, `X-Awm-Timestamp`, `X-Awm-Signature` (HMAC over
18
+ * `<ts>.<rawBody>`) and, on mutations, `X-Awm-Idempotency-Key` (replays return the stored
19
+ * response). Same error contract as PlatformClient: never throws on the request path.
20
+ */
21
+ export declare class ServiceClient {
22
+ private readonly adminUrl;
23
+ private readonly serviceKey;
24
+ private readonly hmacSecret;
25
+ private readonly timeoutMs;
26
+ private readonly uploadTimeoutMs;
27
+ private readonly fetchImpl;
28
+ private readonly now;
29
+ constructor(config: ServiceClientConfig);
30
+ isConfigured(): boolean;
31
+ private request;
32
+ private tenantPath;
33
+ /** `PUT /v1/admin/tenants/:id` — idempotent upsert. */
34
+ upsertTenant(tenantId: string, body: UpsertTenantBody, idempotencyKey: string): Promise<PlatformResult<{
35
+ tenant: Tenant;
36
+ }>>;
37
+ getTenant(tenantId: string): Promise<PlatformResult<TenantDetail>>;
38
+ mintKey(tenantId: string, body: MintKeyBody, idempotencyKey: string): Promise<PlatformResult<MintedKey>>;
39
+ revokeKey(tenantId: string, keyId: string, idempotencyKey: string): Promise<PlatformResult<void>>;
40
+ suspend(tenantId: string, idempotencyKey: string): Promise<PlatformResult<{
41
+ status: string;
42
+ }>>;
43
+ resume(tenantId: string, idempotencyKey: string): Promise<PlatformResult<{
44
+ status: string;
45
+ }>>;
46
+ patchConfig(tenantId: string, config: Record<string, unknown>, idempotencyKey: string): Promise<PlatformResult<{
47
+ tenant: Tenant;
48
+ }>>;
49
+ /** Short-lived `q` key for a test-chat pane — never persisted. Default TTL 15 min. */
50
+ mintTestChatKey(tenantId: string, opts?: {
51
+ name?: string;
52
+ ttlSeconds?: number;
53
+ }): Promise<PlatformResult<MintedKey>>;
54
+ purge(tenantId: string, idempotencyKey: string): Promise<PlatformResult<{
55
+ purge_job_id: string;
56
+ }>>;
57
+ getPurgeJob(purgeJobId: string): Promise<PlatformResult<PurgeJob>>;
58
+ /** Absolute daily counters; the range is capped at 62 days. */
59
+ listUsage(params: {
60
+ sinceDay: string;
61
+ untilDay?: string;
62
+ }): Promise<PlatformResult<UsageRow[]>>;
63
+ listJobs(tenantId: string, params?: {
64
+ status?: string;
65
+ limit?: number;
66
+ cursor?: string;
67
+ }): Promise<PlatformResult<AdminJobsPage>>;
68
+ retryJob(tenantId: string, jobId: string, idempotencyKey: string): Promise<PlatformResult<Enqueued>>;
69
+ listSources(tenantId: string, params?: {
70
+ limit?: number;
71
+ cursor?: string;
72
+ kind?: string;
73
+ tag?: string;
74
+ }): Promise<PlatformResult<SourcesPage>>;
75
+ /** Whole-library counts in one call — for "how much is in here", not for browsing.
76
+ * 404 on a platform that predates the route; `liveSourceTotals()` falls back to paging. */
77
+ sourceSummary(tenantId: string): Promise<PlatformResult<SourceSummary>>;
78
+ createSource(tenantId: string, body: CreateSourceBody, idempotencyKey: string): Promise<PlatformResult<Enqueued>>;
79
+ deleteSource(tenantId: string, sourceId: string, idempotencyKey: string): Promise<PlatformResult<{
80
+ job_id: string;
81
+ }>>;
82
+ createUpload(tenantId: string, body: CreateUploadBody, idempotencyKey: string): Promise<PlatformResult<UploadTicket>>;
83
+ completeUpload(tenantId: string, uploadId: string, body: CompleteUploadBody, idempotencyKey: string): Promise<PlatformResult<{
84
+ upload_id: string;
85
+ status: string;
86
+ }>>;
87
+ /**
88
+ * PUT the staged bytes to `put_url` EXACTLY as the platform returned it — presigned S3 or
89
+ * the platform's query-signed dev route. No service headers: the URL is the credential.
90
+ * A relative `put_url` (FsStore deployments) resolves against `adminUrl`.
91
+ */
92
+ uploadBytes(putUrl: string, body: BodyInit | ReadableStream<Uint8Array>, sizeBytes?: number): Promise<PlatformResult<void>>;
93
+ listPeople(tenantId: string, params?: {
94
+ status?: PersonStatus | "all";
95
+ limit?: number;
96
+ cursor?: string;
97
+ }): Promise<PlatformResult<PeoplePage>>;
98
+ getPerson(tenantId: string, personId: string): Promise<PlatformResult<PersonDetail>>;
99
+ /** Rename (`display_name`, 1–80 chars) or hide/unhide (`status`). The platform propagates a
100
+ * rename into its facets and enqueues a resolve. */
101
+ patchPerson(tenantId: string, personId: string, body: PersonPatchBody, idempotencyKey: string): Promise<PlatformResult<{
102
+ person: PersonMeta;
103
+ relabelled: number;
104
+ job_id: string | null;
105
+ }>>;
106
+ mergePeople(tenantId: string, personId: string, body: {
107
+ into_person_id: string;
108
+ }, idempotencyKey: string): Promise<PlatformResult<MergeResult>>;
109
+ listAliasSuggestions(tenantId: string, params?: {
110
+ status?: "pending" | "accepted" | "rejected";
111
+ kind?: EntityKind;
112
+ limit?: number;
113
+ cursor?: string;
114
+ }): Promise<PlatformResult<AliasesPage>>;
115
+ decideAlias(tenantId: string, body: AliasDecisionBody, idempotencyKey: string): Promise<PlatformResult<{
116
+ alias: string;
117
+ entity_id: string | null;
118
+ job_id: string | null;
119
+ }>>;
120
+ /** 202 `{job_id, status:'queued', position}` when a resolve is enqueued; 200 `{job_id, status}`
121
+ * when one is already queued|running for the tenant. */
122
+ resolveEntities(tenantId: string, idempotencyKey: string, body?: {
123
+ full?: boolean;
124
+ stub?: boolean;
125
+ }): Promise<PlatformResult<Enqueued>>;
126
+ }
127
+ /**
128
+ * The truthful "what is in this tenant" figure: the platform's summary route (one GROUP BY,
129
+ * exact at any size); on a platform that predates it, the paged count — capped, and flagged.
130
+ */
131
+ export declare function liveSourceTotals(client: Pick<ServiceClient, "listSources" | "sourceSummary">, tenantId: string): Promise<PlatformResult<LiveSourceTotals>>;
132
+ /**
133
+ * Live source count by paging the metadata list. Prefer `liveSourceTotals`, which uses the
134
+ * summary route when the platform serves it and falls back to this.
135
+ */
136
+ export declare function countTenantSources(client: Pick<ServiceClient, "listSources">, tenantId: string): Promise<PlatformResult<{
137
+ total: number;
138
+ failed: number;
139
+ truncated: boolean;
140
+ }>>;
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceClient = void 0;
4
+ exports.liveSourceTotals = liveSourceTotals;
5
+ exports.countTenantSources = countTenantSources;
6
+ const client_js_1 = require("./client.js");
7
+ const http_js_1 = require("./http.js");
8
+ const sign_js_1 = require("./sign.js");
9
+ /**
10
+ * Client for the hub-only service channel (`/v1/admin/*`). Every request carries
11
+ * `Authorization: Bearer amk_s_…`, `X-Awm-Timestamp`, `X-Awm-Signature` (HMAC over
12
+ * `<ts>.<rawBody>`) and, on mutations, `X-Awm-Idempotency-Key` (replays return the stored
13
+ * response). Same error contract as PlatformClient: never throws on the request path.
14
+ */
15
+ class ServiceClient {
16
+ adminUrl;
17
+ serviceKey;
18
+ hmacSecret;
19
+ timeoutMs;
20
+ uploadTimeoutMs;
21
+ fetchImpl;
22
+ now;
23
+ constructor(config) {
24
+ this.adminUrl = (0, http_js_1.trimSlash)(config.adminUrl ?? "");
25
+ this.serviceKey = config.serviceKey ?? "";
26
+ this.hmacSecret = config.hmacSecret ?? "";
27
+ this.timeoutMs = config.timeoutMs ?? 10_000;
28
+ this.uploadTimeoutMs = config.uploadTimeoutMs ?? 10 * 60_000;
29
+ this.fetchImpl = config.fetchImpl ?? (0, http_js_1.defaultFetch)();
30
+ this.now = config.now ?? Date.now;
31
+ }
32
+ isConfigured() {
33
+ return Boolean(this.adminUrl && this.serviceKey && this.hmacSecret);
34
+ }
35
+ async request(method, path, body, idempotencyKey) {
36
+ if (!this.isConfigured())
37
+ return http_js_1.UNAVAILABLE;
38
+ const rawBody = body === undefined ? "" : JSON.stringify(body);
39
+ const headers = await (0, sign_js_1.serviceHeaders)({
40
+ serviceKey: this.serviceKey,
41
+ hmacSecret: this.hmacSecret,
42
+ rawBody,
43
+ idempotencyKey,
44
+ now: this.now,
45
+ });
46
+ if (body !== undefined)
47
+ headers["Content-Type"] = "application/json";
48
+ const d = (0, http_js_1.deadline)(this.timeoutMs);
49
+ try {
50
+ const res = await this.fetchImpl(`${this.adminUrl}${path}`, {
51
+ method,
52
+ headers,
53
+ body: body === undefined ? undefined : rawBody,
54
+ signal: d.signal,
55
+ });
56
+ return await (0, http_js_1.resultOf)(res);
57
+ }
58
+ catch {
59
+ return http_js_1.UNAVAILABLE;
60
+ }
61
+ finally {
62
+ d.done();
63
+ }
64
+ }
65
+ tenantPath(tenantId, rest = "") {
66
+ return `/v1/admin/tenants/${(0, http_js_1.enc)(tenantId)}${rest}`;
67
+ }
68
+ // --- tenants and keys ------------------------------------------------------------------
69
+ /** `PUT /v1/admin/tenants/:id` — idempotent upsert. */
70
+ upsertTenant(tenantId, body, idempotencyKey) {
71
+ return this.request("PUT", this.tenantPath(tenantId), body, idempotencyKey);
72
+ }
73
+ getTenant(tenantId) {
74
+ return this.request("GET", this.tenantPath(tenantId));
75
+ }
76
+ mintKey(tenantId, body, idempotencyKey) {
77
+ return this.request("POST", this.tenantPath(tenantId, "/keys"), body, idempotencyKey);
78
+ }
79
+ revokeKey(tenantId, keyId, idempotencyKey) {
80
+ return this.request("DELETE", this.tenantPath(tenantId, `/keys/${(0, http_js_1.enc)(keyId)}`), undefined, idempotencyKey);
81
+ }
82
+ suspend(tenantId, idempotencyKey) {
83
+ return this.request("POST", this.tenantPath(tenantId, "/suspend"), {}, idempotencyKey);
84
+ }
85
+ resume(tenantId, idempotencyKey) {
86
+ return this.request("POST", this.tenantPath(tenantId, "/resume"), {}, idempotencyKey);
87
+ }
88
+ patchConfig(tenantId, config, idempotencyKey) {
89
+ return this.request("PATCH", this.tenantPath(tenantId, "/config"), config, idempotencyKey);
90
+ }
91
+ /** Short-lived `q` key for a test-chat pane — never persisted. Default TTL 15 min. */
92
+ mintTestChatKey(tenantId, opts = {}) {
93
+ return this.mintKey(tenantId, { class: "q", name: opts.name ?? "hub: test chat", expires_in_s: opts.ttlSeconds ?? 900 }, `kt:${tenantId}:testchat:${this.now()}`);
94
+ }
95
+ // --- purge and usage -------------------------------------------------------------------
96
+ purge(tenantId, idempotencyKey) {
97
+ return this.request("POST", this.tenantPath(tenantId, "/purge"), {}, idempotencyKey);
98
+ }
99
+ getPurgeJob(purgeJobId) {
100
+ return this.request("GET", `/v1/admin/purge-jobs/${(0, http_js_1.enc)(purgeJobId)}`);
101
+ }
102
+ /** Absolute daily counters; the range is capped at 62 days. */
103
+ listUsage(params) {
104
+ return this.request("GET", `/v1/admin/usage${(0, http_js_1.queryString)({ since_day: params.sinceDay, until_day: params.untilDay })}`);
105
+ }
106
+ // --- content, metadata only ------------------------------------------------------------
107
+ listJobs(tenantId, params = {}) {
108
+ return this.request("GET", this.tenantPath(tenantId, `/jobs${(0, http_js_1.queryString)(params)}`));
109
+ }
110
+ retryJob(tenantId, jobId, idempotencyKey) {
111
+ return this.request("POST", this.tenantPath(tenantId, `/jobs/${(0, http_js_1.enc)(jobId)}/retry`), {}, idempotencyKey);
112
+ }
113
+ listSources(tenantId, params = {}) {
114
+ return this.request("GET", this.tenantPath(tenantId, `/sources${(0, http_js_1.queryString)(params)}`));
115
+ }
116
+ /** Whole-library counts in one call — for "how much is in here", not for browsing.
117
+ * 404 on a platform that predates the route; `liveSourceTotals()` falls back to paging. */
118
+ sourceSummary(tenantId) {
119
+ return this.request("GET", this.tenantPath(tenantId, "/sources/summary"));
120
+ }
121
+ createSource(tenantId, body, idempotencyKey) {
122
+ return this.request("POST", this.tenantPath(tenantId, "/sources"), body, idempotencyKey);
123
+ }
124
+ deleteSource(tenantId, sourceId, idempotencyKey) {
125
+ return this.request("DELETE", this.tenantPath(tenantId, `/sources/${(0, http_js_1.enc)(sourceId)}`), undefined, idempotencyKey);
126
+ }
127
+ createUpload(tenantId, body, idempotencyKey) {
128
+ return this.request("POST", this.tenantPath(tenantId, "/uploads"), body, idempotencyKey);
129
+ }
130
+ completeUpload(tenantId, uploadId, body, idempotencyKey) {
131
+ return this.request("POST", this.tenantPath(tenantId, `/uploads/${(0, http_js_1.enc)(uploadId)}/complete`), body, idempotencyKey);
132
+ }
133
+ /**
134
+ * PUT the staged bytes to `put_url` EXACTLY as the platform returned it — presigned S3 or
135
+ * the platform's query-signed dev route. No service headers: the URL is the credential.
136
+ * A relative `put_url` (FsStore deployments) resolves against `adminUrl`.
137
+ */
138
+ uploadBytes(putUrl, body, sizeBytes) {
139
+ return (0, client_js_1.uploadTo)(this.fetchImpl, putUrl.startsWith("/") ? `${this.adminUrl}${putUrl}` : putUrl, body, sizeBytes, this.uploadTimeoutMs);
140
+ }
141
+ // --- people, aliases, entity resolution ------------------------------------------------
142
+ listPeople(tenantId, params = {}) {
143
+ return this.request("GET", this.tenantPath(tenantId, `/people${(0, http_js_1.queryString)(params)}`));
144
+ }
145
+ getPerson(tenantId, personId) {
146
+ return this.request("GET", this.tenantPath(tenantId, `/people/${(0, http_js_1.enc)(personId)}`));
147
+ }
148
+ /** Rename (`display_name`, 1–80 chars) or hide/unhide (`status`). The platform propagates a
149
+ * rename into its facets and enqueues a resolve. */
150
+ patchPerson(tenantId, personId, body, idempotencyKey) {
151
+ return this.request("PATCH", this.tenantPath(tenantId, `/people/${(0, http_js_1.enc)(personId)}`), body, idempotencyKey);
152
+ }
153
+ mergePeople(tenantId, personId, body, idempotencyKey) {
154
+ return this.request("POST", this.tenantPath(tenantId, `/people/${(0, http_js_1.enc)(personId)}/merge`), body, idempotencyKey);
155
+ }
156
+ listAliasSuggestions(tenantId, params = {}) {
157
+ return this.request("GET", this.tenantPath(tenantId, `/entities/aliases${(0, http_js_1.queryString)(params)}`));
158
+ }
159
+ decideAlias(tenantId, body, idempotencyKey) {
160
+ return this.request("POST", this.tenantPath(tenantId, "/entities/aliases/decide"), body, idempotencyKey);
161
+ }
162
+ /** 202 `{job_id, status:'queued', position}` when a resolve is enqueued; 200 `{job_id, status}`
163
+ * when one is already queued|running for the tenant. */
164
+ resolveEntities(tenantId, idempotencyKey, body = {}) {
165
+ return this.request("POST", this.tenantPath(tenantId, "/entities/resolve"), body, idempotencyKey);
166
+ }
167
+ }
168
+ exports.ServiceClient = ServiceClient;
169
+ /**
170
+ * The truthful "what is in this tenant" figure: the platform's summary route (one GROUP BY,
171
+ * exact at any size); on a platform that predates it, the paged count — capped, and flagged.
172
+ */
173
+ async function liveSourceTotals(client, tenantId) {
174
+ const summary = await client.sourceSummary(tenantId);
175
+ if (summary.ok) {
176
+ return {
177
+ ok: true,
178
+ status: 200,
179
+ data: {
180
+ total: Number(summary.data.total) || 0,
181
+ failed: Number(summary.data.failed_sources) || 0,
182
+ by_kind: summary.data.by_kind ?? {},
183
+ truncated: false,
184
+ },
185
+ };
186
+ }
187
+ if (!("status" in summary) || summary.status !== 404)
188
+ return summary;
189
+ const counted = await countTenantSources(client, tenantId);
190
+ if (!counted.ok)
191
+ return counted;
192
+ return { ok: true, status: 200, data: counted.data };
193
+ }
194
+ const SOURCE_COUNT_PAGE = 50;
195
+ const SOURCE_COUNT_MAX_PAGES = 20;
196
+ /**
197
+ * Live source count by paging the metadata list. Prefer `liveSourceTotals`, which uses the
198
+ * summary route when the platform serves it and falls back to this.
199
+ */
200
+ async function countTenantSources(client, tenantId) {
201
+ let total = 0;
202
+ let failed = 0;
203
+ let cursor;
204
+ for (let page = 0; page < SOURCE_COUNT_MAX_PAGES; page++) {
205
+ const r = await client.listSources(tenantId, { limit: SOURCE_COUNT_PAGE, cursor });
206
+ if (!r.ok)
207
+ return r;
208
+ total += r.data.sources.length;
209
+ failed += r.data.sources.filter((s) => s.status === "failed").length;
210
+ if (!r.data.next_cursor)
211
+ return { ok: true, status: 200, data: { total, failed, truncated: false } };
212
+ cursor = r.data.next_cursor;
213
+ }
214
+ return { ok: true, status: 200, data: { total, failed, truncated: true } };
215
+ }
216
+ //# 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>>;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ // Service-channel HMAC (docs/api-v1.md § Service channel): the platform verifies
3
+ // hex(hmac_sha256(secret, `${timestamp}.${rawBody}`)) wrapped as `v1=<hex>`, ±5 min skew.
4
+ // WebCrypto so the same code signs in Node ≥ 20 and in browsers; the hub's
5
+ // fleet/lib/ingest-auth.ts computes the identical value with node:crypto.
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.hmacSha256Hex = hmacSha256Hex;
8
+ exports.signServiceRequest = signServiceRequest;
9
+ exports.serviceHeaders = serviceHeaders;
10
+ const textEncoder = new TextEncoder();
11
+ function subtle() {
12
+ const s = globalThis.crypto?.subtle;
13
+ if (!s)
14
+ throw new Error("@awesomate/platform-sdk: WebCrypto (crypto.subtle) is not available");
15
+ return s;
16
+ }
17
+ const toHex = (buf) => Array.from(new Uint8Array(buf), (b) => b.toString(16).padStart(2, "0")).join("");
18
+ async function hmacSha256Hex(secret, message) {
19
+ const key = await subtle().importKey("raw", textEncoder.encode(secret), { name: "HMAC", hash: "SHA-256" }, false, [
20
+ "sign",
21
+ ]);
22
+ const bytes = typeof message === "string" ? textEncoder.encode(message) : message;
23
+ return toHex(await subtle().sign("HMAC", key, bytes));
24
+ }
25
+ /** `X-Awm-Signature` value for an outbound service-channel request. Empty body signs `"<ts>."`. */
26
+ async function signServiceRequest(secret, timestamp, rawBody) {
27
+ return `v1=${await hmacSha256Hex(secret, `${timestamp}.${rawBody}`)}`;
28
+ }
29
+ /** Headers the service channel requires on every request; mutations add the idempotency key. */
30
+ async function serviceHeaders(opts) {
31
+ const timestamp = String((opts.now ?? Date.now)());
32
+ const headers = {
33
+ Authorization: `Bearer ${opts.serviceKey}`,
34
+ "X-Awm-Timestamp": timestamp,
35
+ "X-Awm-Signature": await signServiceRequest(opts.hmacSecret, timestamp, opts.rawBody),
36
+ };
37
+ if (opts.idempotencyKey)
38
+ headers["X-Awm-Idempotency-Key"] = opts.idempotencyKey.slice(0, 96);
39
+ return headers;
40
+ }
41
+ //# 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;;AAa1E,sCAMC;AAGD,gDAEC;AAGD,wCAeC;AAxCD,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;AAE5E,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;AAC5F,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;AACzF,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>;
@@ -0,0 +1,130 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseSSE = parseSSE;
4
+ exports.answerEvents = answerEvents;
5
+ exports.collectAnswer = collectAnswer;
6
+ /**
7
+ * Parses a text/event-stream body into messages. Follows the WHATWG grammar: fields split on
8
+ * the first ":", one optional leading space stripped, multi-line `data:` joined with "\n",
9
+ * a blank line dispatches. `event` defaults to "message". Comments (":" lines) are dropped.
10
+ */
11
+ async function* parseSSE(body) {
12
+ const reader = body.getReader();
13
+ const decoder = new TextDecoder();
14
+ let buffer = "";
15
+ let event = "";
16
+ let data = [];
17
+ let id;
18
+ const dispatch = () => {
19
+ if (data.length === 0 && !event)
20
+ return null;
21
+ const msg = { event: event || "message", data: data.join("\n") };
22
+ if (id !== undefined)
23
+ msg.id = id;
24
+ event = "";
25
+ data = [];
26
+ return msg;
27
+ };
28
+ const handleLine = (line) => {
29
+ if (line === "")
30
+ return dispatch();
31
+ if (line.startsWith(":"))
32
+ return null;
33
+ const colon = line.indexOf(":");
34
+ const field = colon === -1 ? line : line.slice(0, colon);
35
+ let value = colon === -1 ? "" : line.slice(colon + 1);
36
+ if (value.startsWith(" "))
37
+ value = value.slice(1);
38
+ if (field === "event")
39
+ event = value;
40
+ else if (field === "data")
41
+ data.push(value);
42
+ else if (field === "id")
43
+ id = value;
44
+ return null;
45
+ };
46
+ let eof = false;
47
+ try {
48
+ for (;;) {
49
+ const { value, done } = await reader.read();
50
+ buffer += done ? decoder.decode() : decoder.decode(value, { stream: true });
51
+ const lines = buffer.split(/\r\n|\r|\n/);
52
+ buffer = done ? "" : (lines.pop() ?? "");
53
+ for (const line of lines) {
54
+ const msg = handleLine(line);
55
+ if (msg)
56
+ yield msg;
57
+ }
58
+ if (done) {
59
+ eof = true;
60
+ const tail = dispatch();
61
+ if (tail)
62
+ yield tail;
63
+ return;
64
+ }
65
+ }
66
+ }
67
+ finally {
68
+ // A consumer that stops early (the platform's `done` event, a `break`) must release the
69
+ // connection, not just the lock — otherwise the body, and everything wired to it, stays open.
70
+ if (!eof)
71
+ await reader.cancel().catch(() => undefined);
72
+ reader.releaseLock();
73
+ }
74
+ }
75
+ const parseJson = (text, fallback) => {
76
+ try {
77
+ return JSON.parse(text);
78
+ }
79
+ catch {
80
+ return fallback;
81
+ }
82
+ };
83
+ /**
84
+ * Typed view of the platform's answer stream (`POST /v1/answer` or `/v1/agents/:id/chat` with
85
+ * `Accept: text/event-stream`): `sources` (candidates, before any text), `answer`/`reply`
86
+ * chunks that already passed the citation gate, `meta`, `done`. Unknown events are skipped so
87
+ * a client that only knows these keeps working when the platform adds more.
88
+ */
89
+ async function* answerEvents(body) {
90
+ for await (const msg of parseSSE(body)) {
91
+ switch (msg.event) {
92
+ case "sources":
93
+ yield { event: "sources", sources: parseJson(msg.data, []) };
94
+ break;
95
+ case "answer":
96
+ yield { event: "answer", text: msg.data };
97
+ break;
98
+ case "reply":
99
+ yield { event: "reply", text: msg.data };
100
+ break;
101
+ case "meta":
102
+ yield { event: "meta", meta: parseJson(msg.data, { status: "error" }) };
103
+ break;
104
+ case "done":
105
+ yield { event: "done" };
106
+ return;
107
+ case "error":
108
+ yield { event: "error", message: parseJson(msg.data, {}).message ?? msg.data };
109
+ return;
110
+ default:
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ /** Drains an answer stream into its final text + meta, for callers that stream to nobody. */
116
+ async function collectAnswer(body) {
117
+ const out = { text: "", sources: [], meta: null, error: null };
118
+ for await (const e of answerEvents(body)) {
119
+ if (e.event === "sources")
120
+ out.sources = e.sources;
121
+ else if (e.event === "answer" || e.event === "reply")
122
+ out.text += e.text;
123
+ else if (e.event === "meta")
124
+ out.meta = e.meta;
125
+ else if (e.event === "error")
126
+ out.error = e.message;
127
+ }
128
+ return out;
129
+ }
130
+ //# sourceMappingURL=sse.js.map