@simmit/sdk 0.2.0 → 0.3.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.js CHANGED
@@ -21,6 +21,17 @@ var APIError = class _APIError extends SimmitError {
21
21
  this.code = typeof envelope?.code === "string" ? envelope.code : void 0;
22
22
  this.meta = body ? envelope?.meta ?? null : void 0;
23
23
  }
24
+ /**
25
+ * Correlation id for the failed request (`req_...`), for support tickets.
26
+ * Read from the `X-Request-Id` response header, falling back to the body's
27
+ * `requestId` field.
28
+ */
29
+ get requestId() {
30
+ const fromHeader = this.headers?.get("x-request-id");
31
+ if (fromHeader) return fromHeader;
32
+ const { requestId } = this.error ?? {};
33
+ return typeof requestId === "string" ? requestId : void 0;
34
+ }
24
35
  static makeMessage(status, body, message) {
25
36
  const bodyMessage = body?.error;
26
37
  const msg = typeof bodyMessage === "string" ? bodyMessage : body ? JSON.stringify(body) : message;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/error.ts","../src/api-promise.ts","../src/internal/abort.ts","../src/internal/request.ts","../src/resources/artifacts.ts","../src/resources/credits.ts","../src/internal/poll.ts","../src/status.ts","../src/resources/jobs.ts","../src/client.ts","../src/webhook.ts"],"sourcesContent":["import type { Job, JobStatus } from './api-types'\n\nexport class SimmitError extends Error {}\n\n/**\n * Value shapes the API's generic error `meta` bag can carry\n * (400/401/404/410/413 responses): JSON scalars, scalar arrays, or arrays of\n * flat objects.\n */\nexport type MetaValue =\n | string\n | number\n | boolean\n | null\n | Array<string | number | boolean>\n | Array<Record<string, string | number | boolean | null>>\n\nexport type GenericMeta = Record<string, MetaValue>\n\n/** The API's uniform error envelope: `{ error, code, meta }`. */\ninterface ErrorEnvelope {\n error?: unknown\n code?: unknown\n meta?: unknown\n}\n\nexport class APIError<\n TStatus extends number | undefined = number | undefined,\n TCode extends string | undefined = string | undefined,\n TMeta = GenericMeta | null\n> extends SimmitError {\n /** HTTP status of the response that caused the error. */\n readonly status: TStatus\n /** HTTP headers of the response that caused the error. */\n readonly headers: Headers | undefined\n /** Machine-readable `code` from the error envelope. */\n readonly code: TCode\n /** Typed `meta` from the error envelope. */\n readonly meta: TMeta\n /** Raw parsed JSON error body: escape hatch for unmapped fields. */\n readonly error: object | undefined\n\n constructor(\n status: TStatus,\n body: object | undefined,\n message: string | undefined,\n headers: Headers | undefined\n ) {\n super(APIError.makeMessage(status, body, message))\n this.status = status\n this.headers = headers\n this.error = body\n const envelope = body as ErrorEnvelope | undefined\n this.code = (\n typeof envelope?.code === 'string' ? envelope.code : undefined\n ) as TCode\n this.meta = (body ? (envelope?.meta ?? null) : undefined) as TMeta\n }\n\n private static makeMessage(\n status: number | undefined,\n body: object | undefined,\n message: string | undefined\n ): string {\n // The API's human-readable message field is named `error`, not `message`.\n const bodyMessage = (body as ErrorEnvelope | undefined)?.error\n const msg =\n typeof bodyMessage === 'string'\n ? bodyMessage\n : body\n ? JSON.stringify(body)\n : message\n\n if (status && msg) return `${status} ${msg}`\n if (status) return `${status} status code (no body)`\n if (msg) return msg\n return '(no status code or body)'\n }\n\n /**\n * Maps a response to the most specific error class: status selects the base\n * class; an enumerated `code` with structured `meta` selects the subclass;\n * anything unrecognized falls back to the status class so new server codes\n * degrade gracefully without breaking `instanceof` handling.\n */\n static generate(\n status: number | undefined,\n body: object | undefined,\n message: string | undefined,\n headers: Headers | undefined\n ): APIError<\n number | undefined,\n string | undefined,\n GenericMeta | null | undefined\n > {\n if (!status || !headers) {\n return new APIConnectionError({\n message,\n cause: body instanceof Error ? body : undefined\n })\n }\n\n const code = (body as ErrorEnvelope | undefined)?.code\n\n if (status === 400) return new BadRequestError(400, body, message, headers)\n if (status === 401) {\n return new AuthenticationError(401, body, message, headers)\n }\n if (status === 402) {\n if (code === 'insufficient_credits') {\n return new InsufficientCreditsError(402, body, message, headers)\n }\n if (code === 'insufficient_credits_liability') {\n return new InsufficientCreditsLiabilityError(\n 402,\n body,\n message,\n headers\n )\n }\n return new BillingError(402, body, message, headers)\n }\n if (status === 404) return new NotFoundError(404, body, message, headers)\n if (status === 409) {\n if (code === 'idempotency_key_reuse') {\n return new IdempotencyKeyReuseError(409, body, message, headers)\n }\n if (code === 'result_not_ready') {\n return new ResultNotReadyError(409, body, message, headers)\n }\n if (code === 'job_not_cancellable') {\n return new JobNotCancellableError(409, body, message, headers)\n }\n return new ConflictError(409, body, message, headers)\n }\n if (status === 413) {\n return new RequestTooLargeError(413, body, message, headers)\n }\n if (status === 422) {\n if (code === 'input_sanitized_rejected') {\n return new InvalidProfileError(422, body, message, headers)\n }\n if (code === 'result_unavailable') {\n return new ResultUnavailableError(422, body, message, headers)\n }\n return new UnprocessableEntityError(422, body, message, headers)\n }\n if (status === 429) {\n if (code === 'max_active_jobs_exceeded') {\n return new MaxActiveJobsError(429, body, message, headers)\n }\n return new RateLimitError(429, body, message, headers)\n }\n if (status === 503 && isServiceUnavailableBody(body)) {\n return new ServiceUnavailableError(503, body, message, headers)\n }\n if (status >= 500) {\n return new InternalServerError(status, body, message, headers)\n }\n return new APIError(status, body, message, headers)\n }\n}\n\n// ── 4xx status classes (code subclasses where the spec enumerates) ──────────\n\nexport class BadRequestError extends APIError<400, string> {}\n\nexport type AuthenticationErrorCode =\n | 'missing_token'\n | 'invalid_token'\n | 'revoked_token'\n | 'expired_token'\n\nexport class AuthenticationError extends APIError<\n 401,\n AuthenticationErrorCode\n> {}\n\n// 402 codes are docs-enumerated; the spec leaves `code` un-enumerated, so the\n// base class keeps `string` for forward compatibility.\nexport class BillingError extends APIError<402, string> {}\n\nexport type InsufficientCreditsMeta = {\n reason: string\n ceilingRuntimeSeconds?: number\n /** Largest maxRuntimeSeconds the current balance can cover. */\n maxAffordableRuntimeSeconds?: number\n docsUrl?: string\n}\n\nexport class InsufficientCreditsError extends BillingError {\n declare readonly code: 'insufficient_credits'\n declare readonly meta: InsufficientCreditsMeta | null\n}\n\nexport type InsufficientCreditsLiabilityMeta = {\n reason: string\n /** The high-priority fee in effect. Top up, or resubmit at priority 'standard'. */\n priorityFeeCredits: number\n docsUrl?: string\n}\n\nexport class InsufficientCreditsLiabilityError extends BillingError {\n declare readonly code: 'insufficient_credits_liability'\n declare readonly meta: InsufficientCreditsLiabilityMeta | null\n}\n\nexport class NotFoundError extends APIError<404, string> {}\n\nexport class ConflictError extends APIError<409, string> {}\n\nexport class IdempotencyKeyReuseError extends ConflictError {\n declare readonly code: 'idempotency_key_reuse'\n declare readonly meta: {\n reason: 'idempotency_key_reuse'\n /** ID of the job that originally consumed this idempotency key. */\n originalJobId: string\n docsUrl?: string\n }\n}\n\nexport class ResultNotReadyError extends ConflictError {\n declare readonly code: 'result_not_ready'\n declare readonly meta: {\n status: 'pending' | 'queued' | 'starting' | 'running'\n }\n}\n\nexport class JobNotCancellableError extends ConflictError {\n declare readonly code: 'job_not_cancellable'\n declare readonly meta: { id: string; status: JobStatus }\n}\n\nexport class RequestTooLargeError extends APIError<413, string> {}\n\nexport class UnprocessableEntityError extends APIError<422, string> {}\n\nexport class InvalidProfileError extends UnprocessableEntityError {\n declare readonly code: 'input_sanitized_rejected'\n declare readonly meta: {\n reason: 'input_sanitized_rejected'\n message: string\n docsUrl: string\n /** Sample of rejected lines; see blockedCount/blockedTruncated for the full set. */\n blocked: Array<{ line: number; text: string }>\n blockedCount: number\n blockedTruncated: boolean\n }\n}\n\nexport class ResultUnavailableError extends UnprocessableEntityError {\n declare readonly code: 'result_unavailable'\n declare readonly meta: {\n status: 'completed' | 'failed' | 'cancelled' | 'timed_out'\n }\n}\n\nexport type RateLimitErrorCode =\n | 'rate_limit_exceeded'\n | 'max_active_jobs_exceeded'\n\nexport class RateLimitError extends APIError<429, RateLimitErrorCode> {\n declare readonly meta:\n | { scope: 'developer' }\n | {\n reason: 'max_active_jobs_exceeded'\n maxActiveJobs: number\n activeJobs: number\n }\n | null\n}\n\nexport class MaxActiveJobsError extends RateLimitError {\n declare readonly code: 'max_active_jobs_exceeded'\n declare readonly meta: {\n reason: 'max_active_jobs_exceeded'\n /** Maximum number of jobs the account can have in flight. */\n maxActiveJobs: number\n /** Jobs in flight when this request was rejected. */\n activeJobs: number\n }\n}\n\n// ── 5xx ─────────────────────────────────────────────────────────────────────\n\nexport class InternalServerError extends APIError<number, string> {}\n\n/**\n * 503 carries four enumerated codes with distinct meta: a discriminated\n * union, narrowed via `.body`. `api_maintenance` gets no special retry\n * behavior: standard policy applies, and the typed\n * `meta.retryAfterSeconds` is surfaced so callers can schedule their own\n * resubmission.\n */\nexport type ServiceUnavailableBody =\n | {\n code: 'queue_unavailable'\n meta: { reason: 'queue_unavailable'; queueHealth: string }\n }\n | {\n code: 'queue_health_unknown'\n meta: { reason: 'queue_health_unknown'; laneId: string }\n }\n | {\n code: 'secret_store_unavailable'\n meta: { reason: 'secret_store_unavailable' }\n }\n | { code: 'api_maintenance'; meta: { retryAfterSeconds: number } }\n\nconst SERVICE_UNAVAILABLE_CODES = new Set([\n 'queue_unavailable',\n 'queue_health_unknown',\n 'secret_store_unavailable',\n 'api_maintenance'\n])\n\n// A 503 whose body isn't the enumerated envelope (e.g. load-balancer HTML)\n// falls back to InternalServerError so `.body` below never lies.\nfunction isServiceUnavailableBody(\n body: object | undefined\n): body is ServiceUnavailableBody {\n const code = (body as ErrorEnvelope | undefined)?.code\n return typeof code === 'string' && SERVICE_UNAVAILABLE_CODES.has(code)\n}\n\nexport class ServiceUnavailableError extends InternalServerError {\n declare readonly status: 503\n\n /** The discriminated 503 envelope: `if (e.body.code === 'api_maintenance') e.body.meta.retryAfterSeconds`. */\n get body(): ServiceUnavailableBody {\n return this.error as ServiceUnavailableBody\n }\n}\n\n// ── No HTTP response ────────────────────────────────────────────────────────\n\nexport class APIConnectionError extends APIError<\n undefined,\n undefined,\n undefined\n> {\n constructor({\n message,\n cause\n }: { message?: string | undefined; cause?: Error | undefined } = {}) {\n super(undefined, undefined, message ?? 'Connection error.', undefined)\n if (cause) this.cause = cause\n }\n}\n\nexport class APIConnectionTimeoutError extends APIConnectionError {\n constructor({ message }: { message?: string } = {}) {\n super({ message: message ?? 'Request timed out.' })\n }\n}\n\nexport class APIUserAbortError extends APIError<\n undefined,\n undefined,\n undefined\n> {\n constructor({ message }: { message?: string } = {}) {\n super(undefined, undefined, message ?? 'Request was aborted.', undefined)\n }\n}\n\n// ── Job-level errors (thrown only by createAndWait) ──────────────────────────\n\n/** Catch-all for a job that reached a terminal state other than `completed`. */\nexport abstract class JobUnsuccessfulError extends SimmitError {\n readonly job: Job\n\n constructor(job: Job, message?: string) {\n super(\n message ??\n `Job ${job.id} ${job.status}` +\n (job.statusReason ? `: ${job.statusReason}` : '') +\n (job.errorCode ? ` (${job.errorCode})` : '')\n )\n this.job = job\n }\n}\n\nexport class JobFailedError extends JobUnsuccessfulError {}\n\n/** Includes queue_timeout auto-cancellation, not just user cancels. */\nexport class JobCancelledError extends JobUnsuccessfulError {}\n\n/** The job hit its runtime ceiling server-side and is billed for what ran. */\nexport class JobTimedOutError extends JobUnsuccessfulError {}\n\n/**\n * The SDK gave up polling. The job itself is still running and billing.\n * Keep tracking via `jobs.get(jobId)` or stop the spend with `jobs.cancel(jobId)`.\n */\nexport class JobWaitTimeoutError extends SimmitError {\n readonly jobId: string\n readonly lastStatus: JobStatus\n\n constructor(args: {\n jobId: string\n lastStatus: JobStatus\n message?: string\n }) {\n super(\n args.message ??\n `Timed out waiting for job ${args.jobId} (last status: ${args.lastStatus}). ` +\n 'The job is still running server-side and continues to bill.'\n )\n this.jobId = args.jobId\n this.lastStatus = args.lastStatus\n }\n}\n\n// ── Webhook verification (thrown by unwrapWebhook) ───────────────────────────\n\nexport class WebhookVerificationError extends SimmitError {}\n","/**\n * A `Promise<T>` with raw-response access: the generic answer to response\n * headers the return types can't see (`X-Idempotent-Replay`, `X-Active-Jobs`,\n * `X-RateLimit-*`).\n *\n * const { data, response } = await client.jobs.create(params).withResponse()\n * response.headers.get('x-idempotent-replay')\n */\nexport class APIPromise<T> extends Promise<T> {\n // Chained promises (.then/.catch) must be plain Promises: this class's\n // constructor signature is incompatible with the executor the runtime\n // would otherwise pass via the species constructor.\n static override get [Symbol.species]() {\n return Promise\n }\n\n readonly #parsed: Promise<{ data: T; response: Response }>\n\n constructor(parsed: Promise<{ data: T; response: Response }>) {\n // The base promise is a pre-settled placeholder that is never observed:\n // then() below delegates to #parsed lazily (catch/finally route through\n // then() per spec). Subscribing eagerly here would reject this instance\n // even when the caller only consumes withResponse(), leaking an\n // unhandled rejection on failures.\n super((resolve) => resolve(undefined as never))\n this.#parsed = parsed\n }\n\n override then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n return this.#parsed\n .then((result) => result.data)\n .then(onfulfilled, onrejected)\n }\n\n withResponse(): Promise<{ data: T; response: Response }> {\n return this.#parsed\n }\n\n asResponse(): Promise<Response> {\n return this.#parsed.then((result) => result.response)\n }\n}\n","// Abort-aware timing utilities shared by the request layer (backoff sleeps) and\n// the createAndWait poll loop. A pending sleep rejects with APIUserAbortError\n// the moment the caller's signal fires.\nimport { APIUserAbortError } from '../error'\n\nexport function throwIfUserAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new APIUserAbortError()\n}\n\nexport function sleep(\n ms: number,\n signal: AbortSignal | undefined\n): Promise<void> {\n return new Promise((resolve, reject) => {\n throwIfUserAborted(signal)\n const timeoutId = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = () => {\n clearTimeout(timeoutId)\n reject(new APIUserAbortError())\n }\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n}\n","// Internal request layer: header assembly, per-attempt timeout/abort\n// composition, retry with backoff + Retry-After, idempotency-key injection,\n// and error mapping. Not exported from the package.\nimport { APIPromise } from '../api-promise'\nimport {\n APIConnectionError,\n APIConnectionTimeoutError,\n APIError,\n APIUserAbortError\n} from '../error'\nimport type { RequestOptions } from '../client'\nimport { sleep, throwIfUserAborted } from './abort'\n\nexport interface ClientConfig {\n secretKey: string\n baseURL: string\n timeout: number\n maxRetries: number\n defaultHeaders: Record<string, string | null | undefined> | undefined\n fetch: typeof globalThis.fetch\n fetchOptions: RequestInit | undefined\n}\n\nexport interface RequestSpec {\n method: 'GET' | 'POST'\n path: string\n body?: unknown\n /** POST job creation: auto-generate an idempotency-key when none supplied. */\n idempotent?: boolean\n}\n\n// Retry policy constants: typed code config, not env.\nconst INITIAL_BACKOFF_MS = 500\nconst MAX_BACKOFF_MS = 8_000\nconst MAX_RETRY_AFTER_MS = 60_000\n\nexport function makeRequest<T>(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions = {}\n): APIPromise<T> {\n return new APIPromise(run<T>(config, spec, options))\n}\n\nasync function run<T>(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions\n): Promise<{ data: T; response: Response }> {\n const maxRetries = options.maxRetries ?? config.maxRetries\n const timeout = options.timeout ?? config.timeout\n const headers = buildHeaders(config, spec, options)\n const url = `${config.baseURL.replace(/\\/+$/, '')}${spec.path}`\n const body = spec.body === undefined ? undefined : JSON.stringify(spec.body)\n\n for (let attempt = 0; ; attempt++) {\n throwIfUserAborted(options.signal)\n\n let result: AttemptResult\n try {\n result = await fetchAttempt(config, spec, options, {\n url,\n headers,\n body,\n timeout\n })\n } catch (err) {\n if (err instanceof APIUserAbortError) throw err\n // Connection error, malformed success body, or per-attempt timeout.\n // All retryable.\n if (attempt < maxRetries) {\n await backoff(attempt, undefined, options.signal)\n continue\n }\n throw err\n }\n\n const { response, json } = result\n\n if (response.ok) {\n return { data: json as T, response }\n }\n\n if (shouldRetryStatus(response.status) && attempt < maxRetries) {\n await backoff(\n attempt,\n response.headers.get('retry-after'),\n options.signal\n )\n continue\n }\n\n throw APIError.generate(\n response.status,\n typeof json === 'object' && json !== null ? json : undefined,\n response.statusText,\n response.headers\n )\n }\n}\n\ninterface AttemptResult {\n response: Response\n /** Parsed JSON body; undefined when an error response carried a non-JSON body. */\n json: unknown\n}\n\nasync function fetchAttempt(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions,\n attempt: {\n url: string\n headers: Record<string, string>\n body: string | undefined\n timeout: number\n }\n): Promise<AttemptResult> {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), attempt.timeout)\n const onUserAbort = () => controller.abort()\n options.signal?.addEventListener('abort', onUserAbort, { once: true })\n\n try {\n const response = await config.fetch(attempt.url, {\n ...config.fetchOptions,\n method: spec.method,\n headers: attempt.headers,\n ...(attempt.body !== undefined ? { body: attempt.body } : {}),\n signal: controller.signal\n })\n\n // The body is read inside the timed scope too: a stalled body must not\n // hang past the per-attempt timeout (fetch ties the body stream to the\n // controller's signal, so the abort cancels the read).\n let json: unknown\n if (response.ok) {\n // Success bodies must parse; a truncated/malformed one is treated as a\n // transport failure (classified below) and retried like one.\n json = await response.json()\n } else {\n try {\n json = await response.json()\n } catch (err) {\n // Aborted mid-read is a timeout/abort, not a non-JSON body.\n if (controller.signal.aborted) throw err\n json = undefined // e.g. a load-balancer HTML error page\n }\n }\n return { response, json }\n } catch (err) {\n if (options.signal?.aborted) throw new APIUserAbortError()\n if (controller.signal.aborted) {\n throw new APIConnectionTimeoutError()\n }\n throw new APIConnectionError({\n cause: err instanceof Error ? err : undefined\n })\n } finally {\n clearTimeout(timeoutId)\n options.signal?.removeEventListener('abort', onUserAbort)\n }\n}\n\nfunction buildHeaders(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions\n): Record<string, string> {\n const idempotent = spec.idempotent && spec.method === 'POST'\n const merged: Record<string, string | null | undefined> = {\n authorization: `Bearer ${config.secretKey}`,\n ...(spec.body !== undefined ? { 'content-type': 'application/json' } : {}),\n ...(idempotent && !options.idempotencyKey\n ? {\n // Generated once per call and reused across retry attempts. That\n // is what makes POST retries safe by default. The auto\n // key is an SDK built-in default (lowest tier), so defaultHeaders\n // may override it.\n 'idempotency-key': `simmit-node-retry-${crypto.randomUUID()}`\n }\n : {}),\n ...lowercaseKeys(config.defaultHeaders),\n ...(idempotent && options.idempotencyKey\n ? {\n // An explicit key is a per-request option: it must beat constructor\n // defaultHeaders. Raw options.headers still wins last.\n 'idempotency-key': options.idempotencyKey\n }\n : {}),\n ...lowercaseKeys(options.headers)\n }\n\n const headers: Record<string, string> = {}\n for (const [key, value] of Object.entries(merged)) {\n // A null value deletes the header; undefined entries are skipped.\n if (typeof value === 'string') headers[key] = value\n }\n return headers\n}\n\nfunction lowercaseKeys(\n record: Record<string, string | null | undefined> | undefined\n): Record<string, string | null | undefined> {\n if (!record) return {}\n return Object.fromEntries(\n Object.entries(record).map(([key, value]) => [key.toLowerCase(), value])\n )\n}\n\nfunction shouldRetryStatus(status: number): boolean {\n // 408 kept defensively even though the API never emits it. 409 is never\n // retried: result_not_ready is thrown immediately by design and the other\n // 409s are deterministic.\n return status === 408 || status === 429 || status >= 500\n}\n\nasync function backoff(\n attempt: number,\n retryAfterHeader: string | null | undefined,\n signal: AbortSignal | undefined\n): Promise<void> {\n const retryAfterMs = parseRetryAfter(retryAfterHeader)\n const delay =\n retryAfterMs !== undefined\n ? retryAfterMs\n : Math.min(INITIAL_BACKOFF_MS * 2 ** attempt, MAX_BACKOFF_MS) *\n (1 - 0.25 * Math.random())\n await sleep(delay, signal)\n}\n\n/** Accepts `Retry-After` only when it parses to a delay in (0, 60s]: the SDK never sleeps arbitrarily long on a server hint. */\nfunction parseRetryAfter(\n header: string | null | undefined\n): number | undefined {\n if (!header) return undefined\n let ms: number\n if (/^\\d+$/.test(header.trim())) {\n ms = Number(header.trim()) * 1000\n } else {\n ms = new Date(header).getTime() - Date.now()\n }\n return Number.isFinite(ms) && ms > 0 && ms <= MAX_RETRY_AFTER_MS\n ? ms\n : undefined\n}\n","import type { APIPromise } from '../api-promise'\nimport type { ArtifactUrl } from '../api-types'\nimport type Simmit from '../client'\nimport type { RequestOptions } from '../client'\n\n/** The `artifacts` resource. */\nexport class Artifacts {\n readonly #client: Simmit\n\n constructor(client: Simmit) {\n this.#client = client\n }\n\n /**\n * Fetch a stable public download URL for an artifact, valid for the\n * artifact's full retention window: the same URL `jobs.getResult` returns,\n * fetched on demand (e.g. browser flows that control the final fetch). The\n * artifact is gone (410) once its retention window passes.\n */\n getUrl(\n artifactId: string,\n options?: RequestOptions\n ): APIPromise<ArtifactUrl> {\n return this.#client._request<ArtifactUrl>(\n {\n method: 'GET',\n path: `/v1/simc/artifacts/${encodeURIComponent(artifactId)}/url`\n },\n options\n )\n }\n}\n","import type { APIPromise } from '../api-promise'\nimport type { CreditBalance } from '../api-types'\nimport type Simmit from '../client'\nimport type { RequestOptions } from '../client'\n\n/** The `credits` resource. */\nexport class Credits {\n readonly #client: Simmit\n\n constructor(client: Simmit) {\n this.#client = client\n }\n\n /** Fetch the account's current credit balance and per-grant breakdown. */\n get(options?: RequestOptions): APIPromise<CreditBalance> {\n return this.#client._request<CreditBalance>(\n { method: 'GET', path: '/v1/simc/credits' },\n options\n )\n }\n}\n","// Pure helpers for the createAndWait poll loop. Kept separate from the\n// orchestration so the cadence and deadline math are unit-testable.\nimport type { JobCreateResponse } from '../api-types'\n\nexport const MIN_POLL_INTERVAL_MS = 100\nexport const DEFAULT_POLL_INTERVAL_MS = 1_000\nexport const MAX_POLL_INTERVAL_MS = 10_000\nexport const POLL_BACKOFF_FACTOR = 1.5\nconst DEADLINE_GRACE_MS = 60_000\nconst FALLBACK_WAIT_TIMEOUT_MS = 45 * 60 * 1_000\n\n/**\n * Default wait deadline derived from the applied ceilings the create response\n * reports: `(queueSeconds + runtimeSeconds) × 1000` plus a 60s grace, falling\n * back to 45 minutes when either ceiling is null.\n */\nexport function deriveWaitTimeoutMs(created: JobCreateResponse): number {\n const { runtimeSeconds, queueSeconds } = created.runtime.ceiling\n if (runtimeSeconds != null && queueSeconds != null) {\n return (runtimeSeconds + queueSeconds) * 1_000 + DEADLINE_GRACE_MS\n }\n return FALLBACK_WAIT_TIMEOUT_MS\n}\n\n/** Next poll interval: grow ×1.5, capped at 10s. */\nexport function nextPollInterval(interval: number): number {\n return Math.min(interval * POLL_BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS)\n}\n","import type { JobStatus } from './api-types'\n\n/**\n * Job statuses that are terminal: a job in one of these has stopped and will\n * not change again. Terminal does not mean successful; only `completed` carries\n * a result (`failed`, `cancelled`, and `timed_out` do not).\n */\nexport const TERMINAL_JOB_STATUSES = [\n 'completed',\n 'failed',\n 'cancelled',\n 'timed_out'\n] as const satisfies readonly JobStatus[]\n\n/** A `JobStatus` that is terminal: the job has stopped and will not change. */\nexport type TerminalJobStatus = (typeof TERMINAL_JOB_STATUSES)[number]\n\n/** True when `status` is terminal, i.e. the job has reached an end state. */\nexport function isTerminal(status: JobStatus): status is TerminalJobStatus {\n return (TERMINAL_JOB_STATUSES as readonly JobStatus[]).includes(status)\n}\n","import type { APIPromise } from '../api-promise'\nimport type {\n CompletedJob,\n Job,\n JobCancelResponse,\n JobCreateParams,\n JobCreateResponse,\n JobResult,\n JobStatus,\n JobStatusResponse\n} from '../api-types'\nimport type Simmit from '../client'\nimport type { RequestOptions } from '../client'\nimport {\n JobCancelledError,\n JobFailedError,\n JobTimedOutError,\n JobWaitTimeoutError\n} from '../error'\nimport { sleep } from '../internal/abort'\nimport {\n DEFAULT_POLL_INTERVAL_MS,\n deriveWaitTimeoutMs,\n MIN_POLL_INTERVAL_MS,\n nextPollInterval\n} from '../internal/poll'\nimport { isTerminal } from '../status'\n\nexport interface JobWaitOptions extends RequestOptions {\n /** Initial delay between status polls, ms. Grows ×1.5 per poll to a 10s cap; values under 100 are raised to it. Default 1_000. */\n pollIntervalMs?: number\n /** Overall wait deadline, ms. Default derived from the job's applied ceilings. */\n waitTimeoutMs?: number\n /** Fired once with the raw create response (job id, ceilings, input warnings) before polling. */\n onCreated?: (response: JobCreateResponse) => void\n /** Fired after every successful status poll (progress, stage, queue estimate). */\n onPoll?: (status: JobStatusResponse) => void\n}\n\n/**\n * The `jobs` resource. Each single-request method is a thin wrapper over\n * `client._request` with the path/method/types pinned to the spec;\n * `createAndWait` orchestrates several of them.\n */\nexport class Jobs {\n readonly #client: Simmit\n\n constructor(client: Simmit) {\n this.#client = client\n }\n\n /**\n * Submit a new SimC sim. Returns immediately with the job handle; the sim\n * runs asynchronously. `idempotent: true` makes the request layer attach an\n * auto-generated idempotency key so the POST is safe to retry; pass\n * `options.idempotencyKey` to supply your own.\n */\n create(\n params: JobCreateParams,\n options?: RequestOptions\n ): APIPromise<JobCreateResponse> {\n return this.#client._request<JobCreateResponse>(\n { method: 'POST', path: '/v1/simc/jobs', body: params, idempotent: true },\n options\n )\n }\n\n /** Fetch the full record for a job. */\n get(jobId: string, options?: RequestOptions): APIPromise<Job> {\n return this.#client._request<Job>(\n { method: 'GET', path: `/v1/simc/jobs/${encodeURIComponent(jobId)}` },\n options\n )\n }\n\n /**\n * Fetch the live status of a job in any state: `status`, `errorCode`,\n * `progress`, and `queue` estimate. Unlike `getResult`, it never throws for a\n * non-terminal job, so it is the supported way to drive a custom poll loop.\n */\n getStatus(\n jobId: string,\n options?: RequestOptions\n ): APIPromise<JobStatusResponse> {\n return this.#client._request<JobStatusResponse>(\n {\n method: 'GET',\n path: `/v1/simc/jobs/${encodeURIComponent(jobId)}/status`\n },\n options\n )\n }\n\n /**\n * Fetch the result summary of a terminal job. Throws `ResultNotReadyError`\n * (409) while the job is still running. Poll `/status` or use\n * `createAndWait` rather than `/result` for a job in flight.\n */\n getResult(jobId: string, options?: RequestOptions): APIPromise<JobResult> {\n return this.#client._request<JobResult>(\n {\n method: 'GET',\n path: `/v1/simc/jobs/${encodeURIComponent(jobId)}/result`\n },\n options\n )\n }\n\n /**\n * Submit a job and resolve once it reaches a terminal state. Polls\n * `GET /v1/simc/jobs/{id}/status` (first after `pollIntervalMs`, then ×1.5 to\n * a 10s cap), then fetches the full record. Resolves with the `CompletedJob`\n * on success; throws `JobFailedError` / `JobCancelledError` /\n * `JobTimedOutError` for the other terminal states, or `JobWaitTimeoutError`\n * if the deadline passes first. The job keeps running and is **not**\n * cancelled (call `cancel(jobId)` to stop the spend). `signal` aborts the wait\n * with `APIUserAbortError`, also without cancelling.\n */\n async createAndWait(\n params: JobCreateParams,\n options: JobWaitOptions = {}\n ): Promise<CompletedJob> {\n const {\n pollIntervalMs,\n waitTimeoutMs,\n onCreated,\n onPoll,\n ...requestOptions\n } = options\n\n const created = await this.create(params, requestOptions)\n onCreated?.(created)\n\n const deadline =\n Date.now() + (waitTimeoutMs ?? deriveWaitTimeoutMs(created))\n // nextPollInterval only ever grows the interval, so a non-positive seed\n // would hot-poll the status endpoint; floor it.\n let interval = Math.max(\n pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,\n MIN_POLL_INTERVAL_MS\n )\n let lastStatus: JobStatus = 'pending'\n\n for (;;) {\n const remaining = deadline - Date.now()\n if (remaining <= 0) {\n throw new JobWaitTimeoutError({ jobId: created.id, lastStatus })\n }\n // Never sleep past the deadline, so the wait gives up promptly.\n await sleep(Math.min(interval, remaining), requestOptions.signal)\n\n const status = await this.getStatus(created.id, requestOptions)\n onPoll?.(status)\n lastStatus = status.status\n\n if (isTerminal(status.status)) {\n // The status payload is lightweight; the full record carries the fields\n // CompletedJob and the job-error classes expose.\n const job = await this.get(created.id, requestOptions)\n switch (job.status) {\n case 'completed':\n return job as CompletedJob\n case 'failed':\n throw new JobFailedError(job)\n case 'cancelled':\n throw new JobCancelledError(job)\n case 'timed_out':\n throw new JobTimedOutError(job)\n }\n // Raced back to non-terminal between /status and the full record; keep polling.\n lastStatus = job.status\n }\n interval = nextPollInterval(interval)\n }\n }\n\n /**\n * Request cancellation. Returns `status: 'cancelled'` when the job ended\n * before it ran, or `status: 'cancel_requested'` when an in-flight job was\n * signaled to stop. Repeat calls are naturally idempotent, so no key is sent.\n */\n cancel(\n jobId: string,\n options?: RequestOptions\n ): APIPromise<JobCancelResponse> {\n return this.#client._request<JobCancelResponse>(\n {\n method: 'POST',\n path: `/v1/simc/jobs/${encodeURIComponent(jobId)}/cancel`\n },\n options\n )\n }\n}\n","import { APIPromise } from './api-promise'\nimport { SimmitError } from './error'\nimport {\n makeRequest,\n type ClientConfig,\n type RequestSpec\n} from './internal/request'\nimport { Artifacts } from './resources/artifacts'\nimport { Credits } from './resources/credits'\nimport { Jobs } from './resources/jobs'\n\nexport interface ClientOptions {\n /** Defaults to process.env['SIMMIT_SECRET_KEY'], exactly one env fallback. Construction\n * throws SimmitError('Missing secret key. Pass secretKey or set SIMMIT_SECRET_KEY.').\n * \"Secret key\" is the credential noun end to end (dashboard → docs → env var → option →\n * error): it spends credits and must never ship client-side. */\n secretKey?: string | null\n /** Defaults to process.env['SIMMIT_BASE_URL'] ?? 'https://api.simmit.com'. */\n baseURL?: string | null\n /** Per-attempt timeout in ms. Default 60_000. (Retries can extend total wall time.) */\n timeout?: number\n /** Max retries after the first attempt for retryable failures. Default 2. */\n maxRetries?: number\n /** Headers sent with every request. Merged under per-request headers. */\n defaultHeaders?: Record<string, string | null | undefined>\n /** Custom fetch (testing, proxies). Defaults to globalThis.fetch. */\n fetch?: typeof globalThis.fetch\n /** Extra RequestInit fields passed to every fetch call (e.g. undici dispatcher). */\n fetchOptions?: RequestInit\n}\n\nexport interface RequestOptions {\n /** Per-attempt timeout in ms. Overrides ClientOptions.timeout. */\n timeout?: number\n /** Abort the call (including retries and waiting). Throws APIUserAbortError. Never retried. */\n signal?: AbortSignal\n /** Overrides ClientOptions.maxRetries for this call. */\n maxRetries?: number\n /** Merged over defaultHeaders; a null value deletes the header. */\n headers?: Record<string, string | null | undefined>\n /** jobs.create / jobs.createAndWait only: replaces the auto-generated idempotency-key. */\n idempotencyKey?: string\n}\n\nexport default class Simmit {\n readonly jobs: Jobs\n readonly credits: Credits\n readonly artifacts: Artifacts\n\n readonly baseURL: string\n\n readonly #config: ClientConfig\n\n constructor(options: ClientOptions = {}) {\n const secretKey = options.secretKey ?? readEnv('SIMMIT_SECRET_KEY')\n if (!secretKey) {\n throw new SimmitError(\n 'Missing secret key. Pass secretKey or set SIMMIT_SECRET_KEY.'\n )\n }\n\n this.baseURL =\n options.baseURL ?? readEnv('SIMMIT_BASE_URL') ?? 'https://api.simmit.com'\n\n this.#config = {\n secretKey,\n baseURL: this.baseURL,\n timeout: options.timeout ?? 60_000,\n maxRetries: options.maxRetries ?? 2,\n defaultHeaders: options.defaultHeaders,\n // Resolved lazily so a fetch patched onto globalThis after the client\n // is constructed (msw, APM instrumentation) is still honored.\n fetch: options.fetch ?? ((...args) => globalThis.fetch(...args)),\n fetchOptions: options.fetchOptions\n }\n\n this.jobs = new Jobs(this)\n this.credits = new Credits(this)\n this.artifacts = new Artifacts(this)\n }\n\n /** @internal Resource classes route through here; not public surface. */\n _request<T>(spec: RequestSpec, options?: RequestOptions): APIPromise<T> {\n return makeRequest(this.#config, spec, options)\n }\n}\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === 'undefined') return undefined\n const value = process.env?.[name]?.trim()\n return value || undefined\n}\n","// Standalone webhook verification. Not a client method: receivers must not\n// need a secret-key-bearing client (whose constructor throws without a key).\n// WebCrypto only, zero deps, and runs in Workers as well as Node.\nimport type { JobStatus } from './api-types'\nimport { WebhookVerificationError } from './error'\n\nconst DEFAULT_TOLERANCE_SECONDS = 300\n\n/** The one hand-written wire type: the webhook payload has no OpenAPI schema. */\nexport interface WebhookEvent {\n kind: 'job.terminal'\n version: 'v1'\n timestamp: string\n payload: {\n id: string\n statusReason: string | null\n status: Extract<\n JobStatus,\n 'completed' | 'failed' | 'cancelled' | 'timed_out'\n >\n }\n}\n\n/**\n * Verifies an `X-Simmit-Signature` header (`t=<unix>,v1=<hex>`, an HMAC-SHA256\n * (timing-safe) over `${t}.${rawBody}` within a 300s default tolerance) and\n * returns the parsed event. Throws `WebhookVerificationError` on a bad\n * signature, malformed header, or stale timestamp.\n *\n * Pass `rawBody` exactly as received: re-serializing changes the bytes and\n * breaks verification. `secret` is the webhook signing secret (dashboard →\n * Clients & Keys → Webhook), not your API key.\n */\nexport async function unwrapWebhook(\n rawBody: string,\n signatureHeader: string,\n secret: string,\n options?: { toleranceSeconds?: number }\n): Promise<WebhookEvent> {\n // An empty secret would otherwise surface as an opaque WebCrypto DataError;\n // a NaN tolerance would make the age check pass for everything.\n if (!secret) {\n throw new WebhookVerificationError('Webhook signing secret is empty.')\n }\n const tolerance = options?.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS\n if (!Number.isFinite(tolerance) || tolerance < 0) {\n throw new WebhookVerificationError(\n 'toleranceSeconds must be a non-negative number.'\n )\n }\n\n const { timestampRaw, timestamp, signature } =\n parseSignatureHeader(signatureHeader)\n\n const expected = await hmacSha256Hex(secret, `${timestampRaw}.${rawBody}`)\n if (!timingSafeEqual(expected, signature)) {\n throw new WebhookVerificationError('Webhook signature does not match.')\n }\n\n // Compare on whole seconds, matching the header's unix-seconds `t`.\n if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > tolerance) {\n throw new WebhookVerificationError(\n 'Webhook timestamp is outside the tolerance window.'\n )\n }\n\n try {\n return JSON.parse(rawBody) as WebhookEvent\n } catch {\n throw new WebhookVerificationError('Webhook body is not valid JSON.')\n }\n}\n\nfunction parseSignatureHeader(header: string): {\n timestampRaw: string\n timestamp: number\n signature: string\n} {\n let timestampRaw: string | undefined\n let signature: string | undefined\n for (const part of header.split(',')) {\n const eq = part.indexOf('=')\n if (eq === -1) continue\n const key = part.slice(0, eq).trim()\n const value = part.slice(eq + 1).trim()\n if (key === 't') timestampRaw = value\n else if (key === 'v1') signature = value\n }\n\n // `t` is unix whole seconds; reject anything but digits so the accepted\n // header matches the documented contract.\n if (!timestampRaw || !signature || !/^\\d+$/.test(timestampRaw)) {\n throw new WebhookVerificationError(\n 'Malformed signature header; expected \"t=<unix>,v1=<hex>\".'\n )\n }\n // The signed payload uses the timestamp exactly as sent, so keep the raw\n // string for signing and the parsed number only for the tolerance check.\n return { timestampRaw, timestamp: Number(timestampRaw), signature }\n}\n\nasync function hmacSha256Hex(secret: string, payload: string): Promise<string> {\n const encoder = new TextEncoder()\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n const mac = await crypto.subtle.sign('HMAC', key, encoder.encode(payload))\n return toHex(new Uint8Array(mac))\n}\n\nfunction toHex(bytes: Uint8Array): string {\n let hex = ''\n for (const byte of bytes) hex += byte.toString(16).padStart(2, '0')\n return hex\n}\n\n// Constant-time comparison. The digest width is public, so a length mismatch\n// may short-circuit without leaking secret-dependent timing.\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false\n let mismatch = 0\n for (let i = 0; i < a.length; i++) {\n mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n return mismatch === 0\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/error.ts","../src/api-promise.ts","../src/internal/abort.ts","../src/internal/request.ts","../src/resources/artifacts.ts","../src/resources/credits.ts","../src/internal/poll.ts","../src/status.ts","../src/resources/jobs.ts","../src/client.ts","../src/webhook.ts"],"sourcesContent":["import type { Job, JobStatus } from './api-types'\n\nexport class SimmitError extends Error {}\n\n/**\n * Value shapes the API's generic error `meta` bag can carry\n * (400/401/404/410/413 responses): JSON scalars, scalar arrays, or arrays of\n * flat objects.\n */\nexport type MetaValue =\n | string\n | number\n | boolean\n | null\n | Array<string | number | boolean>\n | Array<Record<string, string | number | boolean | null>>\n\nexport type GenericMeta = Record<string, MetaValue>\n\n/** The API's uniform error envelope: `{ error, code, meta }`. */\ninterface ErrorEnvelope {\n error?: unknown\n code?: unknown\n meta?: unknown\n requestId?: unknown\n}\n\nexport class APIError<\n TStatus extends number | undefined = number | undefined,\n TCode extends string | undefined = string | undefined,\n TMeta = GenericMeta | null\n> extends SimmitError {\n /** HTTP status of the response that caused the error. */\n readonly status: TStatus\n /** HTTP headers of the response that caused the error. */\n readonly headers: Headers | undefined\n /** Machine-readable `code` from the error envelope. */\n readonly code: TCode\n /** Typed `meta` from the error envelope. */\n readonly meta: TMeta\n /** Raw parsed JSON error body: escape hatch for unmapped fields. */\n readonly error: object | undefined\n\n constructor(\n status: TStatus,\n body: object | undefined,\n message: string | undefined,\n headers: Headers | undefined\n ) {\n super(APIError.makeMessage(status, body, message))\n this.status = status\n this.headers = headers\n this.error = body\n const envelope = body as ErrorEnvelope | undefined\n this.code = (\n typeof envelope?.code === 'string' ? envelope.code : undefined\n ) as TCode\n this.meta = (body ? (envelope?.meta ?? null) : undefined) as TMeta\n }\n\n /**\n * Correlation id for the failed request (`req_...`), for support tickets.\n * Read from the `X-Request-Id` response header, falling back to the body's\n * `requestId` field.\n */\n get requestId(): string | undefined {\n const fromHeader = this.headers?.get('x-request-id')\n if (fromHeader) return fromHeader\n const { requestId } = (this.error ?? {}) as ErrorEnvelope\n return typeof requestId === 'string' ? requestId : undefined\n }\n\n private static makeMessage(\n status: number | undefined,\n body: object | undefined,\n message: string | undefined\n ): string {\n // The API's human-readable message field is named `error`, not `message`.\n const bodyMessage = (body as ErrorEnvelope | undefined)?.error\n const msg =\n typeof bodyMessage === 'string'\n ? bodyMessage\n : body\n ? JSON.stringify(body)\n : message\n\n if (status && msg) return `${status} ${msg}`\n if (status) return `${status} status code (no body)`\n if (msg) return msg\n return '(no status code or body)'\n }\n\n /**\n * Maps a response to the most specific error class: status selects the base\n * class; an enumerated `code` with structured `meta` selects the subclass;\n * anything unrecognized falls back to the status class so new server codes\n * degrade gracefully without breaking `instanceof` handling.\n */\n static generate(\n status: number | undefined,\n body: object | undefined,\n message: string | undefined,\n headers: Headers | undefined\n ): APIError<\n number | undefined,\n string | undefined,\n GenericMeta | null | undefined\n > {\n if (!status || !headers) {\n return new APIConnectionError({\n message,\n cause: body instanceof Error ? body : undefined\n })\n }\n\n const code = (body as ErrorEnvelope | undefined)?.code\n\n if (status === 400) return new BadRequestError(400, body, message, headers)\n if (status === 401) {\n return new AuthenticationError(401, body, message, headers)\n }\n if (status === 402) {\n if (code === 'insufficient_credits') {\n return new InsufficientCreditsError(402, body, message, headers)\n }\n if (code === 'insufficient_credits_liability') {\n return new InsufficientCreditsLiabilityError(\n 402,\n body,\n message,\n headers\n )\n }\n return new BillingError(402, body, message, headers)\n }\n if (status === 404) return new NotFoundError(404, body, message, headers)\n if (status === 409) {\n if (code === 'idempotency_key_reuse') {\n return new IdempotencyKeyReuseError(409, body, message, headers)\n }\n if (code === 'result_not_ready') {\n return new ResultNotReadyError(409, body, message, headers)\n }\n if (code === 'job_not_cancellable') {\n return new JobNotCancellableError(409, body, message, headers)\n }\n return new ConflictError(409, body, message, headers)\n }\n if (status === 413) {\n return new RequestTooLargeError(413, body, message, headers)\n }\n if (status === 422) {\n if (code === 'input_sanitized_rejected') {\n return new InvalidProfileError(422, body, message, headers)\n }\n if (code === 'result_unavailable') {\n return new ResultUnavailableError(422, body, message, headers)\n }\n return new UnprocessableEntityError(422, body, message, headers)\n }\n if (status === 429) {\n if (code === 'max_active_jobs_exceeded') {\n return new MaxActiveJobsError(429, body, message, headers)\n }\n return new RateLimitError(429, body, message, headers)\n }\n if (status === 503 && isServiceUnavailableBody(body)) {\n return new ServiceUnavailableError(503, body, message, headers)\n }\n if (status >= 500) {\n return new InternalServerError(status, body, message, headers)\n }\n return new APIError(status, body, message, headers)\n }\n}\n\n// ── 4xx status classes (code subclasses where the spec enumerates) ──────────\n\nexport class BadRequestError extends APIError<400, string> {}\n\nexport type AuthenticationErrorCode =\n | 'missing_token'\n | 'invalid_token'\n | 'revoked_token'\n | 'expired_token'\n\nexport class AuthenticationError extends APIError<\n 401,\n AuthenticationErrorCode\n> {}\n\n// 402 codes are docs-enumerated; the spec leaves `code` un-enumerated, so the\n// base class keeps `string` for forward compatibility.\nexport class BillingError extends APIError<402, string> {}\n\nexport type InsufficientCreditsMeta = {\n reason: string\n ceilingRuntimeSeconds?: number\n /** Largest maxRuntimeSeconds the current balance can cover. */\n maxAffordableRuntimeSeconds?: number\n docsUrl?: string\n}\n\nexport class InsufficientCreditsError extends BillingError {\n declare readonly code: 'insufficient_credits'\n declare readonly meta: InsufficientCreditsMeta | null\n}\n\nexport type InsufficientCreditsLiabilityMeta = {\n reason: string\n /** The high-priority fee in effect. Top up, or resubmit at priority 'standard'. */\n priorityFeeCredits: number\n docsUrl?: string\n}\n\nexport class InsufficientCreditsLiabilityError extends BillingError {\n declare readonly code: 'insufficient_credits_liability'\n declare readonly meta: InsufficientCreditsLiabilityMeta | null\n}\n\nexport class NotFoundError extends APIError<404, string> {}\n\nexport class ConflictError extends APIError<409, string> {}\n\nexport class IdempotencyKeyReuseError extends ConflictError {\n declare readonly code: 'idempotency_key_reuse'\n declare readonly meta: {\n reason: 'idempotency_key_reuse'\n /** ID of the job that originally consumed this idempotency key. */\n originalJobId: string\n docsUrl?: string\n }\n}\n\nexport class ResultNotReadyError extends ConflictError {\n declare readonly code: 'result_not_ready'\n declare readonly meta: {\n status: 'pending' | 'queued' | 'starting' | 'running'\n }\n}\n\nexport class JobNotCancellableError extends ConflictError {\n declare readonly code: 'job_not_cancellable'\n declare readonly meta: { id: string; status: JobStatus }\n}\n\nexport class RequestTooLargeError extends APIError<413, string> {}\n\nexport class UnprocessableEntityError extends APIError<422, string> {}\n\nexport class InvalidProfileError extends UnprocessableEntityError {\n declare readonly code: 'input_sanitized_rejected'\n declare readonly meta: {\n reason: 'input_sanitized_rejected'\n message: string\n docsUrl: string\n /** Sample of rejected lines; see blockedCount/blockedTruncated for the full set. */\n blocked: Array<{ line: number; text: string }>\n blockedCount: number\n blockedTruncated: boolean\n }\n}\n\nexport class ResultUnavailableError extends UnprocessableEntityError {\n declare readonly code: 'result_unavailable'\n declare readonly meta: {\n status: 'completed' | 'failed' | 'cancelled' | 'timed_out'\n }\n}\n\nexport type RateLimitErrorCode =\n | 'rate_limit_exceeded'\n | 'max_active_jobs_exceeded'\n\nexport class RateLimitError extends APIError<429, RateLimitErrorCode> {\n declare readonly meta:\n | { scope: 'developer' }\n | {\n reason: 'max_active_jobs_exceeded'\n maxActiveJobs: number\n activeJobs: number\n }\n | null\n}\n\nexport class MaxActiveJobsError extends RateLimitError {\n declare readonly code: 'max_active_jobs_exceeded'\n declare readonly meta: {\n reason: 'max_active_jobs_exceeded'\n /** Maximum number of jobs the account can have in flight. */\n maxActiveJobs: number\n /** Jobs in flight when this request was rejected. */\n activeJobs: number\n }\n}\n\n// ── 5xx ─────────────────────────────────────────────────────────────────────\n\nexport class InternalServerError extends APIError<number, string> {}\n\n/**\n * 503 carries four enumerated codes with distinct meta: a discriminated\n * union, narrowed via `.body`. `api_maintenance` gets no special retry\n * behavior: standard policy applies, and the typed\n * `meta.retryAfterSeconds` is surfaced so callers can schedule their own\n * resubmission.\n */\nexport type ServiceUnavailableBody =\n | {\n code: 'queue_unavailable'\n meta: { reason: 'queue_unavailable'; queueHealth: string }\n }\n | {\n code: 'queue_health_unknown'\n meta: { reason: 'queue_health_unknown'; laneId: string }\n }\n | {\n code: 'secret_store_unavailable'\n meta: { reason: 'secret_store_unavailable' }\n }\n | { code: 'api_maintenance'; meta: { retryAfterSeconds: number } }\n\nconst SERVICE_UNAVAILABLE_CODES = new Set([\n 'queue_unavailable',\n 'queue_health_unknown',\n 'secret_store_unavailable',\n 'api_maintenance'\n])\n\n// A 503 whose body isn't the enumerated envelope (e.g. load-balancer HTML)\n// falls back to InternalServerError so `.body` below never lies.\nfunction isServiceUnavailableBody(\n body: object | undefined\n): body is ServiceUnavailableBody {\n const code = (body as ErrorEnvelope | undefined)?.code\n return typeof code === 'string' && SERVICE_UNAVAILABLE_CODES.has(code)\n}\n\nexport class ServiceUnavailableError extends InternalServerError {\n declare readonly status: 503\n\n /** The discriminated 503 envelope: `if (e.body.code === 'api_maintenance') e.body.meta.retryAfterSeconds`. */\n get body(): ServiceUnavailableBody {\n return this.error as ServiceUnavailableBody\n }\n}\n\n// ── No HTTP response ────────────────────────────────────────────────────────\n\nexport class APIConnectionError extends APIError<\n undefined,\n undefined,\n undefined\n> {\n constructor({\n message,\n cause\n }: { message?: string | undefined; cause?: Error | undefined } = {}) {\n super(undefined, undefined, message ?? 'Connection error.', undefined)\n if (cause) this.cause = cause\n }\n}\n\nexport class APIConnectionTimeoutError extends APIConnectionError {\n constructor({ message }: { message?: string } = {}) {\n super({ message: message ?? 'Request timed out.' })\n }\n}\n\nexport class APIUserAbortError extends APIError<\n undefined,\n undefined,\n undefined\n> {\n constructor({ message }: { message?: string } = {}) {\n super(undefined, undefined, message ?? 'Request was aborted.', undefined)\n }\n}\n\n// ── Job-level errors (thrown only by createAndWait) ──────────────────────────\n\n/** Catch-all for a job that reached a terminal state other than `completed`. */\nexport abstract class JobUnsuccessfulError extends SimmitError {\n readonly job: Job\n\n constructor(job: Job, message?: string) {\n super(\n message ??\n `Job ${job.id} ${job.status}` +\n (job.statusReason ? `: ${job.statusReason}` : '') +\n (job.errorCode ? ` (${job.errorCode})` : '')\n )\n this.job = job\n }\n}\n\nexport class JobFailedError extends JobUnsuccessfulError {}\n\n/** Includes queue_timeout auto-cancellation, not just user cancels. */\nexport class JobCancelledError extends JobUnsuccessfulError {}\n\n/** The job hit its runtime ceiling server-side and is billed for what ran. */\nexport class JobTimedOutError extends JobUnsuccessfulError {}\n\n/**\n * The SDK gave up polling. The job itself is still running and billing.\n * Keep tracking via `jobs.get(jobId)` or stop the spend with `jobs.cancel(jobId)`.\n */\nexport class JobWaitTimeoutError extends SimmitError {\n readonly jobId: string\n readonly lastStatus: JobStatus\n\n constructor(args: {\n jobId: string\n lastStatus: JobStatus\n message?: string\n }) {\n super(\n args.message ??\n `Timed out waiting for job ${args.jobId} (last status: ${args.lastStatus}). ` +\n 'The job is still running server-side and continues to bill.'\n )\n this.jobId = args.jobId\n this.lastStatus = args.lastStatus\n }\n}\n\n// ── Webhook verification (thrown by unwrapWebhook) ───────────────────────────\n\nexport class WebhookVerificationError extends SimmitError {}\n","/**\n * A `Promise<T>` with raw-response access: the generic answer to response\n * headers the return types can't see (`X-Idempotent-Replay`, `X-Active-Jobs`,\n * `X-RateLimit-*`).\n *\n * const { data, response } = await client.jobs.create(params).withResponse()\n * response.headers.get('x-idempotent-replay')\n */\nexport class APIPromise<T> extends Promise<T> {\n // Chained promises (.then/.catch) must be plain Promises: this class's\n // constructor signature is incompatible with the executor the runtime\n // would otherwise pass via the species constructor.\n static override get [Symbol.species]() {\n return Promise\n }\n\n readonly #parsed: Promise<{ data: T; response: Response }>\n\n constructor(parsed: Promise<{ data: T; response: Response }>) {\n // The base promise is a pre-settled placeholder that is never observed:\n // then() below delegates to #parsed lazily (catch/finally route through\n // then() per spec). Subscribing eagerly here would reject this instance\n // even when the caller only consumes withResponse(), leaking an\n // unhandled rejection on failures.\n super((resolve) => resolve(undefined as never))\n this.#parsed = parsed\n }\n\n override then<TResult1 = T, TResult2 = never>(\n onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null\n ): Promise<TResult1 | TResult2> {\n return this.#parsed\n .then((result) => result.data)\n .then(onfulfilled, onrejected)\n }\n\n withResponse(): Promise<{ data: T; response: Response }> {\n return this.#parsed\n }\n\n asResponse(): Promise<Response> {\n return this.#parsed.then((result) => result.response)\n }\n}\n","// Abort-aware timing utilities shared by the request layer (backoff sleeps) and\n// the createAndWait poll loop. A pending sleep rejects with APIUserAbortError\n// the moment the caller's signal fires.\nimport { APIUserAbortError } from '../error'\n\nexport function throwIfUserAborted(signal: AbortSignal | undefined): void {\n if (signal?.aborted) throw new APIUserAbortError()\n}\n\nexport function sleep(\n ms: number,\n signal: AbortSignal | undefined\n): Promise<void> {\n return new Promise((resolve, reject) => {\n throwIfUserAborted(signal)\n const timeoutId = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n const onAbort = () => {\n clearTimeout(timeoutId)\n reject(new APIUserAbortError())\n }\n signal?.addEventListener('abort', onAbort, { once: true })\n })\n}\n","// Internal request layer: header assembly, per-attempt timeout/abort\n// composition, retry with backoff + Retry-After, idempotency-key injection,\n// and error mapping. Not exported from the package.\nimport { APIPromise } from '../api-promise'\nimport {\n APIConnectionError,\n APIConnectionTimeoutError,\n APIError,\n APIUserAbortError\n} from '../error'\nimport type { RequestOptions } from '../client'\nimport { sleep, throwIfUserAborted } from './abort'\n\nexport interface ClientConfig {\n secretKey: string\n baseURL: string\n timeout: number\n maxRetries: number\n defaultHeaders: Record<string, string | null | undefined> | undefined\n fetch: typeof globalThis.fetch\n fetchOptions: RequestInit | undefined\n}\n\nexport interface RequestSpec {\n method: 'GET' | 'POST'\n path: string\n body?: unknown\n /** POST job creation: auto-generate an idempotency-key when none supplied. */\n idempotent?: boolean\n}\n\n// Retry policy constants: typed code config, not env.\nconst INITIAL_BACKOFF_MS = 500\nconst MAX_BACKOFF_MS = 8_000\nconst MAX_RETRY_AFTER_MS = 60_000\n\nexport function makeRequest<T>(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions = {}\n): APIPromise<T> {\n return new APIPromise(run<T>(config, spec, options))\n}\n\nasync function run<T>(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions\n): Promise<{ data: T; response: Response }> {\n const maxRetries = options.maxRetries ?? config.maxRetries\n const timeout = options.timeout ?? config.timeout\n const headers = buildHeaders(config, spec, options)\n const url = `${config.baseURL.replace(/\\/+$/, '')}${spec.path}`\n const body = spec.body === undefined ? undefined : JSON.stringify(spec.body)\n\n for (let attempt = 0; ; attempt++) {\n throwIfUserAborted(options.signal)\n\n let result: AttemptResult\n try {\n result = await fetchAttempt(config, spec, options, {\n url,\n headers,\n body,\n timeout\n })\n } catch (err) {\n if (err instanceof APIUserAbortError) throw err\n // Connection error, malformed success body, or per-attempt timeout.\n // All retryable.\n if (attempt < maxRetries) {\n await backoff(attempt, undefined, options.signal)\n continue\n }\n throw err\n }\n\n const { response, json } = result\n\n if (response.ok) {\n return { data: json as T, response }\n }\n\n if (shouldRetryStatus(response.status) && attempt < maxRetries) {\n await backoff(\n attempt,\n response.headers.get('retry-after'),\n options.signal\n )\n continue\n }\n\n throw APIError.generate(\n response.status,\n typeof json === 'object' && json !== null ? json : undefined,\n response.statusText,\n response.headers\n )\n }\n}\n\ninterface AttemptResult {\n response: Response\n /** Parsed JSON body; undefined when an error response carried a non-JSON body. */\n json: unknown\n}\n\nasync function fetchAttempt(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions,\n attempt: {\n url: string\n headers: Record<string, string>\n body: string | undefined\n timeout: number\n }\n): Promise<AttemptResult> {\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), attempt.timeout)\n const onUserAbort = () => controller.abort()\n options.signal?.addEventListener('abort', onUserAbort, { once: true })\n\n try {\n const response = await config.fetch(attempt.url, {\n ...config.fetchOptions,\n method: spec.method,\n headers: attempt.headers,\n ...(attempt.body !== undefined ? { body: attempt.body } : {}),\n signal: controller.signal\n })\n\n // The body is read inside the timed scope too: a stalled body must not\n // hang past the per-attempt timeout (fetch ties the body stream to the\n // controller's signal, so the abort cancels the read).\n let json: unknown\n if (response.ok) {\n // Success bodies must parse; a truncated/malformed one is treated as a\n // transport failure (classified below) and retried like one.\n json = await response.json()\n } else {\n try {\n json = await response.json()\n } catch (err) {\n // Aborted mid-read is a timeout/abort, not a non-JSON body.\n if (controller.signal.aborted) throw err\n json = undefined // e.g. a load-balancer HTML error page\n }\n }\n return { response, json }\n } catch (err) {\n if (options.signal?.aborted) throw new APIUserAbortError()\n if (controller.signal.aborted) {\n throw new APIConnectionTimeoutError()\n }\n throw new APIConnectionError({\n cause: err instanceof Error ? err : undefined\n })\n } finally {\n clearTimeout(timeoutId)\n options.signal?.removeEventListener('abort', onUserAbort)\n }\n}\n\nfunction buildHeaders(\n config: ClientConfig,\n spec: RequestSpec,\n options: RequestOptions\n): Record<string, string> {\n const idempotent = spec.idempotent && spec.method === 'POST'\n const merged: Record<string, string | null | undefined> = {\n authorization: `Bearer ${config.secretKey}`,\n ...(spec.body !== undefined ? { 'content-type': 'application/json' } : {}),\n ...(idempotent && !options.idempotencyKey\n ? {\n // Generated once per call and reused across retry attempts. That\n // is what makes POST retries safe by default. The auto\n // key is an SDK built-in default (lowest tier), so defaultHeaders\n // may override it.\n 'idempotency-key': `simmit-node-retry-${crypto.randomUUID()}`\n }\n : {}),\n ...lowercaseKeys(config.defaultHeaders),\n ...(idempotent && options.idempotencyKey\n ? {\n // An explicit key is a per-request option: it must beat constructor\n // defaultHeaders. Raw options.headers still wins last.\n 'idempotency-key': options.idempotencyKey\n }\n : {}),\n ...lowercaseKeys(options.headers)\n }\n\n const headers: Record<string, string> = {}\n for (const [key, value] of Object.entries(merged)) {\n // A null value deletes the header; undefined entries are skipped.\n if (typeof value === 'string') headers[key] = value\n }\n return headers\n}\n\nfunction lowercaseKeys(\n record: Record<string, string | null | undefined> | undefined\n): Record<string, string | null | undefined> {\n if (!record) return {}\n return Object.fromEntries(\n Object.entries(record).map(([key, value]) => [key.toLowerCase(), value])\n )\n}\n\nfunction shouldRetryStatus(status: number): boolean {\n // 408 kept defensively even though the API never emits it. 409 is never\n // retried: result_not_ready is thrown immediately by design and the other\n // 409s are deterministic.\n return status === 408 || status === 429 || status >= 500\n}\n\nasync function backoff(\n attempt: number,\n retryAfterHeader: string | null | undefined,\n signal: AbortSignal | undefined\n): Promise<void> {\n const retryAfterMs = parseRetryAfter(retryAfterHeader)\n const delay =\n retryAfterMs !== undefined\n ? retryAfterMs\n : Math.min(INITIAL_BACKOFF_MS * 2 ** attempt, MAX_BACKOFF_MS) *\n (1 - 0.25 * Math.random())\n await sleep(delay, signal)\n}\n\n/** Accepts `Retry-After` only when it parses to a delay in (0, 60s]: the SDK never sleeps arbitrarily long on a server hint. */\nfunction parseRetryAfter(\n header: string | null | undefined\n): number | undefined {\n if (!header) return undefined\n let ms: number\n if (/^\\d+$/.test(header.trim())) {\n ms = Number(header.trim()) * 1000\n } else {\n ms = new Date(header).getTime() - Date.now()\n }\n return Number.isFinite(ms) && ms > 0 && ms <= MAX_RETRY_AFTER_MS\n ? ms\n : undefined\n}\n","import type { APIPromise } from '../api-promise'\nimport type { ArtifactUrl } from '../api-types'\nimport type Simmit from '../client'\nimport type { RequestOptions } from '../client'\n\n/** The `artifacts` resource. */\nexport class Artifacts {\n readonly #client: Simmit\n\n constructor(client: Simmit) {\n this.#client = client\n }\n\n /**\n * Fetch a stable public download URL for an artifact, valid for the\n * artifact's full retention window: the same URL `jobs.getResult` returns,\n * fetched on demand (e.g. browser flows that control the final fetch). The\n * artifact is gone (410) once its retention window passes.\n */\n getUrl(\n artifactId: string,\n options?: RequestOptions\n ): APIPromise<ArtifactUrl> {\n return this.#client._request<ArtifactUrl>(\n {\n method: 'GET',\n path: `/v1/simc/artifacts/${encodeURIComponent(artifactId)}/url`\n },\n options\n )\n }\n}\n","import type { APIPromise } from '../api-promise'\nimport type { CreditBalance } from '../api-types'\nimport type Simmit from '../client'\nimport type { RequestOptions } from '../client'\n\n/** The `credits` resource. */\nexport class Credits {\n readonly #client: Simmit\n\n constructor(client: Simmit) {\n this.#client = client\n }\n\n /** Fetch the account's current credit balance and per-grant breakdown. */\n get(options?: RequestOptions): APIPromise<CreditBalance> {\n return this.#client._request<CreditBalance>(\n { method: 'GET', path: '/v1/simc/credits' },\n options\n )\n }\n}\n","// Pure helpers for the createAndWait poll loop. Kept separate from the\n// orchestration so the cadence and deadline math are unit-testable.\nimport type { JobCreateResponse } from '../api-types'\n\nexport const MIN_POLL_INTERVAL_MS = 100\nexport const DEFAULT_POLL_INTERVAL_MS = 1_000\nexport const MAX_POLL_INTERVAL_MS = 10_000\nexport const POLL_BACKOFF_FACTOR = 1.5\nconst DEADLINE_GRACE_MS = 60_000\nconst FALLBACK_WAIT_TIMEOUT_MS = 45 * 60 * 1_000\n\n/**\n * Default wait deadline derived from the applied ceilings the create response\n * reports: `(queueSeconds + runtimeSeconds) × 1000` plus a 60s grace, falling\n * back to 45 minutes when either ceiling is null.\n */\nexport function deriveWaitTimeoutMs(created: JobCreateResponse): number {\n const { runtimeSeconds, queueSeconds } = created.runtime.ceiling\n if (runtimeSeconds != null && queueSeconds != null) {\n return (runtimeSeconds + queueSeconds) * 1_000 + DEADLINE_GRACE_MS\n }\n return FALLBACK_WAIT_TIMEOUT_MS\n}\n\n/** Next poll interval: grow ×1.5, capped at 10s. */\nexport function nextPollInterval(interval: number): number {\n return Math.min(interval * POLL_BACKOFF_FACTOR, MAX_POLL_INTERVAL_MS)\n}\n","import type { JobStatus } from './api-types'\n\n/**\n * Job statuses that are terminal: a job in one of these has stopped and will\n * not change again. Terminal does not mean successful; only `completed` carries\n * a result (`failed`, `cancelled`, and `timed_out` do not).\n */\nexport const TERMINAL_JOB_STATUSES = [\n 'completed',\n 'failed',\n 'cancelled',\n 'timed_out'\n] as const satisfies readonly JobStatus[]\n\n/** A `JobStatus` that is terminal: the job has stopped and will not change. */\nexport type TerminalJobStatus = (typeof TERMINAL_JOB_STATUSES)[number]\n\n/** True when `status` is terminal, i.e. the job has reached an end state. */\nexport function isTerminal(status: JobStatus): status is TerminalJobStatus {\n return (TERMINAL_JOB_STATUSES as readonly JobStatus[]).includes(status)\n}\n","import type { APIPromise } from '../api-promise'\nimport type {\n CompletedJob,\n Job,\n JobCancelResponse,\n JobCreateParams,\n JobCreateResponse,\n JobResult,\n JobStatus,\n JobStatusResponse\n} from '../api-types'\nimport type Simmit from '../client'\nimport type { RequestOptions } from '../client'\nimport {\n JobCancelledError,\n JobFailedError,\n JobTimedOutError,\n JobWaitTimeoutError\n} from '../error'\nimport { sleep } from '../internal/abort'\nimport {\n DEFAULT_POLL_INTERVAL_MS,\n deriveWaitTimeoutMs,\n MIN_POLL_INTERVAL_MS,\n nextPollInterval\n} from '../internal/poll'\nimport { isTerminal } from '../status'\n\nexport interface JobWaitOptions extends RequestOptions {\n /** Initial delay between status polls, ms. Grows ×1.5 per poll to a 10s cap; values under 100 are raised to it. Default 1_000. */\n pollIntervalMs?: number\n /** Overall wait deadline, ms. Default derived from the job's applied ceilings. */\n waitTimeoutMs?: number\n /** Fired once with the raw create response (job id, ceilings, input warnings) before polling. */\n onCreated?: (response: JobCreateResponse) => void\n /** Fired after every successful status poll (progress, stage, queue estimate). */\n onPoll?: (status: JobStatusResponse) => void\n}\n\n/**\n * The `jobs` resource. Each single-request method is a thin wrapper over\n * `client._request` with the path/method/types pinned to the spec;\n * `createAndWait` orchestrates several of them.\n */\nexport class Jobs {\n readonly #client: Simmit\n\n constructor(client: Simmit) {\n this.#client = client\n }\n\n /**\n * Submit a new SimC sim. Returns immediately with the job handle; the sim\n * runs asynchronously. `idempotent: true` makes the request layer attach an\n * auto-generated idempotency key so the POST is safe to retry; pass\n * `options.idempotencyKey` to supply your own.\n */\n create(\n params: JobCreateParams,\n options?: RequestOptions\n ): APIPromise<JobCreateResponse> {\n return this.#client._request<JobCreateResponse>(\n { method: 'POST', path: '/v1/simc/jobs', body: params, idempotent: true },\n options\n )\n }\n\n /** Fetch the full record for a job. */\n get(jobId: string, options?: RequestOptions): APIPromise<Job> {\n return this.#client._request<Job>(\n { method: 'GET', path: `/v1/simc/jobs/${encodeURIComponent(jobId)}` },\n options\n )\n }\n\n /**\n * Fetch the live status of a job in any state: `status`, `errorCode`,\n * `progress`, and `queue` estimate. Unlike `getResult`, it never throws for a\n * non-terminal job, so it is the supported way to drive a custom poll loop.\n */\n getStatus(\n jobId: string,\n options?: RequestOptions\n ): APIPromise<JobStatusResponse> {\n return this.#client._request<JobStatusResponse>(\n {\n method: 'GET',\n path: `/v1/simc/jobs/${encodeURIComponent(jobId)}/status`\n },\n options\n )\n }\n\n /**\n * Fetch the result summary of a terminal job. Throws `ResultNotReadyError`\n * (409) while the job is still running. Poll `/status` or use\n * `createAndWait` rather than `/result` for a job in flight.\n */\n getResult(jobId: string, options?: RequestOptions): APIPromise<JobResult> {\n return this.#client._request<JobResult>(\n {\n method: 'GET',\n path: `/v1/simc/jobs/${encodeURIComponent(jobId)}/result`\n },\n options\n )\n }\n\n /**\n * Submit a job and resolve once it reaches a terminal state. Polls\n * `GET /v1/simc/jobs/{id}/status` (first after `pollIntervalMs`, then ×1.5 to\n * a 10s cap), then fetches the full record. Resolves with the `CompletedJob`\n * on success; throws `JobFailedError` / `JobCancelledError` /\n * `JobTimedOutError` for the other terminal states, or `JobWaitTimeoutError`\n * if the deadline passes first. The job keeps running and is **not**\n * cancelled (call `cancel(jobId)` to stop the spend). `signal` aborts the wait\n * with `APIUserAbortError`, also without cancelling.\n */\n async createAndWait(\n params: JobCreateParams,\n options: JobWaitOptions = {}\n ): Promise<CompletedJob> {\n const {\n pollIntervalMs,\n waitTimeoutMs,\n onCreated,\n onPoll,\n ...requestOptions\n } = options\n\n const created = await this.create(params, requestOptions)\n onCreated?.(created)\n\n const deadline =\n Date.now() + (waitTimeoutMs ?? deriveWaitTimeoutMs(created))\n // nextPollInterval only ever grows the interval, so a non-positive seed\n // would hot-poll the status endpoint; floor it.\n let interval = Math.max(\n pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS,\n MIN_POLL_INTERVAL_MS\n )\n let lastStatus: JobStatus = 'pending'\n\n for (;;) {\n const remaining = deadline - Date.now()\n if (remaining <= 0) {\n throw new JobWaitTimeoutError({ jobId: created.id, lastStatus })\n }\n // Never sleep past the deadline, so the wait gives up promptly.\n await sleep(Math.min(interval, remaining), requestOptions.signal)\n\n const status = await this.getStatus(created.id, requestOptions)\n onPoll?.(status)\n lastStatus = status.status\n\n if (isTerminal(status.status)) {\n // The status payload is lightweight; the full record carries the fields\n // CompletedJob and the job-error classes expose.\n const job = await this.get(created.id, requestOptions)\n switch (job.status) {\n case 'completed':\n return job as CompletedJob\n case 'failed':\n throw new JobFailedError(job)\n case 'cancelled':\n throw new JobCancelledError(job)\n case 'timed_out':\n throw new JobTimedOutError(job)\n }\n // Raced back to non-terminal between /status and the full record; keep polling.\n lastStatus = job.status\n }\n interval = nextPollInterval(interval)\n }\n }\n\n /**\n * Request cancellation. Returns `status: 'cancelled'` when the job ended\n * before it ran, or `status: 'cancel_requested'` when an in-flight job was\n * signaled to stop. Repeat calls are naturally idempotent, so no key is sent.\n */\n cancel(\n jobId: string,\n options?: RequestOptions\n ): APIPromise<JobCancelResponse> {\n return this.#client._request<JobCancelResponse>(\n {\n method: 'POST',\n path: `/v1/simc/jobs/${encodeURIComponent(jobId)}/cancel`\n },\n options\n )\n }\n}\n","import { APIPromise } from './api-promise'\nimport { SimmitError } from './error'\nimport {\n makeRequest,\n type ClientConfig,\n type RequestSpec\n} from './internal/request'\nimport { Artifacts } from './resources/artifacts'\nimport { Credits } from './resources/credits'\nimport { Jobs } from './resources/jobs'\n\nexport interface ClientOptions {\n /** Defaults to process.env['SIMMIT_SECRET_KEY'], exactly one env fallback. Construction\n * throws SimmitError('Missing secret key. Pass secretKey or set SIMMIT_SECRET_KEY.').\n * \"Secret key\" is the credential noun end to end (dashboard → docs → env var → option →\n * error): it spends credits and must never ship client-side. */\n secretKey?: string | null\n /** Defaults to process.env['SIMMIT_BASE_URL'] ?? 'https://api.simmit.com'. */\n baseURL?: string | null\n /** Per-attempt timeout in ms. Default 60_000. (Retries can extend total wall time.) */\n timeout?: number\n /** Max retries after the first attempt for retryable failures. Default 2. */\n maxRetries?: number\n /** Headers sent with every request. Merged under per-request headers. */\n defaultHeaders?: Record<string, string | null | undefined>\n /** Custom fetch (testing, proxies). Defaults to globalThis.fetch. */\n fetch?: typeof globalThis.fetch\n /** Extra RequestInit fields passed to every fetch call (e.g. undici dispatcher). */\n fetchOptions?: RequestInit\n}\n\nexport interface RequestOptions {\n /** Per-attempt timeout in ms. Overrides ClientOptions.timeout. */\n timeout?: number\n /** Abort the call (including retries and waiting). Throws APIUserAbortError. Never retried. */\n signal?: AbortSignal\n /** Overrides ClientOptions.maxRetries for this call. */\n maxRetries?: number\n /** Merged over defaultHeaders; a null value deletes the header. */\n headers?: Record<string, string | null | undefined>\n /** jobs.create / jobs.createAndWait only: replaces the auto-generated idempotency-key. */\n idempotencyKey?: string\n}\n\nexport default class Simmit {\n readonly jobs: Jobs\n readonly credits: Credits\n readonly artifacts: Artifacts\n\n readonly baseURL: string\n\n readonly #config: ClientConfig\n\n constructor(options: ClientOptions = {}) {\n const secretKey = options.secretKey ?? readEnv('SIMMIT_SECRET_KEY')\n if (!secretKey) {\n throw new SimmitError(\n 'Missing secret key. Pass secretKey or set SIMMIT_SECRET_KEY.'\n )\n }\n\n this.baseURL =\n options.baseURL ?? readEnv('SIMMIT_BASE_URL') ?? 'https://api.simmit.com'\n\n this.#config = {\n secretKey,\n baseURL: this.baseURL,\n timeout: options.timeout ?? 60_000,\n maxRetries: options.maxRetries ?? 2,\n defaultHeaders: options.defaultHeaders,\n // Resolved lazily so a fetch patched onto globalThis after the client\n // is constructed (msw, APM instrumentation) is still honored.\n fetch: options.fetch ?? ((...args) => globalThis.fetch(...args)),\n fetchOptions: options.fetchOptions\n }\n\n this.jobs = new Jobs(this)\n this.credits = new Credits(this)\n this.artifacts = new Artifacts(this)\n }\n\n /** @internal Resource classes route through here; not public surface. */\n _request<T>(spec: RequestSpec, options?: RequestOptions): APIPromise<T> {\n return makeRequest(this.#config, spec, options)\n }\n}\n\nfunction readEnv(name: string): string | undefined {\n if (typeof process === 'undefined') return undefined\n const value = process.env?.[name]?.trim()\n return value || undefined\n}\n","// Standalone webhook verification. Not a client method: receivers must not\n// need a secret-key-bearing client (whose constructor throws without a key).\n// WebCrypto only, zero deps, and runs in Workers as well as Node.\nimport type { WebhookEvent } from './api-types'\nimport { WebhookVerificationError } from './error'\n\nconst DEFAULT_TOLERANCE_SECONDS = 300\n\n/**\n * Verifies an `X-Simmit-Signature` header (`t=<unix>,v1=<hex>`, an HMAC-SHA256\n * (timing-safe) over `${t}.${rawBody}` within a 300s default tolerance) and\n * returns the parsed event. Throws `WebhookVerificationError` on a bad\n * signature, malformed header, or stale timestamp.\n *\n * Pass `rawBody` exactly as received: re-serializing changes the bytes and\n * breaks verification. `secret` is the webhook signing secret (dashboard →\n * Clients & Keys → Webhook), not your API key.\n */\nexport async function unwrapWebhook(\n rawBody: string,\n signatureHeader: string,\n secret: string,\n options?: { toleranceSeconds?: number }\n): Promise<WebhookEvent> {\n // An empty secret would otherwise surface as an opaque WebCrypto DataError;\n // a NaN tolerance would make the age check pass for everything.\n if (!secret) {\n throw new WebhookVerificationError('Webhook signing secret is empty.')\n }\n const tolerance = options?.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS\n if (!Number.isFinite(tolerance) || tolerance < 0) {\n throw new WebhookVerificationError(\n 'toleranceSeconds must be a non-negative number.'\n )\n }\n\n const { timestampRaw, timestamp, signature } =\n parseSignatureHeader(signatureHeader)\n\n const expected = await hmacSha256Hex(secret, `${timestampRaw}.${rawBody}`)\n if (!timingSafeEqual(expected, signature)) {\n throw new WebhookVerificationError('Webhook signature does not match.')\n }\n\n // Compare on whole seconds, matching the header's unix-seconds `t`.\n if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > tolerance) {\n throw new WebhookVerificationError(\n 'Webhook timestamp is outside the tolerance window.'\n )\n }\n\n try {\n return JSON.parse(rawBody) as WebhookEvent\n } catch {\n throw new WebhookVerificationError('Webhook body is not valid JSON.')\n }\n}\n\nfunction parseSignatureHeader(header: string): {\n timestampRaw: string\n timestamp: number\n signature: string\n} {\n let timestampRaw: string | undefined\n let signature: string | undefined\n for (const part of header.split(',')) {\n const eq = part.indexOf('=')\n if (eq === -1) continue\n const key = part.slice(0, eq).trim()\n const value = part.slice(eq + 1).trim()\n if (key === 't') timestampRaw = value\n else if (key === 'v1') signature = value\n }\n\n // `t` is unix whole seconds; reject anything but digits so the accepted\n // header matches the documented contract.\n if (!timestampRaw || !signature || !/^\\d+$/.test(timestampRaw)) {\n throw new WebhookVerificationError(\n 'Malformed signature header; expected \"t=<unix>,v1=<hex>\".'\n )\n }\n // The signed payload uses the timestamp exactly as sent, so keep the raw\n // string for signing and the parsed number only for the tolerance check.\n return { timestampRaw, timestamp: Number(timestampRaw), signature }\n}\n\nasync function hmacSha256Hex(secret: string, payload: string): Promise<string> {\n const encoder = new TextEncoder()\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n )\n const mac = await crypto.subtle.sign('HMAC', key, encoder.encode(payload))\n return toHex(new Uint8Array(mac))\n}\n\nfunction toHex(bytes: Uint8Array): string {\n let hex = ''\n for (const byte of bytes) hex += byte.toString(16).padStart(2, '0')\n return hex\n}\n\n// Constant-time comparison. The digest width is public, so a length mismatch\n// may short-circuit without leaking secret-dependent timing.\nfunction timingSafeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) return false\n let mismatch = 0\n for (let i = 0; i < a.length; i++) {\n mismatch |= a.charCodeAt(i) ^ b.charCodeAt(i)\n }\n return mismatch === 0\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simmit/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "TypeScript SDK for Simmit, an API for running SimulationCraft (SimC) in the cloud",
5
5
  "license": "MIT",
6
6
  "type": "module",