@atribu/node 0.1.4 → 0.2.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/CHANGELOG.md CHANGED
@@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.2.0] — 2026-05-16
11
+
12
+ Phase 1 of the WhatsApp + Instagram surface expansion. Adds 11 new endpoints and 2 new channel-prefixed namespaces. Backwards-compatible — no existing call signatures change.
13
+
14
+ ### Concurrency hardening (pre-publish review fixes)
15
+
16
+ - **Broadcast send race**: `POST /api/v1/whatsapp/broadcasts/{id}/send` now uses an atomic claim (`UPDATE … WHERE status='draft' RETURNING id`). Two concurrent send calls for the same broadcast no longer double-charge; the loser gets `409 invalid_state`.
17
+ - **Cancel-mid-send**: cancel is now sticky. The send loop checks the broadcast status every 10 recipients and breaks out if it flipped to `cancelled`; the final UPDATE filters `WHERE status='sending'` so a late cancel never gets overwritten by `completed`. Pending recipients are swept to `cancelled` whichever path detects the transition first.
18
+ - **OAuth-app authorization check order**: `connection-resolver.ts` runs the `oauth_app_authorizations` grant check *before* the `status='connected'` check. Eliminates a side-channel that let revoked-grant consumers distinguish "exists-but-disconnected" from "not-authorized".
19
+ - **Recipient pagination**: `GET /api/v1/whatsapp/broadcasts/{id}` returns up to 1,000 recipients (matches the broadcast send cap; was 200).
20
+ - **Trigger duplicate-keyword**: returns `409 invalid_state` instead of `409 forbidden` (more accurate error code for switch statements).
21
+ - **Recipient status enum** includes `cancelled` (new state introduced by the cancel sweep).
22
+
23
+ ### Added
24
+
25
+ - **`client.whatsapp.templates`** — list / create / delete message templates. Send approved templates via `messages.send({ content: { type: "template", ... } })` as before; templates created via `create()` start `PENDING` and need Meta review before they're sendable.
26
+ - **`client.whatsapp.broadcasts`** — full CRUD for template broadcasts: `list`, `get`, `create`, `cancel`, `send`. Max 1,000 recipients per broadcast; `send()` is long-running (100ms pacing) and the server caps the route at 5 minutes.
27
+ - **`client.instagram.triggers`** — comment-to-DM trigger CRUD: `list`, `create`, `update`, `delete`, `testDm`, `resumeCircuit`. Keywords match in `contains` / `exact` / `regex` modes; `testDm` uses Meta's HUMAN_AGENT tag and respects the 7-day window.
28
+ - **`client.connections`** — `list`, `get`, `revoke`. OAuth-flow keys see only their authorized connections; direct admin keys see every connection on the profile and cannot self-revoke (400).
29
+ - **`messages.send({ content: { type: "interactive_buttons", ... } })`** — WhatsApp reply buttons (max 3). Taps return as `messaging_postbacks` webhook events with the button id.
30
+
31
+ ### Changed
32
+
33
+ - Extracted `src/lib/api/connection-resolver.ts` on the server side. The `/api/v1/messages` route now uses `resolveConnection()`, `resolveWhatsAppConnection()`, `resolveInstagramConnection()` from this helper instead of inlining the cross-profile + OAuth-app gate. Behavior is identical; the helper deduplicates ~80 LOC per new route.
34
+ - The OpenAPI spec gains 11 new paths + the `interactive_buttons` variant on the `messages` content union.
35
+ - `AtribuClient.withRetry()` chaining now also wraps `connections`, `whatsapp`, and `instagram` resources.
36
+
37
+ ### Internal
38
+
39
+ - 26 new vitest cases covering all new resources (happy path + 403 + 404 + 422 + 502 / 409 where relevant). Total: 108 tests, all passing.
40
+ - Added `whatsapp` + `instagram` + `connections` keys to `MockOverrides` for fixture-driven test mocks.
41
+
10
42
  ## [0.1.4] — 2026-05-15
11
43
 
12
44
  First release published via OIDC trusted publishing (provenance attestation now signs every release). 0.1.3's workflow couldn't resolve `jose` during typecheck because it's an optional peer dep — added it as a devDependency so CI typecheck passes. No runtime / API change.
package/README.md CHANGED
@@ -123,6 +123,119 @@ await atribu.comments.privateReply({
123
123
  });
124
124
  ```
125
125
 
126
+ ### Send WhatsApp reply buttons (interactive)
127
+
128
+ ```typescript
129
+ await atribu.messages.send({
130
+ connection_id: connectionId,
131
+ channel: "whatsapp",
132
+ to: "+15551234567",
133
+ content: {
134
+ type: "interactive_buttons",
135
+ body: "Pick a plan:",
136
+ header: "Pricing",
137
+ buttons: [
138
+ { id: "plan_basic", title: "Basic" },
139
+ { id: "plan_pro", title: "Pro" },
140
+ { id: "plan_enterprise", title: "Enterprise" },
141
+ ],
142
+ },
143
+ });
144
+ // Tap returns the chosen `id` on the `messaging_postbacks` webhook field.
145
+ ```
146
+
147
+ ### Manage WhatsApp templates
148
+
149
+ ```typescript
150
+ // List every template on the WABA (all statuses).
151
+ const templates = await atribu.whatsapp.templates.list({ connectionId });
152
+
153
+ // Create one — submits to Meta for review.
154
+ // Body text uses `{{param_name}}` placeholders; named example block is auto-generated.
155
+ const { id, status } = await atribu.whatsapp.templates.create({
156
+ connection_id: connectionId,
157
+ name: "appointment_reminder",
158
+ category: "UTILITY",
159
+ language: "en_US",
160
+ body_text: "Hi {{customer_name}}, your appointment is at {{appointment_time}}.",
161
+ });
162
+
163
+ // Once status === "APPROVED" you can send it via messages.send({ type: "template", ... }).
164
+
165
+ // Delete by name when you're done with it:
166
+ await atribu.whatsapp.templates.delete("appointment_reminder", { connectionId });
167
+ ```
168
+
169
+ ### Send a WhatsApp broadcast
170
+
171
+ ```typescript
172
+ // 1. Create a draft (capped at 1,000 recipients per broadcast).
173
+ const broadcast = await atribu.whatsapp.broadcasts.create({
174
+ connection_id: connectionId,
175
+ template_name: "appointment_reminder",
176
+ template_language: "en_US",
177
+ recipients: customers.map((c) => ({
178
+ phone_number: c.phone,
179
+ template_params: { customer_name: c.name, appointment_time: c.timeIso },
180
+ })),
181
+ name: "Q2 appointment reminders",
182
+ });
183
+
184
+ // 2. Send it. This is a long-running call (100ms pacing between recipients).
185
+ // The Atribu server caps the route at 5 minutes — wrap your fetch with a
186
+ // matching timeout, or extend `timeoutMs` on AtribuClient.
187
+ const completed = await atribu.whatsapp.broadcasts.send(broadcast.id);
188
+ console.log(`sent: ${completed.sent_count}, failed: ${completed.failed_count}`);
189
+
190
+ // Cancel an in-flight broadcast (already-sent messages are NOT recalled):
191
+ await atribu.whatsapp.broadcasts.cancel(broadcast.id);
192
+ ```
193
+
194
+ ### Manage Instagram comment-to-DM triggers
195
+
196
+ ```typescript
197
+ // Create a trigger — when an inbound comment matches the keyword,
198
+ // the commenter gets `opening_message` as a DM (HUMAN_AGENT tag).
199
+ const trigger = await atribu.instagram.triggers.create({
200
+ connection_id: connectionId,
201
+ keyword: "PRICE",
202
+ keyword_match_mode: "contains", // or "exact" | "regex"
203
+ case_sensitive: false,
204
+ opening_message: "Here's our pricing — happy to chat!",
205
+ public_comment_reply: "Sent you a DM!", // optional public reply on the comment
206
+ enabled: true,
207
+ });
208
+
209
+ // QA the opening_message against a real IGSID (must have DMed your account in last 7d):
210
+ await atribu.instagram.triggers.testDm(trigger.id, {
211
+ recipient_igsid: "1234567890",
212
+ });
213
+
214
+ // Update / pause / delete:
215
+ await atribu.instagram.triggers.update(trigger.id, { enabled: false });
216
+ await atribu.instagram.triggers.delete(trigger.id);
217
+
218
+ // Clear the circuit-breaker if it tripped after a comment-spam wave:
219
+ await atribu.instagram.triggers.resumeCircuit({ connectionId });
220
+ ```
221
+
222
+ ### List authorized connections
223
+
224
+ ```typescript
225
+ // What can this key act on?
226
+ const connections = await atribu.connections.list();
227
+ for (const conn of connections) {
228
+ console.log(`${conn.channel} — ${conn.display_name} (${conn.id})`);
229
+ }
230
+
231
+ // Filter by channel:
232
+ const igOnly = await atribu.connections.list({ channel: "instagram" });
233
+
234
+ // Revoke this OAuth app's authorization for one connection (other consumers
235
+ // + the Atribu app UI continue to use it; only this app loses access):
236
+ await atribu.connections.revoke(connectionId);
237
+ ```
238
+
126
239
  ### Manage webhook subscriptions
127
240
 
128
241
  ```typescript
@@ -351,12 +464,15 @@ The SDK's `User-Agent` and Atribu's `X-Request-Id` give you log-grep correlation
351
464
 
352
465
  ## SDK Reference
353
466
 
354
- ### Messaging — `@atribu/node`
467
+ ### Messaging + cross-channel — `@atribu/node`
355
468
  | Method | Description |
356
469
  |---|---|
357
- | `messages.send()` | Send a WhatsApp or Instagram message |
470
+ | `messages.send()` | Send a WhatsApp or Instagram message (text / template / image / video / audio / document / interactive_buttons / quick_replies) |
358
471
  | `comments.reply()` | Public reply on an IG comment thread |
359
472
  | `comments.privateReply()` | Send a DM to the user who left an IG comment |
473
+ | `connections.list()` | List the connections this OAuth app is authorized for |
474
+ | `connections.get()` | Fetch one connection by id |
475
+ | `connections.revoke()` | Revoke this OAuth app's authorization for a connection |
360
476
  | `webhooks.subscriptions.list()` | List your webhook subscriptions |
361
477
  | `webhooks.subscriptions.create()` | Create a webhook subscription (secret shown once) |
362
478
  | `webhooks.subscriptions.update()` | Update URL / events / providers / status |
@@ -366,6 +482,28 @@ The SDK's `User-Agent` and Atribu's `X-Request-Id` give you log-grep correlation
366
482
  | `webhooks.deliveries.replay()` | Re-deliver a dead webhook |
367
483
  | `withRetry()` | Return a new client that retries transient errors |
368
484
 
485
+ ### WhatsApp namespace — `client.whatsapp`
486
+ | Method | Description |
487
+ |---|---|
488
+ | `whatsapp.templates.list()` | List every message template on the WABA (all statuses) |
489
+ | `whatsapp.templates.create()` | Submit a new template for Meta review |
490
+ | `whatsapp.templates.delete()` | Delete a template by name |
491
+ | `whatsapp.broadcasts.list()` | List up to 50 most-recent broadcasts |
492
+ | `whatsapp.broadcasts.create()` | Create a draft broadcast with recipients |
493
+ | `whatsapp.broadcasts.get()` | Get a broadcast + its recipients (max 200 returned) |
494
+ | `whatsapp.broadcasts.cancel()` | Cancel an in-flight broadcast |
495
+ | `whatsapp.broadcasts.send()` | Start sending a draft broadcast (long-running) |
496
+
497
+ ### Instagram namespace — `client.instagram`
498
+ | Method | Description |
499
+ |---|---|
500
+ | `instagram.triggers.list()` | List comment-to-DM triggers for a connection |
501
+ | `instagram.triggers.create()` | Create a new comment-to-DM trigger |
502
+ | `instagram.triggers.update()` | Partial-update a trigger |
503
+ | `instagram.triggers.delete()` | Delete a trigger |
504
+ | `instagram.triggers.testDm()` | Send the opening_message as a one-off DM to a test IGSID |
505
+ | `instagram.triggers.resumeCircuit()` | Manually clear a tripped comment-to-DM circuit |
506
+
369
507
  ### Webhook verification — `@atribu/node/webhooks`
370
508
  | Symbol | Description |
371
509
  |---|---|
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors.ts","../../src/retry.ts","../../src/version.ts","../../src/runtime.ts","../../src/http.ts","../../src/config.ts","../../src/admin/oauth-apps.ts","../../src/admin/client.ts"],"names":["code","body"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Atribu error class hierarchy.\n *\n * Why typed errors: consumers need to branch on auth-failure vs rate-limit vs\n * server-error vs validation-error to decide whether to retry, refresh\n * credentials, or surface to the user. A single `Error` with a status code\n * forces every consumer to write the same `if (err.status === 401)` ladder.\n *\n * Why no automatic retries: the SDK derives a `retry` hint from status +\n * Retry-After + error code, but consumers' queue/job systems decide whether\n * to act on it. Auto-retry inside the SDK hides backpressure signals and\n * makes error budgets opaque.\n */\n\nimport type { RetryHint } from \"./retry\";\n\nexport type ApiErrorCode =\n | \"unauthorized\"\n | \"forbidden\"\n | \"insufficient_scope\"\n | \"not_found\"\n | \"invalid_parameter\"\n | \"invalid_request\"\n | \"validation_error\"\n | \"invalid_content\"\n | \"invalid_date_range\"\n | \"rate_limit_exceeded\"\n | \"connection_not_ready\"\n | \"provider_error\"\n | \"service_unavailable\"\n | \"internal_error\"\n | string;\n\nexport class AtribuError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class AtribuConfigError extends AtribuError {}\n\nexport class AtribuTransportError extends AtribuError {\n readonly cause: unknown;\n constructor(message: string, cause: unknown) {\n super(message);\n this.cause = cause;\n }\n}\n\nexport interface ApiErrorBody {\n code: ApiErrorCode;\n message: string;\n status: number;\n request_id?: string;\n}\n\nexport class AtribuApiError extends AtribuError {\n readonly code: ApiErrorCode;\n readonly status: number;\n readonly requestId: string | null;\n readonly retry: RetryHint;\n readonly responseBody: unknown;\n\n constructor(args: {\n code: ApiErrorCode;\n message: string;\n status: number;\n requestId: string | null;\n retry: RetryHint;\n responseBody: unknown;\n }) {\n super(`[${args.code}] ${args.message}`);\n this.code = args.code;\n this.status = args.status;\n this.requestId = args.requestId;\n this.retry = args.retry;\n this.responseBody = args.responseBody;\n }\n\n isRetryable(): boolean {\n return this.retry.action === \"retry\" || this.retry.action === \"retry_after\";\n }\n isAuthFailure(): boolean {\n return this.status === 401 || this.code === \"unauthorized\";\n }\n isRateLimit(): boolean {\n return this.status === 429 || this.code === \"rate_limit_exceeded\";\n }\n}\n\nexport type OauthErrorCode =\n | \"invalid_request\"\n | \"invalid_client\"\n | \"invalid_grant\"\n | \"unauthorized_client\"\n | \"unsupported_grant_type\"\n | \"invalid_scope\"\n | \"server_error\"\n | \"unsupported_token_type\"\n | string;\n\nexport class AtribuOauthError extends AtribuError {\n readonly code: OauthErrorCode;\n readonly status: number;\n readonly description: string | null;\n\n constructor(args: { code: OauthErrorCode; description: string | null; status: number }) {\n super(`[oauth/${args.code}] ${args.description ?? args.code}`);\n this.code = args.code;\n this.status = args.status;\n this.description = args.description;\n }\n}\n\nexport type WebhookErrorCode =\n | \"missing_signature\"\n | \"malformed_header\"\n | \"expired_timestamp\"\n | \"invalid_signature\";\n\nexport class AtribuWebhookError extends AtribuError {\n readonly code: WebhookErrorCode;\n constructor(code: WebhookErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n","/**\n * Retry hints derived from HTTP status + headers.\n *\n * The SDK never retries automatically. It derives a hint and surfaces it on\n * AtribuApiError.retry so consumers' queue systems can decide. Hiding retry\n * logic in the SDK hides backpressure signals.\n */\n\nexport type RetryHint =\n | { action: \"retry\" }\n | { action: \"retry_after\"; retryAfterMs: number }\n | { action: \"refresh_token\" }\n | { action: \"fix_and_retry\" }\n | { action: \"do_not_retry\" };\n\nexport interface DeriveRetryInput {\n status: number;\n retryAfterHeader: string | null;\n errorCode: string | null;\n}\n\nexport function deriveRetryHint(input: DeriveRetryInput): RetryHint {\n const retryAfterMs = parseRetryAfter(input.retryAfterHeader);\n if (retryAfterMs !== null) {\n return { action: \"retry_after\", retryAfterMs };\n }\n if (input.status === 401) return { action: \"refresh_token\" };\n if (input.status === 403 || input.errorCode === \"forbidden\" || input.errorCode === \"insufficient_scope\") {\n return { action: \"do_not_retry\" };\n }\n if (input.status === 408) return { action: \"retry\" };\n if (input.status === 409) return { action: \"fix_and_retry\" };\n if (input.status === 422 || input.errorCode === \"validation_error\" || input.errorCode === \"invalid_content\") {\n return { action: \"fix_and_retry\" };\n }\n if (input.status === 429 || input.errorCode === \"rate_limit_exceeded\") {\n return { action: \"retry_after\", retryAfterMs: 1000 };\n }\n if (input.status >= 500) return { action: \"retry\" };\n if (input.status >= 400) return { action: \"fix_and_retry\" };\n return { action: \"do_not_retry\" };\n}\n\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) return null;\n const asInt = Number(header);\n if (Number.isFinite(asInt) && asInt >= 0) return Math.round(asInt * 1000);\n const asDate = Date.parse(header);\n if (Number.isFinite(asDate)) return Math.max(0, asDate - Date.now());\n return null;\n}\n","export const SDK_VERSION = \"0.1.4\";\n","export type Runtime = \"node\" | \"bun\" | \"deno\" | \"edge\" | \"browser\" | \"unknown\";\n\ndeclare const Deno: unknown;\ndeclare const Bun: unknown;\ndeclare const EdgeRuntime: unknown;\n\nexport function detectRuntime(): Runtime {\n if (typeof Deno !== \"undefined\") return \"deno\";\n if (typeof Bun !== \"undefined\") return \"bun\";\n if (typeof EdgeRuntime !== \"undefined\") return \"edge\";\n if (\n typeof process !== \"undefined\" &&\n typeof (process as { versions?: { node?: string } }).versions?.node === \"string\"\n ) {\n return \"node\";\n }\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") return \"browser\";\n return \"unknown\";\n}\n\nexport function runtimeTag(): string {\n const rt = detectRuntime();\n if (rt === \"node\") {\n const v = (process as { versions?: { node?: string } }).versions?.node;\n return v ? `node/${v}` : \"node\";\n }\n return rt;\n}\n","/**\n * HTTP request layer.\n *\n * Single entry point for every API call: handles auth headers, timeout via\n * AbortController, idempotency-key generation, error envelope parsing, and\n * RetryHint derivation. Resources call `request()` and parse `data` from the\n * envelope.\n */\n\nimport {\n AtribuApiError,\n AtribuOauthError,\n AtribuTransportError,\n type ApiErrorBody,\n type ApiErrorCode,\n type OauthErrorCode,\n} from \"./errors\";\nimport { deriveRetryHint } from \"./retry\";\nimport { SDK_VERSION } from \"./version\";\nimport { runtimeTag } from \"./runtime\";\nimport type { ResolvedConfig } from \"./config\";\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\" | \"PUT\";\n path: string;\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n /** Form-urlencoded body (used by /oauth/token, /oauth/revoke). */\n form?: Record<string, string>;\n /** Override the Authorization header (used by /oauth/* with client-credentials). */\n authOverride?: string;\n idempotencyKey?: string;\n signal?: AbortSignal;\n /** When true, parse 200-body as RFC 6749/7009 OAuth response shape. */\n oauthErrorShape?: boolean;\n /** When true, return raw Response without JSON parse (used by 204 / RFC 7009 empty 200). */\n expectEmpty?: boolean;\n /** Extra headers to merge. */\n headers?: Record<string, string>;\n}\n\nexport interface ApiEnvelope<T> {\n data: T;\n meta?: Record<string, unknown>;\n}\n\nconst SDK_UA = `@atribu/node/${SDK_VERSION} (${runtimeTag()})`;\n\n/**\n * Minimum surface a transport needs to be usable by resources. Lets us\n * stack RetryingHttpClient on top of HttpClient without inheritance.\n */\nexport interface HttpClientLike {\n request<T>(opts: RequestOptions): Promise<T>;\n}\n\nexport class HttpClient implements HttpClientLike {\n constructor(private readonly cfg: ResolvedConfig) {}\n\n async request<T>(opts: RequestOptions): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query);\n const headers = this.buildHeaders(opts);\n\n let body: BodyInit | undefined;\n if (opts.form) {\n body = new URLSearchParams(opts.form).toString();\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n body = JSON.stringify(opts.body);\n }\n\n const userSignal = opts.signal;\n const timeoutController = new AbortController();\n const timeout = setTimeout(() => timeoutController.abort(), this.cfg.timeoutMs);\n const signal = userSignal ? mergeSignals(userSignal, timeoutController.signal) : timeoutController.signal;\n\n let res: Response;\n try {\n res = await this.cfg.fetch(url, {\n method: opts.method,\n headers,\n body,\n signal,\n });\n } catch (err) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new AtribuTransportError(`Request aborted (timeout ${this.cfg.timeoutMs}ms)`, err);\n }\n throw new AtribuTransportError(\n err instanceof Error ? err.message : \"fetch failed\",\n err,\n );\n }\n clearTimeout(timeout);\n\n if (opts.expectEmpty && res.ok) {\n return undefined as T;\n }\n\n const requestId = res.headers.get(\"x-request-id\");\n const text = await res.text();\n const parsed = text ? safeJson(text) : null;\n\n if (!res.ok) {\n if (opts.oauthErrorShape) {\n const { code, description } = parseOauthError(parsed);\n throw new AtribuOauthError({ code, description, status: res.status });\n }\n const body = (parsed as { error?: ApiErrorBody } | null)?.error ?? null;\n const code: ApiErrorCode = body?.code ?? `http_${res.status}`;\n const message = body?.message ?? `HTTP ${res.status}`;\n const retry = deriveRetryHint({\n status: res.status,\n retryAfterHeader: res.headers.get(\"retry-after\"),\n errorCode: code,\n });\n throw new AtribuApiError({\n code,\n message,\n status: res.status,\n requestId: requestId ?? body?.request_id ?? null,\n retry,\n responseBody: parsed,\n });\n }\n\n return parsed as T;\n }\n\n private buildUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(path.startsWith(\"/\") ? path : `/${path}`, this.cfg.baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue;\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n }\n\n private buildHeaders(opts: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"User-Agent\": this.cfg.userAgentSuffix\n ? `${SDK_UA} ${this.cfg.userAgentSuffix}`\n : SDK_UA,\n };\n if (opts.form) {\n headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n headers[\"Content-Type\"] = \"application/json\";\n }\n headers.Authorization = opts.authOverride ?? `Bearer ${this.cfg.apiKey}`;\n if (mutating(opts.method)) {\n headers[\"Idempotency-Key\"] = opts.idempotencyKey ?? this.cfg.generateIdempotencyKey();\n }\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;\n }\n return headers;\n }\n}\n\nfunction mutating(method: RequestOptions[\"method\"]): boolean {\n return method === \"POST\" || method === \"PATCH\" || method === \"PUT\" || method === \"DELETE\";\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction parseOauthError(parsed: unknown): { code: OauthErrorCode; description: string | null } {\n if (parsed && typeof parsed === \"object\") {\n const obj = parsed as { error?: unknown; error_description?: unknown };\n const code = typeof obj.error === \"string\" ? obj.error : \"server_error\";\n const description = typeof obj.error_description === \"string\" ? obj.error_description : null;\n return { code, description };\n }\n return { code: \"server_error\", description: null };\n}\n\nfunction mergeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof AbortSignal !== \"undefined\" && \"any\" in AbortSignal) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (AbortSignal as unknown as { any: (s: AbortSignal[]) => AbortSignal }).any([a, b]);\n }\n const c = new AbortController();\n const onA = (): void => c.abort(a.reason);\n const onB = (): void => c.abort(b.reason);\n if (a.aborted) c.abort(a.reason);\n else a.addEventListener(\"abort\", onA, { once: true });\n if (b.aborted) c.abort(b.reason);\n else b.addEventListener(\"abort\", onB, { once: true });\n return c.signal;\n}\n","import { AtribuConfigError } from \"./errors\";\n\nexport const DEFAULT_BASE_URL = \"https://www.atribu.app\";\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface AtribuClientConfig {\n apiKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n defaultIdempotencyKeyGenerator?: () => string;\n}\n\nexport interface ResolvedConfig {\n apiKey: string;\n baseUrl: string;\n fetch: typeof fetch;\n timeoutMs: number;\n userAgentSuffix: string | null;\n generateIdempotencyKey: () => string;\n}\n\nexport function resolveConfig(config: AtribuClientConfig): ResolvedConfig {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new AtribuConfigError(\"apiKey is required\");\n }\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n return {\n apiKey: config.apiKey,\n baseUrl,\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? null,\n generateIdempotencyKey: config.defaultIdempotencyKeyGenerator ?? defaultUuid,\n };\n}\n\nfunction defaultUuid(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n // Fallback for older runtimes — a v4-ish UUID via Math.random. Not\n // cryptographically strong; idempotency keys don't need to be.\n const hex = \"0123456789abcdef\";\n let out = \"\";\n for (let i = 0; i < 32; i++) {\n const c = Math.floor(Math.random() * 16);\n out += hex[i === 12 ? 4 : i === 16 ? (c & 0x3) | 0x8 : c];\n if (i === 7 || i === 11 || i === 15 || i === 19) out += \"-\";\n }\n return out;\n}\n","import type { paths } from \"../__generated__/api\";\nimport type { HttpClientLike } from \"../http\";\n\ntype CreateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype CreateResponse =\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"responses\"][201][\"content\"][\"application/json\"];\n\ntype UpdateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype UpdateResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype SuspendResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"delete\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype RotateClientResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateClientBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\ntype RotateJwtResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateJwtBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\nexport type OauthAppCreateInput = CreateBody;\nexport type OauthAppCreated = CreateResponse[\"data\"];\nexport type OauthAppUpdateInput = UpdateBody;\nexport type OauthApp = UpdateResponse[\"data\"];\nexport type OauthAppSuspendResult = SuspendResponse[\"data\"];\nexport type OauthAppRotateClientResult = RotateClientResponse[\"data\"];\nexport type OauthAppRotateJwtResult = RotateJwtResponse[\"data\"];\nexport type RotateOptions = RotateClientBody;\n\nexport interface AdminMutationOptions {\n idempotencyKey?: string;\n signal?: AbortSignal;\n}\n\nexport class OauthAppsResource {\n constructor(private readonly http: HttpClientLike) {}\n\n async create(input: OauthAppCreateInput, opts: AdminMutationOptions = {}): Promise<OauthAppCreated> {\n const res = await this.http.request<CreateResponse>({\n method: \"POST\",\n path: \"/api/v1/admin/oauth-apps\",\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async update(id: string, input: OauthAppUpdateInput, opts: AdminMutationOptions = {}): Promise<OauthApp> {\n const res = await this.http.request<UpdateResponse>({\n method: \"PATCH\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async suspend(id: string, opts: AdminMutationOptions = {}): Promise<OauthAppSuspendResult> {\n const res = await this.http.request<SuspendResponse>({\n method: \"DELETE\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateClientSecret(\n id: string,\n options: RotateOptions = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateClientResult> {\n const res = await this.http.request<RotateClientResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-client-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateJwtSecret(\n id: string,\n options: RotateJwtBody = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateJwtResult> {\n const res = await this.http.request<RotateJwtResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-jwt-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n}\n","import { AtribuConfigError } from \"../errors\";\nimport { HttpClient } from \"../http\";\nimport { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS } from \"../config\";\nimport { OauthAppsResource } from \"./oauth-apps\";\n\nexport interface AtribuAdminClientConfig {\n adminSecret: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport class AtribuAdminClient {\n readonly oauthApps: OauthAppsResource;\n\n constructor(config: AtribuAdminClientConfig) {\n if (!config.adminSecret) throw new AtribuConfigError(\"adminSecret is required\");\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const http = new HttpClient({\n apiKey: config.adminSecret,\n baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? \"admin\",\n generateIdempotencyKey:\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? () => crypto.randomUUID()\n : () => `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n });\n this.oauthApps = new OauthAppsResource(http);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/errors.ts","../../src/retry.ts","../../src/version.ts","../../src/runtime.ts","../../src/http.ts","../../src/config.ts","../../src/admin/oauth-apps.ts","../../src/admin/client.ts"],"names":["code","body"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Atribu error class hierarchy.\n *\n * Why typed errors: consumers need to branch on auth-failure vs rate-limit vs\n * server-error vs validation-error to decide whether to retry, refresh\n * credentials, or surface to the user. A single `Error` with a status code\n * forces every consumer to write the same `if (err.status === 401)` ladder.\n *\n * Why no automatic retries: the SDK derives a `retry` hint from status +\n * Retry-After + error code, but consumers' queue/job systems decide whether\n * to act on it. Auto-retry inside the SDK hides backpressure signals and\n * makes error budgets opaque.\n */\n\nimport type { RetryHint } from \"./retry\";\n\nexport type ApiErrorCode =\n | \"unauthorized\"\n | \"forbidden\"\n | \"insufficient_scope\"\n | \"not_found\"\n | \"invalid_parameter\"\n | \"invalid_request\"\n | \"validation_error\"\n | \"invalid_content\"\n | \"invalid_date_range\"\n | \"rate_limit_exceeded\"\n | \"connection_not_ready\"\n | \"provider_error\"\n | \"service_unavailable\"\n | \"internal_error\"\n | string;\n\nexport class AtribuError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class AtribuConfigError extends AtribuError {}\n\nexport class AtribuTransportError extends AtribuError {\n readonly cause: unknown;\n constructor(message: string, cause: unknown) {\n super(message);\n this.cause = cause;\n }\n}\n\nexport interface ApiErrorBody {\n code: ApiErrorCode;\n message: string;\n status: number;\n request_id?: string;\n}\n\nexport class AtribuApiError extends AtribuError {\n readonly code: ApiErrorCode;\n readonly status: number;\n readonly requestId: string | null;\n readonly retry: RetryHint;\n readonly responseBody: unknown;\n\n constructor(args: {\n code: ApiErrorCode;\n message: string;\n status: number;\n requestId: string | null;\n retry: RetryHint;\n responseBody: unknown;\n }) {\n super(`[${args.code}] ${args.message}`);\n this.code = args.code;\n this.status = args.status;\n this.requestId = args.requestId;\n this.retry = args.retry;\n this.responseBody = args.responseBody;\n }\n\n isRetryable(): boolean {\n return this.retry.action === \"retry\" || this.retry.action === \"retry_after\";\n }\n isAuthFailure(): boolean {\n return this.status === 401 || this.code === \"unauthorized\";\n }\n isRateLimit(): boolean {\n return this.status === 429 || this.code === \"rate_limit_exceeded\";\n }\n}\n\nexport type OauthErrorCode =\n | \"invalid_request\"\n | \"invalid_client\"\n | \"invalid_grant\"\n | \"unauthorized_client\"\n | \"unsupported_grant_type\"\n | \"invalid_scope\"\n | \"server_error\"\n | \"unsupported_token_type\"\n | string;\n\nexport class AtribuOauthError extends AtribuError {\n readonly code: OauthErrorCode;\n readonly status: number;\n readonly description: string | null;\n\n constructor(args: { code: OauthErrorCode; description: string | null; status: number }) {\n super(`[oauth/${args.code}] ${args.description ?? args.code}`);\n this.code = args.code;\n this.status = args.status;\n this.description = args.description;\n }\n}\n\nexport type WebhookErrorCode =\n | \"missing_signature\"\n | \"malformed_header\"\n | \"expired_timestamp\"\n | \"invalid_signature\";\n\nexport class AtribuWebhookError extends AtribuError {\n readonly code: WebhookErrorCode;\n constructor(code: WebhookErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n","/**\n * Retry hints derived from HTTP status + headers.\n *\n * The SDK never retries automatically. It derives a hint and surfaces it on\n * AtribuApiError.retry so consumers' queue systems can decide. Hiding retry\n * logic in the SDK hides backpressure signals.\n */\n\nexport type RetryHint =\n | { action: \"retry\" }\n | { action: \"retry_after\"; retryAfterMs: number }\n | { action: \"refresh_token\" }\n | { action: \"fix_and_retry\" }\n | { action: \"do_not_retry\" };\n\nexport interface DeriveRetryInput {\n status: number;\n retryAfterHeader: string | null;\n errorCode: string | null;\n}\n\nexport function deriveRetryHint(input: DeriveRetryInput): RetryHint {\n const retryAfterMs = parseRetryAfter(input.retryAfterHeader);\n if (retryAfterMs !== null) {\n return { action: \"retry_after\", retryAfterMs };\n }\n if (input.status === 401) return { action: \"refresh_token\" };\n if (input.status === 403 || input.errorCode === \"forbidden\" || input.errorCode === \"insufficient_scope\") {\n return { action: \"do_not_retry\" };\n }\n if (input.status === 408) return { action: \"retry\" };\n if (input.status === 409) return { action: \"fix_and_retry\" };\n if (input.status === 422 || input.errorCode === \"validation_error\" || input.errorCode === \"invalid_content\") {\n return { action: \"fix_and_retry\" };\n }\n if (input.status === 429 || input.errorCode === \"rate_limit_exceeded\") {\n return { action: \"retry_after\", retryAfterMs: 1000 };\n }\n if (input.status >= 500) return { action: \"retry\" };\n if (input.status >= 400) return { action: \"fix_and_retry\" };\n return { action: \"do_not_retry\" };\n}\n\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) return null;\n const asInt = Number(header);\n if (Number.isFinite(asInt) && asInt >= 0) return Math.round(asInt * 1000);\n const asDate = Date.parse(header);\n if (Number.isFinite(asDate)) return Math.max(0, asDate - Date.now());\n return null;\n}\n","export const SDK_VERSION = \"0.1.4\";\n","export type Runtime = \"node\" | \"bun\" | \"deno\" | \"edge\" | \"browser\" | \"unknown\";\n\ndeclare const Deno: unknown;\ndeclare const Bun: unknown;\ndeclare const EdgeRuntime: unknown;\n\nexport function detectRuntime(): Runtime {\n if (typeof Deno !== \"undefined\") return \"deno\";\n if (typeof Bun !== \"undefined\") return \"bun\";\n if (typeof EdgeRuntime !== \"undefined\") return \"edge\";\n if (\n typeof process !== \"undefined\" &&\n typeof (process as { versions?: { node?: string } }).versions?.node === \"string\"\n ) {\n return \"node\";\n }\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") return \"browser\";\n return \"unknown\";\n}\n\nexport function runtimeTag(): string {\n const rt = detectRuntime();\n if (rt === \"node\") {\n const v = (process as { versions?: { node?: string } }).versions?.node;\n return v ? `node/${v}` : \"node\";\n }\n return rt;\n}\n","/**\n * HTTP request layer.\n *\n * Single entry point for every API call: handles auth headers, timeout via\n * AbortController, idempotency-key generation, error envelope parsing, and\n * RetryHint derivation. Resources call `request()` and parse `data` from the\n * envelope.\n */\n\nimport {\n AtribuApiError,\n AtribuOauthError,\n AtribuTransportError,\n type ApiErrorBody,\n type ApiErrorCode,\n type OauthErrorCode,\n} from \"./errors\";\nimport { deriveRetryHint } from \"./retry\";\nimport { SDK_VERSION } from \"./version\";\nimport { runtimeTag } from \"./runtime\";\nimport type { ResolvedConfig } from \"./config\";\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\" | \"PUT\";\n path: string;\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n /** Form-urlencoded body (used by /oauth/token, /oauth/revoke). */\n form?: Record<string, string>;\n /** Override the Authorization header (used by /oauth/* with client-credentials). */\n authOverride?: string;\n idempotencyKey?: string;\n signal?: AbortSignal;\n /** When true, parse 200-body as RFC 6749/7009 OAuth response shape. */\n oauthErrorShape?: boolean;\n /** When true, return raw Response without JSON parse (used by 204 / RFC 7009 empty 200). */\n expectEmpty?: boolean;\n /** Extra headers to merge. */\n headers?: Record<string, string>;\n}\n\nexport interface ApiEnvelope<T> {\n data: T;\n meta?: Record<string, unknown>;\n}\n\nconst SDK_UA = `@atribu/node/${SDK_VERSION} (${runtimeTag()})`;\n\n/**\n * Minimum surface a transport needs to be usable by resources. Lets us\n * stack RetryingHttpClient on top of HttpClient without inheritance.\n */\nexport interface HttpClientLike {\n request<T>(opts: RequestOptions): Promise<T>;\n}\n\nexport class HttpClient implements HttpClientLike {\n constructor(private readonly cfg: ResolvedConfig) {}\n\n async request<T>(opts: RequestOptions): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query);\n const headers = this.buildHeaders(opts);\n\n let body: BodyInit | undefined;\n if (opts.form) {\n body = new URLSearchParams(opts.form).toString();\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n body = JSON.stringify(opts.body);\n }\n\n const userSignal = opts.signal;\n const timeoutController = new AbortController();\n const timeout = setTimeout(() => timeoutController.abort(), this.cfg.timeoutMs);\n const signal = userSignal ? mergeSignals(userSignal, timeoutController.signal) : timeoutController.signal;\n\n let res: Response;\n try {\n res = await this.cfg.fetch(url, {\n method: opts.method,\n headers,\n body,\n signal,\n });\n } catch (err) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new AtribuTransportError(`Request aborted (timeout ${this.cfg.timeoutMs}ms)`, err);\n }\n throw new AtribuTransportError(\n err instanceof Error ? err.message : \"fetch failed\",\n err,\n );\n }\n clearTimeout(timeout);\n\n if (opts.expectEmpty && res.ok) {\n return undefined as T;\n }\n\n const requestId = res.headers.get(\"x-request-id\");\n const text = await res.text();\n const parsed = text ? safeJson(text) : null;\n\n if (!res.ok) {\n if (opts.oauthErrorShape) {\n const { code, description } = parseOauthError(parsed);\n throw new AtribuOauthError({ code, description, status: res.status });\n }\n const body = (parsed as { error?: ApiErrorBody } | null)?.error ?? null;\n const code: ApiErrorCode = body?.code ?? `http_${res.status}`;\n const message = body?.message ?? `HTTP ${res.status}`;\n const retry = deriveRetryHint({\n status: res.status,\n retryAfterHeader: res.headers.get(\"retry-after\"),\n errorCode: code,\n });\n throw new AtribuApiError({\n code,\n message,\n status: res.status,\n requestId: requestId ?? body?.request_id ?? null,\n retry,\n responseBody: parsed,\n });\n }\n\n return parsed as T;\n }\n\n private buildUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(path.startsWith(\"/\") ? path : `/${path}`, this.cfg.baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue;\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n }\n\n private buildHeaders(opts: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"User-Agent\": this.cfg.userAgentSuffix\n ? `${SDK_UA} ${this.cfg.userAgentSuffix}`\n : SDK_UA,\n };\n if (opts.form) {\n headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n headers[\"Content-Type\"] = \"application/json\";\n }\n headers.Authorization = opts.authOverride ?? `Bearer ${this.cfg.apiKey}`;\n if (mutating(opts.method)) {\n headers[\"Idempotency-Key\"] = opts.idempotencyKey ?? this.cfg.generateIdempotencyKey();\n }\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;\n }\n return headers;\n }\n}\n\nfunction mutating(method: RequestOptions[\"method\"]): boolean {\n return method === \"POST\" || method === \"PATCH\" || method === \"PUT\" || method === \"DELETE\";\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction parseOauthError(parsed: unknown): { code: OauthErrorCode; description: string | null } {\n if (parsed && typeof parsed === \"object\") {\n const obj = parsed as { error?: unknown; error_description?: unknown };\n const code = typeof obj.error === \"string\" ? obj.error : \"server_error\";\n const description = typeof obj.error_description === \"string\" ? obj.error_description : null;\n return { code, description };\n }\n return { code: \"server_error\", description: null };\n}\n\nfunction mergeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof AbortSignal !== \"undefined\" && \"any\" in AbortSignal) {\n \n return (AbortSignal as unknown as { any: (s: AbortSignal[]) => AbortSignal }).any([a, b]);\n }\n const c = new AbortController();\n const onA = (): void => c.abort(a.reason);\n const onB = (): void => c.abort(b.reason);\n if (a.aborted) c.abort(a.reason);\n else a.addEventListener(\"abort\", onA, { once: true });\n if (b.aborted) c.abort(b.reason);\n else b.addEventListener(\"abort\", onB, { once: true });\n return c.signal;\n}\n","import { AtribuConfigError } from \"./errors\";\n\nexport const DEFAULT_BASE_URL = \"https://www.atribu.app\";\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface AtribuClientConfig {\n apiKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n defaultIdempotencyKeyGenerator?: () => string;\n}\n\nexport interface ResolvedConfig {\n apiKey: string;\n baseUrl: string;\n fetch: typeof fetch;\n timeoutMs: number;\n userAgentSuffix: string | null;\n generateIdempotencyKey: () => string;\n}\n\nexport function resolveConfig(config: AtribuClientConfig): ResolvedConfig {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new AtribuConfigError(\"apiKey is required\");\n }\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n return {\n apiKey: config.apiKey,\n baseUrl,\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? null,\n generateIdempotencyKey: config.defaultIdempotencyKeyGenerator ?? defaultUuid,\n };\n}\n\nfunction defaultUuid(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n // Fallback for older runtimes — a v4-ish UUID via Math.random. Not\n // cryptographically strong; idempotency keys don't need to be.\n const hex = \"0123456789abcdef\";\n let out = \"\";\n for (let i = 0; i < 32; i++) {\n const c = Math.floor(Math.random() * 16);\n out += hex[i === 12 ? 4 : i === 16 ? (c & 0x3) | 0x8 : c];\n if (i === 7 || i === 11 || i === 15 || i === 19) out += \"-\";\n }\n return out;\n}\n","import type { paths } from \"../__generated__/api\";\nimport type { HttpClientLike } from \"../http\";\n\ntype CreateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype CreateResponse =\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"responses\"][201][\"content\"][\"application/json\"];\n\ntype UpdateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype UpdateResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype SuspendResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"delete\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype RotateClientResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateClientBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\ntype RotateJwtResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateJwtBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\nexport type OauthAppCreateInput = CreateBody;\nexport type OauthAppCreated = CreateResponse[\"data\"];\nexport type OauthAppUpdateInput = UpdateBody;\nexport type OauthApp = UpdateResponse[\"data\"];\nexport type OauthAppSuspendResult = SuspendResponse[\"data\"];\nexport type OauthAppRotateClientResult = RotateClientResponse[\"data\"];\nexport type OauthAppRotateJwtResult = RotateJwtResponse[\"data\"];\nexport type RotateOptions = RotateClientBody;\n\nexport interface AdminMutationOptions {\n idempotencyKey?: string;\n signal?: AbortSignal;\n}\n\nexport class OauthAppsResource {\n constructor(private readonly http: HttpClientLike) {}\n\n async create(input: OauthAppCreateInput, opts: AdminMutationOptions = {}): Promise<OauthAppCreated> {\n const res = await this.http.request<CreateResponse>({\n method: \"POST\",\n path: \"/api/v1/admin/oauth-apps\",\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async update(id: string, input: OauthAppUpdateInput, opts: AdminMutationOptions = {}): Promise<OauthApp> {\n const res = await this.http.request<UpdateResponse>({\n method: \"PATCH\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async suspend(id: string, opts: AdminMutationOptions = {}): Promise<OauthAppSuspendResult> {\n const res = await this.http.request<SuspendResponse>({\n method: \"DELETE\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateClientSecret(\n id: string,\n options: RotateOptions = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateClientResult> {\n const res = await this.http.request<RotateClientResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-client-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateJwtSecret(\n id: string,\n options: RotateJwtBody = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateJwtResult> {\n const res = await this.http.request<RotateJwtResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-jwt-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n}\n","import { AtribuConfigError } from \"../errors\";\nimport { HttpClient } from \"../http\";\nimport { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS } from \"../config\";\nimport { OauthAppsResource } from \"./oauth-apps\";\n\nexport interface AtribuAdminClientConfig {\n adminSecret: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport class AtribuAdminClient {\n readonly oauthApps: OauthAppsResource;\n\n constructor(config: AtribuAdminClientConfig) {\n if (!config.adminSecret) throw new AtribuConfigError(\"adminSecret is required\");\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const http = new HttpClient({\n apiKey: config.adminSecret,\n baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? \"admin\",\n generateIdempotencyKey:\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? () => crypto.randomUUID()\n : () => `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n });\n this.oauthApps = new OauthAppsResource(http);\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { H as HttpClientLike, p as paths } from '../api.d-BXINTQo6.cjs';
1
+ import { H as HttpClientLike, p as paths } from '../api.d-CRypizsD.cjs';
2
2
 
3
3
  type CreateBody = NonNullable<paths["/api/v1/admin/oauth-apps"]["post"]["requestBody"]>["content"]["application/json"];
4
4
  type CreateResponse = paths["/api/v1/admin/oauth-apps"]["post"]["responses"][201]["content"]["application/json"];
@@ -1,4 +1,4 @@
1
- import { H as HttpClientLike, p as paths } from '../api.d-BXINTQo6.js';
1
+ import { H as HttpClientLike, p as paths } from '../api.d-CRypizsD.js';
2
2
 
3
3
  type CreateBody = NonNullable<paths["/api/v1/admin/oauth-apps"]["post"]["requestBody"]>["content"]["application/json"];
4
4
  type CreateResponse = paths["/api/v1/admin/oauth-apps"]["post"]["responses"][201]["content"]["application/json"];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/errors.ts","../../src/retry.ts","../../src/version.ts","../../src/runtime.ts","../../src/http.ts","../../src/config.ts","../../src/admin/oauth-apps.ts","../../src/admin/client.ts"],"names":["code","body"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Atribu error class hierarchy.\n *\n * Why typed errors: consumers need to branch on auth-failure vs rate-limit vs\n * server-error vs validation-error to decide whether to retry, refresh\n * credentials, or surface to the user. A single `Error` with a status code\n * forces every consumer to write the same `if (err.status === 401)` ladder.\n *\n * Why no automatic retries: the SDK derives a `retry` hint from status +\n * Retry-After + error code, but consumers' queue/job systems decide whether\n * to act on it. Auto-retry inside the SDK hides backpressure signals and\n * makes error budgets opaque.\n */\n\nimport type { RetryHint } from \"./retry\";\n\nexport type ApiErrorCode =\n | \"unauthorized\"\n | \"forbidden\"\n | \"insufficient_scope\"\n | \"not_found\"\n | \"invalid_parameter\"\n | \"invalid_request\"\n | \"validation_error\"\n | \"invalid_content\"\n | \"invalid_date_range\"\n | \"rate_limit_exceeded\"\n | \"connection_not_ready\"\n | \"provider_error\"\n | \"service_unavailable\"\n | \"internal_error\"\n | string;\n\nexport class AtribuError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class AtribuConfigError extends AtribuError {}\n\nexport class AtribuTransportError extends AtribuError {\n readonly cause: unknown;\n constructor(message: string, cause: unknown) {\n super(message);\n this.cause = cause;\n }\n}\n\nexport interface ApiErrorBody {\n code: ApiErrorCode;\n message: string;\n status: number;\n request_id?: string;\n}\n\nexport class AtribuApiError extends AtribuError {\n readonly code: ApiErrorCode;\n readonly status: number;\n readonly requestId: string | null;\n readonly retry: RetryHint;\n readonly responseBody: unknown;\n\n constructor(args: {\n code: ApiErrorCode;\n message: string;\n status: number;\n requestId: string | null;\n retry: RetryHint;\n responseBody: unknown;\n }) {\n super(`[${args.code}] ${args.message}`);\n this.code = args.code;\n this.status = args.status;\n this.requestId = args.requestId;\n this.retry = args.retry;\n this.responseBody = args.responseBody;\n }\n\n isRetryable(): boolean {\n return this.retry.action === \"retry\" || this.retry.action === \"retry_after\";\n }\n isAuthFailure(): boolean {\n return this.status === 401 || this.code === \"unauthorized\";\n }\n isRateLimit(): boolean {\n return this.status === 429 || this.code === \"rate_limit_exceeded\";\n }\n}\n\nexport type OauthErrorCode =\n | \"invalid_request\"\n | \"invalid_client\"\n | \"invalid_grant\"\n | \"unauthorized_client\"\n | \"unsupported_grant_type\"\n | \"invalid_scope\"\n | \"server_error\"\n | \"unsupported_token_type\"\n | string;\n\nexport class AtribuOauthError extends AtribuError {\n readonly code: OauthErrorCode;\n readonly status: number;\n readonly description: string | null;\n\n constructor(args: { code: OauthErrorCode; description: string | null; status: number }) {\n super(`[oauth/${args.code}] ${args.description ?? args.code}`);\n this.code = args.code;\n this.status = args.status;\n this.description = args.description;\n }\n}\n\nexport type WebhookErrorCode =\n | \"missing_signature\"\n | \"malformed_header\"\n | \"expired_timestamp\"\n | \"invalid_signature\";\n\nexport class AtribuWebhookError extends AtribuError {\n readonly code: WebhookErrorCode;\n constructor(code: WebhookErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n","/**\n * Retry hints derived from HTTP status + headers.\n *\n * The SDK never retries automatically. It derives a hint and surfaces it on\n * AtribuApiError.retry so consumers' queue systems can decide. Hiding retry\n * logic in the SDK hides backpressure signals.\n */\n\nexport type RetryHint =\n | { action: \"retry\" }\n | { action: \"retry_after\"; retryAfterMs: number }\n | { action: \"refresh_token\" }\n | { action: \"fix_and_retry\" }\n | { action: \"do_not_retry\" };\n\nexport interface DeriveRetryInput {\n status: number;\n retryAfterHeader: string | null;\n errorCode: string | null;\n}\n\nexport function deriveRetryHint(input: DeriveRetryInput): RetryHint {\n const retryAfterMs = parseRetryAfter(input.retryAfterHeader);\n if (retryAfterMs !== null) {\n return { action: \"retry_after\", retryAfterMs };\n }\n if (input.status === 401) return { action: \"refresh_token\" };\n if (input.status === 403 || input.errorCode === \"forbidden\" || input.errorCode === \"insufficient_scope\") {\n return { action: \"do_not_retry\" };\n }\n if (input.status === 408) return { action: \"retry\" };\n if (input.status === 409) return { action: \"fix_and_retry\" };\n if (input.status === 422 || input.errorCode === \"validation_error\" || input.errorCode === \"invalid_content\") {\n return { action: \"fix_and_retry\" };\n }\n if (input.status === 429 || input.errorCode === \"rate_limit_exceeded\") {\n return { action: \"retry_after\", retryAfterMs: 1000 };\n }\n if (input.status >= 500) return { action: \"retry\" };\n if (input.status >= 400) return { action: \"fix_and_retry\" };\n return { action: \"do_not_retry\" };\n}\n\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) return null;\n const asInt = Number(header);\n if (Number.isFinite(asInt) && asInt >= 0) return Math.round(asInt * 1000);\n const asDate = Date.parse(header);\n if (Number.isFinite(asDate)) return Math.max(0, asDate - Date.now());\n return null;\n}\n","export const SDK_VERSION = \"0.1.4\";\n","export type Runtime = \"node\" | \"bun\" | \"deno\" | \"edge\" | \"browser\" | \"unknown\";\n\ndeclare const Deno: unknown;\ndeclare const Bun: unknown;\ndeclare const EdgeRuntime: unknown;\n\nexport function detectRuntime(): Runtime {\n if (typeof Deno !== \"undefined\") return \"deno\";\n if (typeof Bun !== \"undefined\") return \"bun\";\n if (typeof EdgeRuntime !== \"undefined\") return \"edge\";\n if (\n typeof process !== \"undefined\" &&\n typeof (process as { versions?: { node?: string } }).versions?.node === \"string\"\n ) {\n return \"node\";\n }\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") return \"browser\";\n return \"unknown\";\n}\n\nexport function runtimeTag(): string {\n const rt = detectRuntime();\n if (rt === \"node\") {\n const v = (process as { versions?: { node?: string } }).versions?.node;\n return v ? `node/${v}` : \"node\";\n }\n return rt;\n}\n","/**\n * HTTP request layer.\n *\n * Single entry point for every API call: handles auth headers, timeout via\n * AbortController, idempotency-key generation, error envelope parsing, and\n * RetryHint derivation. Resources call `request()` and parse `data` from the\n * envelope.\n */\n\nimport {\n AtribuApiError,\n AtribuOauthError,\n AtribuTransportError,\n type ApiErrorBody,\n type ApiErrorCode,\n type OauthErrorCode,\n} from \"./errors\";\nimport { deriveRetryHint } from \"./retry\";\nimport { SDK_VERSION } from \"./version\";\nimport { runtimeTag } from \"./runtime\";\nimport type { ResolvedConfig } from \"./config\";\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\" | \"PUT\";\n path: string;\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n /** Form-urlencoded body (used by /oauth/token, /oauth/revoke). */\n form?: Record<string, string>;\n /** Override the Authorization header (used by /oauth/* with client-credentials). */\n authOverride?: string;\n idempotencyKey?: string;\n signal?: AbortSignal;\n /** When true, parse 200-body as RFC 6749/7009 OAuth response shape. */\n oauthErrorShape?: boolean;\n /** When true, return raw Response without JSON parse (used by 204 / RFC 7009 empty 200). */\n expectEmpty?: boolean;\n /** Extra headers to merge. */\n headers?: Record<string, string>;\n}\n\nexport interface ApiEnvelope<T> {\n data: T;\n meta?: Record<string, unknown>;\n}\n\nconst SDK_UA = `@atribu/node/${SDK_VERSION} (${runtimeTag()})`;\n\n/**\n * Minimum surface a transport needs to be usable by resources. Lets us\n * stack RetryingHttpClient on top of HttpClient without inheritance.\n */\nexport interface HttpClientLike {\n request<T>(opts: RequestOptions): Promise<T>;\n}\n\nexport class HttpClient implements HttpClientLike {\n constructor(private readonly cfg: ResolvedConfig) {}\n\n async request<T>(opts: RequestOptions): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query);\n const headers = this.buildHeaders(opts);\n\n let body: BodyInit | undefined;\n if (opts.form) {\n body = new URLSearchParams(opts.form).toString();\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n body = JSON.stringify(opts.body);\n }\n\n const userSignal = opts.signal;\n const timeoutController = new AbortController();\n const timeout = setTimeout(() => timeoutController.abort(), this.cfg.timeoutMs);\n const signal = userSignal ? mergeSignals(userSignal, timeoutController.signal) : timeoutController.signal;\n\n let res: Response;\n try {\n res = await this.cfg.fetch(url, {\n method: opts.method,\n headers,\n body,\n signal,\n });\n } catch (err) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new AtribuTransportError(`Request aborted (timeout ${this.cfg.timeoutMs}ms)`, err);\n }\n throw new AtribuTransportError(\n err instanceof Error ? err.message : \"fetch failed\",\n err,\n );\n }\n clearTimeout(timeout);\n\n if (opts.expectEmpty && res.ok) {\n return undefined as T;\n }\n\n const requestId = res.headers.get(\"x-request-id\");\n const text = await res.text();\n const parsed = text ? safeJson(text) : null;\n\n if (!res.ok) {\n if (opts.oauthErrorShape) {\n const { code, description } = parseOauthError(parsed);\n throw new AtribuOauthError({ code, description, status: res.status });\n }\n const body = (parsed as { error?: ApiErrorBody } | null)?.error ?? null;\n const code: ApiErrorCode = body?.code ?? `http_${res.status}`;\n const message = body?.message ?? `HTTP ${res.status}`;\n const retry = deriveRetryHint({\n status: res.status,\n retryAfterHeader: res.headers.get(\"retry-after\"),\n errorCode: code,\n });\n throw new AtribuApiError({\n code,\n message,\n status: res.status,\n requestId: requestId ?? body?.request_id ?? null,\n retry,\n responseBody: parsed,\n });\n }\n\n return parsed as T;\n }\n\n private buildUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(path.startsWith(\"/\") ? path : `/${path}`, this.cfg.baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue;\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n }\n\n private buildHeaders(opts: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"User-Agent\": this.cfg.userAgentSuffix\n ? `${SDK_UA} ${this.cfg.userAgentSuffix}`\n : SDK_UA,\n };\n if (opts.form) {\n headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n headers[\"Content-Type\"] = \"application/json\";\n }\n headers.Authorization = opts.authOverride ?? `Bearer ${this.cfg.apiKey}`;\n if (mutating(opts.method)) {\n headers[\"Idempotency-Key\"] = opts.idempotencyKey ?? this.cfg.generateIdempotencyKey();\n }\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;\n }\n return headers;\n }\n}\n\nfunction mutating(method: RequestOptions[\"method\"]): boolean {\n return method === \"POST\" || method === \"PATCH\" || method === \"PUT\" || method === \"DELETE\";\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction parseOauthError(parsed: unknown): { code: OauthErrorCode; description: string | null } {\n if (parsed && typeof parsed === \"object\") {\n const obj = parsed as { error?: unknown; error_description?: unknown };\n const code = typeof obj.error === \"string\" ? obj.error : \"server_error\";\n const description = typeof obj.error_description === \"string\" ? obj.error_description : null;\n return { code, description };\n }\n return { code: \"server_error\", description: null };\n}\n\nfunction mergeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof AbortSignal !== \"undefined\" && \"any\" in AbortSignal) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (AbortSignal as unknown as { any: (s: AbortSignal[]) => AbortSignal }).any([a, b]);\n }\n const c = new AbortController();\n const onA = (): void => c.abort(a.reason);\n const onB = (): void => c.abort(b.reason);\n if (a.aborted) c.abort(a.reason);\n else a.addEventListener(\"abort\", onA, { once: true });\n if (b.aborted) c.abort(b.reason);\n else b.addEventListener(\"abort\", onB, { once: true });\n return c.signal;\n}\n","import { AtribuConfigError } from \"./errors\";\n\nexport const DEFAULT_BASE_URL = \"https://www.atribu.app\";\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface AtribuClientConfig {\n apiKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n defaultIdempotencyKeyGenerator?: () => string;\n}\n\nexport interface ResolvedConfig {\n apiKey: string;\n baseUrl: string;\n fetch: typeof fetch;\n timeoutMs: number;\n userAgentSuffix: string | null;\n generateIdempotencyKey: () => string;\n}\n\nexport function resolveConfig(config: AtribuClientConfig): ResolvedConfig {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new AtribuConfigError(\"apiKey is required\");\n }\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n return {\n apiKey: config.apiKey,\n baseUrl,\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? null,\n generateIdempotencyKey: config.defaultIdempotencyKeyGenerator ?? defaultUuid,\n };\n}\n\nfunction defaultUuid(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n // Fallback for older runtimes — a v4-ish UUID via Math.random. Not\n // cryptographically strong; idempotency keys don't need to be.\n const hex = \"0123456789abcdef\";\n let out = \"\";\n for (let i = 0; i < 32; i++) {\n const c = Math.floor(Math.random() * 16);\n out += hex[i === 12 ? 4 : i === 16 ? (c & 0x3) | 0x8 : c];\n if (i === 7 || i === 11 || i === 15 || i === 19) out += \"-\";\n }\n return out;\n}\n","import type { paths } from \"../__generated__/api\";\nimport type { HttpClientLike } from \"../http\";\n\ntype CreateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype CreateResponse =\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"responses\"][201][\"content\"][\"application/json\"];\n\ntype UpdateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype UpdateResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype SuspendResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"delete\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype RotateClientResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateClientBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\ntype RotateJwtResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateJwtBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\nexport type OauthAppCreateInput = CreateBody;\nexport type OauthAppCreated = CreateResponse[\"data\"];\nexport type OauthAppUpdateInput = UpdateBody;\nexport type OauthApp = UpdateResponse[\"data\"];\nexport type OauthAppSuspendResult = SuspendResponse[\"data\"];\nexport type OauthAppRotateClientResult = RotateClientResponse[\"data\"];\nexport type OauthAppRotateJwtResult = RotateJwtResponse[\"data\"];\nexport type RotateOptions = RotateClientBody;\n\nexport interface AdminMutationOptions {\n idempotencyKey?: string;\n signal?: AbortSignal;\n}\n\nexport class OauthAppsResource {\n constructor(private readonly http: HttpClientLike) {}\n\n async create(input: OauthAppCreateInput, opts: AdminMutationOptions = {}): Promise<OauthAppCreated> {\n const res = await this.http.request<CreateResponse>({\n method: \"POST\",\n path: \"/api/v1/admin/oauth-apps\",\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async update(id: string, input: OauthAppUpdateInput, opts: AdminMutationOptions = {}): Promise<OauthApp> {\n const res = await this.http.request<UpdateResponse>({\n method: \"PATCH\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async suspend(id: string, opts: AdminMutationOptions = {}): Promise<OauthAppSuspendResult> {\n const res = await this.http.request<SuspendResponse>({\n method: \"DELETE\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateClientSecret(\n id: string,\n options: RotateOptions = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateClientResult> {\n const res = await this.http.request<RotateClientResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-client-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateJwtSecret(\n id: string,\n options: RotateJwtBody = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateJwtResult> {\n const res = await this.http.request<RotateJwtResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-jwt-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n}\n","import { AtribuConfigError } from \"../errors\";\nimport { HttpClient } from \"../http\";\nimport { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS } from \"../config\";\nimport { OauthAppsResource } from \"./oauth-apps\";\n\nexport interface AtribuAdminClientConfig {\n adminSecret: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport class AtribuAdminClient {\n readonly oauthApps: OauthAppsResource;\n\n constructor(config: AtribuAdminClientConfig) {\n if (!config.adminSecret) throw new AtribuConfigError(\"adminSecret is required\");\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const http = new HttpClient({\n apiKey: config.adminSecret,\n baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? \"admin\",\n generateIdempotencyKey:\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? () => crypto.randomUUID()\n : () => `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n });\n this.oauthApps = new OauthAppsResource(http);\n }\n}\n"]}
1
+ {"version":3,"sources":["../../src/errors.ts","../../src/retry.ts","../../src/version.ts","../../src/runtime.ts","../../src/http.ts","../../src/config.ts","../../src/admin/oauth-apps.ts","../../src/admin/client.ts"],"names":["code","body"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Atribu error class hierarchy.\n *\n * Why typed errors: consumers need to branch on auth-failure vs rate-limit vs\n * server-error vs validation-error to decide whether to retry, refresh\n * credentials, or surface to the user. A single `Error` with a status code\n * forces every consumer to write the same `if (err.status === 401)` ladder.\n *\n * Why no automatic retries: the SDK derives a `retry` hint from status +\n * Retry-After + error code, but consumers' queue/job systems decide whether\n * to act on it. Auto-retry inside the SDK hides backpressure signals and\n * makes error budgets opaque.\n */\n\nimport type { RetryHint } from \"./retry\";\n\nexport type ApiErrorCode =\n | \"unauthorized\"\n | \"forbidden\"\n | \"insufficient_scope\"\n | \"not_found\"\n | \"invalid_parameter\"\n | \"invalid_request\"\n | \"validation_error\"\n | \"invalid_content\"\n | \"invalid_date_range\"\n | \"rate_limit_exceeded\"\n | \"connection_not_ready\"\n | \"provider_error\"\n | \"service_unavailable\"\n | \"internal_error\"\n | string;\n\nexport class AtribuError extends Error {\n constructor(message: string) {\n super(message);\n this.name = new.target.name;\n }\n}\n\nexport class AtribuConfigError extends AtribuError {}\n\nexport class AtribuTransportError extends AtribuError {\n readonly cause: unknown;\n constructor(message: string, cause: unknown) {\n super(message);\n this.cause = cause;\n }\n}\n\nexport interface ApiErrorBody {\n code: ApiErrorCode;\n message: string;\n status: number;\n request_id?: string;\n}\n\nexport class AtribuApiError extends AtribuError {\n readonly code: ApiErrorCode;\n readonly status: number;\n readonly requestId: string | null;\n readonly retry: RetryHint;\n readonly responseBody: unknown;\n\n constructor(args: {\n code: ApiErrorCode;\n message: string;\n status: number;\n requestId: string | null;\n retry: RetryHint;\n responseBody: unknown;\n }) {\n super(`[${args.code}] ${args.message}`);\n this.code = args.code;\n this.status = args.status;\n this.requestId = args.requestId;\n this.retry = args.retry;\n this.responseBody = args.responseBody;\n }\n\n isRetryable(): boolean {\n return this.retry.action === \"retry\" || this.retry.action === \"retry_after\";\n }\n isAuthFailure(): boolean {\n return this.status === 401 || this.code === \"unauthorized\";\n }\n isRateLimit(): boolean {\n return this.status === 429 || this.code === \"rate_limit_exceeded\";\n }\n}\n\nexport type OauthErrorCode =\n | \"invalid_request\"\n | \"invalid_client\"\n | \"invalid_grant\"\n | \"unauthorized_client\"\n | \"unsupported_grant_type\"\n | \"invalid_scope\"\n | \"server_error\"\n | \"unsupported_token_type\"\n | string;\n\nexport class AtribuOauthError extends AtribuError {\n readonly code: OauthErrorCode;\n readonly status: number;\n readonly description: string | null;\n\n constructor(args: { code: OauthErrorCode; description: string | null; status: number }) {\n super(`[oauth/${args.code}] ${args.description ?? args.code}`);\n this.code = args.code;\n this.status = args.status;\n this.description = args.description;\n }\n}\n\nexport type WebhookErrorCode =\n | \"missing_signature\"\n | \"malformed_header\"\n | \"expired_timestamp\"\n | \"invalid_signature\";\n\nexport class AtribuWebhookError extends AtribuError {\n readonly code: WebhookErrorCode;\n constructor(code: WebhookErrorCode, message: string) {\n super(message);\n this.code = code;\n }\n}\n","/**\n * Retry hints derived from HTTP status + headers.\n *\n * The SDK never retries automatically. It derives a hint and surfaces it on\n * AtribuApiError.retry so consumers' queue systems can decide. Hiding retry\n * logic in the SDK hides backpressure signals.\n */\n\nexport type RetryHint =\n | { action: \"retry\" }\n | { action: \"retry_after\"; retryAfterMs: number }\n | { action: \"refresh_token\" }\n | { action: \"fix_and_retry\" }\n | { action: \"do_not_retry\" };\n\nexport interface DeriveRetryInput {\n status: number;\n retryAfterHeader: string | null;\n errorCode: string | null;\n}\n\nexport function deriveRetryHint(input: DeriveRetryInput): RetryHint {\n const retryAfterMs = parseRetryAfter(input.retryAfterHeader);\n if (retryAfterMs !== null) {\n return { action: \"retry_after\", retryAfterMs };\n }\n if (input.status === 401) return { action: \"refresh_token\" };\n if (input.status === 403 || input.errorCode === \"forbidden\" || input.errorCode === \"insufficient_scope\") {\n return { action: \"do_not_retry\" };\n }\n if (input.status === 408) return { action: \"retry\" };\n if (input.status === 409) return { action: \"fix_and_retry\" };\n if (input.status === 422 || input.errorCode === \"validation_error\" || input.errorCode === \"invalid_content\") {\n return { action: \"fix_and_retry\" };\n }\n if (input.status === 429 || input.errorCode === \"rate_limit_exceeded\") {\n return { action: \"retry_after\", retryAfterMs: 1000 };\n }\n if (input.status >= 500) return { action: \"retry\" };\n if (input.status >= 400) return { action: \"fix_and_retry\" };\n return { action: \"do_not_retry\" };\n}\n\nfunction parseRetryAfter(header: string | null): number | null {\n if (!header) return null;\n const asInt = Number(header);\n if (Number.isFinite(asInt) && asInt >= 0) return Math.round(asInt * 1000);\n const asDate = Date.parse(header);\n if (Number.isFinite(asDate)) return Math.max(0, asDate - Date.now());\n return null;\n}\n","export const SDK_VERSION = \"0.1.4\";\n","export type Runtime = \"node\" | \"bun\" | \"deno\" | \"edge\" | \"browser\" | \"unknown\";\n\ndeclare const Deno: unknown;\ndeclare const Bun: unknown;\ndeclare const EdgeRuntime: unknown;\n\nexport function detectRuntime(): Runtime {\n if (typeof Deno !== \"undefined\") return \"deno\";\n if (typeof Bun !== \"undefined\") return \"bun\";\n if (typeof EdgeRuntime !== \"undefined\") return \"edge\";\n if (\n typeof process !== \"undefined\" &&\n typeof (process as { versions?: { node?: string } }).versions?.node === \"string\"\n ) {\n return \"node\";\n }\n if (typeof window !== \"undefined\" && typeof document !== \"undefined\") return \"browser\";\n return \"unknown\";\n}\n\nexport function runtimeTag(): string {\n const rt = detectRuntime();\n if (rt === \"node\") {\n const v = (process as { versions?: { node?: string } }).versions?.node;\n return v ? `node/${v}` : \"node\";\n }\n return rt;\n}\n","/**\n * HTTP request layer.\n *\n * Single entry point for every API call: handles auth headers, timeout via\n * AbortController, idempotency-key generation, error envelope parsing, and\n * RetryHint derivation. Resources call `request()` and parse `data` from the\n * envelope.\n */\n\nimport {\n AtribuApiError,\n AtribuOauthError,\n AtribuTransportError,\n type ApiErrorBody,\n type ApiErrorCode,\n type OauthErrorCode,\n} from \"./errors\";\nimport { deriveRetryHint } from \"./retry\";\nimport { SDK_VERSION } from \"./version\";\nimport { runtimeTag } from \"./runtime\";\nimport type { ResolvedConfig } from \"./config\";\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\" | \"PUT\";\n path: string;\n query?: Record<string, string | number | boolean | undefined | null>;\n body?: unknown;\n /** Form-urlencoded body (used by /oauth/token, /oauth/revoke). */\n form?: Record<string, string>;\n /** Override the Authorization header (used by /oauth/* with client-credentials). */\n authOverride?: string;\n idempotencyKey?: string;\n signal?: AbortSignal;\n /** When true, parse 200-body as RFC 6749/7009 OAuth response shape. */\n oauthErrorShape?: boolean;\n /** When true, return raw Response without JSON parse (used by 204 / RFC 7009 empty 200). */\n expectEmpty?: boolean;\n /** Extra headers to merge. */\n headers?: Record<string, string>;\n}\n\nexport interface ApiEnvelope<T> {\n data: T;\n meta?: Record<string, unknown>;\n}\n\nconst SDK_UA = `@atribu/node/${SDK_VERSION} (${runtimeTag()})`;\n\n/**\n * Minimum surface a transport needs to be usable by resources. Lets us\n * stack RetryingHttpClient on top of HttpClient without inheritance.\n */\nexport interface HttpClientLike {\n request<T>(opts: RequestOptions): Promise<T>;\n}\n\nexport class HttpClient implements HttpClientLike {\n constructor(private readonly cfg: ResolvedConfig) {}\n\n async request<T>(opts: RequestOptions): Promise<T> {\n const url = this.buildUrl(opts.path, opts.query);\n const headers = this.buildHeaders(opts);\n\n let body: BodyInit | undefined;\n if (opts.form) {\n body = new URLSearchParams(opts.form).toString();\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n body = JSON.stringify(opts.body);\n }\n\n const userSignal = opts.signal;\n const timeoutController = new AbortController();\n const timeout = setTimeout(() => timeoutController.abort(), this.cfg.timeoutMs);\n const signal = userSignal ? mergeSignals(userSignal, timeoutController.signal) : timeoutController.signal;\n\n let res: Response;\n try {\n res = await this.cfg.fetch(url, {\n method: opts.method,\n headers,\n body,\n signal,\n });\n } catch (err) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === \"AbortError\") {\n throw new AtribuTransportError(`Request aborted (timeout ${this.cfg.timeoutMs}ms)`, err);\n }\n throw new AtribuTransportError(\n err instanceof Error ? err.message : \"fetch failed\",\n err,\n );\n }\n clearTimeout(timeout);\n\n if (opts.expectEmpty && res.ok) {\n return undefined as T;\n }\n\n const requestId = res.headers.get(\"x-request-id\");\n const text = await res.text();\n const parsed = text ? safeJson(text) : null;\n\n if (!res.ok) {\n if (opts.oauthErrorShape) {\n const { code, description } = parseOauthError(parsed);\n throw new AtribuOauthError({ code, description, status: res.status });\n }\n const body = (parsed as { error?: ApiErrorBody } | null)?.error ?? null;\n const code: ApiErrorCode = body?.code ?? `http_${res.status}`;\n const message = body?.message ?? `HTTP ${res.status}`;\n const retry = deriveRetryHint({\n status: res.status,\n retryAfterHeader: res.headers.get(\"retry-after\"),\n errorCode: code,\n });\n throw new AtribuApiError({\n code,\n message,\n status: res.status,\n requestId: requestId ?? body?.request_id ?? null,\n retry,\n responseBody: parsed,\n });\n }\n\n return parsed as T;\n }\n\n private buildUrl(path: string, query?: RequestOptions[\"query\"]): string {\n const url = new URL(path.startsWith(\"/\") ? path : `/${path}`, this.cfg.baseUrl);\n if (query) {\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue;\n url.searchParams.set(key, String(value));\n }\n }\n return url.toString();\n }\n\n private buildHeaders(opts: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = {\n Accept: \"application/json\",\n \"User-Agent\": this.cfg.userAgentSuffix\n ? `${SDK_UA} ${this.cfg.userAgentSuffix}`\n : SDK_UA,\n };\n if (opts.form) {\n headers[\"Content-Type\"] = \"application/x-www-form-urlencoded\";\n } else if (opts.body !== undefined && opts.method !== \"GET\") {\n headers[\"Content-Type\"] = \"application/json\";\n }\n headers.Authorization = opts.authOverride ?? `Bearer ${this.cfg.apiKey}`;\n if (mutating(opts.method)) {\n headers[\"Idempotency-Key\"] = opts.idempotencyKey ?? this.cfg.generateIdempotencyKey();\n }\n if (opts.headers) {\n for (const [k, v] of Object.entries(opts.headers)) headers[k] = v;\n }\n return headers;\n }\n}\n\nfunction mutating(method: RequestOptions[\"method\"]): boolean {\n return method === \"POST\" || method === \"PATCH\" || method === \"PUT\" || method === \"DELETE\";\n}\n\nfunction safeJson(text: string): unknown {\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n}\n\nfunction parseOauthError(parsed: unknown): { code: OauthErrorCode; description: string | null } {\n if (parsed && typeof parsed === \"object\") {\n const obj = parsed as { error?: unknown; error_description?: unknown };\n const code = typeof obj.error === \"string\" ? obj.error : \"server_error\";\n const description = typeof obj.error_description === \"string\" ? obj.error_description : null;\n return { code, description };\n }\n return { code: \"server_error\", description: null };\n}\n\nfunction mergeSignals(a: AbortSignal, b: AbortSignal): AbortSignal {\n if (typeof AbortSignal !== \"undefined\" && \"any\" in AbortSignal) {\n \n return (AbortSignal as unknown as { any: (s: AbortSignal[]) => AbortSignal }).any([a, b]);\n }\n const c = new AbortController();\n const onA = (): void => c.abort(a.reason);\n const onB = (): void => c.abort(b.reason);\n if (a.aborted) c.abort(a.reason);\n else a.addEventListener(\"abort\", onA, { once: true });\n if (b.aborted) c.abort(b.reason);\n else b.addEventListener(\"abort\", onB, { once: true });\n return c.signal;\n}\n","import { AtribuConfigError } from \"./errors\";\n\nexport const DEFAULT_BASE_URL = \"https://www.atribu.app\";\nexport const DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface AtribuClientConfig {\n apiKey: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n defaultIdempotencyKeyGenerator?: () => string;\n}\n\nexport interface ResolvedConfig {\n apiKey: string;\n baseUrl: string;\n fetch: typeof fetch;\n timeoutMs: number;\n userAgentSuffix: string | null;\n generateIdempotencyKey: () => string;\n}\n\nexport function resolveConfig(config: AtribuClientConfig): ResolvedConfig {\n if (!config.apiKey || typeof config.apiKey !== \"string\") {\n throw new AtribuConfigError(\"apiKey is required\");\n }\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const baseUrl = (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\");\n return {\n apiKey: config.apiKey,\n baseUrl,\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? null,\n generateIdempotencyKey: config.defaultIdempotencyKeyGenerator ?? defaultUuid,\n };\n}\n\nfunction defaultUuid(): string {\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n // Fallback for older runtimes — a v4-ish UUID via Math.random. Not\n // cryptographically strong; idempotency keys don't need to be.\n const hex = \"0123456789abcdef\";\n let out = \"\";\n for (let i = 0; i < 32; i++) {\n const c = Math.floor(Math.random() * 16);\n out += hex[i === 12 ? 4 : i === 16 ? (c & 0x3) | 0x8 : c];\n if (i === 7 || i === 11 || i === 15 || i === 19) out += \"-\";\n }\n return out;\n}\n","import type { paths } from \"../__generated__/api\";\nimport type { HttpClientLike } from \"../http\";\n\ntype CreateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype CreateResponse =\n paths[\"/api/v1/admin/oauth-apps\"][\"post\"][\"responses\"][201][\"content\"][\"application/json\"];\n\ntype UpdateBody = NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\ntype UpdateResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"patch\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype SuspendResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}\"][\"delete\"][\"responses\"][200][\"content\"][\"application/json\"];\n\ntype RotateClientResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateClientBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-client-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\ntype RotateJwtResponse =\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"responses\"][200][\"content\"][\"application/json\"];\ntype RotateJwtBody = NonNullable<\n NonNullable<\n paths[\"/api/v1/admin/oauth-apps/{id}/rotate-jwt-secret\"][\"post\"][\"requestBody\"]\n >[\"content\"][\"application/json\"]\n>;\n\nexport type OauthAppCreateInput = CreateBody;\nexport type OauthAppCreated = CreateResponse[\"data\"];\nexport type OauthAppUpdateInput = UpdateBody;\nexport type OauthApp = UpdateResponse[\"data\"];\nexport type OauthAppSuspendResult = SuspendResponse[\"data\"];\nexport type OauthAppRotateClientResult = RotateClientResponse[\"data\"];\nexport type OauthAppRotateJwtResult = RotateJwtResponse[\"data\"];\nexport type RotateOptions = RotateClientBody;\n\nexport interface AdminMutationOptions {\n idempotencyKey?: string;\n signal?: AbortSignal;\n}\n\nexport class OauthAppsResource {\n constructor(private readonly http: HttpClientLike) {}\n\n async create(input: OauthAppCreateInput, opts: AdminMutationOptions = {}): Promise<OauthAppCreated> {\n const res = await this.http.request<CreateResponse>({\n method: \"POST\",\n path: \"/api/v1/admin/oauth-apps\",\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async update(id: string, input: OauthAppUpdateInput, opts: AdminMutationOptions = {}): Promise<OauthApp> {\n const res = await this.http.request<UpdateResponse>({\n method: \"PATCH\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n body: input,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async suspend(id: string, opts: AdminMutationOptions = {}): Promise<OauthAppSuspendResult> {\n const res = await this.http.request<SuspendResponse>({\n method: \"DELETE\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}`,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateClientSecret(\n id: string,\n options: RotateOptions = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateClientResult> {\n const res = await this.http.request<RotateClientResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-client-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n\n async rotateJwtSecret(\n id: string,\n options: RotateJwtBody = {},\n opts: AdminMutationOptions = {},\n ): Promise<OauthAppRotateJwtResult> {\n const res = await this.http.request<RotateJwtResponse>({\n method: \"POST\",\n path: `/api/v1/admin/oauth-apps/${encodeURIComponent(id)}/rotate-jwt-secret`,\n body: options,\n idempotencyKey: opts.idempotencyKey,\n signal: opts.signal,\n });\n return res.data;\n }\n}\n","import { AtribuConfigError } from \"../errors\";\nimport { HttpClient } from \"../http\";\nimport { DEFAULT_BASE_URL, DEFAULT_TIMEOUT_MS } from \"../config\";\nimport { OauthAppsResource } from \"./oauth-apps\";\n\nexport interface AtribuAdminClientConfig {\n adminSecret: string;\n baseUrl?: string;\n fetch?: typeof fetch;\n timeoutMs?: number;\n userAgent?: string;\n}\n\nexport class AtribuAdminClient {\n readonly oauthApps: OauthAppsResource;\n\n constructor(config: AtribuAdminClientConfig) {\n if (!config.adminSecret) throw new AtribuConfigError(\"adminSecret is required\");\n const fetchImpl = config.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== \"function\") {\n throw new AtribuConfigError(\n \"globalThis.fetch is not available; pass a `fetch` implementation in config\",\n );\n }\n const http = new HttpClient({\n apiKey: config.adminSecret,\n baseUrl: (config.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, \"\"),\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n userAgentSuffix: config.userAgent ?? \"admin\",\n generateIdempotencyKey:\n typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\"\n ? () => crypto.randomUUID()\n : () => `${Date.now()}-${Math.random().toString(36).slice(2)}`,\n });\n this.oauthApps = new OauthAppsResource(http);\n }\n}\n"]}