@omnistreams/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 ADDED
@@ -0,0 +1,138 @@
1
+ # @omnistreams/sdk
2
+
3
+ Official **TypeScript SDK** for the [OmniStream](https://github.com/Cepat-Kilat-Teknologi/omnistream)
4
+ omnichannel CRM API. Types are generated from the published OpenAPI spec; the
5
+ runtime adds auth, retries, pagination, idempotency and webhook verification.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm install @omnistreams/sdk
11
+ ```
12
+
13
+ Requires Node.js ≥ 18 (uses the global `fetch` and Web Crypto).
14
+
15
+ ## Quick start
16
+
17
+ ```ts
18
+ import { OmnistreamClient } from "@omnistreams/sdk";
19
+
20
+ const client = new OmnistreamClient({
21
+ apiKey: process.env.OMNISTREAM_API_KEY!, // create in Developer → API Keys
22
+ baseUrl: "https://your-omnistream-host", // default http://localhost:3000
23
+ });
24
+
25
+ // Typed resource helpers
26
+ const open = await client.conversations.list({ status: "open" });
27
+ const message = await client.conversations.sendMessage(open[0].id, {
28
+ type: "text",
29
+ content: { text: "Hi! How can I help?" },
30
+ });
31
+ ```
32
+
33
+ ## Features
34
+
35
+ ### Auth
36
+
37
+ Every request sends your key as `X-API-Key`. Lock the key down with an **IP
38
+ allow list** (Developer → API Keys) for server-to-server use.
39
+
40
+ ### Retries & rate limits
41
+
42
+ Failed requests are retried automatically with exponential backoff and full
43
+ jitter. `429` responses honour the `Retry-After` header. Safe methods (`GET`)
44
+ retry on network/5xx errors; unsafe methods only retry on `429` — unless you
45
+ pass an idempotency key (see below).
46
+
47
+ ```ts
48
+ const client = new OmnistreamClient({ apiKey, maxRetries: 3, timeoutMs: 15000 });
49
+ ```
50
+
51
+ ### Idempotency
52
+
53
+ Pass an idempotency key so a `POST` can be safely retried on transient failures:
54
+
55
+ ```ts
56
+ import { generateIdempotencyKey } from "@omnistreams/sdk";
57
+
58
+ await client.conversations.sendMessage(
59
+ id,
60
+ { type: "text", content: { text: "hi" } },
61
+ { idempotencyKey: generateIdempotencyKey() },
62
+ );
63
+ ```
64
+
65
+ ### Pagination
66
+
67
+ `paginate()` returns an async iterator that walks page-numbered list endpoints
68
+ lazily:
69
+
70
+ ```ts
71
+ import type { Contact } from "@omnistreams/sdk";
72
+
73
+ for await (const contact of client.paginate<Contact>("/api/contacts", { search: "acme" })) {
74
+ console.log(contact.name);
75
+ }
76
+ ```
77
+
78
+ ### Typed errors
79
+
80
+ ```ts
81
+ import { OmnistreamApiError, OmnistreamNetworkError } from "@omnistreams/sdk";
82
+
83
+ try {
84
+ await client.conversations.get("does-not-exist");
85
+ } catch (err) {
86
+ if (err instanceof OmnistreamApiError && err.isNotFound) {
87
+ // 404
88
+ } else if (err instanceof OmnistreamNetworkError && err.timedOut) {
89
+ // request timed out
90
+ }
91
+ }
92
+ ```
93
+
94
+ `OmnistreamApiError` exposes `status`, `code`, `body`, and helpers:
95
+ `isAuthError` (401), `isForbidden` (403), `isNotFound` (404),
96
+ `isValidationError` (422), `isRateLimited` (429), `isServerError` (5xx).
97
+
98
+ ### Webhook verification
99
+
100
+ Verify inbound webhooks signed by the gateway (`X-Omnistream-Signature`,
101
+ HMAC-SHA256 hex). Works in Node, browsers and edge runtimes.
102
+
103
+ ```ts
104
+ import { verifyWebhookSignature, verifyWebhookSignatureWithRotation } from "@omnistreams/sdk";
105
+
106
+ // rawBody must be the exact bytes received — verify BEFORE JSON.parse.
107
+ const ok = await verifyWebhookSignature(rawBody, req.headers["x-omnistream-signature"], secret);
108
+
109
+ // During a secret rotation, accept the current OR previous signature:
110
+ const okRotating = await verifyWebhookSignatureWithRotation(rawBody, secret, {
111
+ current: req.headers["x-omnistream-signature"],
112
+ previous: req.headers["x-omnistream-signature-previous"],
113
+ });
114
+ ```
115
+
116
+ ## Low-level access
117
+
118
+ Every endpoint is reachable through the generic verbs, and the full generated
119
+ OpenAPI types are exported:
120
+
121
+ ```ts
122
+ import type { components } from "@omnistreams/sdk";
123
+ type Campaign = components["schemas"]["Campaign"];
124
+
125
+ const campaigns = await client.get<Campaign[]>("/api/campaigns", { page: 1 });
126
+ await client.request("DELETE", `/api/api-keys/${keyId}`);
127
+ ```
128
+
129
+ ## Development
130
+
131
+ ```bash
132
+ npm install
133
+ npm run generate # regenerate src/generated/openapi.ts from ../../docs/openapi.yaml
134
+ npm run build
135
+ npm test
136
+ ```
137
+
138
+ Regenerate the types whenever `docs/openapi.yaml` changes.
@@ -0,0 +1,226 @@
1
+ /**
2
+ * OmniStream API client.
3
+ *
4
+ * A small, typed wrapper around the OmniStream REST API with:
5
+ * - API-key auth (`X-API-Key`),
6
+ * - automatic retries with exponential backoff (honouring `Retry-After`),
7
+ * - optional idempotency keys for safe POST retries,
8
+ * - typed errors,
9
+ * - an async pagination helper.
10
+ *
11
+ * Response types come from the generated OpenAPI schema (`./generated/openapi`).
12
+ */
13
+ import type { components } from "./generated/openapi.js";
14
+ type Schemas = components["schemas"];
15
+ export type Conversation = Schemas["ConversationWithContact"];
16
+ export type Contact = Schemas["Contact"];
17
+ export type Message = Schemas["Message"];
18
+ export type MessageListResponse = Schemas["MessageListResponse"];
19
+ export type WaTemplate = Schemas["WaTemplate"];
20
+ export type ApiKey = Schemas["ApiKey"];
21
+ export type SendMessageRequest = Schemas["SendMessageRequest"];
22
+ export type CreateApiKeyRequest = Schemas["CreateApiKeyRequest"];
23
+ export type ApiKeyCreateResponse = Schemas["ApiKeyCreateResponse"];
24
+ export type ConversationStatus = Schemas["ConversationStatus"];
25
+ /** Query parameters; nullish values are omitted. */
26
+ export type Query = Record<string, string | number | boolean | undefined | null>;
27
+ /** Options accepted by the client constructor. */
28
+ export interface OmnistreamClientOptions {
29
+ /** REST API key (`os_..._...`), sent as `X-API-Key`. */
30
+ apiKey: string;
31
+ /** API gateway base URL. Default `http://localhost:3000`. */
32
+ baseUrl?: string;
33
+ /** Per-request timeout in milliseconds. Default 30000. */
34
+ timeoutMs?: number;
35
+ /** Max automatic retries per request. Default 2. */
36
+ maxRetries?: number;
37
+ /** Injectable fetch implementation (defaults to the global). */
38
+ fetch?: typeof fetch;
39
+ }
40
+ /** Per-request options. */
41
+ export interface RequestOptions {
42
+ query?: Query;
43
+ body?: unknown;
44
+ /**
45
+ * Idempotency key sent as `Idempotency-Key`. When set, POST requests become
46
+ * safe to retry on network/5xx failures.
47
+ */
48
+ idempotencyKey?: string;
49
+ /** Caller-supplied abort signal (combined with the client timeout). */
50
+ signal?: AbortSignal;
51
+ /** Override the client's `maxRetries` for this request. */
52
+ maxRetries?: number;
53
+ }
54
+ /** Serialize a query object, skipping nullish values. */
55
+ export declare function buildQueryString(query?: Query): string;
56
+ /** Generate a random idempotency key (RFC 4122 UUID). */
57
+ export declare function generateIdempotencyKey(): string;
58
+ export declare class OmnistreamClient {
59
+ private readonly apiKey;
60
+ private readonly baseUrl;
61
+ private readonly timeoutMs;
62
+ private readonly maxRetries;
63
+ private readonly fetchImpl;
64
+ constructor(options: OmnistreamClientOptions);
65
+ readonly conversations: {
66
+ /** List conversations (filter by status / assigned agent, paginated). */
67
+ list: (params?: {
68
+ status?: ConversationStatus;
69
+ assigned_agent_id?: string;
70
+ page?: number;
71
+ per_page?: number;
72
+ }) => Promise<{
73
+ id: string;
74
+ contact_id: string;
75
+ assigned_agent_id?: string | null;
76
+ assigned_agent_name?: string | null;
77
+ status: components["schemas"]["ConversationStatus"];
78
+ last_message_at: string;
79
+ unread_count: number;
80
+ created_at: string;
81
+ updated_at: string;
82
+ contact_name?: string | null;
83
+ contact_phone?: string | null;
84
+ contact_channel: string;
85
+ assignees?: components["schemas"]["Assignee"][] | null;
86
+ }[]>;
87
+ /** Get a single conversation by id. */
88
+ get: (id: string) => Promise<{
89
+ id: string;
90
+ contact_id: string;
91
+ assigned_agent_id?: string | null;
92
+ assigned_agent_name?: string | null;
93
+ status: components["schemas"]["ConversationStatus"];
94
+ last_message_at: string;
95
+ unread_count: number;
96
+ created_at: string;
97
+ updated_at: string;
98
+ contact_name?: string | null;
99
+ contact_phone?: string | null;
100
+ contact_channel: string;
101
+ assignees?: components["schemas"]["Assignee"][] | null;
102
+ }>;
103
+ /** List messages in a conversation (cursor paginated, newest first). */
104
+ messages: (id: string, params?: {
105
+ cursor?: string;
106
+ limit?: number;
107
+ }) => Promise<{
108
+ messages: components["schemas"]["Message"][];
109
+ next_cursor?: string | null;
110
+ has_more: boolean;
111
+ }>;
112
+ /** Send an outbound message. */
113
+ sendMessage: (id: string, body: SendMessageRequest, options?: RequestOptions) => Promise<{
114
+ _id?: string;
115
+ conversation_id: string;
116
+ external_id?: string | null;
117
+ direction: components["schemas"]["MessageDirection"];
118
+ type: components["schemas"]["MessageType"];
119
+ content: unknown;
120
+ status: components["schemas"]["MessageStatus"];
121
+ sender_phone?: string | null;
122
+ error_message?: string | null;
123
+ error_code?: string | null;
124
+ error_source?: string | null;
125
+ error_details?: Record<string, never> | null;
126
+ created_at: string;
127
+ }>;
128
+ };
129
+ readonly contacts: {
130
+ /** List/search contacts. */
131
+ list: (params?: {
132
+ search?: string;
133
+ tag?: string;
134
+ page?: number;
135
+ per_page?: number;
136
+ }) => Promise<{
137
+ id: string;
138
+ phone_number?: string | null;
139
+ name?: string | null;
140
+ email?: string | null;
141
+ channel_source: string;
142
+ tags: string[];
143
+ created_at: string;
144
+ updated_at: string;
145
+ }[]>;
146
+ };
147
+ readonly messages: {
148
+ /** Full-text search across message content. */
149
+ search: (q: string, limit?: number) => Promise<{
150
+ _id?: string;
151
+ conversation_id: string;
152
+ external_id?: string | null;
153
+ direction: components["schemas"]["MessageDirection"];
154
+ type: components["schemas"]["MessageType"];
155
+ content: unknown;
156
+ status: components["schemas"]["MessageStatus"];
157
+ sender_phone?: string | null;
158
+ error_message?: string | null;
159
+ error_code?: string | null;
160
+ error_source?: string | null;
161
+ error_details?: Record<string, never> | null;
162
+ created_at: string;
163
+ }[]>;
164
+ };
165
+ readonly templates: {
166
+ /** List WhatsApp templates. */
167
+ list: (params?: {
168
+ status?: string;
169
+ category?: string;
170
+ waba_id?: string;
171
+ }) => Promise<{
172
+ id: string;
173
+ meta_template_id?: string | null;
174
+ waba_id: string;
175
+ name: string;
176
+ language: string;
177
+ category: "MARKETING" | "UTILITY" | "AUTHENTICATION";
178
+ status: "APPROVED" | "PENDING" | "REJECTED" | "PAUSED" | "DISABLED";
179
+ components: unknown;
180
+ header_media_url?: string | null;
181
+ created_at: string;
182
+ updated_at: string;
183
+ }[]>;
184
+ };
185
+ readonly apiKeys: {
186
+ /** List the caller's API keys. */
187
+ list: () => Promise<{
188
+ id: string;
189
+ agent_id: string;
190
+ name: string;
191
+ key_type: "rest" | "webhook_signing";
192
+ key_prefix: string;
193
+ scopes: unknown;
194
+ last_used_at?: string | null;
195
+ expires_at?: string | null;
196
+ is_active: boolean;
197
+ created_at: string;
198
+ revoked_at?: string | null;
199
+ }[]>;
200
+ /** Create an API key (returns the plaintext key once). */
201
+ create: (body: CreateApiKeyRequest) => Promise<{
202
+ key: components["schemas"]["ApiKey"];
203
+ plaintext_key: string;
204
+ }>;
205
+ /** Revoke an API key. */
206
+ revoke: (id: string) => Promise<void>;
207
+ };
208
+ get<T>(path: string, query?: Query): Promise<T>;
209
+ post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T>;
210
+ /**
211
+ * Iterate every item across a page-numbered list endpoint that returns a
212
+ * JSON array (e.g. `/api/conversations`, `/api/contacts`). Fetches lazily.
213
+ */
214
+ paginate<T>(path: string, params?: Query, options?: {
215
+ perPage?: number;
216
+ }): AsyncGenerator<T, void, unknown>;
217
+ /**
218
+ * Low-level request with auth, timeout and retry. Throws
219
+ * {@link OmnistreamApiError} on non-2xx and {@link OmnistreamNetworkError} on
220
+ * network/timeout failures.
221
+ */
222
+ request<T>(method: string, path: string, options?: RequestOptions): Promise<T>;
223
+ /** Build an abort signal combining the client timeout with a caller signal. */
224
+ private deadline;
225
+ }
226
+ export {};
package/dist/client.js ADDED
@@ -0,0 +1,245 @@
1
+ /**
2
+ * OmniStream API client.
3
+ *
4
+ * A small, typed wrapper around the OmniStream REST API with:
5
+ * - API-key auth (`X-API-Key`),
6
+ * - automatic retries with exponential backoff (honouring `Retry-After`),
7
+ * - optional idempotency keys for safe POST retries,
8
+ * - typed errors,
9
+ * - an async pagination helper.
10
+ *
11
+ * Response types come from the generated OpenAPI schema (`./generated/openapi`).
12
+ */
13
+ import { OmnistreamApiError, OmnistreamNetworkError } from "./errors.js";
14
+ const DEFAULT_BASE_URL = "http://localhost:3000";
15
+ const DEFAULT_TIMEOUT_MS = 30_000;
16
+ const DEFAULT_MAX_RETRIES = 2;
17
+ const RETRY_BASE_DELAY_MS = 200;
18
+ const RETRY_MAX_DELAY_MS = 5_000;
19
+ /** Serialize a query object, skipping nullish values. */
20
+ export function buildQueryString(query) {
21
+ if (!query)
22
+ return "";
23
+ const params = new URLSearchParams();
24
+ for (const [key, value] of Object.entries(query)) {
25
+ if (value === undefined || value === null)
26
+ continue;
27
+ params.append(key, String(value));
28
+ }
29
+ const qs = params.toString();
30
+ return qs ? `?${qs}` : "";
31
+ }
32
+ /** Generate a random idempotency key (RFC 4122 UUID). */
33
+ export function generateIdempotencyKey() {
34
+ return crypto.randomUUID();
35
+ }
36
+ export class OmnistreamClient {
37
+ apiKey;
38
+ baseUrl;
39
+ timeoutMs;
40
+ maxRetries;
41
+ fetchImpl;
42
+ constructor(options) {
43
+ if (!options.apiKey)
44
+ throw new Error("OmnistreamClient: `apiKey` is required.");
45
+ this.apiKey = options.apiKey;
46
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
47
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
48
+ this.maxRetries = options.maxRetries ?? DEFAULT_MAX_RETRIES;
49
+ const f = options.fetch ?? globalThis.fetch;
50
+ if (!f)
51
+ throw new Error("OmnistreamClient: no fetch implementation (Node >= 18 required).");
52
+ this.fetchImpl = f.bind(globalThis);
53
+ }
54
+ // ── Resource helpers ──────────────────────────────────────────────────
55
+ conversations = {
56
+ /** List conversations (filter by status / assigned agent, paginated). */
57
+ list: (params) => this.get("/api/conversations", params),
58
+ /** Get a single conversation by id. */
59
+ get: (id) => this.get(`/api/conversations/${enc(id)}`),
60
+ /** List messages in a conversation (cursor paginated, newest first). */
61
+ messages: (id, params) => this.get(`/api/conversations/${enc(id)}/messages`, params),
62
+ /** Send an outbound message. */
63
+ sendMessage: (id, body, options) => this.post(`/api/conversations/${enc(id)}/messages`, body, options),
64
+ };
65
+ contacts = {
66
+ /** List/search contacts. */
67
+ list: (params) => this.get("/api/contacts", params),
68
+ };
69
+ messages = {
70
+ /** Full-text search across message content. */
71
+ search: (q, limit) => this.get("/api/messages/search", { q, limit }),
72
+ };
73
+ templates = {
74
+ /** List WhatsApp templates. */
75
+ list: (params) => this.get("/api/wa-templates", params),
76
+ };
77
+ apiKeys = {
78
+ /** List the caller's API keys. */
79
+ list: () => this.get("/api/api-keys"),
80
+ /** Create an API key (returns the plaintext key once). */
81
+ create: (body) => this.post("/api/api-keys", body),
82
+ /** Revoke an API key. */
83
+ revoke: (id) => this.request("DELETE", `/api/api-keys/${enc(id)}`),
84
+ };
85
+ // ── Generic verbs ─────────────────────────────────────────────────────
86
+ get(path, query) {
87
+ return this.request("GET", path, { query });
88
+ }
89
+ post(path, body, options) {
90
+ return this.request("POST", path, { ...options, body });
91
+ }
92
+ /**
93
+ * Iterate every item across a page-numbered list endpoint that returns a
94
+ * JSON array (e.g. `/api/conversations`, `/api/contacts`). Fetches lazily.
95
+ */
96
+ async *paginate(path, params = {}, options = {}) {
97
+ const perPage = options.perPage ?? 50;
98
+ let page = 1;
99
+ for (;;) {
100
+ const items = await this.get(path, { ...params, page, per_page: perPage });
101
+ for (const item of items)
102
+ yield item;
103
+ if (!Array.isArray(items) || items.length < perPage)
104
+ break;
105
+ page += 1;
106
+ }
107
+ }
108
+ /**
109
+ * Low-level request with auth, timeout and retry. Throws
110
+ * {@link OmnistreamApiError} on non-2xx and {@link OmnistreamNetworkError} on
111
+ * network/timeout failures.
112
+ */
113
+ async request(method, path, options = {}) {
114
+ const url = `${this.baseUrl}${path}${buildQueryString(options.query)}`;
115
+ const hasBody = options.body !== undefined;
116
+ const maxRetries = options.maxRetries ?? this.maxRetries;
117
+ const headers = { "X-API-Key": this.apiKey, Accept: "application/json" };
118
+ if (hasBody)
119
+ headers["Content-Type"] = "application/json";
120
+ if (options.idempotencyKey)
121
+ headers["Idempotency-Key"] = options.idempotencyKey;
122
+ const body = hasBody ? JSON.stringify(options.body) : undefined;
123
+ let attempt = 0;
124
+ for (;;) {
125
+ const { signal, cancel } = this.deadline(options.signal);
126
+ let res;
127
+ try {
128
+ res = await this.fetchImpl(url, { method, headers, body, signal });
129
+ }
130
+ catch (err) {
131
+ cancel();
132
+ const timedOut = isAbortError(err) && !options.signal?.aborted;
133
+ // External abort → propagate; timeout/network → maybe retry.
134
+ if (isAbortError(err) && options.signal?.aborted) {
135
+ throw new OmnistreamNetworkError("Request aborted by caller", false, err);
136
+ }
137
+ if (attempt < maxRetries && retryableOnNetwork(method, options.idempotencyKey)) {
138
+ await sleep(backoffDelay(attempt));
139
+ attempt += 1;
140
+ continue;
141
+ }
142
+ throw new OmnistreamNetworkError(timedOut ? `Request timed out after ${this.timeoutMs}ms` : `Network error: ${errMessage(err)}`, timedOut, err);
143
+ }
144
+ cancel();
145
+ if (res.ok) {
146
+ return (await parseJson(res));
147
+ }
148
+ // Retry on 429 (all methods) and 5xx (idempotent/keyed methods).
149
+ const retryable = res.status === 429 || (res.status >= 500 && retryableOnNetwork(method, options.idempotencyKey));
150
+ if (attempt < maxRetries && retryable) {
151
+ await sleep(retryAfterMs(res) ?? backoffDelay(attempt));
152
+ attempt += 1;
153
+ continue;
154
+ }
155
+ const parsed = await parseJson(res);
156
+ throw new OmnistreamApiError(res.status, extractErrorMessage(parsed, res.status), extractErrorCode(parsed), parsed);
157
+ }
158
+ }
159
+ /** Build an abort signal combining the client timeout with a caller signal. */
160
+ deadline(external) {
161
+ const controller = new AbortController();
162
+ const onExternalAbort = () => controller.abort(external?.reason);
163
+ if (external) {
164
+ if (external.aborted)
165
+ controller.abort(external.reason);
166
+ else
167
+ external.addEventListener("abort", onExternalAbort, { once: true });
168
+ }
169
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
170
+ const cancel = () => {
171
+ clearTimeout(timer);
172
+ external?.removeEventListener("abort", onExternalAbort);
173
+ };
174
+ return { signal: controller.signal, cancel };
175
+ }
176
+ }
177
+ /** URL-encode a path segment. */
178
+ function enc(segment) {
179
+ return encodeURIComponent(segment);
180
+ }
181
+ function isAbortError(err) {
182
+ return err instanceof Error && err.name === "AbortError";
183
+ }
184
+ function errMessage(err) {
185
+ return err instanceof Error ? err.message : String(err);
186
+ }
187
+ /** GET is always safe to retry; POST/PUT/PATCH/DELETE only with an idempotency key. */
188
+ function retryableOnNetwork(method, idempotencyKey) {
189
+ return method.toUpperCase() === "GET" || idempotencyKey !== undefined;
190
+ }
191
+ /** Exponential backoff with full jitter. */
192
+ function backoffDelay(attempt) {
193
+ const capped = Math.min(RETRY_MAX_DELAY_MS, RETRY_BASE_DELAY_MS * 2 ** attempt);
194
+ return Math.floor(Math.random() * capped);
195
+ }
196
+ /** Parse a `Retry-After` header (seconds) into milliseconds, if present. */
197
+ function retryAfterMs(res) {
198
+ const header = res.headers.get("retry-after");
199
+ if (!header)
200
+ return undefined;
201
+ const seconds = Number(header);
202
+ return Number.isFinite(seconds) && seconds >= 0 ? seconds * 1000 : undefined;
203
+ }
204
+ function sleep(ms) {
205
+ return new Promise((resolve) => setTimeout(resolve, ms));
206
+ }
207
+ async function parseJson(res) {
208
+ const text = await res.text();
209
+ if (!text)
210
+ return undefined;
211
+ try {
212
+ return JSON.parse(text);
213
+ }
214
+ catch {
215
+ return text;
216
+ }
217
+ }
218
+ function extractErrorMessage(body, status) {
219
+ if (typeof body === "string" && body.trim())
220
+ return body.trim();
221
+ if (body && typeof body === "object") {
222
+ const err = body.error;
223
+ if (typeof err === "string")
224
+ return err;
225
+ if (err && typeof err === "object" && typeof err.message === "string") {
226
+ return err.message;
227
+ }
228
+ const msg = body.message;
229
+ if (typeof msg === "string")
230
+ return msg;
231
+ }
232
+ return `HTTP ${status}`;
233
+ }
234
+ function extractErrorCode(body) {
235
+ if (body && typeof body === "object") {
236
+ const err = body.error;
237
+ if (err && typeof err === "object") {
238
+ const code = err.code;
239
+ if (typeof code === "string" || typeof code === "number")
240
+ return code;
241
+ }
242
+ }
243
+ return undefined;
244
+ }
245
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /** Error types thrown by the OmniStream SDK. */
2
+ /** Base class for every error the SDK throws. */
3
+ export declare class OmnistreamError extends Error {
4
+ constructor(message: string);
5
+ }
6
+ /**
7
+ * Thrown for non-2xx API responses. Carries the HTTP status, the API error
8
+ * `code` when present, and the raw parsed body. Convenience getters classify
9
+ * common cases.
10
+ */
11
+ export declare class OmnistreamApiError extends OmnistreamError {
12
+ readonly status: number;
13
+ readonly code?: string | number | undefined;
14
+ readonly body?: unknown | undefined;
15
+ constructor(status: number, message: string, code?: string | number | undefined, body?: unknown | undefined);
16
+ /** 401 — missing/invalid credentials (or a source IP outside a key's allow list). */
17
+ get isAuthError(): boolean;
18
+ /** 403 — authenticated but not permitted. */
19
+ get isForbidden(): boolean;
20
+ /** 404 — resource not found. */
21
+ get isNotFound(): boolean;
22
+ /** 422 — request validation failed. */
23
+ get isValidationError(): boolean;
24
+ /** 429 — rate limited. */
25
+ get isRateLimited(): boolean;
26
+ /** 5xx — server-side error. */
27
+ get isServerError(): boolean;
28
+ }
29
+ /** Thrown when a request never got a response (network failure or timeout). */
30
+ export declare class OmnistreamNetworkError extends OmnistreamError {
31
+ /** Whether the failure was a client-side timeout. */
32
+ readonly timedOut: boolean;
33
+ readonly cause?: unknown | undefined;
34
+ constructor(message: string,
35
+ /** Whether the failure was a client-side timeout. */
36
+ timedOut?: boolean, cause?: unknown | undefined);
37
+ }