@vitrina/api 11.55.0 → 11.102.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/dist/index.cjs +2 -43
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +54733 -35717
- package/dist/index.d.ts +54733 -35717
- package/dist/index.js +2 -43
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -16,6 +16,7 @@ var ERROR_CODES = [
|
|
|
16
16
|
"UNAUTHORIZED",
|
|
17
17
|
"FORBIDDEN",
|
|
18
18
|
"CONFLICT",
|
|
19
|
+
"VERSION_CONFLICT",
|
|
19
20
|
"UNIQUE_CONFLICT",
|
|
20
21
|
"IDEMPOTENCY_KEY_CONFLICT",
|
|
21
22
|
"VERTICAL_NOT_ENABLED",
|
|
@@ -65,49 +66,7 @@ var ERROR_CODES = [
|
|
|
65
66
|
"TASADOR_ANON_DAILY_LIMIT",
|
|
66
67
|
"TASADOR_CAPACITY_REACHED",
|
|
67
68
|
"CLINIC_PLAN_REQUIRED",
|
|
68
|
-
"TENANT_BILLING_PAUSED"
|
|
69
|
-
"FACEBOOK_MARKETPLACE_NOT_AVAILABLE",
|
|
70
|
-
"WORKSPACE_MEMBER_INACTIVE",
|
|
71
|
-
"DEVICE_AGENT_ALREADY_PAIRED",
|
|
72
|
-
"DEVICE_AGENT_SELF_REQUIRES_USER",
|
|
73
|
-
"DEVICE_AGENT_KIND_NOT_ALLOWED",
|
|
74
|
-
"DEVICE_TASK_STATUS_NOT_ALLOWED",
|
|
75
|
-
"FACEBOOK_MARKETPLACE_NO_PHONE_AGENT",
|
|
76
|
-
"FACEBOOK_MARKETPLACE_THREAD_NOT_ADDRESSABLE",
|
|
77
|
-
"FACEBOOK_MARKETPLACE_ATTACHMENT_UNSUPPORTED",
|
|
78
|
-
"REPLY_PACING_LOCKED",
|
|
79
|
-
"SANDBOX_CHANNEL_FORBIDDEN",
|
|
80
|
-
"SANDBOX_BILLING_FORBIDDEN",
|
|
81
|
-
"SANDBOX_NOT_PROVISIONED",
|
|
82
|
-
"SANDBOX_RESET_UNAVAILABLE",
|
|
83
|
-
"CONNECTED_APP_SENSITIVE_DATA",
|
|
84
|
-
"handoff_mismatch",
|
|
85
|
-
"sync_in_flight",
|
|
86
|
-
"disconnect_refused",
|
|
87
|
-
"start_again",
|
|
88
|
-
"reconnect",
|
|
89
|
-
"not_selecting",
|
|
90
|
-
"selection_expired",
|
|
91
|
-
"selection_conflict",
|
|
92
|
-
"account_connected_elsewhere",
|
|
93
|
-
"candidate_unavailable",
|
|
94
|
-
"integration_managed",
|
|
95
|
-
"stage_not_found",
|
|
96
|
-
"stage_not_writable",
|
|
97
|
-
"stages_write_blocked",
|
|
98
|
-
"invalid_outcome",
|
|
99
|
-
"not_connected",
|
|
100
|
-
"partner_token_invalid",
|
|
101
|
-
"OUTBOUND_BLOCKED",
|
|
102
|
-
"OUTBOUND_WARNING",
|
|
103
|
-
"dpa_acceptance_required",
|
|
104
|
-
"EMAIL_SENDER_UNRESOLVED",
|
|
105
|
-
"CAMPAIGN_FROM_CONNECTED_MAILBOX",
|
|
106
|
-
"BANK_FEED_NOT_CONFIGURED",
|
|
107
|
-
"ADDON_NOT_PRICED",
|
|
108
|
-
"ADDON_NOT_OFFERED",
|
|
109
|
-
"MIRROR_LINES_UNMAPPED",
|
|
110
|
-
"MONTH_OWNED_BY_VENDOR"
|
|
69
|
+
"TENANT_BILLING_PAUSED"
|
|
111
70
|
];
|
|
112
71
|
|
|
113
72
|
// src/errors.ts
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/generated/error-codes.ts","../src/errors.ts","../src/webhooks.ts","../src/events.ts","../src/client.ts","../src/pagination.ts","../src/idempotency.ts"],"names":["createHmac","timingSafeEqual","createOpenApiClient","randomUUID"],"mappings":"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","file":"index.cjs","sourcesContent":["// AUTO-GENERATED by scripts/generate-error-codes.ts from the repo-root src/errors/index.ts's `ErrorCode` union — do not edit by hand.\n\n/**\n * Every code the API error envelope can carry as `error.code`, at the\n * commit this SDK was generated from. Kept OPEN (see `OpenErrorCode` in\n * `../errors.ts`) because a server can ship a new code before this SDK\n * is regenerated — narrow on the ones you handle, never assume this\n * list is exhaustive at runtime.\n */\nexport type ErrorCode =\n | 'VALIDATION_ERROR'\n | 'NOT_FOUND'\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'CONFLICT'\n | 'UNIQUE_CONFLICT'\n | 'IDEMPOTENCY_KEY_CONFLICT'\n | 'VERTICAL_NOT_ENABLED'\n | 'ENTITLEMENT_NOT_ACTIVE'\n | 'UNSUPPORTED_VEHICLE_TYPE'\n | 'NO_OFFERING_ADAPTER'\n | 'PAYLOAD_TOO_LARGE'\n | 'UNSUPPORTED_MEDIA_TYPE'\n | 'UPSTREAM_ERROR'\n | 'RATE_LIMITED'\n | 'GONE'\n | 'INTERNAL_ERROR'\n | 'MESSAGING_ACCOUNT_TENANT_MISSING'\n | 'COPILOT_APPROVALS_UNAVAILABLE'\n | 'COPILOT_APPROVAL_REPLAY_BLOCKED'\n | 'COPILOT_DISABLED'\n | 'COPILOT_BUDGET_EXCEEDED'\n | 'DEALER_SITES_NOT_CONFIGURED'\n | 'STOREFRONT_ZONES_NOT_CONFIGURED'\n | 'RECONTACTO_NOT_ENABLED'\n | 'SYNC_QUEUE_UNAVAILABLE'\n | 'SHARE_IMAGE_UNAVAILABLE'\n | 'ATTRIBUTION_PROFILE_UNAVAILABLE'\n | 'DOCUMENT_LOGO_UNAVAILABLE'\n | 'ATTRIBUTION_PROFILE_MISMATCH'\n | 'ADS_KEY_NEEDS_REMINT'\n | 'ADS_ACTION_READ_UNAVAILABLE'\n | 'ADS_ACTION_REPLAY_BLOCKED'\n | 'ADS_ACTION_NOT_AVAILABLE'\n | 'ADS_ACTION_NOT_REVERSIBLE'\n | 'ADS_ACTION_CONSENT_REQUIRED'\n | 'GTM_NOT_CONFIGURED'\n | 'GTM_NOT_CONNECTED'\n | 'GTM_CONSENT_REQUIRED'\n | 'GTM_PERMISSION_DENIED'\n | 'GTM_CONTAINER_REQUIRED'\n | 'GTM_PENDING_CHANGES'\n | 'GTM_WORKSPACE_CONFLICT'\n | 'GTM_WORKSPACE_LIMIT'\n | 'MISSING_SIGNATURE'\n | 'MALFORMED_SIGNATURE'\n | 'STALE_SIGNATURE'\n | 'INVALID_SIGNATURE'\n | 'REPLAY_DETECTED'\n | 'TURNSTILE_UNAVAILABLE'\n | 'TASADOR_QUOTA_EXHAUSTED'\n | 'TASADOR_ANON_DAILY_LIMIT'\n | 'TASADOR_CAPACITY_REACHED'\n | 'CLINIC_PLAN_REQUIRED'\n | 'TENANT_BILLING_PAUSED'\n | 'FACEBOOK_MARKETPLACE_NOT_AVAILABLE'\n | 'WORKSPACE_MEMBER_INACTIVE'\n | 'DEVICE_AGENT_ALREADY_PAIRED'\n | 'DEVICE_AGENT_SELF_REQUIRES_USER'\n | 'DEVICE_AGENT_KIND_NOT_ALLOWED'\n | 'DEVICE_TASK_STATUS_NOT_ALLOWED'\n | 'FACEBOOK_MARKETPLACE_NO_PHONE_AGENT'\n | 'FACEBOOK_MARKETPLACE_THREAD_NOT_ADDRESSABLE'\n | 'FACEBOOK_MARKETPLACE_ATTACHMENT_UNSUPPORTED'\n | 'REPLY_PACING_LOCKED'\n | 'SANDBOX_CHANNEL_FORBIDDEN'\n | 'SANDBOX_BILLING_FORBIDDEN'\n | 'SANDBOX_NOT_PROVISIONED'\n | 'SANDBOX_RESET_UNAVAILABLE'\n | 'CONNECTED_APP_SENSITIVE_DATA'\n | 'handoff_mismatch'\n | 'sync_in_flight'\n | 'disconnect_refused'\n | 'start_again'\n | 'reconnect'\n | 'not_selecting'\n | 'selection_expired'\n | 'selection_conflict'\n | 'account_connected_elsewhere'\n | 'candidate_unavailable'\n | 'integration_managed'\n | 'stage_not_found'\n | 'stage_not_writable'\n | 'stages_write_blocked'\n | 'invalid_outcome'\n | 'not_connected'\n | 'partner_token_invalid'\n | 'OUTBOUND_BLOCKED'\n | 'OUTBOUND_WARNING'\n | 'dpa_acceptance_required'\n | 'EMAIL_SENDER_UNRESOLVED'\n | 'CAMPAIGN_FROM_CONNECTED_MAILBOX'\n | 'BANK_FEED_NOT_CONFIGURED'\n | 'ADDON_NOT_PRICED'\n | 'ADDON_NOT_OFFERED'\n | 'MIRROR_LINES_UNMAPPED'\n | 'MONTH_OWNED_BY_VENDOR';\n\nexport const ERROR_CODES: readonly ErrorCode[] = [\n 'VALIDATION_ERROR',\n 'NOT_FOUND',\n 'UNAUTHORIZED',\n 'FORBIDDEN',\n 'CONFLICT',\n 'UNIQUE_CONFLICT',\n 'IDEMPOTENCY_KEY_CONFLICT',\n 'VERTICAL_NOT_ENABLED',\n 'ENTITLEMENT_NOT_ACTIVE',\n 'UNSUPPORTED_VEHICLE_TYPE',\n 'NO_OFFERING_ADAPTER',\n 'PAYLOAD_TOO_LARGE',\n 'UNSUPPORTED_MEDIA_TYPE',\n 'UPSTREAM_ERROR',\n 'RATE_LIMITED',\n 'GONE',\n 'INTERNAL_ERROR',\n 'MESSAGING_ACCOUNT_TENANT_MISSING',\n 'COPILOT_APPROVALS_UNAVAILABLE',\n 'COPILOT_APPROVAL_REPLAY_BLOCKED',\n 'COPILOT_DISABLED',\n 'COPILOT_BUDGET_EXCEEDED',\n 'DEALER_SITES_NOT_CONFIGURED',\n 'STOREFRONT_ZONES_NOT_CONFIGURED',\n 'RECONTACTO_NOT_ENABLED',\n 'SYNC_QUEUE_UNAVAILABLE',\n 'SHARE_IMAGE_UNAVAILABLE',\n 'ATTRIBUTION_PROFILE_UNAVAILABLE',\n 'DOCUMENT_LOGO_UNAVAILABLE',\n 'ATTRIBUTION_PROFILE_MISMATCH',\n 'ADS_KEY_NEEDS_REMINT',\n 'ADS_ACTION_READ_UNAVAILABLE',\n 'ADS_ACTION_REPLAY_BLOCKED',\n 'ADS_ACTION_NOT_AVAILABLE',\n 'ADS_ACTION_NOT_REVERSIBLE',\n 'ADS_ACTION_CONSENT_REQUIRED',\n 'GTM_NOT_CONFIGURED',\n 'GTM_NOT_CONNECTED',\n 'GTM_CONSENT_REQUIRED',\n 'GTM_PERMISSION_DENIED',\n 'GTM_CONTAINER_REQUIRED',\n 'GTM_PENDING_CHANGES',\n 'GTM_WORKSPACE_CONFLICT',\n 'GTM_WORKSPACE_LIMIT',\n 'MISSING_SIGNATURE',\n 'MALFORMED_SIGNATURE',\n 'STALE_SIGNATURE',\n 'INVALID_SIGNATURE',\n 'REPLAY_DETECTED',\n 'TURNSTILE_UNAVAILABLE',\n 'TASADOR_QUOTA_EXHAUSTED',\n 'TASADOR_ANON_DAILY_LIMIT',\n 'TASADOR_CAPACITY_REACHED',\n 'CLINIC_PLAN_REQUIRED',\n 'TENANT_BILLING_PAUSED',\n 'FACEBOOK_MARKETPLACE_NOT_AVAILABLE',\n 'WORKSPACE_MEMBER_INACTIVE',\n 'DEVICE_AGENT_ALREADY_PAIRED',\n 'DEVICE_AGENT_SELF_REQUIRES_USER',\n 'DEVICE_AGENT_KIND_NOT_ALLOWED',\n 'DEVICE_TASK_STATUS_NOT_ALLOWED',\n 'FACEBOOK_MARKETPLACE_NO_PHONE_AGENT',\n 'FACEBOOK_MARKETPLACE_THREAD_NOT_ADDRESSABLE',\n 'FACEBOOK_MARKETPLACE_ATTACHMENT_UNSUPPORTED',\n 'REPLY_PACING_LOCKED',\n 'SANDBOX_CHANNEL_FORBIDDEN',\n 'SANDBOX_BILLING_FORBIDDEN',\n 'SANDBOX_NOT_PROVISIONED',\n 'SANDBOX_RESET_UNAVAILABLE',\n 'CONNECTED_APP_SENSITIVE_DATA',\n 'handoff_mismatch',\n 'sync_in_flight',\n 'disconnect_refused',\n 'start_again',\n 'reconnect',\n 'not_selecting',\n 'selection_expired',\n 'selection_conflict',\n 'account_connected_elsewhere',\n 'candidate_unavailable',\n 'integration_managed',\n 'stage_not_found',\n 'stage_not_writable',\n 'stages_write_blocked',\n 'invalid_outcome',\n 'not_connected',\n 'partner_token_invalid',\n 'OUTBOUND_BLOCKED',\n 'OUTBOUND_WARNING',\n 'dpa_acceptance_required',\n 'EMAIL_SENDER_UNRESOLVED',\n 'CAMPAIGN_FROM_CONNECTED_MAILBOX',\n 'BANK_FEED_NOT_CONFIGURED',\n 'ADDON_NOT_PRICED',\n 'ADDON_NOT_OFFERED',\n 'MIRROR_LINES_UNMAPPED',\n 'MONTH_OWNED_BY_VENDOR',\n] as const;\n","/**\n * Typed errors over the API's one error envelope: `{ error: { code, message,\n * details?, field_errors?, requestId?, ...extensions } }` (`src/errors/\n * index.ts` + `src/middlewares/error-handler.ts` in vitrina-app). `code` is\n * generated from the committed error catalogue (see `generated/error-codes.ts`\n * and `../scripts/generate-error-codes.ts`) but kept OPEN at the type level —\n * `ErrorCode | (string & Record<string, never>)` — because a server release\n * can ship a new code before this SDK is regenerated; never treat the union\n * as exhaustive at runtime (no `switch` without a `default`).\n */\nimport { ERROR_CODES, type ErrorCode } from './generated/error-codes';\n\nexport { ERROR_CODES };\nexport type { ErrorCode };\n\n/** `error.code`, widened so an unrecognised future code still type-checks.\n * The `Record<string, never>` intersection (not a bare `{}`) is what keeps\n * known `ErrorCode` literals showing up in autocomplete while still\n * accepting any string. */\nexport type OpenErrorCode = ErrorCode | (string & Record<string, never>);\n\n/** One entry of `error.details.reasons` on an outbound-policy verdict (C4). */\nexport interface OutboundVerdictReason {\n code: string;\n kind: 'bloqueo' | 'advertencia';\n hint: string;\n detail?: string;\n}\n\n/** The wire shape of `error` inside the envelope. */\nexport interface ApiErrorBody {\n code: OpenErrorCode;\n message: string;\n details?: unknown;\n field_errors?: Record<string, string>;\n requestId?: string;\n /** Send-verdict envelopes (C4) put `reasons`/`hint` at this level too. */\n reasons?: OutboundVerdictReason[];\n hint?: string;\n [key: string]: unknown;\n}\n\nexport interface ApiErrorOptions {\n requestUrl?: string;\n requestMethod?: string;\n}\n\n/** Base class for every error this SDK throws for a non-2xx API response. */\nexport class VitrinaApiError extends Error {\n /** The catalogue code — branch on this, never on `message`. */\n readonly code: OpenErrorCode;\n\n /** HTTP status of the response that produced this error. */\n readonly status: number;\n\n readonly details?: unknown;\n\n readonly fieldErrors?: Record<string, string>;\n\n /** Correlates this failure with the server's own logs. */\n readonly requestId?: string;\n\n /** The full parsed `error` object, for anything not surfaced above. */\n readonly body: ApiErrorBody;\n\n readonly requestUrl?: string;\n\n readonly requestMethod?: string;\n\n constructor(\n status: number,\n body: ApiErrorBody,\n options: ApiErrorOptions = {},\n ) {\n super(body.message || `Vitrina API error ${body.code} (HTTP ${status})`);\n this.name = 'VitrinaApiError';\n this.status = status;\n this.code = body.code;\n this.details = body.details;\n this.fieldErrors = body.field_errors;\n this.requestId = body.requestId;\n this.body = body;\n this.requestUrl = options.requestUrl;\n this.requestMethod = options.requestMethod;\n }\n\n /** `429 RATE_LIMITED`. */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /** `401` — no credential, or one the server does not recognise. */\n get isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n /** `403` — a real credential, missing the scope this call needs. */\n get isForbidden(): boolean {\n return this.status === 403;\n }\n\n /** `404 NOT_FOUND`. */\n get isNotFound(): boolean {\n return this.status === 404;\n }\n\n /** `409 IDEMPOTENCY_KEY_CONFLICT` — same `Idempotency-Key`, different body. */\n get isIdempotencyConflict(): boolean {\n return this.code === 'IDEMPOTENCY_KEY_CONFLICT';\n }\n}\n\n/**\n * `422 OUTBOUND_BLOCKED` (a Bloqueo, never overridable) or `409\n * OUTBOUND_WARNING` (an Advertencia — resend the same call with\n * `acknowledge: reasons.map(r => r.code)` in the body to proceed). Cross-\n * ticket contract C4 — `src/services/api-send-verdicts.ts` in vitrina-app.\n */\nexport class OutboundVerdictError extends VitrinaApiError {\n /** Every reason the send was stopped for, with its kind and hint. */\n readonly reasons: OutboundVerdictReason[];\n\n /** The first reason's hint, surfaced at the top level like the wire body. */\n readonly hint: string;\n\n constructor(\n status: number,\n body: ApiErrorBody,\n options: ApiErrorOptions = {},\n ) {\n super(status, body, options);\n this.name = 'OutboundVerdictError';\n const detailsReasons = (\n body.details as { reasons?: OutboundVerdictReason[] } | undefined\n )?.reasons;\n this.reasons = body.reasons ?? detailsReasons ?? [];\n this.hint = body.hint ?? this.reasons[0]?.hint ?? '';\n }\n\n /** A Bloqueo — the law, the customer or the provider already said no. */\n get isBlocked(): boolean {\n return this.code === 'OUTBOUND_BLOCKED';\n }\n\n /** An Advertencia — resend once with `acknowledge` to proceed. */\n get isWarning(): boolean {\n return this.code === 'OUTBOUND_WARNING';\n }\n\n /** `reasons` codes, ready to pass back as `{ acknowledge: [...] }`. */\n get acknowledgeCodes(): string[] {\n return this.reasons.map((r) => r.code);\n }\n}\n\nfunction asErrorBody(payload: unknown, status: number): ApiErrorBody {\n if (payload && typeof payload === 'object') {\n const maybeEnvelope = payload as { error?: unknown };\n const candidate =\n maybeEnvelope.error && typeof maybeEnvelope.error === 'object'\n ? (maybeEnvelope.error as Record<string, unknown>)\n : (payload as Record<string, unknown>);\n if (\n typeof candidate.code === 'string' &&\n typeof candidate.message === 'string'\n ) {\n return candidate as unknown as ApiErrorBody;\n }\n }\n return {\n code: 'INTERNAL_ERROR',\n message: `HTTP ${status} with an unrecognised response body`,\n };\n}\n\n/** Turns a non-2xx response's status + parsed JSON body into a typed error. */\nexport function toApiError(\n status: number,\n payload: unknown,\n options: ApiErrorOptions = {},\n): VitrinaApiError {\n const body = asErrorBody(payload, status);\n if (body.code === 'OUTBOUND_BLOCKED' || body.code === 'OUTBOUND_WARNING') {\n return new OutboundVerdictError(status, body, options);\n }\n return new VitrinaApiError(status, body, options);\n}\n\n/** The subset of an `openapi-fetch` call's resolved value `unwrap` needs. */\nexport interface UnwrappableResult<T> {\n data?: T;\n error?: unknown;\n response: Response;\n}\n\n/**\n * `const location = unwrap(await api.GET('/locations/{id}', ...))` — throws\n * a typed `VitrinaApiError` (or `OutboundVerdictError`) instead of making\n * every call site check `error` by hand. `openapi-fetch` itself never\n * throws; reach for the raw `{ data, error }` result directly when you want\n * that instead.\n */\nexport function unwrap<T>(\n result: UnwrappableResult<T>,\n options: ApiErrorOptions = {},\n): T {\n if (result.error !== undefined) {\n throw toApiError(result.response.status, result.error, options);\n }\n if (result.data === undefined) {\n throw new VitrinaApiError(\n result.response.status,\n {\n code: 'INTERNAL_ERROR',\n message: 'Response had neither data nor error',\n },\n options,\n );\n }\n return result.data;\n}\n","/**\n * Webhook Evento envelope + Stripe-style signature verification, matching\n * the dispatch service's own `signPayload`/`buildHeaders`\n * (`src/services/webhook-dispatch.service.ts` in vitrina-app; cross-ticket\n * contract C3). The signature is an HMAC-SHA256 over `${timestamp}.${body}`\n * with the subscription's `whsec_...` secret, carried as\n * `X-Webhook-Signature: t=<unix_seconds>,v1=<hex>`.\n *\n * `tests/api-sdk-webhook-signature.test.ts` (vitrina-app repo root) verifies\n * this against the REAL `signPayload` the dispatch service calls in\n * production — not a hand-written fixture.\n */\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\n/** `resource` on the envelope — what changed, and where to read it. */\nexport interface WebhookEventResource {\n type: string;\n id: string | null;\n /** Absolute `GET` URL for this resource, or `null` when none is available\n * (e.g. the event has no single owning record). Feeds `event.fetch()`. */\n url: string | null;\n}\n\n/** Who did it — see `Author` in vitrina-app's `src/types/author.ts` (C3). */\nexport interface WebhookEventAuthor {\n kind: 'member' | 'api_key' | 'ai_agent' | 'system' | 'contact';\n id: string | null;\n name: string | null;\n via?: { kind: 'connected_app' | 'personal_token'; name: string };\n}\n\n/** Why `data` is absent — every reason a subscription's owner can be denied\n * the resource body. `missing_scope:<scope>` is a family, not one literal. */\nexport type DataOmittedReason =\n | 'not_requested'\n | 'sensitive'\n | 'owner_unavailable'\n | 'restricted_visibility'\n | `missing_scope:${string}`;\n\n/** One Evento, exactly as it arrives on the wire. Exactly one of `data` /\n * `data_omitted` is ever present. */\nexport interface WebhookEventEnvelope<TData = Record<string, unknown>> {\n id: string;\n type: string;\n version: number;\n /** `false` for an event from a sandbox (test-mode) workspace, `true`\n * otherwise; mirrored on the delivery's `Vitrina-Livemode` header.\n * Optional here only so an envelope captured before vitrina-app#2693\n * still satisfies this type — every envelope on the wire carries it. */\n livemode?: boolean;\n created_at: string;\n tenant_id: string;\n resource: WebhookEventResource;\n changes?: Record<string, { from: unknown; to: unknown }>;\n author: WebhookEventAuthor;\n data?: TData;\n data_omitted?: DataOmittedReason;\n}\n\nexport interface VerifySignatureOptions {\n /** How far `X-Webhook-Timestamp` may drift from now before a signature\n * that otherwise matches is rejected as stale (replay protection).\n * Default 300 (5 minutes), matching the docs' own verifier. */\n toleranceSeconds?: number;\n /** Override \"now\", in Unix seconds — for tests. */\n nowUnix?: number;\n}\n\nexport type VerifyResult =\n | { ok: true }\n | { ok: false; reason: 'malformed_header' | 'bad_signature' | 'stale' };\n\nfunction parseSignatureHeader(\n header: string,\n): { timestamp: number; v1: string } | null {\n const parts: Record<string, string> = {};\n for (const pair of header.split(',')) {\n const at = pair.indexOf('=');\n if (at === -1) continue;\n parts[pair.slice(0, at).trim()] = pair.slice(at + 1).trim();\n }\n const timestamp = Number(parts.t);\n if (!Number.isFinite(timestamp) || !parts.v1) return null;\n return { timestamp, v1: parts.v1 };\n}\n\n/**\n * Verifies an `X-Webhook-Signature` header against the raw delivery body.\n * Never throws — returns `{ ok: false, reason }` so a caller can log why a\n * delivery was rejected. `rawBody` must be the exact bytes the delivery\n * sent, before any JSON re-serialization (re-stringifying a parsed body\n * produces different bytes and the signature will never match).\n */\nexport function verifyWebhookSignature(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n): VerifyResult {\n const parsed = parseSignatureHeader(params.signatureHeader);\n if (!parsed) return { ok: false, reason: 'malformed_header' };\n\n const body =\n typeof params.rawBody === 'string'\n ? params.rawBody\n : params.rawBody.toString('utf8');\n const expected = createHmac('sha256', params.secret)\n .update(`${parsed.timestamp}.${body}`)\n .digest('hex');\n\n const given = Buffer.from(parsed.v1, 'utf8');\n const mine = Buffer.from(expected, 'utf8');\n const signatureMatches =\n given.length === mine.length && timingSafeEqual(given, mine);\n if (!signatureMatches) return { ok: false, reason: 'bad_signature' };\n\n const tolerance = params.toleranceSeconds ?? 300;\n const now = params.nowUnix ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - parsed.timestamp) > tolerance) {\n return { ok: false, reason: 'stale' };\n }\n return { ok: true };\n}\n\nexport class WebhookSignatureError extends Error {\n readonly reason: Exclude<VerifyResult, { ok: true }>['reason'];\n\n constructor(reason: Exclude<VerifyResult, { ok: true }>['reason']) {\n super(`Webhook signature verification failed: ${reason}`);\n this.name = 'WebhookSignatureError';\n this.reason = reason;\n }\n}\n\n/**\n * Verifies + parses an Evento delivery in one call (Stripe's\n * `constructEvent` naming, same idea): throws `WebhookSignatureError`\n * instead of returning a result a caller might forget to check before\n * trusting `rawBody`.\n */\nexport function constructEventEnvelope<TData = Record<string, unknown>>(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n): WebhookEventEnvelope<TData> {\n const result = verifyWebhookSignature(params);\n if (!result.ok) throw new WebhookSignatureError(result.reason);\n const body =\n typeof params.rawBody === 'string'\n ? params.rawBody\n : params.rawBody.toString('utf8');\n return JSON.parse(body) as WebhookEventEnvelope<TData>;\n}\n","/**\n * `event.fetch()` — read an Evento's resource in one call, using the same\n * credentials the client was created with. `resource.url` is the absolute\n * `GET` URL the server already computed (`apiPublicUrl()` in\n * `webhook-dispatch.service.ts`), so this is a plain authenticated fetch of\n * that URL — no per-resource-type routing table to keep in sync.\n */\nimport { toApiError } from './errors';\nimport {\n constructEventEnvelope,\n verifyWebhookSignature,\n type VerifySignatureOptions,\n type WebhookEventEnvelope,\n} from './webhooks';\n\nexport class EventResourceUnavailableError extends Error {\n readonly event: WebhookEventEnvelope;\n\n constructor(event: WebhookEventEnvelope) {\n super(\n event.data_omitted\n ? `Event ${event.id} (${event.type}) carries no resource URL — data_omitted: ${event.data_omitted}`\n : `Event ${event.id} (${event.type}) carries no resource URL`,\n );\n this.name = 'EventResourceUnavailableError';\n this.event = event;\n }\n}\n\n/** A parsed Evento, plus a `fetch()` bound to the client it came from. */\nexport type VitrinaEvent<TData = Record<string, unknown>> =\n WebhookEventEnvelope<TData> & {\n /**\n * `GET`s `resource.url` with this client's credentials and returns its\n * `data`. Throws `EventResourceUnavailableError` when the envelope has no\n * URL (an event with no single owning resource, or one whose `data` you\n * already have inline). Pass a type argument to get the resource typed:\n * `await event.fetch<Contact>()`.\n */\n fetch<TResource = TData>(): Promise<TResource>;\n };\n\nexport interface EventFetcherDeps {\n headers: HeadersInit;\n fetch: typeof fetch;\n}\n\n/** Builds the `events` namespace `createClient()` attaches to every client:\n * signature verification bound to nothing (pure functions), and\n * `constructEvent` bound to this client's own auth so the returned event's\n * `.fetch()` needs no arguments. */\nexport function createEventsNamespace(deps: EventFetcherDeps) {\n // `WebhookEventEnvelope<any>`: this helper only ever reads `resource` /\n // `data_omitted` / `id` / `type`, never `.data`, so it is deliberately\n // NOT generic over TData — a `WebhookEventEnvelope<TData>` for any TData\n // must be assignable here.\n async function fetchResource<TResource>(\n event: WebhookEventEnvelope<any>,\n ): Promise<TResource> {\n if (!event.resource.url) throw new EventResourceUnavailableError(event);\n const res = await deps.fetch(event.resource.url, { headers: deps.headers });\n let json: unknown;\n try {\n json = await res.json();\n } catch {\n json = undefined;\n }\n if (!res.ok) {\n throw toApiError(res.status, json, {\n requestUrl: event.resource.url,\n requestMethod: 'GET',\n });\n }\n return (json as { data: TResource })?.data;\n }\n\n return {\n /** Verifies an `X-Webhook-Signature` header. Never throws. */\n verifySignature: (\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ) => verifyWebhookSignature(params),\n\n /**\n * Verifies + parses a webhook delivery and returns it with a bound\n * `.fetch()`. Throws `WebhookSignatureError` on a bad/stale signature.\n *\n * const event = client.events.constructEvent({\n * secret: subscriptionSecret,\n * signatureHeader: req.headers['x-webhook-signature'],\n * rawBody: req.rawBody,\n * });\n * if (event.type === 'contact.created') {\n * const contact = await event.fetch<Contact>();\n * }\n */\n constructEvent<TData = Record<string, unknown>>(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ): VitrinaEvent<TData> {\n const envelope = constructEventEnvelope<TData>(params);\n return Object.assign(envelope, {\n fetch: <TResource = TData>() => fetchResource<TResource>(envelope),\n });\n },\n };\n}\n","/**\n * `createClient()` — a typed `openapi-fetch` client over the API pública\n * (`paths` generated from the committed `openapi.public.json`), plus the\n * `events` namespace (webhook signature verification + `event.fetch()`).\n *\n * Auth: pass an `sk_*` API key (workspace credential or personal token —\n * both are Bearer) or a raw bearer token you manage yourself. Exactly one of\n * `apiKey` / `bearer`.\n */\nimport createOpenApiClient, { type Client } from 'openapi-fetch';\n\nimport { createEventsNamespace, type VitrinaEvent } from './events';\nimport type { paths } from './generated/api-types';\nimport type { VerifySignatureOptions, VerifyResult } from './webhooks';\n\nexport interface CreateClientOptions {\n /** Absolute base URL, e.g. `https://api.vitrinadev.com/api/v1`. No trailing slash. */\n baseUrl: string;\n /** An `sk_*` API key (workspace key or personal token). Mutually exclusive with `bearer`. */\n apiKey?: string;\n /** A raw bearer token, for a caller that manages tokens itself (e.g. a Supabase session JWT). */\n bearer?: string;\n /** Extra headers merged onto every request (e.g. a custom `User-Agent`). */\n headers?: Record<string, string>;\n /** Override `fetch` — Node <18, undici, msw, a test double. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface VitrinaEventsNamespace {\n /** Verifies an `X-Webhook-Signature` header. Never throws. */\n verifySignature(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ): VerifyResult;\n /** Verifies + parses a webhook delivery; the returned event carries a\n * `.fetch()` bound to this client. Throws `WebhookSignatureError`. */\n constructEvent<TData = Record<string, unknown>>(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ): VitrinaEvent<TData>;\n}\n\n/** The typed REST client (`GET`/`POST`/.../`use`/`eject`, from `openapi-fetch`)\n * plus the `events` namespace. */\nexport type VitrinaClient = Client<paths> & { events: VitrinaEventsNamespace };\n\nexport function createClient(opts: CreateClientOptions): VitrinaClient {\n if (opts.apiKey && opts.bearer) {\n throw new RangeError(\n 'createClient(): pass at most one of `apiKey` / `bearer`, not both',\n );\n }\n const credential = opts.apiKey ?? opts.bearer;\n const headers: Record<string, string> = {\n ...(credential ? { Authorization: `Bearer ${credential}` } : {}),\n ...opts.headers,\n };\n const fetchImpl = opts.fetch ?? fetch;\n\n const base = createOpenApiClient<paths>({\n baseUrl: opts.baseUrl,\n headers,\n fetch: fetchImpl,\n });\n\n const events = createEventsNamespace({ headers, fetch: fetchImpl });\n\n return Object.assign(base, { events });\n}\n","/**\n * Cursor pagination — walks a list endpoint page by page, yielding one item\n * at a time (`for await`). Vitrina's list envelopes carry the cursor as\n * `meta.pagination.nextCursor` (the shape every v1 list route in production\n * answers with — `ok(res, rows, { pagination: { nextCursor, limit } })`,\n * `src/routes/api/v1/*.ts`) with a `meta.nextCursor` fallback for the flat\n * `PaginationMeta` OpenAPI shape (`src/api/openapi-responses.ts`) some\n * generated docs describe; this helper reads either. The opaque cursor\n * itself is a base64url-encoded `{ ts, id }` pair (`src/api/pagination.ts`)\n * — never decode it, just pass it back as the next page's `cursor` query\n * param.\n */\nimport { toApiError } from './errors';\n\nexport interface PaginationMeta {\n pagination?: {\n nextCursor?: string | null;\n prevCursor?: string | null;\n limit?: number;\n };\n nextCursor?: string | null;\n prevCursor?: string | null;\n total?: number;\n limit?: number;\n [key: string]: unknown;\n}\n\nexport interface ListEnvelope<T> {\n data?: T[];\n meta?: PaginationMeta;\n}\n\n/** The subset of an `openapi-fetch` GET call's resolved value `paginate` needs. */\nexport interface FetchPageResult<T> {\n data?: ListEnvelope<T>;\n error?: unknown;\n response: Response;\n}\n\nfunction nextCursorOf(meta: PaginationMeta | undefined): string | undefined {\n const cursor = meta?.pagination?.nextCursor ?? meta?.nextCursor ?? null;\n return cursor ?? undefined;\n}\n\n/**\n * Walks every page of a cursor-paginated list, yielding one item at a time.\n *\n * for await (const appointment of paginate((cursor) =>\n * api.GET('/appointments', { params: { query: { cursor, limit: 100 } } }),\n * )) {\n * console.log(appointment.id);\n * }\n *\n * CURSOR IS THE MINORITY SHAPE, so check the route before reaching for this.\n * Measured against the published contract: exactly two operations take a\n * `cursor` — `GET /appointments` and `GET /conversations/{id}/messages`.\n * Fifteen take `offset`/`limit` (`/stock`, `/vehicles`, `/contacts/search`,\n * `/webhooks/{id}/deliveries` and the rest), and others take `page`/`page_size`\n * (`/leads` among them). Passing `cursor` to one of those is a type error, not\n * a silent first page — which is the point of generating this package from the\n * contract.\n *\n * `fetchPage` is any typed `api.GET(...)` call, called once per page with\n * the previous page's cursor (`undefined` for the first page). Throws a\n * typed `VitrinaApiError` if a page comes back as an error, same as\n * `unwrap()`.\n */\nexport async function* paginate<T>(\n fetchPage: (cursor: string | undefined) => Promise<FetchPageResult<T>>,\n): AsyncGenerator<T, void, unknown> {\n let cursor: string | undefined;\n for (;;) {\n // eslint-disable-next-line no-await-in-loop -- pages are inherently sequential (each cursor depends on the last)\n const result = await fetchPage(cursor);\n if (result.error !== undefined) {\n throw toApiError(result.response.status, result.error);\n }\n const page = result.data;\n if (!page || !Array.isArray(page.data)) return;\n for (const item of page.data) yield item;\n const next = nextCursorOf(page.meta);\n if (!next) return;\n cursor = next;\n }\n}\n\n/** Same as `paginate`, but collects every page into one array. Only reach\n * for this on a list you know is bounded — an unbounded one belongs on the\n * `for await` form above. */\nexport async function paginateAll<T>(\n fetchPage: (cursor: string | undefined) => Promise<FetchPageResult<T>>,\n): Promise<T[]> {\n const items: T[] = [];\n // eslint-disable-next-line no-restricted-syntax -- collecting an async generator IS the sequential-await case for-await exists for\n for await (const item of paginate(fetchPage)) items.push(item);\n return items;\n}\n","/**\n * `Idempotency-Key` — replay-safe retries on the 39 published write\n * operations that accept it (ADR 0106 §2.3/#2400). Resending the SAME key\n * with the SAME body returns the original response (`X-Idempotent-Replay:\n * 1`) instead of creating a second copy; the same key with a DIFFERENT body\n * answers `409 IDEMPOTENCY_KEY_CONFLICT` (`VitrinaApiError#isIdempotencyConflict`).\n *\n * The generated types already carry `Idempotency-Key` as a typed header\n * parameter per operation — `idempotencyKey()` just builds a well-formed\n * value to put there:\n *\n * await api.POST('/pipelines', {\n * params: { header: idempotencyKey(`provision-${userId}-2026-04-24`) },\n * body: { ... },\n * });\n */\nimport { randomUUID } from 'node:crypto';\n\nconst KEY_PATTERN = /^[A-Za-z0-9_-]{8,200}$/;\n\nexport interface IdempotencyKeyHeader {\n 'Idempotency-Key': string;\n}\n\n/**\n * Validates `key` against the server's own constraint (`minLength: 8,\n * maxLength: 200, pattern: ^[A-Za-z0-9_-]+$` on every operation that accepts\n * it) and returns it as a header object to spread into `params.header`.\n * Throws `RangeError` on a malformed key — better to fail before the\n * request leaves than to get back a generic `VALIDATION_ERROR`.\n */\nexport function idempotencyKey(key: string): IdempotencyKeyHeader {\n if (!KEY_PATTERN.test(key)) {\n throw new RangeError(\n `Idempotency-Key must be 8-200 characters of [A-Za-z0-9_-], got: ${JSON.stringify(key)}`,\n );\n }\n return { 'Idempotency-Key': key };\n}\n\n/**\n * A fresh, valid `Idempotency-Key`. Mint ONE per logical operation and reuse\n * it across THAT operation's retries — generating a new key per attempt\n * defeats the point (each attempt would look like a different write). `\n * prefix` is optional and purely for your own log-grepping; it plays no\n * role on the server.\n */\nexport function generateIdempotencyKey(prefix?: string): string {\n const id = randomUUID().replace(/-/g, '');\n return prefix ? `${prefix}-${id}` : id;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/generated/error-codes.ts","../src/errors.ts","../src/webhooks.ts","../src/events.ts","../src/client.ts","../src/pagination.ts","../src/idempotency.ts"],"names":["createHmac","timingSafeEqual","createOpenApiClient","randomUUID"],"mappings":"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","file":"index.cjs","sourcesContent":["// AUTO-GENERATED by scripts/generate-error-codes.ts from the repo-root src/errors/index.ts's `ErrorCode` union — do not edit by hand.\n\n/**\n * Every code the API error envelope can carry as `error.code`, at the\n * commit this SDK was generated from. Kept OPEN (see `OpenErrorCode` in\n * `../errors.ts`) because a server can ship a new code before this SDK\n * is regenerated — narrow on the ones you handle, never assume this\n * list is exhaustive at runtime.\n */\nexport type ErrorCode =\n | 'VALIDATION_ERROR'\n | 'NOT_FOUND'\n | 'UNAUTHORIZED'\n | 'FORBIDDEN'\n | 'CONFLICT'\n | 'VERSION_CONFLICT'\n | 'UNIQUE_CONFLICT'\n | 'IDEMPOTENCY_KEY_CONFLICT'\n | 'VERTICAL_NOT_ENABLED'\n | 'ENTITLEMENT_NOT_ACTIVE'\n | 'UNSUPPORTED_VEHICLE_TYPE'\n | 'NO_OFFERING_ADAPTER'\n | 'PAYLOAD_TOO_LARGE'\n | 'UNSUPPORTED_MEDIA_TYPE'\n | 'UPSTREAM_ERROR'\n | 'RATE_LIMITED'\n | 'GONE'\n | 'INTERNAL_ERROR'\n | 'MESSAGING_ACCOUNT_TENANT_MISSING'\n | 'COPILOT_APPROVALS_UNAVAILABLE'\n | 'COPILOT_APPROVAL_REPLAY_BLOCKED'\n | 'COPILOT_DISABLED'\n | 'COPILOT_BUDGET_EXCEEDED'\n | 'DEALER_SITES_NOT_CONFIGURED'\n | 'STOREFRONT_ZONES_NOT_CONFIGURED'\n | 'RECONTACTO_NOT_ENABLED'\n | 'SYNC_QUEUE_UNAVAILABLE'\n | 'SHARE_IMAGE_UNAVAILABLE'\n | 'ATTRIBUTION_PROFILE_UNAVAILABLE'\n | 'DOCUMENT_LOGO_UNAVAILABLE'\n | 'ATTRIBUTION_PROFILE_MISMATCH'\n | 'ADS_KEY_NEEDS_REMINT'\n | 'ADS_ACTION_READ_UNAVAILABLE'\n | 'ADS_ACTION_REPLAY_BLOCKED'\n | 'ADS_ACTION_NOT_AVAILABLE'\n | 'ADS_ACTION_NOT_REVERSIBLE'\n | 'ADS_ACTION_CONSENT_REQUIRED'\n | 'GTM_NOT_CONFIGURED'\n | 'GTM_NOT_CONNECTED'\n | 'GTM_CONSENT_REQUIRED'\n | 'GTM_PERMISSION_DENIED'\n | 'GTM_CONTAINER_REQUIRED'\n | 'GTM_PENDING_CHANGES'\n | 'GTM_WORKSPACE_CONFLICT'\n | 'GTM_WORKSPACE_LIMIT'\n | 'MISSING_SIGNATURE'\n | 'MALFORMED_SIGNATURE'\n | 'STALE_SIGNATURE'\n | 'INVALID_SIGNATURE'\n | 'REPLAY_DETECTED'\n | 'TURNSTILE_UNAVAILABLE'\n | 'TASADOR_QUOTA_EXHAUSTED'\n | 'TASADOR_ANON_DAILY_LIMIT'\n | 'TASADOR_CAPACITY_REACHED'\n | 'CLINIC_PLAN_REQUIRED'\n | 'TENANT_BILLING_PAUSED';\n\nexport const ERROR_CODES: readonly ErrorCode[] = [\n 'VALIDATION_ERROR',\n 'NOT_FOUND',\n 'UNAUTHORIZED',\n 'FORBIDDEN',\n 'CONFLICT',\n 'VERSION_CONFLICT',\n 'UNIQUE_CONFLICT',\n 'IDEMPOTENCY_KEY_CONFLICT',\n 'VERTICAL_NOT_ENABLED',\n 'ENTITLEMENT_NOT_ACTIVE',\n 'UNSUPPORTED_VEHICLE_TYPE',\n 'NO_OFFERING_ADAPTER',\n 'PAYLOAD_TOO_LARGE',\n 'UNSUPPORTED_MEDIA_TYPE',\n 'UPSTREAM_ERROR',\n 'RATE_LIMITED',\n 'GONE',\n 'INTERNAL_ERROR',\n 'MESSAGING_ACCOUNT_TENANT_MISSING',\n 'COPILOT_APPROVALS_UNAVAILABLE',\n 'COPILOT_APPROVAL_REPLAY_BLOCKED',\n 'COPILOT_DISABLED',\n 'COPILOT_BUDGET_EXCEEDED',\n 'DEALER_SITES_NOT_CONFIGURED',\n 'STOREFRONT_ZONES_NOT_CONFIGURED',\n 'RECONTACTO_NOT_ENABLED',\n 'SYNC_QUEUE_UNAVAILABLE',\n 'SHARE_IMAGE_UNAVAILABLE',\n 'ATTRIBUTION_PROFILE_UNAVAILABLE',\n 'DOCUMENT_LOGO_UNAVAILABLE',\n 'ATTRIBUTION_PROFILE_MISMATCH',\n 'ADS_KEY_NEEDS_REMINT',\n 'ADS_ACTION_READ_UNAVAILABLE',\n 'ADS_ACTION_REPLAY_BLOCKED',\n 'ADS_ACTION_NOT_AVAILABLE',\n 'ADS_ACTION_NOT_REVERSIBLE',\n 'ADS_ACTION_CONSENT_REQUIRED',\n 'GTM_NOT_CONFIGURED',\n 'GTM_NOT_CONNECTED',\n 'GTM_CONSENT_REQUIRED',\n 'GTM_PERMISSION_DENIED',\n 'GTM_CONTAINER_REQUIRED',\n 'GTM_PENDING_CHANGES',\n 'GTM_WORKSPACE_CONFLICT',\n 'GTM_WORKSPACE_LIMIT',\n 'MISSING_SIGNATURE',\n 'MALFORMED_SIGNATURE',\n 'STALE_SIGNATURE',\n 'INVALID_SIGNATURE',\n 'REPLAY_DETECTED',\n 'TURNSTILE_UNAVAILABLE',\n 'TASADOR_QUOTA_EXHAUSTED',\n 'TASADOR_ANON_DAILY_LIMIT',\n 'TASADOR_CAPACITY_REACHED',\n 'CLINIC_PLAN_REQUIRED',\n 'TENANT_BILLING_PAUSED',\n] as const;\n","/**\n * Typed errors over the API's one error envelope: `{ error: { code, message,\n * details?, field_errors?, requestId?, ...extensions } }` (`src/errors/\n * index.ts` + `src/middlewares/error-handler.ts` in vitrina-app). `code` is\n * generated from the committed error catalogue (see `generated/error-codes.ts`\n * and `../scripts/generate-error-codes.ts`) but kept OPEN at the type level —\n * `ErrorCode | (string & Record<string, never>)` — because a server release\n * can ship a new code before this SDK is regenerated; never treat the union\n * as exhaustive at runtime (no `switch` without a `default`).\n */\nimport { ERROR_CODES, type ErrorCode } from './generated/error-codes';\n\nexport { ERROR_CODES };\nexport type { ErrorCode };\n\n/** `error.code`, widened so an unrecognised future code still type-checks.\n * The `Record<string, never>` intersection (not a bare `{}`) is what keeps\n * known `ErrorCode` literals showing up in autocomplete while still\n * accepting any string. */\nexport type OpenErrorCode = ErrorCode | (string & Record<string, never>);\n\n/** One entry of `error.details.reasons` on an outbound-policy verdict (C4). */\nexport interface OutboundVerdictReason {\n code: string;\n kind: 'bloqueo' | 'advertencia';\n hint: string;\n detail?: string;\n}\n\n/** The wire shape of `error` inside the envelope. */\nexport interface ApiErrorBody {\n code: OpenErrorCode;\n message: string;\n details?: unknown;\n field_errors?: Record<string, string>;\n requestId?: string;\n /** Send-verdict envelopes (C4) put `reasons`/`hint` at this level too. */\n reasons?: OutboundVerdictReason[];\n hint?: string;\n [key: string]: unknown;\n}\n\nexport interface ApiErrorOptions {\n requestUrl?: string;\n requestMethod?: string;\n}\n\n/** Base class for every error this SDK throws for a non-2xx API response. */\nexport class VitrinaApiError extends Error {\n /** The catalogue code — branch on this, never on `message`. */\n readonly code: OpenErrorCode;\n\n /** HTTP status of the response that produced this error. */\n readonly status: number;\n\n readonly details?: unknown;\n\n readonly fieldErrors?: Record<string, string>;\n\n /** Correlates this failure with the server's own logs. */\n readonly requestId?: string;\n\n /** The full parsed `error` object, for anything not surfaced above. */\n readonly body: ApiErrorBody;\n\n readonly requestUrl?: string;\n\n readonly requestMethod?: string;\n\n constructor(\n status: number,\n body: ApiErrorBody,\n options: ApiErrorOptions = {},\n ) {\n super(body.message || `Vitrina API error ${body.code} (HTTP ${status})`);\n this.name = 'VitrinaApiError';\n this.status = status;\n this.code = body.code;\n this.details = body.details;\n this.fieldErrors = body.field_errors;\n this.requestId = body.requestId;\n this.body = body;\n this.requestUrl = options.requestUrl;\n this.requestMethod = options.requestMethod;\n }\n\n /** `429 RATE_LIMITED`. */\n get isRateLimited(): boolean {\n return this.status === 429;\n }\n\n /** `401` — no credential, or one the server does not recognise. */\n get isUnauthorized(): boolean {\n return this.status === 401;\n }\n\n /** `403` — a real credential, missing the scope this call needs. */\n get isForbidden(): boolean {\n return this.status === 403;\n }\n\n /** `404 NOT_FOUND`. */\n get isNotFound(): boolean {\n return this.status === 404;\n }\n\n /** `409 IDEMPOTENCY_KEY_CONFLICT` — same `Idempotency-Key`, different body. */\n get isIdempotencyConflict(): boolean {\n return this.code === 'IDEMPOTENCY_KEY_CONFLICT';\n }\n}\n\n/**\n * `422 OUTBOUND_BLOCKED` (a Bloqueo, never overridable) or `409\n * OUTBOUND_WARNING` (an Advertencia — resend the same call with\n * `acknowledge: reasons.map(r => r.code)` in the body to proceed). Cross-\n * ticket contract C4 — `src/services/api-send-verdicts.ts` in vitrina-app.\n */\nexport class OutboundVerdictError extends VitrinaApiError {\n /** Every reason the send was stopped for, with its kind and hint. */\n readonly reasons: OutboundVerdictReason[];\n\n /** The first reason's hint, surfaced at the top level like the wire body. */\n readonly hint: string;\n\n constructor(\n status: number,\n body: ApiErrorBody,\n options: ApiErrorOptions = {},\n ) {\n super(status, body, options);\n this.name = 'OutboundVerdictError';\n const detailsReasons = (\n body.details as { reasons?: OutboundVerdictReason[] } | undefined\n )?.reasons;\n this.reasons = body.reasons ?? detailsReasons ?? [];\n this.hint = body.hint ?? this.reasons[0]?.hint ?? '';\n }\n\n /** A Bloqueo — the law, the customer or the provider already said no. */\n get isBlocked(): boolean {\n return this.code === 'OUTBOUND_BLOCKED';\n }\n\n /** An Advertencia — resend once with `acknowledge` to proceed. */\n get isWarning(): boolean {\n return this.code === 'OUTBOUND_WARNING';\n }\n\n /** `reasons` codes, ready to pass back as `{ acknowledge: [...] }`. */\n get acknowledgeCodes(): string[] {\n return this.reasons.map((r) => r.code);\n }\n}\n\nfunction asErrorBody(payload: unknown, status: number): ApiErrorBody {\n if (payload && typeof payload === 'object') {\n const maybeEnvelope = payload as { error?: unknown };\n const candidate =\n maybeEnvelope.error && typeof maybeEnvelope.error === 'object'\n ? (maybeEnvelope.error as Record<string, unknown>)\n : (payload as Record<string, unknown>);\n if (\n typeof candidate.code === 'string' &&\n typeof candidate.message === 'string'\n ) {\n return candidate as unknown as ApiErrorBody;\n }\n }\n return {\n code: 'INTERNAL_ERROR',\n message: `HTTP ${status} with an unrecognised response body`,\n };\n}\n\n/** Turns a non-2xx response's status + parsed JSON body into a typed error. */\nexport function toApiError(\n status: number,\n payload: unknown,\n options: ApiErrorOptions = {},\n): VitrinaApiError {\n const body = asErrorBody(payload, status);\n if (body.code === 'OUTBOUND_BLOCKED' || body.code === 'OUTBOUND_WARNING') {\n return new OutboundVerdictError(status, body, options);\n }\n return new VitrinaApiError(status, body, options);\n}\n\n/** The subset of an `openapi-fetch` call's resolved value `unwrap` needs. */\nexport interface UnwrappableResult<T> {\n data?: T;\n error?: unknown;\n response: Response;\n}\n\n/**\n * `const location = unwrap(await api.GET('/locations/{id}', ...))` — throws\n * a typed `VitrinaApiError` (or `OutboundVerdictError`) instead of making\n * every call site check `error` by hand. `openapi-fetch` itself never\n * throws; reach for the raw `{ data, error }` result directly when you want\n * that instead.\n */\nexport function unwrap<T>(\n result: UnwrappableResult<T>,\n options: ApiErrorOptions = {},\n): T {\n if (result.error !== undefined) {\n throw toApiError(result.response.status, result.error, options);\n }\n if (result.data === undefined) {\n throw new VitrinaApiError(\n result.response.status,\n {\n code: 'INTERNAL_ERROR',\n message: 'Response had neither data nor error',\n },\n options,\n );\n }\n return result.data;\n}\n","/**\n * Webhook Evento envelope + Stripe-style signature verification, matching\n * the dispatch service's own `signPayload`/`buildHeaders`\n * (`src/services/webhook-dispatch.service.ts` in vitrina-app; cross-ticket\n * contract C3). The signature is an HMAC-SHA256 over `${timestamp}.${body}`\n * with the subscription's `whsec_...` secret, carried as\n * `X-Webhook-Signature: t=<unix_seconds>,v1=<hex>`.\n *\n * `tests/api-sdk-webhook-signature.test.ts` (vitrina-app repo root) verifies\n * this against the REAL `signPayload` the dispatch service calls in\n * production — not a hand-written fixture.\n */\nimport { createHmac, timingSafeEqual } from 'node:crypto';\n\n/** `resource` on the envelope — what changed, and where to read it. */\nexport interface WebhookEventResource {\n type: string;\n id: string | null;\n /** Absolute `GET` URL for this resource, or `null` when none is available\n * (e.g. the event has no single owning record). Feeds `event.fetch()`. */\n url: string | null;\n}\n\n/** Who did it — see `Author` in vitrina-app's `src/types/author.ts` (C3). */\nexport interface WebhookEventAuthor {\n kind: 'member' | 'api_key' | 'ai_agent' | 'system' | 'contact';\n id: string | null;\n name: string | null;\n via?: { kind: 'connected_app' | 'personal_token'; name: string };\n}\n\n/** Why `data` is absent — every reason a subscription's owner can be denied\n * the resource body. `missing_scope:<scope>` is a family, not one literal. */\nexport type DataOmittedReason =\n | 'not_requested'\n | 'sensitive'\n | 'owner_unavailable'\n | 'restricted_visibility'\n | `missing_scope:${string}`;\n\n/** One Evento, exactly as it arrives on the wire. Exactly one of `data` /\n * `data_omitted` is ever present. */\nexport interface WebhookEventEnvelope<TData = Record<string, unknown>> {\n id: string;\n type: string;\n version: number;\n /** `false` for an event from a sandbox (test-mode) workspace, `true`\n * otherwise; mirrored on the delivery's `Vitrina-Livemode` header.\n * Optional here only so an envelope captured before vitrina-app#2693\n * still satisfies this type — every envelope on the wire carries it. */\n livemode?: boolean;\n created_at: string;\n tenant_id: string;\n resource: WebhookEventResource;\n changes?: Record<string, { from: unknown; to: unknown }>;\n author: WebhookEventAuthor;\n data?: TData;\n data_omitted?: DataOmittedReason;\n}\n\nexport interface VerifySignatureOptions {\n /** How far `X-Webhook-Timestamp` may drift from now before a signature\n * that otherwise matches is rejected as stale (replay protection).\n * Default 300 (5 minutes), matching the docs' own verifier. */\n toleranceSeconds?: number;\n /** Override \"now\", in Unix seconds — for tests. */\n nowUnix?: number;\n}\n\nexport type VerifyResult =\n | { ok: true }\n | { ok: false; reason: 'malformed_header' | 'bad_signature' | 'stale' };\n\nfunction parseSignatureHeader(\n header: string,\n): { timestamp: number; v1: string } | null {\n const parts: Record<string, string> = {};\n for (const pair of header.split(',')) {\n const at = pair.indexOf('=');\n if (at === -1) continue;\n parts[pair.slice(0, at).trim()] = pair.slice(at + 1).trim();\n }\n const timestamp = Number(parts.t);\n if (!Number.isFinite(timestamp) || !parts.v1) return null;\n return { timestamp, v1: parts.v1 };\n}\n\n/**\n * Verifies an `X-Webhook-Signature` header against the raw delivery body.\n * Never throws — returns `{ ok: false, reason }` so a caller can log why a\n * delivery was rejected. `rawBody` must be the exact bytes the delivery\n * sent, before any JSON re-serialization (re-stringifying a parsed body\n * produces different bytes and the signature will never match).\n */\nexport function verifyWebhookSignature(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n): VerifyResult {\n const parsed = parseSignatureHeader(params.signatureHeader);\n if (!parsed) return { ok: false, reason: 'malformed_header' };\n\n const body =\n typeof params.rawBody === 'string'\n ? params.rawBody\n : params.rawBody.toString('utf8');\n const expected = createHmac('sha256', params.secret)\n .update(`${parsed.timestamp}.${body}`)\n .digest('hex');\n\n const given = Buffer.from(parsed.v1, 'utf8');\n const mine = Buffer.from(expected, 'utf8');\n const signatureMatches =\n given.length === mine.length && timingSafeEqual(given, mine);\n if (!signatureMatches) return { ok: false, reason: 'bad_signature' };\n\n const tolerance = params.toleranceSeconds ?? 300;\n const now = params.nowUnix ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - parsed.timestamp) > tolerance) {\n return { ok: false, reason: 'stale' };\n }\n return { ok: true };\n}\n\nexport class WebhookSignatureError extends Error {\n readonly reason: Exclude<VerifyResult, { ok: true }>['reason'];\n\n constructor(reason: Exclude<VerifyResult, { ok: true }>['reason']) {\n super(`Webhook signature verification failed: ${reason}`);\n this.name = 'WebhookSignatureError';\n this.reason = reason;\n }\n}\n\n/**\n * Verifies + parses an Evento delivery in one call (Stripe's\n * `constructEvent` naming, same idea): throws `WebhookSignatureError`\n * instead of returning a result a caller might forget to check before\n * trusting `rawBody`.\n */\nexport function constructEventEnvelope<TData = Record<string, unknown>>(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n): WebhookEventEnvelope<TData> {\n const result = verifyWebhookSignature(params);\n if (!result.ok) throw new WebhookSignatureError(result.reason);\n const body =\n typeof params.rawBody === 'string'\n ? params.rawBody\n : params.rawBody.toString('utf8');\n return JSON.parse(body) as WebhookEventEnvelope<TData>;\n}\n","/**\n * `event.fetch()` — read an Evento's resource in one call, using the same\n * credentials the client was created with. `resource.url` is the absolute\n * `GET` URL the server already computed (`apiPublicUrl()` in\n * `webhook-dispatch.service.ts`), so this is a plain authenticated fetch of\n * that URL — no per-resource-type routing table to keep in sync.\n */\nimport { toApiError } from './errors';\nimport {\n constructEventEnvelope,\n verifyWebhookSignature,\n type VerifySignatureOptions,\n type WebhookEventEnvelope,\n} from './webhooks';\n\nexport class EventResourceUnavailableError extends Error {\n readonly event: WebhookEventEnvelope;\n\n constructor(event: WebhookEventEnvelope) {\n super(\n event.data_omitted\n ? `Event ${event.id} (${event.type}) carries no resource URL — data_omitted: ${event.data_omitted}`\n : `Event ${event.id} (${event.type}) carries no resource URL`,\n );\n this.name = 'EventResourceUnavailableError';\n this.event = event;\n }\n}\n\n/** A parsed Evento, plus a `fetch()` bound to the client it came from. */\nexport type VitrinaEvent<TData = Record<string, unknown>> =\n WebhookEventEnvelope<TData> & {\n /**\n * `GET`s `resource.url` with this client's credentials and returns its\n * `data`. Throws `EventResourceUnavailableError` when the envelope has no\n * URL (an event with no single owning resource, or one whose `data` you\n * already have inline). Pass a type argument to get the resource typed:\n * `await event.fetch<Contact>()`.\n */\n fetch<TResource = TData>(): Promise<TResource>;\n };\n\nexport interface EventFetcherDeps {\n headers: HeadersInit;\n fetch: typeof fetch;\n}\n\n/** Builds the `events` namespace `createClient()` attaches to every client:\n * signature verification bound to nothing (pure functions), and\n * `constructEvent` bound to this client's own auth so the returned event's\n * `.fetch()` needs no arguments. */\nexport function createEventsNamespace(deps: EventFetcherDeps) {\n // `WebhookEventEnvelope<any>`: this helper only ever reads `resource` /\n // `data_omitted` / `id` / `type`, never `.data`, so it is deliberately\n // NOT generic over TData — a `WebhookEventEnvelope<TData>` for any TData\n // must be assignable here.\n async function fetchResource<TResource>(\n event: WebhookEventEnvelope<any>,\n ): Promise<TResource> {\n if (!event.resource.url) throw new EventResourceUnavailableError(event);\n const res = await deps.fetch(event.resource.url, { headers: deps.headers });\n let json: unknown;\n try {\n json = await res.json();\n } catch {\n json = undefined;\n }\n if (!res.ok) {\n throw toApiError(res.status, json, {\n requestUrl: event.resource.url,\n requestMethod: 'GET',\n });\n }\n return (json as { data: TResource })?.data;\n }\n\n return {\n /** Verifies an `X-Webhook-Signature` header. Never throws. */\n verifySignature: (\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ) => verifyWebhookSignature(params),\n\n /**\n * Verifies + parses a webhook delivery and returns it with a bound\n * `.fetch()`. Throws `WebhookSignatureError` on a bad/stale signature.\n *\n * const event = client.events.constructEvent({\n * secret: subscriptionSecret,\n * signatureHeader: req.headers['x-webhook-signature'],\n * rawBody: req.rawBody,\n * });\n * if (event.type === 'contact.created') {\n * const contact = await event.fetch<Contact>();\n * }\n */\n constructEvent<TData = Record<string, unknown>>(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ): VitrinaEvent<TData> {\n const envelope = constructEventEnvelope<TData>(params);\n return Object.assign(envelope, {\n fetch: <TResource = TData>() => fetchResource<TResource>(envelope),\n });\n },\n };\n}\n","/**\n * `createClient()` — a typed `openapi-fetch` client over the API pública\n * (`paths` generated from the committed `openapi.public.json`), plus the\n * `events` namespace (webhook signature verification + `event.fetch()`).\n *\n * Auth: pass an `sk_*` API key (workspace credential or personal token —\n * both are Bearer) or a raw bearer token you manage yourself. Exactly one of\n * `apiKey` / `bearer`.\n */\nimport createOpenApiClient, { type Client } from 'openapi-fetch';\n\nimport { createEventsNamespace, type VitrinaEvent } from './events';\nimport type { paths } from './generated/api-types';\nimport type { VerifySignatureOptions, VerifyResult } from './webhooks';\n\nexport interface CreateClientOptions {\n /** Absolute base URL, e.g. `https://api.vitrinadev.com/api/v1`. No trailing slash. */\n baseUrl: string;\n /** An `sk_*` API key (workspace key or personal token). Mutually exclusive with `bearer`. */\n apiKey?: string;\n /** A raw bearer token, for a caller that manages tokens itself (e.g. a Supabase session JWT). */\n bearer?: string;\n /** Extra headers merged onto every request (e.g. a custom `User-Agent`). */\n headers?: Record<string, string>;\n /** Override `fetch` — Node <18, undici, msw, a test double. Defaults to `globalThis.fetch`. */\n fetch?: typeof fetch;\n}\n\nexport interface VitrinaEventsNamespace {\n /** Verifies an `X-Webhook-Signature` header. Never throws. */\n verifySignature(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ): VerifyResult;\n /** Verifies + parses a webhook delivery; the returned event carries a\n * `.fetch()` bound to this client. Throws `WebhookSignatureError`. */\n constructEvent<TData = Record<string, unknown>>(\n params: {\n secret: string;\n signatureHeader: string;\n rawBody: string | Buffer;\n } & VerifySignatureOptions,\n ): VitrinaEvent<TData>;\n}\n\n/** The typed REST client (`GET`/`POST`/.../`use`/`eject`, from `openapi-fetch`)\n * plus the `events` namespace. */\nexport type VitrinaClient = Client<paths> & { events: VitrinaEventsNamespace };\n\nexport function createClient(opts: CreateClientOptions): VitrinaClient {\n if (opts.apiKey && opts.bearer) {\n throw new RangeError(\n 'createClient(): pass at most one of `apiKey` / `bearer`, not both',\n );\n }\n const credential = opts.apiKey ?? opts.bearer;\n const headers: Record<string, string> = {\n ...(credential ? { Authorization: `Bearer ${credential}` } : {}),\n ...opts.headers,\n };\n const fetchImpl = opts.fetch ?? fetch;\n\n const base = createOpenApiClient<paths>({\n baseUrl: opts.baseUrl,\n headers,\n fetch: fetchImpl,\n });\n\n const events = createEventsNamespace({ headers, fetch: fetchImpl });\n\n return Object.assign(base, { events });\n}\n","/**\n * Cursor pagination — walks a list endpoint page by page, yielding one item\n * at a time (`for await`). Vitrina's list envelopes carry the cursor as\n * `meta.pagination.nextCursor` (the shape every v1 list route in production\n * answers with — `ok(res, rows, { pagination: { nextCursor, limit } })`,\n * `src/routes/api/v1/*.ts`) with a `meta.nextCursor` fallback for the flat\n * `PaginationMeta` OpenAPI shape (`src/api/openapi-responses.ts`) some\n * generated docs describe; this helper reads either. The opaque cursor\n * itself is a base64url-encoded `{ ts, id }` pair (`src/api/pagination.ts`)\n * — never decode it, just pass it back as the next page's `cursor` query\n * param.\n */\nimport { toApiError } from './errors';\n\nexport interface PaginationMeta {\n pagination?: {\n nextCursor?: string | null;\n prevCursor?: string | null;\n limit?: number;\n };\n nextCursor?: string | null;\n prevCursor?: string | null;\n total?: number;\n limit?: number;\n [key: string]: unknown;\n}\n\nexport interface ListEnvelope<T> {\n data?: T[];\n meta?: PaginationMeta;\n}\n\n/** The subset of an `openapi-fetch` GET call's resolved value `paginate` needs. */\nexport interface FetchPageResult<T> {\n data?: ListEnvelope<T>;\n error?: unknown;\n response: Response;\n}\n\nfunction nextCursorOf(meta: PaginationMeta | undefined): string | undefined {\n const cursor = meta?.pagination?.nextCursor ?? meta?.nextCursor ?? null;\n return cursor ?? undefined;\n}\n\n/**\n * Walks every page of a cursor-paginated list, yielding one item at a time.\n *\n * for await (const appointment of paginate((cursor) =>\n * api.GET('/appointments', { params: { query: { cursor, limit: 100 } } }),\n * )) {\n * console.log(appointment.id);\n * }\n *\n * CURSOR IS THE MINORITY SHAPE, so check the route before reaching for this.\n * Measured against the published contract: exactly two operations take a\n * `cursor` — `GET /appointments` and `GET /conversations/{id}/messages`.\n * Fifteen take `offset`/`limit` (`/stock`, `/vehicles`, `/contacts/search`,\n * `/webhooks/{id}/deliveries` and the rest), and others take `page`/`page_size`\n * (`/leads` among them). Passing `cursor` to one of those is a type error, not\n * a silent first page — which is the point of generating this package from the\n * contract.\n *\n * `fetchPage` is any typed `api.GET(...)` call, called once per page with\n * the previous page's cursor (`undefined` for the first page). Throws a\n * typed `VitrinaApiError` if a page comes back as an error, same as\n * `unwrap()`.\n */\nexport async function* paginate<T>(\n fetchPage: (cursor: string | undefined) => Promise<FetchPageResult<T>>,\n): AsyncGenerator<T, void, unknown> {\n let cursor: string | undefined;\n for (;;) {\n // eslint-disable-next-line no-await-in-loop -- pages are inherently sequential (each cursor depends on the last)\n const result = await fetchPage(cursor);\n if (result.error !== undefined) {\n throw toApiError(result.response.status, result.error);\n }\n const page = result.data;\n if (!page || !Array.isArray(page.data)) return;\n for (const item of page.data) yield item;\n const next = nextCursorOf(page.meta);\n if (!next) return;\n cursor = next;\n }\n}\n\n/** Same as `paginate`, but collects every page into one array. Only reach\n * for this on a list you know is bounded — an unbounded one belongs on the\n * `for await` form above. */\nexport async function paginateAll<T>(\n fetchPage: (cursor: string | undefined) => Promise<FetchPageResult<T>>,\n): Promise<T[]> {\n const items: T[] = [];\n // eslint-disable-next-line no-restricted-syntax -- collecting an async generator IS the sequential-await case for-await exists for\n for await (const item of paginate(fetchPage)) items.push(item);\n return items;\n}\n","/**\n * `Idempotency-Key` — replay-safe retries on the 39 published write\n * operations that accept it (ADR 0106 §2.3/#2400). Resending the SAME key\n * with the SAME body returns the original response (`X-Idempotent-Replay:\n * 1`) instead of creating a second copy; the same key with a DIFFERENT body\n * answers `409 IDEMPOTENCY_KEY_CONFLICT` (`VitrinaApiError#isIdempotencyConflict`).\n *\n * The generated types already carry `Idempotency-Key` as a typed header\n * parameter per operation — `idempotencyKey()` just builds a well-formed\n * value to put there:\n *\n * await api.POST('/pipelines', {\n * params: { header: idempotencyKey(`provision-${userId}-2026-04-24`) },\n * body: { ... },\n * });\n */\nimport { randomUUID } from 'node:crypto';\n\nconst KEY_PATTERN = /^[A-Za-z0-9_-]{8,200}$/;\n\nexport interface IdempotencyKeyHeader {\n 'Idempotency-Key': string;\n}\n\n/**\n * Validates `key` against the server's own constraint (`minLength: 8,\n * maxLength: 200, pattern: ^[A-Za-z0-9_-]+$` on every operation that accepts\n * it) and returns it as a header object to spread into `params.header`.\n * Throws `RangeError` on a malformed key — better to fail before the\n * request leaves than to get back a generic `VALIDATION_ERROR`.\n */\nexport function idempotencyKey(key: string): IdempotencyKeyHeader {\n if (!KEY_PATTERN.test(key)) {\n throw new RangeError(\n `Idempotency-Key must be 8-200 characters of [A-Za-z0-9_-], got: ${JSON.stringify(key)}`,\n );\n }\n return { 'Idempotency-Key': key };\n}\n\n/**\n * A fresh, valid `Idempotency-Key`. Mint ONE per logical operation and reuse\n * it across THAT operation's retries — generating a new key per attempt\n * defeats the point (each attempt would look like a different write). `\n * prefix` is optional and purely for your own log-grepping; it plays no\n * role on the server.\n */\nexport function generateIdempotencyKey(prefix?: string): string {\n const id = randomUUID().replace(/-/g, '');\n return prefix ? `${prefix}-${id}` : id;\n}\n"]}
|