kaibo 0.0.0-stage → 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.
@@ -0,0 +1,360 @@
1
+ import { A as Project, B as WebhookEventType, D as MemoryStatus, F as RememberResult, H as WhoAmI, I as StoredEvent, L as Usage, M as RecallInput, N as ReceiptVerification, P as RememberInput, R as Webhook, S as JobStatus, T as Memory, _ as ForgetDryRun, a as ContextPack, b as ImportResult, c as CreatedWebhook, f as EventInput, g as ExportRecord, h as ExportInput, i as ContextItem, j as RecallEvent, k as Page, l as DeletionReceipt, m as Explanation, n as AttestVerification, o as CreateKeyInput, r as Citation, s as CreatedApiKey, t as ApiKey, u as Diff, v as ImportInput, z as WebhookDelivery } from "./types-q09Fds4e.cjs";
2
+ /** What most code wants from a recall, without digging through `abstain` and `items[0]`. */
3
+ interface Shared {
4
+ /** Every item's text, one per line, for putting in a prompt. Empty when there is no answer. */
5
+ readonly text: string;
6
+ /** The events the items came from, each once. */
7
+ readonly sources: Citation[];
8
+ }
9
+ /** Something citable matched. */
10
+ interface Found extends Shared {
11
+ readonly found: true;
12
+ /** The best match. */
13
+ readonly top: ContextItem;
14
+ /** The best match's text. */
15
+ readonly answer: string;
16
+ readonly reason: null;
17
+ }
18
+ /** Nothing citable matched: say you do not know instead of guessing. */
19
+ interface NotFound extends Shared {
20
+ readonly found: false;
21
+ readonly top: null;
22
+ readonly answer: null;
23
+ /** Why there is no answer. */
24
+ readonly reason: string;
25
+ }
26
+ type PackHelpers = Found | NotFound;
27
+ /**
28
+ * A recall result: the plain JSON from the server plus the helpers above. Check `pack.found` and
29
+ * TypeScript knows `pack.top` and `pack.answer` are there.
30
+ */
31
+ type Pack = ContextPack & PackHelpers;
32
+ /**
33
+ * Adds the helpers as non-enumerable properties, so `JSON.stringify(pack)` and `verifyPack(pack)`
34
+ * still see exactly what the server sent.
35
+ */
36
+ declare function withHelpers(pack: ContextPack): Pack;
37
+ interface TransportOptions {
38
+ apiKey: string;
39
+ baseUrl: string;
40
+ /** Sent as `X-Project-Id`. Only needed for org-wide keys; project-bound keys carry theirs. */
41
+ project?: string | undefined;
42
+ fetch?: typeof fetch | undefined;
43
+ /** Retries after the first attempt. Default 2. */
44
+ retries?: number | undefined;
45
+ /** Per-attempt timeout. Default 30 000. */
46
+ timeoutMs?: number | undefined;
47
+ userAgent?: string | undefined;
48
+ /** Replaceable in tests so backoff does not take real time. */
49
+ sleep?: ((ms: number) => Promise<void>) | undefined;
50
+ /** Replaceable in tests so jitter is deterministic. */
51
+ random?: (() => number) | undefined;
52
+ }
53
+ interface RequestOptions {
54
+ method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
55
+ path: string;
56
+ query?: Record<string, string | number | undefined>;
57
+ body?: unknown;
58
+ headers?: Record<string, string>;
59
+ /** Retry on 5xx, 429 and network errors. Only for requests that are safe to repeat. */
60
+ retry: boolean;
61
+ signal?: AbortSignal | undefined;
62
+ /** Return the raw response (for streaming). */
63
+ raw?: boolean;
64
+ }
65
+ declare class Transport {
66
+ private readonly o;
67
+ constructor(options: TransportOptions);
68
+ private url;
69
+ /** Sends a request, retrying when allowed. Throws a typed `KaiboError` on failure. */
70
+ request<T>(opts: RequestOptions): Promise<T>;
71
+ /** Like `request`, but returns the successful response untouched (for streaming bodies). */
72
+ stream(opts: RequestOptions): Promise<Response>;
73
+ private send;
74
+ }
75
+ interface KaiboOptions {
76
+ /** `kaibo_...` key from the dashboard. Defaults to the `KAIBO_KEY` environment variable. */
77
+ apiKey?: string;
78
+ /** The address of your kaibo site (the API lives under `/v1` there). Defaults to the `KAIBO_URL` environment variable. */
79
+ baseUrl?: string;
80
+ /** Project id, only for org-wide keys. Defaults to `KAIBO_PROJECT`. */
81
+ project?: string;
82
+ /** Custom `fetch` (proxies, tests, edge runtimes). Defaults to the global one. */
83
+ fetch?: typeof fetch;
84
+ /** Retries after the first attempt, for requests that are safe to repeat. Default 2. */
85
+ retries?: number;
86
+ /** Per-attempt timeout in ms. Default 30 000. */
87
+ timeoutMs?: number;
88
+ }
89
+ declare const SDK_VERSION = "0.1.0";
90
+ interface WaitOptions {
91
+ /** Give up after this long. Default 10 000. */
92
+ timeoutMs?: number;
93
+ /** First poll delay, doubled up to 1 s. Default 100. */
94
+ intervalMs?: number;
95
+ signal?: AbortSignal;
96
+ }
97
+ /**
98
+ * Client for the four memory operations and the data behind them.
99
+ *
100
+ * @example
101
+ * ```ts
102
+ * const kaibo = new Kaibo(); // reads KAIBO_KEY (and KAIBO_URL, KAIBO_PROJECT) from the environment
103
+ * await kaibo.remember('Move the release target from July 13 to July 17.', { wait: true });
104
+ * const pack = await kaibo.recall('release target');
105
+ * console.log(pack.found ? pack.answer : `no answer: ${pack.reason}`, pack.sources);
106
+ * ```
107
+ */
108
+ /** A memory id, or anything that carries one: a recalled item (`pack.top`), a memory from a list. */
109
+ type MemoryRef = string | {
110
+ memoryId: string;
111
+ } | {
112
+ id: string;
113
+ };
114
+ declare class Kaibo {
115
+ /** @internal */
116
+ readonly t: Transport;
117
+ readonly events: EventsApi;
118
+ readonly memories: MemoriesApi;
119
+ readonly jobs: JobsApi;
120
+ /** Manage webhook endpoints. Needs an `admin` key. */
121
+ readonly webhooks: WebhooksApi;
122
+ /** Bring memory in from Mem0, Zep, Letta, JSON Lines or Markdown. Needs a key that can write. */
123
+ readonly imports: ImportsApi;
124
+ /** Take events and memories out as JSON Lines. */
125
+ readonly exports: ExportsApi;
126
+ /** Create, list and revoke API keys. Needs an `admin` key. */
127
+ readonly keys: KeysApi;
128
+ /** List, create and rename projects. Needs an `admin` key. */
129
+ readonly projects: ProjectsApi;
130
+ /** Same as `new Kaibo()`: configuration comes from `KAIBO_KEY`, `KAIBO_URL` and `KAIBO_PROJECT`. */
131
+ static fromEnv(overrides?: KaiboOptions): Kaibo;
132
+ private readonly resolved;
133
+ /** The same client, acting on one project. For org-wide keys, which must say which project a call is about. */
134
+ withProject(project: string): Kaibo;
135
+ constructor(options?: KaiboOptions & Partial<Pick<TransportOptions, 'sleep' | 'random'>>);
136
+ /**
137
+ * Store raw events. Returns once they are durably appended and hash-chained; turning them into
138
+ * memory happens right after. Pass `wait: true` to return only when that has finished.
139
+ * Safe to retry: every request carries an idempotency key.
140
+ */
141
+ remember(input: string | RememberInput, options?: {
142
+ wait?: boolean | WaitOptions;
143
+ signal?: AbortSignal;
144
+ }): Promise<RememberResult>;
145
+ /**
146
+ * The smallest context that answers `query`, with a citation for every item. When nothing
147
+ * citable matches, `pack.found` is false and `pack.reason` says why: say you do not know instead of guessing.
148
+ * `pack.answer` is the best match's text, `pack.text` all of them for a prompt, `pack.sources` the events they came from.
149
+ */
150
+ recall: {
151
+ (input: string | RecallInput, options?: {
152
+ signal?: AbortSignal;
153
+ }): Promise<Pack>;
154
+ /** Same request, as server-sent events: candidates, packing, then the final pack. */
155
+ stream(input: string | RecallInput, options?: {
156
+ signal?: AbortSignal;
157
+ }): AsyncGenerator<RecallEvent>;
158
+ };
159
+ private recallStream;
160
+ /**
161
+ * Recall, rendered as text you can put straight into a prompt: delimited as stored data, with
162
+ * citations, and with outdated, unverified and untrusted items marked. Says so when there is no answer.
163
+ */
164
+ context(input: string | RecallInput, options?: {
165
+ signal?: AbortSignal;
166
+ }): Promise<string>;
167
+ /** Is this pack unchanged since kaibo issued it, and do its citations still match the stored events? */
168
+ verifyPack(pack: ContextPack, options?: {
169
+ signal?: AbortSignal;
170
+ }): Promise<AttestVerification>;
171
+ /** What became true and what stopped being true between two instants. Pair with `recall({ asOf })` to replay what an agent knew. */
172
+ diff(range: {
173
+ from: string;
174
+ to: string;
175
+ }, options?: {
176
+ signal?: AbortSignal;
177
+ }): Promise<Diff>;
178
+ /** Confirm a memory is still true; its freshness clock restarts. */
179
+ verifyMemory(memory: MemoryRef, options?: {
180
+ signal?: AbortSignal;
181
+ }): Promise<{
182
+ memoryId: string;
183
+ verifiedAt: string;
184
+ }>;
185
+ /** Why does this memory say what it says? Provenance back to the source events. */
186
+ explain(memory: MemoryRef, options?: {
187
+ depth?: number;
188
+ signal?: AbortSignal;
189
+ }): Promise<Explanation>;
190
+ /**
191
+ * Forget by memory id or by query. Recall stops returning it immediately; the text is purged
192
+ * after a grace window. Use `dryRun: true` first when selecting by query.
193
+ * Needs a key with the `forget` scope.
194
+ */
195
+ forget: {
196
+ (selector: {
197
+ memoryId: string;
198
+ } | {
199
+ query: string;
200
+ }, options: {
201
+ reason: string;
202
+ dryRun: true;
203
+ signal?: AbortSignal;
204
+ }): Promise<ForgetDryRun>;
205
+ (selector: {
206
+ memoryId: string;
207
+ } | {
208
+ query: string;
209
+ }, options: {
210
+ reason: string;
211
+ dryRun?: false;
212
+ signal?: AbortSignal;
213
+ }): Promise<{
214
+ receipt: DeletionReceipt;
215
+ }>;
216
+ /** Recompute the deletion ledger and check the memories are gone. */
217
+ verify(receiptId: string): Promise<ReceiptVerification>;
218
+ receipt(receiptId: string): Promise<DeletionReceipt>;
219
+ };
220
+ private verifyReceipt;
221
+ private getReceipt;
222
+ /** Counts for the project: events, memories by status, receipts. Numbers stop at 1000 and say so (`capped`). */
223
+ usage(): Promise<Usage>;
224
+ /** Describes the key in use (prefix, scopes, project). Handy as a connection check. */
225
+ whoami(): Promise<WhoAmI>;
226
+ }
227
+ declare class EventsApi {
228
+ private readonly t;
229
+ constructor(t: Transport);
230
+ /** Low-level append. Prefer `remember` unless you are shaping events yourself. */
231
+ append(events: EventInput[], options?: {
232
+ streamId?: string;
233
+ signal?: AbortSignal;
234
+ }): Promise<{
235
+ streamId: string;
236
+ firstSeq: number;
237
+ lastSeq: number;
238
+ headHash: string;
239
+ events: Array<{
240
+ id: string;
241
+ seq: number;
242
+ hash: string;
243
+ replayed: boolean;
244
+ }>;
245
+ }>;
246
+ get(id: string): Promise<StoredEvent>;
247
+ /** One page, with the cursor for the next. */
248
+ page(params?: {
249
+ stream?: string;
250
+ limit?: number;
251
+ cursor?: string;
252
+ }): Promise<Page<StoredEvent>>;
253
+ /** Every event of a stream in order, fetching pages as you iterate. */
254
+ list(params?: {
255
+ stream?: string;
256
+ pageSize?: number;
257
+ }): AsyncGenerator<StoredEvent>;
258
+ /** Pages as they arrive, for callers that batch. */
259
+ pages(params?: {
260
+ stream?: string;
261
+ pageSize?: number;
262
+ }): AsyncGenerator<StoredEvent[]>;
263
+ }
264
+ declare class MemoriesApi {
265
+ private readonly t;
266
+ constructor(t: Transport);
267
+ get(memory: MemoryRef): Promise<Memory>;
268
+ /**
269
+ * Replace what a current memory says. The old text stays as a superseded version, so history,
270
+ * `asOf` recall and `explain` still work. Returns the new version. Needs `write`.
271
+ */
272
+ edit(memory: MemoryRef, content: string): Promise<Memory>;
273
+ page(params?: {
274
+ status?: MemoryStatus;
275
+ limit?: number;
276
+ cursor?: string;
277
+ }): Promise<Page<Memory>>;
278
+ list(params?: {
279
+ status?: MemoryStatus;
280
+ pageSize?: number;
281
+ }): AsyncGenerator<Memory>;
282
+ }
283
+ declare class WebhooksApi {
284
+ private readonly t;
285
+ constructor(t: Transport);
286
+ /**
287
+ * Register an https endpoint. The signing secret is in the response and is never shown again.
288
+ * Verify deliveries with `verifyWebhook` from `kaibo/webhooks`.
289
+ */
290
+ create(input: {
291
+ url: string;
292
+ events?: WebhookEventType[];
293
+ }): Promise<CreatedWebhook>;
294
+ list(): Promise<Webhook[]>;
295
+ /** Recent deliveries, newest first, with status and attempts. */
296
+ deliveries(webhookId: string, options?: {
297
+ limit?: number;
298
+ }): Promise<WebhookDelivery[]>;
299
+ /** Queue a signed `webhook.test` delivery. */
300
+ test(webhookId: string): Promise<{
301
+ queued: true;
302
+ }>;
303
+ delete(webhookId: string): Promise<void>;
304
+ }
305
+ declare class ImportsApi {
306
+ private readonly t;
307
+ constructor(t: Transport);
308
+ /**
309
+ * Parse an export and append its events. With `dryRun: true` nothing is written and you get the
310
+ * report: what was read, what would be created, what was skipped and why. Safe to repeat: events
311
+ * carry idempotency keys derived from the records. The file must fit in one request (about 1 MB
312
+ * and 2000 events); `kaibo import` sends bigger files in chunks.
313
+ */
314
+ create(input: ImportInput, options?: {
315
+ dryRun?: boolean;
316
+ signal?: AbortSignal;
317
+ }): Promise<ImportResult>;
318
+ }
319
+ declare class ExportsApi {
320
+ private readonly t;
321
+ constructor(t: Transport);
322
+ /**
323
+ * The project's events and memories, one record at a time. Throws if the stream ends without
324
+ * its `end` record, because that means the export was cut off. At most 10 exports an hour per key.
325
+ */
326
+ stream(input?: ExportInput, options?: {
327
+ signal?: AbortSignal;
328
+ }): AsyncGenerator<ExportRecord>;
329
+ /** Collects a whole export in memory. Fine for small projects; prefer `stream`. */
330
+ create(input?: ExportInput, options?: {
331
+ signal?: AbortSignal;
332
+ }): Promise<ExportRecord[]>;
333
+ }
334
+ declare class ProjectsApi {
335
+ private readonly t;
336
+ constructor(t: Transport);
337
+ list(): Promise<Project[]>;
338
+ /** Needs an organization-wide admin key; a project-bound key cannot create projects. */
339
+ create(name: string): Promise<Project>;
340
+ /** Permanent: the project stops working at once and its data is removed in the background. Needs an organization-wide admin key. */
341
+ delete(projectId: string): Promise<void>;
342
+ rename(projectId: string, name: string): Promise<Project>;
343
+ }
344
+ declare class KeysApi {
345
+ private readonly t;
346
+ constructor(t: Transport);
347
+ list(): Promise<ApiKey[]>;
348
+ /** The secret is in `key` and is never shown again. A key can only grant scopes it holds. */
349
+ create(input: CreateKeyInput): Promise<CreatedApiKey>;
350
+ /** Revokes at once. Revoking the key you are calling with works and ends your access. */
351
+ revoke(keyId: string): Promise<ApiKey>;
352
+ }
353
+ declare class JobsApi {
354
+ private readonly t;
355
+ constructor(t: Transport);
356
+ get(jobId: string): Promise<JobStatus>;
357
+ /** Polls with a growing delay until extraction has caught up, or throws `TimeoutError`. */
358
+ wait(jobId: string, options?: WaitOptions): Promise<JobStatus>;
359
+ }
360
+ export { Kaibo as a, MemoriesApi as c, WaitOptions as d, WebhooksApi as f, withHelpers as h, JobsApi as i, ProjectsApi as l, PackHelpers as m, ExportsApi as n, KaiboOptions as o, Pack as p, ImportsApi as r, KeysApi as s, EventsApi as t, SDK_VERSION as u };
@@ -0,0 +1,51 @@
1
+ // src/errors.ts
2
+ /** Base class for everything this SDK throws. */
3
+ var KaiboError = class extends Error {
4
+ name = "KaiboError";
5
+ };
6
+ /** The API answered with an error envelope. */
7
+ var ApiError = class extends KaiboError {
8
+ code;
9
+ status;
10
+ requestId;
11
+ name = "ApiError";
12
+ constructor(message, code, status, requestId) {
13
+ super(message);
14
+ this.code = code;
15
+ this.status = status;
16
+ this.requestId = requestId;
17
+ }
18
+ /** What to try next, for the errors that have a standard fix. */
19
+ get hint() {
20
+ switch (this.code) {
21
+ case "unauthenticated": return "the key is missing, mistyped or revoked. check KAIBO_KEY, or create a key in the dashboard.";
22
+ case "forbidden": return "this key lacks the scope for the call (forget needs the forget scope, key and webhook management need admin).";
23
+ case "invalid_request": return "the request did not match the contract. GET /v1/openapi.json on your kaibo address lists every field.";
24
+ case "payload_too_large": return "split the request into smaller batches.";
25
+ default: return null;
26
+ }
27
+ }
28
+ };
29
+ /** HTTP 429. `retryAfter` is in seconds when the server said so. */
30
+ var RateLimitError = class extends ApiError {
31
+ retryAfter;
32
+ name = "RateLimitError";
33
+ constructor(message, requestId, retryAfter) {
34
+ super(message, "rate_limited", 429, requestId);
35
+ this.retryAfter = retryAfter;
36
+ }
37
+ };
38
+ /** The request never produced an HTTP response (DNS, connection reset, offline). */
39
+ var NetworkError = class extends KaiboError {
40
+ cause;
41
+ name = "NetworkError";
42
+ constructor(message, cause) {
43
+ super(message);
44
+ this.cause = cause;
45
+ }
46
+ };
47
+ /** `timeoutMs` elapsed, or the caller's `AbortSignal` fired. */
48
+ var TimeoutError = class extends KaiboError {
49
+ name = "TimeoutError";
50
+ };
51
+ export { TimeoutError as a, RateLimitError as i, KaiboError as n, NetworkError as r, ApiError as t };
@@ -0,0 +1,80 @@
1
+ // src/errors.ts
2
+ /** Base class for everything this SDK throws. */
3
+ var KaiboError = class extends Error {
4
+ name = "KaiboError";
5
+ };
6
+ /** The API answered with an error envelope. */
7
+ var ApiError = class extends KaiboError {
8
+ code;
9
+ status;
10
+ requestId;
11
+ name = "ApiError";
12
+ constructor(message, code, status, requestId) {
13
+ super(message);
14
+ this.code = code;
15
+ this.status = status;
16
+ this.requestId = requestId;
17
+ }
18
+ /** What to try next, for the errors that have a standard fix. */
19
+ get hint() {
20
+ switch (this.code) {
21
+ case "unauthenticated": return "the key is missing, mistyped or revoked. check KAIBO_KEY, or create a key in the dashboard.";
22
+ case "forbidden": return "this key lacks the scope for the call (forget needs the forget scope, key and webhook management need admin).";
23
+ case "invalid_request": return "the request did not match the contract. GET /v1/openapi.json on your kaibo address lists every field.";
24
+ case "payload_too_large": return "split the request into smaller batches.";
25
+ default: return null;
26
+ }
27
+ }
28
+ };
29
+ /** HTTP 429. `retryAfter` is in seconds when the server said so. */
30
+ var RateLimitError = class extends ApiError {
31
+ retryAfter;
32
+ name = "RateLimitError";
33
+ constructor(message, requestId, retryAfter) {
34
+ super(message, "rate_limited", 429, requestId);
35
+ this.retryAfter = retryAfter;
36
+ }
37
+ };
38
+ /** The request never produced an HTTP response (DNS, connection reset, offline). */
39
+ var NetworkError = class extends KaiboError {
40
+ cause;
41
+ name = "NetworkError";
42
+ constructor(message, cause) {
43
+ super(message);
44
+ this.cause = cause;
45
+ }
46
+ };
47
+ /** `timeoutMs` elapsed, or the caller's `AbortSignal` fired. */
48
+ var TimeoutError = class extends KaiboError {
49
+ name = "TimeoutError";
50
+ };
51
+ Object.defineProperty(exports, "ApiError", {
52
+ enumerable: true,
53
+ get: function() {
54
+ return ApiError;
55
+ }
56
+ });
57
+ Object.defineProperty(exports, "KaiboError", {
58
+ enumerable: true,
59
+ get: function() {
60
+ return KaiboError;
61
+ }
62
+ });
63
+ Object.defineProperty(exports, "NetworkError", {
64
+ enumerable: true,
65
+ get: function() {
66
+ return NetworkError;
67
+ }
68
+ });
69
+ Object.defineProperty(exports, "RateLimitError", {
70
+ enumerable: true,
71
+ get: function() {
72
+ return RateLimitError;
73
+ }
74
+ });
75
+ Object.defineProperty(exports, "TimeoutError", {
76
+ enumerable: true,
77
+ get: function() {
78
+ return TimeoutError;
79
+ }
80
+ });
@@ -0,0 +1,39 @@
1
+ /** Stable machine-readable codes returned by the API. */
2
+ type ErrorCode = 'unauthenticated' | 'forbidden' | 'not_found' | 'invalid_request' | 'conflict' | 'idempotency_mismatch' | 'payload_too_large' | 'rate_limited' | 'internal';
3
+ /** Base class for everything this SDK throws. */
4
+ declare class KaiboError extends Error {
5
+ name: string;
6
+ }
7
+ /** The API answered with an error envelope. */
8
+ declare class ApiError extends KaiboError {
9
+ /** Stable code; switch on this, not on `message`. */
10
+ readonly code: ErrorCode | 'unknown';
11
+ readonly status: number;
12
+ /** Quote this when asking for support. */
13
+ readonly requestId: string | null;
14
+ name: string;
15
+ constructor(message: string,
16
+ /** Stable code; switch on this, not on `message`. */
17
+ code: ErrorCode | 'unknown', status: number,
18
+ /** Quote this when asking for support. */
19
+ requestId: string | null);
20
+ /** What to try next, for the errors that have a standard fix. */
21
+ get hint(): string | null;
22
+ }
23
+ /** HTTP 429. `retryAfter` is in seconds when the server said so. */
24
+ declare class RateLimitError extends ApiError {
25
+ readonly retryAfter: number | null;
26
+ name: string;
27
+ constructor(message: string, requestId: string | null, retryAfter: number | null);
28
+ }
29
+ /** The request never produced an HTTP response (DNS, connection reset, offline). */
30
+ declare class NetworkError extends KaiboError {
31
+ readonly cause?: unknown | undefined;
32
+ name: string;
33
+ constructor(message: string, cause?: unknown | undefined);
34
+ }
35
+ /** `timeoutMs` elapsed, or the caller's `AbortSignal` fired. */
36
+ declare class TimeoutError extends KaiboError {
37
+ name: string;
38
+ }
39
+ export { RateLimitError as a, NetworkError as i, ErrorCode as n, TimeoutError as o, KaiboError as r, ApiError as t };
@@ -0,0 +1,39 @@
1
+ /** Stable machine-readable codes returned by the API. */
2
+ type ErrorCode = 'unauthenticated' | 'forbidden' | 'not_found' | 'invalid_request' | 'conflict' | 'idempotency_mismatch' | 'payload_too_large' | 'rate_limited' | 'internal';
3
+ /** Base class for everything this SDK throws. */
4
+ declare class KaiboError extends Error {
5
+ name: string;
6
+ }
7
+ /** The API answered with an error envelope. */
8
+ declare class ApiError extends KaiboError {
9
+ /** Stable code; switch on this, not on `message`. */
10
+ readonly code: ErrorCode | 'unknown';
11
+ readonly status: number;
12
+ /** Quote this when asking for support. */
13
+ readonly requestId: string | null;
14
+ name: string;
15
+ constructor(message: string,
16
+ /** Stable code; switch on this, not on `message`. */
17
+ code: ErrorCode | 'unknown', status: number,
18
+ /** Quote this when asking for support. */
19
+ requestId: string | null);
20
+ /** What to try next, for the errors that have a standard fix. */
21
+ get hint(): string | null;
22
+ }
23
+ /** HTTP 429. `retryAfter` is in seconds when the server said so. */
24
+ declare class RateLimitError extends ApiError {
25
+ readonly retryAfter: number | null;
26
+ name: string;
27
+ constructor(message: string, requestId: string | null, retryAfter: number | null);
28
+ }
29
+ /** The request never produced an HTTP response (DNS, connection reset, offline). */
30
+ declare class NetworkError extends KaiboError {
31
+ readonly cause?: unknown | undefined;
32
+ name: string;
33
+ constructor(message: string, cause?: unknown | undefined);
34
+ }
35
+ /** `timeoutMs` elapsed, or the caller's `AbortSignal` fired. */
36
+ declare class TimeoutError extends KaiboError {
37
+ name: string;
38
+ }
39
+ export { RateLimitError as a, NetworkError as i, ErrorCode as n, TimeoutError as o, KaiboError as r, ApiError as t };
@@ -0,0 +1,77 @@
1
+ // ../config/src/index.ts
2
+ const DISPLAY_NAME = "Kaibo";
3
+ /** Ledger/event hash chain genesis value. */
4
+ const GENESIS_HASH = "0".repeat(64);
5
+ const WEBHOOK = {
6
+ maxPerProject: 10,
7
+ timeoutMs: 1e4,
8
+ signatureHeader: `X-${DISPLAY_NAME}-Signature`,
9
+ replayWindowSeconds: 300,
10
+ retryDelaysSeconds: [
11
+ 60,
12
+ 300,
13
+ 1800,
14
+ 7200,
15
+ 43200
16
+ ]
17
+ };
18
+ // ../engine/src/hash.ts
19
+ const encoder = new TextEncoder();
20
+ function toHex(bytes) {
21
+ let out = "";
22
+ for (const b of bytes) out += b.toString(16).padStart(2, "0");
23
+ return out;
24
+ }
25
+ /** SHA-256 of UTF-8 text or raw bytes, lowercase hex. Uses Web Crypto so it runs in Convex, Workers, Node and browsers. */
26
+ async function sha256Hex(data) {
27
+ const bytes = typeof data === "string" ? encoder.encode(data) : new Uint8Array(data);
28
+ const digest = await crypto.subtle.digest("SHA-256", bytes);
29
+ return toHex(new Uint8Array(digest));
30
+ }
31
+ /**
32
+ * Rejects anything that would hash differently from what a reader of the stored JSON sees:
33
+ * `undefined` (dropped from objects, `null` in arrays), non-finite numbers, bigint, functions,
34
+ * symbols, non-plain objects (Date, Map, class instances) and lone surrogates (not I-JSON, RFC 7493).
35
+ */
36
+ function assertIJson(value, path = "$") {
37
+ switch (typeof value) {
38
+ case "string":
39
+ if (!value.isWellFormed()) throw new TypeError(`${path}: lone surrogate in string`);
40
+ return;
41
+ case "boolean": return;
42
+ case "number":
43
+ if (!Number.isFinite(value)) throw new TypeError(`${path}: non-finite number`);
44
+ return;
45
+ case "object": {
46
+ if (value === null) return;
47
+ if (Array.isArray(value)) {
48
+ value.forEach((v, i) => assertIJson(v, `${path}[${i}]`));
49
+ return;
50
+ }
51
+ const proto = Object.getPrototypeOf(value);
52
+ if (proto !== Object.prototype && proto !== null) throw new TypeError(`${path}: not a plain object`);
53
+ for (const [k, v] of Object.entries(value)) {
54
+ if (!k.isWellFormed()) throw new TypeError(`${path}: lone surrogate in key`);
55
+ assertIJson(v, `${path}.${k}`);
56
+ }
57
+ return;
58
+ }
59
+ default: throw new TypeError(`${path}: ${typeof value} is not JSON`);
60
+ }
61
+ }
62
+ /**
63
+ * RFC 8785 JSON Canonicalization Scheme over I-JSON values. Dependency-free: object keys sort by
64
+ * UTF-16 code units (the default JS sort) and numbers and strings serialize exactly as
65
+ * `JSON.stringify`, which is what the RFC specifies for ECMAScript. Throws on anything else.
66
+ */
67
+ function jcs(value) {
68
+ assertIJson(value);
69
+ return serialize(value);
70
+ }
71
+ function serialize(v) {
72
+ if (v === null || typeof v === "string" || typeof v === "number" || typeof v === "boolean") return JSON.stringify(v);
73
+ if (Array.isArray(v)) return `[${v.map(serialize).join(",")}]`;
74
+ const o = v;
75
+ return `{${Object.keys(o).sort().map((k) => `${JSON.stringify(k)}:${serialize(o[k])}`).join(",")}}`;
76
+ }
77
+ export { WEBHOOK as a, GENESIS_HASH as i, sha256Hex as n, toHex as r, jcs as t };