@signingstudio/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/LICENSE +21 -0
- package/README.md +239 -0
- package/dist/index.cjs +696 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +702 -0
- package/dist/index.d.ts +702 -0
- package/dist/index.js +660 -0
- package/dist/index.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/http.ts","../src/errors/index.ts","../src/resources/documents.ts","../src/resources/templates.ts","../src/client.ts","../src/webhooks.ts"],"sourcesContent":["export { SigningStudio, type ClientOptions } from \"./client.js\";\nexport { Documents } from \"./resources/documents.js\";\nexport { Templates, type PdfInput } from \"./resources/templates.js\";\nexport { verifyWebhook } from \"./webhooks.js\";\nexport {\n SigningStudioError,\n ApiError,\n AuthenticationError,\n NotFoundError,\n ValidationError,\n RateLimitError,\n} from \"./errors/index.js\";\nexport type * from \"./types.js\";\n","import { setTimeout as sleep } from \"node:timers/promises\";\nimport { request as undiciRequest, FormData as UndiciFormData } from \"undici\";\nimport {\n ApiError,\n AuthenticationError,\n NotFoundError,\n RateLimitError,\n SigningStudioError,\n ValidationError,\n} from \"./errors/index.js\";\n\nexport interface HttpClientOptions {\n apiKey: string;\n baseUrl: string;\n maxRetries: number;\n requestTimeoutMs: number;\n userAgent: string;\n /** Test seam — overridable fetch-like transport for the test suite. */\n fetchImpl?: FetchFn;\n}\n\n/**\n * Minimal fetch surface the SDK consumes. Undici's `request` fits this\n * shape; tests use a mocked implementation.\n */\nexport type FetchFn = typeof undiciRequest;\n\n/**\n * Successful response with the envelope unwrapped and rate-limit metadata\n * hoisted to typed fields for easy access.\n */\nexport interface ApiResponse<T> {\n data: T;\n meta: Record<string, unknown>;\n requestId: string | null;\n rateLimit: {\n remainingMinute: number | null;\n remainingDay: number | null;\n limitMinute: number | null;\n limitDay: number | null;\n };\n}\n\nexport interface RequestOptions {\n method: \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n path: string;\n query?: Record<string, string | number | boolean | undefined | null>;\n json?: unknown;\n /**\n * Multipart body — passed straight to undici. Provide a FormData with\n * one entry per field; PDF upload fields must be named `file`.\n */\n form?: UndiciFormData;\n /**\n * If true, the raw response body is returned as a Uint8Array instead of\n * being decoded as JSON. Used for the `?redirect=1` PDF download endpoints.\n */\n binary?: boolean;\n}\n\n/**\n * HTTP transport for the SDK. Wraps undici with:\n * - Authorization header injection\n * - JSON / multipart body handling\n * - Envelope unwrap ({ success, data, meta })\n * - Status → typed error mapping\n * - Bounded retry on 429 (with Retry-After ≤ 60s) + 5xx + network errors\n */\nexport class HttpClient {\n private readonly opts: Required<HttpClientOptions>;\n\n constructor(opts: HttpClientOptions) {\n this.opts = {\n ...opts,\n fetchImpl: opts.fetchImpl ?? undiciRequest,\n };\n }\n\n /**\n * JSON-returning request. Callers get the parsed data + envelope meta +\n * rate-limit + request-id, or a typed error.\n */\n async requestJson<T>(req: RequestOptions): Promise<ApiResponse<T>> {\n const raw = await this.execute(req, \"json\");\n return raw as ApiResponse<T>;\n }\n\n /**\n * Binary-returning request (PDF download). Skips JSON parsing; returns\n * the raw body as a Uint8Array.\n */\n async requestBinary(req: RequestOptions): Promise<Uint8Array> {\n const raw = await this.execute({ ...req, binary: true }, \"binary\");\n return raw as Uint8Array;\n }\n\n private async execute(\n req: RequestOptions,\n kind: \"json\" | \"binary\",\n ): Promise<ApiResponse<unknown> | Uint8Array> {\n const url = this.buildUrl(req.path, req.query);\n const headers: Record<string, string> = {\n authorization: `Bearer ${this.opts.apiKey}`,\n accept: kind === \"binary\" ? \"application/pdf, application/octet-stream, */*\" : \"application/json\",\n \"user-agent\": this.opts.userAgent,\n };\n\n let body: string | Buffer | UndiciFormData | undefined;\n if (req.form !== undefined) {\n body = req.form;\n } else if (req.json !== undefined) {\n body = JSON.stringify(req.json);\n headers[\"content-type\"] = \"application/json\";\n }\n\n let attempt = 0;\n // Retry ceiling: `maxRetries` retries → up to `maxRetries + 1` calls.\n // A retry only fires on transient failures (network error, 429 with\n // short Retry-After, 5xx).\n while (true) {\n let response: Awaited<ReturnType<FetchFn>>;\n try {\n response = await this.opts.fetchImpl(url, {\n method: req.method,\n headers,\n // Only include `body` when we actually have one — undici's\n // RequestOptions.body doesn't accept undefined under\n // exactOptionalPropertyTypes, so conditional-spread it.\n ...(body !== undefined ? { body } : {}),\n bodyTimeout: this.opts.requestTimeoutMs,\n headersTimeout: this.opts.requestTimeoutMs,\n });\n } catch (err) {\n if (attempt >= this.opts.maxRetries) {\n throw new SigningStudioError(\n `Network error contacting Signing Studio: ${(err as Error).message}`,\n { cause: err },\n );\n }\n await sleep(this.backoffMs(attempt));\n attempt += 1;\n continue;\n }\n\n const status = response.statusCode;\n\n if (status >= 200 && status < 300) {\n if (kind === \"binary\") {\n return await this.readBinary(response);\n }\n return await this.parseSuccess(response, status);\n }\n\n // 429 with a short Retry-After → sleep and retry, up to the SDK ceiling.\n if (status === 429 && attempt < this.opts.maxRetries) {\n const retryAfter = this.extractRetryAfter(response);\n if (retryAfter !== null && retryAfter <= 60) {\n await sleep(retryAfter * 1000);\n attempt += 1;\n continue;\n }\n }\n\n // Transient server errors → exponential backoff.\n if (status >= 500 && attempt < this.opts.maxRetries) {\n await sleep(this.backoffMs(attempt));\n attempt += 1;\n continue;\n }\n\n throw await this.buildApiError(response, status);\n }\n }\n\n private buildUrl(\n path: string,\n query: Record<string, string | number | boolean | undefined | null> | undefined,\n ): string {\n const base = `${this.opts.baseUrl.replace(/\\/$/, \"\")}/api/v1/`;\n const url = new URL(path.replace(/^\\/+/, \"\"), base);\n if (query) {\n for (const [k, v] of Object.entries(query)) {\n if (v === undefined || v === null) continue;\n url.searchParams.set(k, String(v));\n }\n }\n return url.toString();\n }\n\n private async parseSuccess(\n response: Awaited<ReturnType<FetchFn>>,\n status: number,\n ): Promise<ApiResponse<unknown>> {\n const bodyStr = await this.readText(response);\n const requestId = this.headerString(response, \"x-request-id\");\n if (bodyStr === \"\") {\n return {\n data: null,\n meta: {},\n requestId,\n rateLimit: this.readRateLimit(response),\n };\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(bodyStr);\n } catch (err) {\n throw new SigningStudioError(\n `Malformed JSON in server response (HTTP ${status})`,\n { cause: err },\n );\n }\n const envelope =\n typeof parsed === \"object\" && parsed !== null\n ? (parsed as { data?: unknown; meta?: unknown })\n : {};\n return {\n data: envelope.data ?? null,\n meta:\n typeof envelope.meta === \"object\" && envelope.meta !== null\n ? (envelope.meta as Record<string, unknown>)\n : {},\n requestId,\n rateLimit: this.readRateLimit(response),\n };\n }\n\n private readRateLimit(response: Awaited<ReturnType<FetchFn>>): ApiResponse<unknown>[\"rateLimit\"] {\n return {\n remainingMinute: this.parseIntHeader(response, \"x-ratelimit-remaining-minute\"),\n remainingDay: this.parseIntHeader(response, \"x-ratelimit-remaining-day\"),\n limitMinute: this.parseIntHeader(response, \"x-ratelimit-limit-minute\"),\n limitDay: this.parseIntHeader(response, \"x-ratelimit-limit-day\"),\n };\n }\n\n private async buildApiError(\n response: Awaited<ReturnType<FetchFn>>,\n status: number,\n ): Promise<ApiError> {\n let body: Record<string, unknown> | null = null;\n let message = `Signing Studio API returned HTTP ${status}`;\n let requestId = this.headerString(response, \"x-request-id\");\n\n const raw = await this.readText(response);\n if (raw !== \"\") {\n try {\n const parsed = JSON.parse(raw);\n if (typeof parsed === \"object\" && parsed !== null) {\n body = parsed as Record<string, unknown>;\n if (typeof body.message === \"string\") message = body.message;\n if (!requestId && typeof body.requestId === \"string\") requestId = body.requestId;\n }\n } catch {\n // Non-JSON error body — keep the generic message.\n }\n }\n\n const init = { statusCode: status, requestId, body };\n switch (status) {\n case 401:\n return new AuthenticationError(message, init);\n case 404:\n return new NotFoundError(message, init);\n case 422: {\n const errors =\n body && typeof body.errors === \"object\" && body.errors !== null\n ? (body.errors as Record<string, string[]>)\n : {};\n return new ValidationError(message, { ...init, errors });\n }\n case 429:\n return new RateLimitError(message, {\n ...init,\n retryAfter: this.extractRetryAfter(response),\n window: this.headerString(response, \"x-ratelimit-window\"),\n });\n default:\n return new ApiError(message, init);\n }\n }\n\n private extractRetryAfter(response: Awaited<ReturnType<FetchFn>>): number | null {\n const raw = this.headerString(response, \"retry-after\");\n if (raw === null) return null;\n const n = Number(raw);\n return Number.isFinite(n) ? Math.trunc(n) : null;\n }\n\n private headerString(response: Awaited<ReturnType<FetchFn>>, name: string): string | null {\n const value = response.headers[name];\n if (value === undefined) return null;\n if (Array.isArray(value)) return value[0] ?? null;\n return String(value);\n }\n\n private parseIntHeader(response: Awaited<ReturnType<FetchFn>>, name: string): number | null {\n const s = this.headerString(response, name);\n if (s === null) return null;\n const n = Number(s);\n return Number.isFinite(n) ? Math.trunc(n) : null;\n }\n\n private async readText(response: Awaited<ReturnType<FetchFn>>): Promise<string> {\n try {\n return await response.body.text();\n } catch {\n return \"\";\n }\n }\n\n private async readBinary(response: Awaited<ReturnType<FetchFn>>): Promise<Uint8Array> {\n const chunks: Buffer[] = [];\n for await (const chunk of response.body) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return new Uint8Array(Buffer.concat(chunks));\n }\n\n /**\n * Exponential backoff (500 ms · 1 s · 2 s · 4 s) plus a small jitter to\n * avoid herd effects when many callers retry at once.\n */\n private backoffMs(attempt: number): number {\n const base = 500 * 2 ** attempt;\n const jitter = Math.floor(Math.random() * (base / 4));\n return base + jitter;\n }\n}\n","/**\n * Every exception the SDK throws extends {@link SigningStudioError}, so\n * integrators can catch a single type at the outer boundary of their code\n * and inspect the subclass for specifics.\n *\n * try {\n * await client.documents.send(payload);\n * } catch (err) {\n * if (err instanceof ValidationError) { /* field-map available */ }\n * if (err instanceof RateLimitError) { /* retryAfter, window */ }\n * if (err instanceof SigningStudioError) { /* fallback */ }\n * throw err;\n * }\n */\n\nexport class SigningStudioError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.name = \"SigningStudioError\";\n if (options?.cause !== undefined) {\n // Node 18+ supports the standard Error `cause` option; older\n // versions won't, so we set it explicitly to keep the field.\n (this as { cause?: unknown }).cause = options.cause;\n }\n }\n}\n\nexport interface ApiErrorInit {\n statusCode: number;\n requestId?: string | null;\n body?: Record<string, unknown> | null;\n}\n\n/**\n * Non-2xx HTTP response from the API. Carries the parsed error envelope,\n * the request id (for support tickets), and the status code (for\n * programmatic branching).\n */\nexport class ApiError extends SigningStudioError {\n readonly statusCode: number;\n readonly requestId: string | null;\n readonly body: Record<string, unknown> | null;\n\n constructor(message: string, init: ApiErrorInit) {\n super(message);\n this.name = \"ApiError\";\n this.statusCode = init.statusCode;\n this.requestId = init.requestId ?? null;\n this.body = init.body ?? null;\n }\n}\n\n/** HTTP 401 — API key missing, unknown, or the account behind it is inactive. */\nexport class AuthenticationError extends ApiError {\n constructor(message: string, init: ApiErrorInit) {\n super(message, init);\n this.name = \"AuthenticationError\";\n }\n}\n\n/** HTTP 404 — resource does not exist under the caller's account. */\nexport class NotFoundError extends ApiError {\n constructor(message: string, init: ApiErrorInit) {\n super(message, init);\n this.name = \"NotFoundError\";\n }\n}\n\nexport interface ValidationErrorInit extends ApiErrorInit {\n errors: Record<string, string[]>;\n}\n\n/**\n * HTTP 422 — Zod-level or business-rule validation failure. `errors` is\n * the field-name → messages map from the server; empty when the failure\n * was purely business-rule (e.g. prefill of a signature field).\n */\nexport class ValidationError extends ApiError {\n readonly errors: Record<string, string[]>;\n\n constructor(message: string, init: ValidationErrorInit) {\n super(message, init);\n this.name = \"ValidationError\";\n this.errors = init.errors;\n }\n}\n\nexport interface RateLimitErrorInit extends ApiErrorInit {\n retryAfter: number | null;\n window: string | null;\n}\n\n/**\n * HTTP 429 — rate limit or monthly quota. `retryAfter` is present for\n * sliding-window rate limits (seconds until safe to retry) and null for\n * monthly quota exhaustion.\n */\nexport class RateLimitError extends ApiError {\n readonly retryAfter: number | null;\n readonly window: string | null;\n\n constructor(message: string, init: RateLimitErrorInit) {\n super(message, init);\n this.name = \"RateLimitError\";\n this.retryAfter = init.retryAfter;\n this.window = init.window;\n }\n}\n","import type { HttpClient } from \"../http.js\";\nimport type {\n ActivityEntry,\n DeleteResponse,\n DocumentDetail,\n DocumentListParams,\n DocumentListResponse,\n DocumentProgress,\n PresignedUrl,\n RemindResponse,\n SendDocumentPayload,\n SuccessAck,\n} from \"../types.js\";\n\n/**\n * Documents resource — send documents from templates, poll status,\n * download completed PDFs, remind signers.\n *\n * Every method returns the parsed data payload. If you need the full\n * envelope (rate-limit headers, request id) drop down to\n * `client.http.requestJson`.\n */\nexport class Documents {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List documents. All parameters are optional.\n *\n * The `view` toggle controls which lifecycle bucket to read from:\n * - `active` (default) — non-archived, non-deleted\n * - `archived` — archived only\n * - `deleted` — soft-deleted only\n * - `all` — active + archived, still excludes trash\n */\n async list(params: DocumentListParams = {}): Promise<DocumentListResponse> {\n const response = await this.http.requestJson<DocumentListResponse[\"data\"]>({\n method: \"GET\",\n path: \"documents\",\n query: {\n status: params.status,\n view: params.view,\n limit: params.limit,\n offset: params.offset,\n },\n });\n return {\n data: response.data ?? [],\n meta: (response.meta as unknown as DocumentListResponse[\"meta\"]) ?? {\n total: 0,\n limit: 50,\n offset: 0,\n view: params.view ?? \"active\",\n },\n };\n }\n\n /**\n * Send a new document built from a template.\n *\n * Server-side rules to be aware of (surfaced as {@link import(\"../errors/index.js\").ValidationError}):\n * - `template_id` is required.\n * - At least one recipient must be supplied.\n * - `prefill_values[]` needs either `field_id` or `field_name` + `value`.\n * - Signature / initials fields can't be prefilled.\n * - Any template field that is both required AND readonly must be prefilled.\n *\n * Successful sends count against the account's monthly document quota.\n */\n async send(payload: SendDocumentPayload): Promise<DocumentDetail> {\n const response = await this.http.requestJson<DocumentDetail>({\n method: \"POST\",\n path: \"documents\",\n json: payload,\n });\n return response.data;\n }\n\n async get(id: string): Promise<DocumentDetail> {\n const response = await this.http.requestJson<DocumentDetail>({\n method: \"GET\",\n path: `documents/${encodeURIComponent(id)}`,\n });\n return response.data;\n }\n\n /**\n * Delete a document. `hard: true` also purges the file from storage.\n * Only valid on cancelled / completed / declined / expired documents;\n * cancel first if the document is still in flight.\n */\n async delete(id: string, options: { hard?: boolean } = {}): Promise<DeleteResponse> {\n const response = await this.http.requestJson<DeleteResponse>({\n method: \"DELETE\",\n path: `documents/${encodeURIComponent(id)}`,\n ...(options.hard && { query: { hard: \"true\" } }),\n });\n return response.data;\n }\n\n async restore(id: string): Promise<SuccessAck> {\n return (\n await this.http.requestJson<SuccessAck>({\n method: \"POST\",\n path: `documents/${encodeURIComponent(id)}/restore`,\n })\n ).data;\n }\n\n async archive(id: string): Promise<SuccessAck> {\n return (\n await this.http.requestJson<SuccessAck>({\n method: \"POST\",\n path: `documents/${encodeURIComponent(id)}/archive`,\n })\n ).data;\n }\n\n async unarchive(id: string): Promise<SuccessAck> {\n return (\n await this.http.requestJson<SuccessAck>({\n method: \"POST\",\n path: `documents/${encodeURIComponent(id)}/unarchive`,\n })\n ).data;\n }\n\n async cancel(id: string): Promise<SuccessAck> {\n return (\n await this.http.requestJson<SuccessAck>({\n method: \"POST\",\n path: `documents/${encodeURIComponent(id)}/cancel`,\n })\n ).data;\n }\n\n /**\n * Read the current signing progress — cheaper than {@link get} when\n * polling. Returns overall counts plus per-recipient state, no field\n * or template data.\n */\n async progress(id: string): Promise<DocumentProgress> {\n return (\n await this.http.requestJson<DocumentProgress>({\n method: \"GET\",\n path: `documents/${encodeURIComponent(id)}/progress`,\n })\n ).data;\n }\n\n /**\n * Get a presigned download URL for the document PDF. For completed\n * documents this is the flattened final PDF plus the audit-trail page;\n * while in flight it's the in-progress snapshot (or source PDF if no\n * signatures yet).\n */\n async downloadUrl(id: string): Promise<PresignedUrl> {\n return (\n await this.http.requestJson<PresignedUrl>({\n method: \"GET\",\n path: `documents/${encodeURIComponent(id)}/download`,\n })\n ).data;\n }\n\n /**\n * Fetch the document PDF as raw bytes in one call (follows the presigned\n * URL redirect server-side). Handy for saving straight to disk.\n */\n async downloadPdf(id: string): Promise<Uint8Array> {\n return await this.http.requestBinary({\n method: \"GET\",\n path: `documents/${encodeURIComponent(id)}/download`,\n query: { redirect: \"1\" },\n });\n }\n\n async activity(id: string): Promise<ActivityEntry[]> {\n const response = await this.http.requestJson<ActivityEntry[]>({\n method: \"GET\",\n path: `documents/${encodeURIComponent(id)}/activity`,\n });\n return response.data ?? [];\n }\n\n /**\n * Re-send the signing invite (or first invite, if it hasn't gone out\n * yet) to a specific recipient. Response includes a freshly-minted\n * signing URL — this is the only endpoint where a URL is returned in\n * plaintext, so capture it if you need to relay it out-of-band.\n */\n async remind(documentId: string, recipientId: string): Promise<RemindResponse> {\n return (\n await this.http.requestJson<RemindResponse>({\n method: \"POST\",\n path: `documents/${encodeURIComponent(documentId)}/recipients/${encodeURIComponent(recipientId)}/remind`,\n })\n ).data;\n }\n}\n","import { readFile } from \"node:fs/promises\";\nimport { Buffer } from \"node:buffer\";\n// Blob is globally available since Node 18 (WHATWG); undici@6+ no longer re-exports it.\nimport { FormData as UndiciFormData } from \"undici\";\nimport type { HttpClient } from \"../http.js\";\nimport type {\n PresignedUrl,\n SuccessAck,\n TemplateDetail,\n TemplateFieldInput,\n TemplateHistoryEntry,\n TemplateListItem,\n TemplateMetadata,\n TemplateField,\n} from \"../types.js\";\n\n/** Anything the SDK accepts as a PDF payload. */\nexport type PdfInput =\n | string // filesystem path\n | Uint8Array | Buffer // raw bytes\n | Blob // web Blob\n | { path: string } // explicit path wrapper\n | { data: Uint8Array | Buffer; filename?: string; contentType?: string };\n\n/**\n * Templates resource — create / update / version PDF templates.\n *\n * PDF upload constraints (server-enforced, 400 on violation):\n * - Max 50 MB per file\n * - `application/pdf` only\n * - Multipart form field must be `file` — the SDK sets this for you\n */\nexport class Templates {\n constructor(private readonly http: HttpClient) {}\n\n async list(): Promise<TemplateListItem[]> {\n const response = await this.http.requestJson<TemplateListItem[]>({\n method: \"GET\",\n path: \"templates\",\n });\n return response.data ?? [];\n }\n\n /**\n * Create a new template from a PDF plus metadata.\n *\n * The `pdf` argument can be a filesystem path, a Uint8Array/Buffer of\n * raw bytes, a Blob, or an object with an explicit filename. See\n * {@link PdfInput}.\n */\n async create(\n pdf: PdfInput,\n metadata: TemplateMetadata,\n options: { filename?: string } = {},\n ): Promise<TemplateDetail> {\n const form = await this.buildPdfForm(pdf, options.filename, metadata);\n const response = await this.http.requestJson<TemplateDetail>({\n method: \"POST\",\n path: \"templates\",\n form,\n });\n return response.data;\n }\n\n async get(id: string): Promise<TemplateDetail> {\n return (\n await this.http.requestJson<TemplateDetail>({\n method: \"GET\",\n path: `templates/${encodeURIComponent(id)}`,\n })\n ).data;\n }\n\n async update(id: string, metadata: TemplateMetadata): Promise<TemplateDetail> {\n return (\n await this.http.requestJson<TemplateDetail>({\n method: \"PATCH\",\n path: `templates/${encodeURIComponent(id)}`,\n json: metadata,\n })\n ).data;\n }\n\n /**\n * Soft-delete. There is no hard-delete on this route; contact support\n * if you need permanent removal.\n */\n async delete(id: string): Promise<SuccessAck> {\n return (\n await this.http.requestJson<SuccessAck>({\n method: \"DELETE\",\n path: `templates/${encodeURIComponent(id)}`,\n })\n ).data;\n }\n\n async pdfUrl(id: string): Promise<PresignedUrl> {\n return (\n await this.http.requestJson<PresignedUrl>({\n method: \"GET\",\n path: `templates/${encodeURIComponent(id)}/pdf`,\n })\n ).data;\n }\n\n async downloadPdf(id: string): Promise<Uint8Array> {\n return await this.http.requestBinary({\n method: \"GET\",\n path: `templates/${encodeURIComponent(id)}/pdf`,\n query: { redirect: \"1\" },\n });\n }\n\n /**\n * Replace the template's PDF. Prior versions are kept in history —\n * download via {@link historyPdfUrl}.\n */\n async replacePdf(\n id: string,\n pdf: PdfInput,\n options: { filename?: string } = {},\n ): Promise<TemplateDetail> {\n const form = await this.buildPdfForm(pdf, options.filename);\n return (\n await this.http.requestJson<TemplateDetail>({\n method: \"PUT\",\n path: `templates/${encodeURIComponent(id)}/pdf`,\n form,\n })\n ).data;\n }\n\n /**\n * Replace ALL fields on the template. The server deletes existing rows\n * and inserts the supplied set — the SDK does not support partial\n * updates because the server doesn't.\n */\n async setFields(id: string, fields: TemplateFieldInput[]): Promise<TemplateField[]> {\n const response = await this.http.requestJson<TemplateField[]>({\n method: \"PUT\",\n path: `templates/${encodeURIComponent(id)}/fields`,\n json: { fields },\n });\n return response.data ?? [];\n }\n\n async duplicate(id: string): Promise<TemplateDetail> {\n return (\n await this.http.requestJson<TemplateDetail>({\n method: \"POST\",\n path: `templates/${encodeURIComponent(id)}/duplicate`,\n })\n ).data;\n }\n\n async archive(id: string): Promise<SuccessAck> {\n return (\n await this.http.requestJson<SuccessAck>({\n method: \"POST\",\n path: `templates/${encodeURIComponent(id)}/archive`,\n })\n ).data;\n }\n\n async history(id: string): Promise<TemplateHistoryEntry[]> {\n const response = await this.http.requestJson<TemplateHistoryEntry[]>({\n method: \"GET\",\n path: `templates/${encodeURIComponent(id)}/history`,\n });\n return response.data ?? [];\n }\n\n async historyPdfUrl(templateId: string, historyId: number): Promise<PresignedUrl> {\n return (\n await this.http.requestJson<PresignedUrl>({\n method: \"GET\",\n path: `templates/${encodeURIComponent(templateId)}/history/${historyId}/pdf`,\n })\n ).data;\n }\n\n async downloadHistoryPdf(templateId: string, historyId: number): Promise<Uint8Array> {\n return await this.http.requestBinary({\n method: \"GET\",\n path: `templates/${encodeURIComponent(templateId)}/history/${historyId}/pdf`,\n query: { redirect: \"1\" },\n });\n }\n\n /**\n * Build the multipart form: PDF blob under field name `file` (required\n * by the server) + JSON-encoded scalar/array metadata fields.\n *\n * Nested arrays/objects (like `signers`, `delivery_methods`) are\n * serialized with JSON.stringify so they survive the form-data trip —\n * the server route unwraps them.\n */\n private async buildPdfForm(\n pdf: PdfInput,\n filenameOverride?: string,\n metadata?: TemplateMetadata,\n ): Promise<UndiciFormData> {\n const form = new UndiciFormData();\n if (metadata) {\n for (const [key, value] of Object.entries(metadata)) {\n if (value === undefined || value === null) continue;\n const encoded =\n typeof value === \"string\" ? value : JSON.stringify(value);\n form.append(key, encoded);\n }\n }\n const { blob, filename } = await this.resolvePdf(pdf, filenameOverride);\n form.append(\"file\", blob, filename);\n return form;\n }\n\n private async resolvePdf(\n pdf: PdfInput,\n override: string | undefined,\n ): Promise<{ blob: Blob; filename: string }> {\n if (typeof pdf === \"string\") {\n const data = await readFile(pdf);\n return {\n blob: new Blob([data], { type: \"application/pdf\" }),\n filename: override ?? basename(pdf),\n };\n }\n if (pdf instanceof Uint8Array) {\n return {\n blob: new Blob([pdf], { type: \"application/pdf\" }),\n filename: override ?? \"template.pdf\",\n };\n }\n if (pdf instanceof Blob) {\n return { blob: pdf, filename: override ?? \"template.pdf\" };\n }\n if (\"path\" in pdf) {\n const data = await readFile(pdf.path);\n return {\n blob: new Blob([data], { type: \"application/pdf\" }),\n filename: override ?? basename(pdf.path),\n };\n }\n return {\n blob: new Blob([pdf.data], { type: pdf.contentType ?? \"application/pdf\" }),\n filename: override ?? pdf.filename ?? \"template.pdf\",\n };\n }\n}\n\n/**\n * Tiny filename helper — avoids pulling in `node:path` for one call and\n * works with both `/` and `\\` separators (Windows friendliness).\n */\nfunction basename(p: string): string {\n const trimmed = p.replace(/[\\\\/]+$/, \"\");\n const idx = Math.max(trimmed.lastIndexOf(\"/\"), trimmed.lastIndexOf(\"\\\\\"));\n return idx === -1 ? trimmed : trimmed.slice(idx + 1);\n}\n","import { HttpClient, type FetchFn } from \"./http.js\";\nimport { Documents } from \"./resources/documents.js\";\nimport { Templates } from \"./resources/templates.js\";\n\nexport interface ClientOptions {\n /** Your API key from Signing Studio → Settings → API Keys. Required. */\n apiKey: string;\n /** Override for staging / self-hosted deployments. Default: production. */\n baseUrl?: string;\n /** How many times to retry transient failures (429 short Retry-After, 5xx, network). Default 3. */\n maxRetries?: number;\n /** Full request-timeout in milliseconds — generous by default so a 50 MB PDF upload has time to finish. */\n requestTimeoutMs?: number;\n /** Custom User-Agent — replace or extend with your app's identifier. */\n userAgent?: string;\n /**\n * Test-only seam. Replace the transport with a mocked implementation\n * in the test suite. Undici's `request` fits by default.\n */\n fetchImpl?: FetchFn;\n}\n\n/**\n * Top-level entry point for the Signing Studio Node.js SDK.\n *\n * import { SigningStudio } from \"@signingstudio/sdk\";\n *\n * const client = new SigningStudio({ apiKey: process.env.SIGNING_STUDIO_API_KEY! });\n * const doc = await client.documents.send({\n * template_id: \"…\",\n * title: \"MSA — Acme\",\n * recipients: [{ name: \"Alex\", email: \"alex@acme.com\" }],\n * });\n *\n * The Client is safe to reuse across concurrent requests. Undici keeps an\n * internal connection pool per host, which is the recommended shape for\n * long-running processes (workers, cron, servers).\n */\nexport class SigningStudio {\n readonly documents: Documents;\n readonly templates: Templates;\n /** Escape hatch — the raw HTTP layer for callers that need to consume\n * headers (rate-limit remaining, request id) alongside the parsed data. */\n readonly http: HttpClient;\n\n constructor(options: ClientOptions) {\n if (!options.apiKey) {\n throw new TypeError(\"SigningStudio: `apiKey` is required\");\n }\n this.http = new HttpClient({\n apiKey: options.apiKey,\n baseUrl: options.baseUrl ?? \"https://api.signingstudio.com\",\n maxRetries: options.maxRetries ?? 3,\n requestTimeoutMs: options.requestTimeoutMs ?? 120_000,\n userAgent: options.userAgent ?? \"signingstudio-node/1.0\",\n fetchImpl: options.fetchImpl ?? (undefined as unknown as FetchFn),\n });\n this.documents = new Documents(this.http);\n this.templates = new Templates(this.http);\n }\n}\n","import { createHmac, timingSafeEqual } from \"node:crypto\";\nimport { Buffer } from \"node:buffer\";\n\n/**\n * Verify an incoming Signing Studio webhook delivery.\n *\n * The server signs the raw JSON body with HMAC-SHA256 keyed on the\n * webhook's secret and sends it as `X-DDS-Signature: sha256=<hex>`.\n *\n * Usage (Express-style example):\n *\n * import express from \"express\";\n * import { verifyWebhook } from \"@signingstudio/sdk\";\n *\n * const app = express();\n * app.post(\"/webhooks/signing-studio\",\n * express.raw({ type: \"application/json\" }), // do NOT pre-parse\n * (req, res) => {\n * const ok = verifyWebhook(req.body, req.get(\"X-DDS-Signature\"), SECRET);\n * if (!ok) return res.status(401).end();\n * const payload = JSON.parse(req.body.toString(\"utf8\"));\n * // ...act on payload.event\n * res.status(200).end();\n * }\n * );\n *\n * You MUST pass the RAW body — a parsed & re-serialized body will fail\n * verification, even if it looks identical.\n */\nexport function verifyWebhook(\n rawBody: string | Uint8Array | Buffer,\n header: string | null | undefined,\n secret: string,\n): boolean {\n if (!secret || typeof secret !== \"string\") {\n throw new TypeError(\"verifyWebhook: secret must be a non-empty string\");\n }\n if (header == null || header === \"\") return false;\n\n const received = header.startsWith(\"sha256=\") ? header.slice(\"sha256=\".length) : header;\n // Hex is length-fixed; a fast-fail rejects payloads mangled in transit\n // before we spend cycles on the HMAC.\n if (received.length !== 64 || !/^[0-9a-f]+$/i.test(received)) return false;\n\n const bodyBuf =\n typeof rawBody === \"string\"\n ? Buffer.from(rawBody, \"utf8\")\n : Buffer.from(rawBody);\n const expected = createHmac(\"sha256\", secret).update(bodyBuf).digest(\"hex\");\n\n const receivedBuf = Buffer.from(received, \"hex\");\n const expectedBuf = Buffer.from(expected, \"hex\");\n if (receivedBuf.length !== expectedBuf.length) return false;\n return timingSafeEqual(expectedBuf, receivedBuf);\n}\n"],"mappings":"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","names":["undiciRequest","sleep","import_promises","import_undici","UndiciFormData"]}
|