@pdfcraft-dev/pdf 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -196,11 +196,12 @@ access to run your unit tests.
196
196
 
197
197
  ## Contributing
198
198
 
199
- This repository is generated from the PDFCraft monorepo, where the client and the API share
200
- one source of truth for option types and error codes. That means **pull requests here get
201
- overwritten** on the next release.
199
+ Issues and pull requests are welcome.
202
200
 
203
- Bug reports and API feedback are very welcome as issues that is what this repo is for.
201
+ One exception: `src/contract/` is generated from the API's own option, plan and error
202
+ definitions, so the client and the server cannot disagree about them. A change there has to
203
+ start on the server side — open an issue and it will come back through as a release.
204
+ Everything else is ordinary source.
204
205
 
205
206
  ## License
206
207
 
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/sdk/src/client.ts\nimport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n RenderRequest,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n} from './contract/index.js';\nimport { PDFCraftError, toError } from './errors.js';\n\nexport interface RendererOptions {\n /** Override for testing or a self-hosted gateway. */\n baseUrl?: string;\n /** Retries on 429 and 5xx only. Default 3. */\n maxRetries?: number;\n /** Per-request timeout in milliseconds. Default 130000, just past the API's own ceiling. */\n timeoutMs?: number;\n fetch?: typeof globalThis.fetch;\n}\n\nconst DEFAULTS = {\n baseUrl: 'https://api.pdfcraft.dev',\n maxRetries: 3,\n timeoutMs: 130_000,\n};\n\n/**\n * The method you call decides the output mode, so passing `output` yourself\n * could only ever contradict it. Excluded from the type rather than ignored at\n * runtime: `render({ output: 'url' })` returning bytes is the kind of silent\n * surprise that costs someone an afternoon.\n */\nexport type RenderInput = Omit<RenderRequest, 'output'>;\nexport type AsyncRenderInput = Omit<AsyncRenderRequest, 'output'>;\n\nexport class Renderer {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly doFetch: typeof globalThis.fetch;\n\n constructor(apiKey: string, options: RendererOptions = {}) {\n if (!apiKey) throw new PDFCraftError('invalid_api_key', 'An API key is required.', 401);\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULTS.baseUrl).replace(/\\/+$/, '');\n this.maxRetries = options.maxRetries ?? DEFAULTS.maxRetries;\n this.timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs;\n this.doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The PDF bytes. In Node this is a Buffer, which is a Uint8Array. */\n async render(input: RenderInput, idempotencyKey?: string): Promise<Uint8Array> {\n const response = await this.send('/v1/render', { ...input, output: 'binary' }, idempotencyKey);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return typeof Buffer === 'undefined' ? bytes : Buffer.from(bytes);\n }\n\n /** Uploads the PDF and returns a signed link instead of the bytes. */\n async renderToUrl(input: RenderInput, idempotencyKey?: string): Promise<RenderUrlResponse> {\n const response = await this.send('/v1/render', { ...input, output: 'url' }, idempotencyKey);\n return (await response.json()) as RenderUrlResponse;\n }\n\n /** Queues the render and calls back when it settles. */\n async renderAsync(\n input: AsyncRenderInput,\n idempotencyKey?: string,\n ): Promise<AsyncRenderAccepted> {\n const response = await this.send('/v1/render/async', input, idempotencyKey);\n return (await response.json()) as AsyncRenderAccepted;\n }\n\n async getRender(id: string): Promise<RenderStatusResponse> {\n const response = await this.request(`/v1/renders/${encodeURIComponent(id)}`, { method: 'GET' });\n return (await response.json()) as RenderStatusResponse;\n }\n\n async usage(): Promise<UsageResponse> {\n const response = await this.request('/v1/usage', { method: 'GET' });\n return (await response.json()) as UsageResponse;\n }\n\n private send(path: string, body: unknown, idempotencyKey?: string): Promise<Response> {\n return this.request(path, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(idempotencyKey ? { 'idempotency-key': idempotencyKey } : {}),\n },\n body: JSON.stringify(body),\n });\n }\n\n private async request(path: string, init: RequestInit): Promise<Response> {\n let lastError: PDFCraftError | null = null;\n for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {\n let response: Response;\n try {\n response = await this.doFetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n authorization: `Bearer ${this.apiKey}`,\n 'user-agent': 'pdfcraft-sdk-js/1.0.0',\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n } catch (cause) {\n lastError = new PDFCraftError('network_error', `Could not reach PDFCraft: ${cause}`, 0);\n if (attempt === this.maxRetries) throw lastError;\n await sleep(backoffMs(attempt));\n continue;\n }\n\n if (response.ok) return response;\n\n const error = toError(response.status, await response.text());\n // 4xx other than 429 will fail identically no matter how many times we ask.\n if (!error.retryable || attempt === this.maxRetries) throw error;\n lastError = error;\n await sleep(retryAfterMs(response) ?? backoffMs(attempt));\n }\n throw lastError ?? new PDFCraftError('internal_error', 'Request failed.', 500);\n }\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.round(500 * 2 ** attempt * (0.75 + Math.random() * 0.5));\n}\n\nfunction retryAfterMs(response: Response): number | null {\n const header = response.headers.get('retry-after');\n if (!header) return null;\n const seconds = Number(header);\n return Number.isFinite(seconds) ? Math.max(0, seconds) * 1000 : null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":";;;AASA,2CAAqD;AAYrD,MAAM,QAAQ,GAAG;IACf,OAAO,EAAE,0BAA0B;IACnC,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,OAAO;CACnB,CAAC;AAWF,MAAa,QAAQ;IACF,MAAM,CAAS;IACf,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,SAAS,CAAS;IAClB,OAAO,CAA0B;IAElD,YAAY,MAAc,EAAE,UAA2B,EAAE;QACvD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,yBAAa,CAAC,iBAAiB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;QACxF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC;QACzD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,MAAM,CAAC,KAAkB,EAAE,cAAuB;QACtD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,cAAc,CAAC,CAAC;QAC/F,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3D,OAAO,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,WAAW,CAAC,KAAkB,EAAE,cAAuB;QAC3D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,cAAc,CAAC,CAAC;QAC5F,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB,CAAC;IACtD,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,WAAW,CACf,KAAuB,EACvB,cAAuB;QAEvB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;QAC5E,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAChG,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAkB,CAAC;IAClD,CAAC;IAEO,IAAI,CAAC,IAAY,EAAE,IAAa,EAAE,cAAuB;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjE;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,IAAiB;QACnD,IAAI,SAAS,GAAyB,IAAI,CAAC;QAC3C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YAC/D,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;oBACtD,GAAG,IAAI;oBACP,OAAO,EAAE;wBACP,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;wBACtC,YAAY,EAAE,uBAAuB;wBACrC,GAAI,IAAI,CAAC,OAA8C;qBACxD;oBACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;iBAC5C,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,IAAI,yBAAa,CAAC,eAAe,EAAE,6BAA6B,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;gBACxF,IAAI,OAAO,KAAK,IAAI,CAAC,UAAU;oBAAE,MAAM,SAAS,CAAC;gBACjD,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBAChC,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,CAAC,EAAE;gBAAE,OAAO,QAAQ,CAAC;YAEjC,MAAM,KAAK,GAAG,IAAA,mBAAO,EAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9D,4EAA4E;YAC5E,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,KAAK,IAAI,CAAC,UAAU;gBAAE,MAAM,KAAK,CAAC;YACjE,SAAS,GAAG,KAAK,CAAC;YAClB,MAAM,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,SAAS,IAAI,IAAI,yBAAa,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACjF,CAAC;CACF;AA1FD,4BA0FC;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,YAAY,CAAC,QAAkB;IACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["// src/client.ts\nimport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n RenderRequest,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n} from './contract/index.js';\nimport { PDFCraftError, toError } from './errors.js';\n\nexport interface RendererOptions {\n /** Override for testing or a self-hosted gateway. */\n baseUrl?: string;\n /** Retries on 429 and 5xx only. Default 3. */\n maxRetries?: number;\n /** Per-request timeout in milliseconds. Default 130000, just past the API's own ceiling. */\n timeoutMs?: number;\n fetch?: typeof globalThis.fetch;\n}\n\nconst DEFAULTS = {\n baseUrl: 'https://api.pdfcraft.dev',\n maxRetries: 3,\n timeoutMs: 130_000,\n};\n\n/**\n * The method you call decides the output mode, so passing `output` yourself\n * could only ever contradict it. Excluded from the type rather than ignored at\n * runtime: `render({ output: 'url' })` returning bytes is the kind of silent\n * surprise that costs someone an afternoon.\n */\nexport type RenderInput = Omit<RenderRequest, 'output'>;\nexport type AsyncRenderInput = Omit<AsyncRenderRequest, 'output'>;\n\nexport class Renderer {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly doFetch: typeof globalThis.fetch;\n\n constructor(apiKey: string, options: RendererOptions = {}) {\n if (!apiKey) throw new PDFCraftError('invalid_api_key', 'An API key is required.', 401);\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULTS.baseUrl).replace(/\\/+$/, '');\n this.maxRetries = options.maxRetries ?? DEFAULTS.maxRetries;\n this.timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs;\n this.doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The PDF bytes. In Node this is a Buffer, which is a Uint8Array. */\n async render(input: RenderInput, idempotencyKey?: string): Promise<Uint8Array> {\n const response = await this.send('/v1/render', { ...input, output: 'binary' }, idempotencyKey);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return typeof Buffer === 'undefined' ? bytes : Buffer.from(bytes);\n }\n\n /** Uploads the PDF and returns a signed link instead of the bytes. */\n async renderToUrl(input: RenderInput, idempotencyKey?: string): Promise<RenderUrlResponse> {\n const response = await this.send('/v1/render', { ...input, output: 'url' }, idempotencyKey);\n return (await response.json()) as RenderUrlResponse;\n }\n\n /** Queues the render and calls back when it settles. */\n async renderAsync(\n input: AsyncRenderInput,\n idempotencyKey?: string,\n ): Promise<AsyncRenderAccepted> {\n const response = await this.send('/v1/render/async', input, idempotencyKey);\n return (await response.json()) as AsyncRenderAccepted;\n }\n\n async getRender(id: string): Promise<RenderStatusResponse> {\n const response = await this.request(`/v1/renders/${encodeURIComponent(id)}`, { method: 'GET' });\n return (await response.json()) as RenderStatusResponse;\n }\n\n async usage(): Promise<UsageResponse> {\n const response = await this.request('/v1/usage', { method: 'GET' });\n return (await response.json()) as UsageResponse;\n }\n\n private send(path: string, body: unknown, idempotencyKey?: string): Promise<Response> {\n return this.request(path, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(idempotencyKey ? { 'idempotency-key': idempotencyKey } : {}),\n },\n body: JSON.stringify(body),\n });\n }\n\n private async request(path: string, init: RequestInit): Promise<Response> {\n let lastError: PDFCraftError | null = null;\n for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {\n let response: Response;\n try {\n response = await this.doFetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n authorization: `Bearer ${this.apiKey}`,\n 'user-agent': 'pdfcraft-sdk-js/1.0.0',\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n } catch (cause) {\n lastError = new PDFCraftError('network_error', `Could not reach PDFCraft: ${cause}`, 0);\n if (attempt === this.maxRetries) throw lastError;\n await sleep(backoffMs(attempt));\n continue;\n }\n\n if (response.ok) return response;\n\n const error = toError(response.status, await response.text());\n // 4xx other than 429 will fail identically no matter how many times we ask.\n if (!error.retryable || attempt === this.maxRetries) throw error;\n lastError = error;\n await sleep(retryAfterMs(response) ?? backoffMs(attempt));\n }\n throw lastError ?? new PDFCraftError('internal_error', 'Request failed.', 500);\n }\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.round(500 * 2 ** attempt * (0.75 + Math.random() * 0.5));\n}\n\nfunction retryAfterMs(response: Response): number | null {\n const header = response.headers.get('retry-after');\n if (!header) return null;\n const seconds = Number(header);\n return Number.isFinite(seconds) ? Math.max(0, seconds) * 1000 : null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- // packages/contract/src/errors.ts
2
+ // src/contract/errors.ts — generated; see index.ts
3
3
  //
4
4
  // Every error the API can return. The exception filter maps domain errors onto
5
5
  // this table, the SDK exposes `.code` from it, and the docs error reference is
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/contract/errors.ts"],"names":[],"mappings":";AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;;;AAqG3E,gCAEC;AArGY,QAAA,WAAW,GAAG,sBAAsB,CAAC;AAErC,QAAA,WAAW,GAAG;IACzB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,gBAAgB;CACR,CAAC;AAaE,QAAA,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,4EAA4E;QAClF,QAAQ,EAAE,mFAAmF;KAC9F;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8EAA8E;QACpF,QAAQ,EAAE,+EAA+E;KAC1F;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,mEAAmE;QACzE,QAAQ,EAAE,qFAAqF;KAChG;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,iDAAiD;QACvD,QAAQ,EACN,8FAA8F;KACjG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gEAAgE;QACtE,QAAQ,EACN,wGAAwG;KAC3G;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,yFAAyF;QAC/F,QAAQ,EACN,yFAAyF;KAC5F;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gDAAgD;QACtD,QAAQ,EAAE,wEAAwE;KACnF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,qEAAqE;QAC3E,QAAQ,EACN,qGAAqG;KACxG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8BAA8B;QACpC,QAAQ,EAAE,0EAA0E;KACrF;CACsC,CAAC;AAE7B,QAAA,kBAAkB,GAA2C,MAAM,CAAC,WAAW,CAC1F,mBAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACb,CAAC;AAElC,SAAgB,UAAU,CAAC,IAAe;IACxC,OAAO,GAAG,mBAAW,WAAW,IAAI,EAAE,CAAC;AACzC,CAAC","sourcesContent":["// packages/contract/src/errors.ts\n//\n// Every error the API can return. The exception filter maps domain errors onto\n// this table, the SDK exposes `.code` from it, and the docs error reference is\n// generated from it — each anchor matches the docs_url the API hands back.\n\nexport const DOCS_ORIGIN = 'https://pdfcraft.dev';\n\nexport const ERROR_CODES = [\n 'invalid_request',\n 'invalid_api_key',\n 'payment_required',\n 'not_found',\n 'render_timeout',\n 'render_failed',\n 'rate_limited',\n 'quota_exceeded',\n 'internal_error',\n] as const;\n\nexport type ErrorCode = (typeof ERROR_CODES)[number];\n\nexport interface ErrorSpec {\n readonly code: ErrorCode;\n readonly status: number;\n /** True when Chromium actually ran, which is what makes a render billable. */\n readonly billable: boolean;\n readonly when: string;\n readonly whatToDo: string;\n}\n\nexport const ERROR_TABLE = [\n {\n code: 'invalid_request',\n status: 400,\n billable: false,\n when: 'Both html and url were supplied, or neither, or an option is out of range.',\n whatToDo: 'Read the message — it names the offending field. Send exactly one of html or url.',\n },\n {\n code: 'invalid_api_key',\n status: 401,\n billable: false,\n when: 'The Authorization header is missing, malformed, or the key has been revoked.',\n whatToDo: 'Send \"Authorization: Bearer sk_live_…\". Issue a fresh key from the dashboard.',\n },\n {\n code: 'payment_required',\n status: 402,\n billable: false,\n when: 'The last subscription payment failed, so the account is past_due.',\n whatToDo: 'Update the card on the billing portal. Rendering resumes the moment payment clears.',\n },\n {\n code: 'not_found',\n status: 404,\n billable: false,\n when: 'No render with that id belongs to your account.',\n whatToDo:\n 'Check the id. Ids from another account also return 404, never 403, so they cannot be probed.',\n },\n {\n code: 'render_timeout',\n status: 408,\n billable: false,\n when: 'The page did not finish within timeoutMs and was force-closed.',\n whatToDo:\n 'Raise timeoutMs (max 120000), or relax waitFor — networkIdle on a page with a long-poll never settles.',\n },\n {\n code: 'render_failed',\n status: 422,\n billable: true,\n when: 'Chromium ran but the page threw, navigation failed, or waitFor.selector never appeared.',\n whatToDo:\n 'Load the same HTML in a browser. This one is billable because the browser did the work.',\n },\n {\n code: 'rate_limited',\n status: 429,\n billable: false,\n when: 'More requests per second than the plan allows.',\n whatToDo: 'Honour the Retry-After header and back off. Paid plans allow 20 req/s.',\n },\n {\n code: 'quota_exceeded',\n status: 429,\n billable: false,\n when: 'A free-plan account has used all 100 renders in the current period.',\n whatToDo:\n 'Upgrade, or wait for resets_at from GET /v1/usage. Paid plans never hard-stop; they accrue overage.',\n },\n {\n code: 'internal_error',\n status: 500,\n billable: false,\n when: 'Something on our side broke.',\n whatToDo: 'Retry with backoff. Never billed. If it persists, send us the render id.',\n },\n] as const satisfies readonly ErrorSpec[];\n\nexport const ERROR_SPEC_BY_CODE: Readonly<Record<ErrorCode, ErrorSpec>> = Object.fromEntries(\n ERROR_TABLE.map((spec) => [spec.code, spec]),\n) as Record<ErrorCode, ErrorSpec>;\n\nexport function docsUrlFor(code: ErrorCode): string {\n return `${DOCS_ORIGIN}/errors#${code}`;\n}\n\nexport interface ApiErrorBody {\n error: {\n code: ErrorCode;\n message: string;\n docs_url: string;\n };\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/contract/errors.ts"],"names":[],"mappings":";AAAA,mDAAmD;AACnD,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;;;AAqG3E,gCAEC;AArGY,QAAA,WAAW,GAAG,sBAAsB,CAAC;AAErC,QAAA,WAAW,GAAG;IACzB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,gBAAgB;CACR,CAAC;AAaE,QAAA,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,4EAA4E;QAClF,QAAQ,EAAE,mFAAmF;KAC9F;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8EAA8E;QACpF,QAAQ,EAAE,+EAA+E;KAC1F;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,mEAAmE;QACzE,QAAQ,EAAE,qFAAqF;KAChG;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,iDAAiD;QACvD,QAAQ,EACN,8FAA8F;KACjG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gEAAgE;QACtE,QAAQ,EACN,wGAAwG;KAC3G;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,yFAAyF;QAC/F,QAAQ,EACN,yFAAyF;KAC5F;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gDAAgD;QACtD,QAAQ,EAAE,wEAAwE;KACnF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,qEAAqE;QAC3E,QAAQ,EACN,qGAAqG;KACxG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8BAA8B;QACpC,QAAQ,EAAE,0EAA0E;KACrF;CACsC,CAAC;AAE7B,QAAA,kBAAkB,GAA2C,MAAM,CAAC,WAAW,CAC1F,mBAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACb,CAAC;AAElC,SAAgB,UAAU,CAAC,IAAe;IACxC,OAAO,GAAG,mBAAW,WAAW,IAAI,EAAE,CAAC;AACzC,CAAC","sourcesContent":["// src/contract/errors.ts — generated; see index.ts\n//\n// Every error the API can return. The exception filter maps domain errors onto\n// this table, the SDK exposes `.code` from it, and the docs error reference is\n// generated from it — each anchor matches the docs_url the API hands back.\n\nexport const DOCS_ORIGIN = 'https://pdfcraft.dev';\n\nexport const ERROR_CODES = [\n 'invalid_request',\n 'invalid_api_key',\n 'payment_required',\n 'not_found',\n 'render_timeout',\n 'render_failed',\n 'rate_limited',\n 'quota_exceeded',\n 'internal_error',\n] as const;\n\nexport type ErrorCode = (typeof ERROR_CODES)[number];\n\nexport interface ErrorSpec {\n readonly code: ErrorCode;\n readonly status: number;\n /** True when Chromium actually ran, which is what makes a render billable. */\n readonly billable: boolean;\n readonly when: string;\n readonly whatToDo: string;\n}\n\nexport const ERROR_TABLE = [\n {\n code: 'invalid_request',\n status: 400,\n billable: false,\n when: 'Both html and url were supplied, or neither, or an option is out of range.',\n whatToDo: 'Read the message — it names the offending field. Send exactly one of html or url.',\n },\n {\n code: 'invalid_api_key',\n status: 401,\n billable: false,\n when: 'The Authorization header is missing, malformed, or the key has been revoked.',\n whatToDo: 'Send \"Authorization: Bearer sk_live_…\". Issue a fresh key from the dashboard.',\n },\n {\n code: 'payment_required',\n status: 402,\n billable: false,\n when: 'The last subscription payment failed, so the account is past_due.',\n whatToDo: 'Update the card on the billing portal. Rendering resumes the moment payment clears.',\n },\n {\n code: 'not_found',\n status: 404,\n billable: false,\n when: 'No render with that id belongs to your account.',\n whatToDo:\n 'Check the id. Ids from another account also return 404, never 403, so they cannot be probed.',\n },\n {\n code: 'render_timeout',\n status: 408,\n billable: false,\n when: 'The page did not finish within timeoutMs and was force-closed.',\n whatToDo:\n 'Raise timeoutMs (max 120000), or relax waitFor — networkIdle on a page with a long-poll never settles.',\n },\n {\n code: 'render_failed',\n status: 422,\n billable: true,\n when: 'Chromium ran but the page threw, navigation failed, or waitFor.selector never appeared.',\n whatToDo:\n 'Load the same HTML in a browser. This one is billable because the browser did the work.',\n },\n {\n code: 'rate_limited',\n status: 429,\n billable: false,\n when: 'More requests per second than the plan allows.',\n whatToDo: 'Honour the Retry-After header and back off. Paid plans allow 20 req/s.',\n },\n {\n code: 'quota_exceeded',\n status: 429,\n billable: false,\n when: 'A free-plan account has used all 100 renders in the current period.',\n whatToDo:\n 'Upgrade, or wait for resets_at from GET /v1/usage. Paid plans never hard-stop; they accrue overage.',\n },\n {\n code: 'internal_error',\n status: 500,\n billable: false,\n when: 'Something on our side broke.',\n whatToDo: 'Retry with backoff. Never billed. If it persists, send us the render id.',\n },\n] as const satisfies readonly ErrorSpec[];\n\nexport const ERROR_SPEC_BY_CODE: Readonly<Record<ErrorCode, ErrorSpec>> = Object.fromEntries(\n ERROR_TABLE.map((spec) => [spec.code, spec]),\n) as Record<ErrorCode, ErrorSpec>;\n\nexport function docsUrlFor(code: ErrorCode): string {\n return `${DOCS_ORIGIN}/errors#${code}`;\n}\n\nexport interface ApiErrorBody {\n error: {\n code: ErrorCode;\n message: string;\n docs_url: string;\n };\n}\n"]}
@@ -1,10 +1,11 @@
1
1
  "use strict";
2
- // packages/contract/src/render-options.ts
2
+ // src/contract/render-options.ts — generated; see index.ts
3
3
  //
4
4
  // The one description of the render option surface. The API builds its validator
5
5
  // from RENDER_OPTIONS_SPEC and the docs site builds its reference table from the
6
- // same constant, so the two cannot drift. The SDK vendors this file verbatim at
7
- // build time (see packages/sdk/scripts/vendor-contract.mjs) to stay dependency-free.
6
+ // same constant, so the two cannot drift. The SDK, which lives in its own repo,
7
+ // keeps a copy written by scripts/sync-sdk.mjs so it can stay dependency-free
8
+ // apps/api/test/contract-sync.spec.ts fails when this file changes without it.
8
9
  Object.defineProperty(exports, "__esModule", { value: true });
9
10
  exports.SPEC_MATCHES_TYPES = exports.RENDER_OPTIONS_SPEC = exports.MAX_HTML_BYTES = exports.DEFAULT_TIMEOUT_MS = exports.MAX_TIMEOUT_MS = exports.EMULATE_MEDIA = exports.PAGE_FORMATS = void 0;
10
11
  exports.PAGE_FORMATS = ['A4', 'A3', 'A5', 'Letter', 'Legal', 'Tabloid'];
@@ -1 +1 @@
1
- {"version":3,"file":"render-options.js","sourceRoot":"","sources":["../../../src/contract/render-options.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/contract/src/render-options.ts\n//\n// The one description of the render option surface. The API builds its validator\n// from RENDER_OPTIONS_SPEC and the docs site builds its reference table from the\n// same constant, so the two cannot drift. The SDK vendors this file verbatim at\n// build time (see packages/sdk/scripts/vendor-contract.mjs) to stay dependency-free.\n\nexport type OptionKind =\n | { readonly kind: 'enum'; readonly values: readonly string[] }\n | { readonly kind: 'boolean' }\n | { readonly kind: 'number'; readonly min: number; readonly max: number }\n | { readonly kind: 'integer'; readonly min: number; readonly max: number }\n | { readonly kind: 'string'; readonly maxLength: number; readonly pattern?: string }\n | { readonly kind: 'css-length' }\n | { readonly kind: 'object'; readonly fields: readonly OptionField[] };\n\nexport interface OptionField {\n readonly name: string;\n readonly type: OptionKind;\n readonly default?: string | number | boolean;\n readonly description: string;\n}\n\nexport const PAGE_FORMATS = ['A4', 'A3', 'A5', 'Letter', 'Legal', 'Tabloid'] as const;\nexport const EMULATE_MEDIA = ['print', 'screen'] as const;\n\nexport const MAX_TIMEOUT_MS = 120_000;\nexport const DEFAULT_TIMEOUT_MS = 30_000;\nexport const MAX_HTML_BYTES = 5_000_000;\n\nexport const RENDER_OPTIONS_SPEC = [\n {\n name: 'format',\n type: { kind: 'enum', values: PAGE_FORMATS },\n default: 'A4',\n description: 'Paper size. Ignored if the page CSS declares its own @page size.',\n },\n {\n name: 'landscape',\n type: { kind: 'boolean' },\n default: false,\n description: 'Rotate the paper to landscape orientation.',\n },\n {\n name: 'margin',\n type: {\n kind: 'object',\n fields: [\n { name: 'top', type: { kind: 'css-length' }, description: 'e.g. \"20mm\", \"1in\", \"72px\".' },\n { name: 'right', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n { name: 'bottom', type: { kind: 'css-length' }, description: 'e.g. \"20mm\".' },\n { name: 'left', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n ],\n },\n description: 'Page margins. Any side may be omitted; omitted sides default to 0.',\n },\n {\n name: 'scale',\n type: { kind: 'number', min: 0.1, max: 2 },\n default: 1,\n description: 'Rendering scale factor.',\n },\n {\n name: 'printBackground',\n type: { kind: 'boolean' },\n default: true,\n description:\n 'Print background colours and images. Off by default in browsers; on by default here.',\n },\n {\n name: 'pageRanges',\n type: { kind: 'string', maxLength: 100, pattern: '^[0-9,\\\\-\\\\s]+$' },\n description: 'Subset of pages to keep, e.g. \"1-5\" or \"1,4,7-9\". Empty means all pages.',\n },\n {\n name: 'headerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description:\n 'HTML for the running header. Supports Chromium print classes: date, title, url, pageNumber, totalPages. Needs a top margin to be visible.',\n },\n {\n name: 'footerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description: 'HTML for the running footer. Same classes as headerHtml; needs a bottom margin.',\n },\n {\n name: 'waitFor',\n type: {\n kind: 'object',\n fields: [\n {\n name: 'selector',\n type: { kind: 'string', maxLength: 500 },\n description: 'Wait until this CSS selector is attached to the DOM.',\n },\n {\n name: 'networkIdle',\n type: { kind: 'boolean' },\n default: false,\n description: 'Wait until there have been no network connections for 500 ms.',\n },\n {\n name: 'delayMs',\n type: { kind: 'integer', min: 0, max: 30_000 },\n default: 0,\n description: 'Fixed pause after the other wait conditions are satisfied.',\n },\n ],\n },\n description: 'Conditions to satisfy before the PDF is taken. All of them apply, in order.',\n },\n {\n name: 'emulateMedia',\n type: { kind: 'enum', values: EMULATE_MEDIA },\n default: 'print',\n description: 'Which CSS media type the page sees.',\n },\n {\n name: 'timeoutMs',\n type: { kind: 'integer', min: 1000, max: MAX_TIMEOUT_MS },\n default: DEFAULT_TIMEOUT_MS,\n description: 'Hard ceiling on the whole render. Exceeding it returns 408 render_timeout.',\n },\n] as const satisfies readonly OptionField[];\n\nexport interface Margin {\n top?: string;\n right?: string;\n bottom?: string;\n left?: string;\n}\n\nexport interface WaitFor {\n selector?: string;\n networkIdle?: boolean;\n delayMs?: number;\n}\n\nexport interface RenderOptions {\n format?: (typeof PAGE_FORMATS)[number];\n landscape?: boolean;\n margin?: Margin;\n scale?: number;\n printBackground?: boolean;\n pageRanges?: string;\n headerHtml?: string;\n footerHtml?: string;\n waitFor?: WaitFor;\n emulateMedia?: (typeof EMULATE_MEDIA)[number];\n timeoutMs?: number;\n}\n\ntype SpecFieldName = (typeof RENDER_OPTIONS_SPEC)[number]['name'];\n\n// Compile-time drift guard: this assignment stops type-checking the moment\n// RENDER_OPTIONS_SPEC and RenderOptions describe different sets of options.\nconst driftCheck: [Exclude<keyof RenderOptions, SpecFieldName>] extends [never]\n ? [Exclude<SpecFieldName, keyof RenderOptions>] extends [never]\n ? true\n : never\n : never = true;\n\nexport const SPEC_MATCHES_TYPES: boolean = driftCheck;\n"]}
1
+ {"version":3,"file":"render-options.js","sourceRoot":"","sources":["../../../src/contract/render-options.ts"],"names":[],"mappings":"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","sourcesContent":["// src/contract/render-options.ts — generated; see index.ts\n//\n// The one description of the render option surface. The API builds its validator\n// from RENDER_OPTIONS_SPEC and the docs site builds its reference table from the\n// same constant, so the two cannot drift. The SDK, which lives in its own repo,\n// keeps a copy written by scripts/sync-sdk.mjs so it can stay dependency-free —\n// apps/api/test/contract-sync.spec.ts fails when this file changes without it.\n\nexport type OptionKind =\n | { readonly kind: 'enum'; readonly values: readonly string[] }\n | { readonly kind: 'boolean' }\n | { readonly kind: 'number'; readonly min: number; readonly max: number }\n | { readonly kind: 'integer'; readonly min: number; readonly max: number }\n | { readonly kind: 'string'; readonly maxLength: number; readonly pattern?: string }\n | { readonly kind: 'css-length' }\n | { readonly kind: 'object'; readonly fields: readonly OptionField[] };\n\nexport interface OptionField {\n readonly name: string;\n readonly type: OptionKind;\n readonly default?: string | number | boolean;\n readonly description: string;\n}\n\nexport const PAGE_FORMATS = ['A4', 'A3', 'A5', 'Letter', 'Legal', 'Tabloid'] as const;\nexport const EMULATE_MEDIA = ['print', 'screen'] as const;\n\nexport const MAX_TIMEOUT_MS = 120_000;\nexport const DEFAULT_TIMEOUT_MS = 30_000;\nexport const MAX_HTML_BYTES = 5_000_000;\n\nexport const RENDER_OPTIONS_SPEC = [\n {\n name: 'format',\n type: { kind: 'enum', values: PAGE_FORMATS },\n default: 'A4',\n description: 'Paper size. Ignored if the page CSS declares its own @page size.',\n },\n {\n name: 'landscape',\n type: { kind: 'boolean' },\n default: false,\n description: 'Rotate the paper to landscape orientation.',\n },\n {\n name: 'margin',\n type: {\n kind: 'object',\n fields: [\n { name: 'top', type: { kind: 'css-length' }, description: 'e.g. \"20mm\", \"1in\", \"72px\".' },\n { name: 'right', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n { name: 'bottom', type: { kind: 'css-length' }, description: 'e.g. \"20mm\".' },\n { name: 'left', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n ],\n },\n description: 'Page margins. Any side may be omitted; omitted sides default to 0.',\n },\n {\n name: 'scale',\n type: { kind: 'number', min: 0.1, max: 2 },\n default: 1,\n description: 'Rendering scale factor.',\n },\n {\n name: 'printBackground',\n type: { kind: 'boolean' },\n default: true,\n description:\n 'Print background colours and images. Off by default in browsers; on by default here.',\n },\n {\n name: 'pageRanges',\n type: { kind: 'string', maxLength: 100, pattern: '^[0-9,\\\\-\\\\s]+$' },\n description: 'Subset of pages to keep, e.g. \"1-5\" or \"1,4,7-9\". Empty means all pages.',\n },\n {\n name: 'headerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description:\n 'HTML for the running header. Supports Chromium print classes: date, title, url, pageNumber, totalPages. Needs a top margin to be visible.',\n },\n {\n name: 'footerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description: 'HTML for the running footer. Same classes as headerHtml; needs a bottom margin.',\n },\n {\n name: 'waitFor',\n type: {\n kind: 'object',\n fields: [\n {\n name: 'selector',\n type: { kind: 'string', maxLength: 500 },\n description: 'Wait until this CSS selector is attached to the DOM.',\n },\n {\n name: 'networkIdle',\n type: { kind: 'boolean' },\n default: false,\n description: 'Wait until there have been no network connections for 500 ms.',\n },\n {\n name: 'delayMs',\n type: { kind: 'integer', min: 0, max: 30_000 },\n default: 0,\n description: 'Fixed pause after the other wait conditions are satisfied.',\n },\n ],\n },\n description: 'Conditions to satisfy before the PDF is taken. All of them apply, in order.',\n },\n {\n name: 'emulateMedia',\n type: { kind: 'enum', values: EMULATE_MEDIA },\n default: 'print',\n description: 'Which CSS media type the page sees.',\n },\n {\n name: 'timeoutMs',\n type: { kind: 'integer', min: 1000, max: MAX_TIMEOUT_MS },\n default: DEFAULT_TIMEOUT_MS,\n description: 'Hard ceiling on the whole render. Exceeding it returns 408 render_timeout.',\n },\n] as const satisfies readonly OptionField[];\n\nexport interface Margin {\n top?: string;\n right?: string;\n bottom?: string;\n left?: string;\n}\n\nexport interface WaitFor {\n selector?: string;\n networkIdle?: boolean;\n delayMs?: number;\n}\n\nexport interface RenderOptions {\n format?: (typeof PAGE_FORMATS)[number];\n landscape?: boolean;\n margin?: Margin;\n scale?: number;\n printBackground?: boolean;\n pageRanges?: string;\n headerHtml?: string;\n footerHtml?: string;\n waitFor?: WaitFor;\n emulateMedia?: (typeof EMULATE_MEDIA)[number];\n timeoutMs?: number;\n}\n\ntype SpecFieldName = (typeof RENDER_OPTIONS_SPEC)[number]['name'];\n\n// Compile-time drift guard: this assignment stops type-checking the moment\n// RENDER_OPTIONS_SPEC and RenderOptions describe different sets of options.\nconst driftCheck: [Exclude<keyof RenderOptions, SpecFieldName>] extends [never]\n ? [Exclude<SpecFieldName, keyof RenderOptions>] extends [never]\n ? true\n : never\n : never = true;\n\nexport const SPEC_MATCHES_TYPES: boolean = driftCheck;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/contract/request.ts"],"names":[],"mappings":";;;AAGa,QAAA,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAC;AAG1C,QAAA,eAAe,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAG1E,QAAA,cAAc,GAAG,CAAC,MAAM,EAAE,KAAK,CAAU,CAAC;AAG1C,QAAA,gBAAgB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAuE7E,kEAAkE;AACrD,QAAA,mBAAmB,GAAG;IACjC;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;QAC9C,WAAW,EAAE,+EAA+E;KAC7F;IACD;QACE,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;QACzC,WAAW,EAAE,+DAA+D;KAC7E;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAY,EAAE;QAC5C,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,iFAAiF;KAC/F;IACD;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE;QACxC,OAAO,EAAE,cAAc;QACvB,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,iFAAiF;KAC/F;CACwC,CAAC","sourcesContent":["// packages/contract/src/request.ts\nimport { type OptionField, type RenderOptions } from './render-options.js';\n\nexport const OUTPUT_MODES = ['binary', 'url'] as const;\nexport type OutputMode = (typeof OUTPUT_MODES)[number];\n\nexport const RENDER_STATUSES = ['queued', 'rendering', 'succeeded', 'failed'] as const;\nexport type RenderStatus = (typeof RENDER_STATUSES)[number];\n\nexport const RENDER_SOURCES = ['html', 'url'] as const;\nexport type RenderSource = (typeof RENDER_SOURCES)[number];\n\nexport const ACCOUNT_STATUSES = ['active', 'past_due', 'cancelled'] as const;\nexport type AccountStatus = (typeof ACCOUNT_STATUSES)[number];\n\nexport interface Cookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n}\n\nexport interface RenderRequest {\n /** Exactly one of html or url. */\n html?: string;\n url?: string;\n options?: RenderOptions;\n output?: OutputMode;\n filename?: string;\n /** url input only: extra request headers, so an authenticated page can be rendered. */\n headers?: Record<string, string>;\n /** url input only: cookies to seed the context with. */\n cookies?: Cookie[];\n}\n\nexport interface AsyncRenderRequest extends RenderRequest {\n callback_url: string;\n}\n\nexport interface RenderUrlResponse {\n id: string;\n url: string;\n expires_at: string;\n pages: number;\n bytes: number;\n duration_ms: number;\n}\n\nexport interface AsyncRenderAccepted {\n id: string;\n status: 'queued';\n}\n\nexport interface RenderStatusResponse {\n id: string;\n status: RenderStatus;\n url?: string;\n expires_at?: string;\n pages?: number;\n bytes?: number;\n duration_ms?: number;\n error?: { code: string; message: string };\n}\n\nexport interface UsageResponse {\n used: number;\n limit: number;\n overage_count: number;\n period_start: string;\n resets_at: string;\n}\n\n/** Body sent to callback_url when an async render settles. */\nexport interface WebhookPayload {\n id: string;\n status: 'succeeded' | 'failed';\n url?: string;\n pages?: number;\n bytes?: number;\n duration_ms: number;\n error?: { code: string; message: string };\n}\n\n/** Top-level request fields, for the generated docs reference. */\nexport const REQUEST_FIELDS_SPEC = [\n {\n name: 'html',\n type: { kind: 'string', maxLength: 5_000_000 },\n description: 'The document to render. Mutually exclusive with url; exactly one is required.',\n },\n {\n name: 'url',\n type: { kind: 'string', maxLength: 2000 },\n description: 'A public http(s) URL to render. Mutually exclusive with html.',\n },\n {\n name: 'output',\n type: { kind: 'enum', values: OUTPUT_MODES },\n default: 'binary',\n description: '\"binary\" streams application/pdf back; \"url\" uploads and returns a signed link.',\n },\n {\n name: 'filename',\n type: { kind: 'string', maxLength: 255 },\n default: 'document.pdf',\n description: 'Used for Content-Disposition on binary output and in the signed URL.',\n },\n {\n name: 'headers',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Extra request headers, e.g. an Authorization header.',\n },\n {\n name: 'cookies',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Array of {name, value, domain?, path?} seeded into the context.',\n },\n] as const satisfies readonly OptionField[];\n"]}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/contract/request.ts"],"names":[],"mappings":";;;AAGa,QAAA,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAC;AAG1C,QAAA,eAAe,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAG1E,QAAA,cAAc,GAAG,CAAC,MAAM,EAAE,KAAK,CAAU,CAAC;AAG1C,QAAA,gBAAgB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAuE7E,kEAAkE;AACrD,QAAA,mBAAmB,GAAG;IACjC;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;QAC9C,WAAW,EAAE,+EAA+E;KAC7F;IACD;QACE,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;QACzC,WAAW,EAAE,+DAA+D;KAC7E;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAY,EAAE;QAC5C,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,iFAAiF;KAC/F;IACD;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE;QACxC,OAAO,EAAE,cAAc;QACvB,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,iFAAiF;KAC/F;CACwC,CAAC","sourcesContent":["// src/contract/request.ts — generated; see index.ts\nimport { type OptionField, type RenderOptions } from './render-options.js';\n\nexport const OUTPUT_MODES = ['binary', 'url'] as const;\nexport type OutputMode = (typeof OUTPUT_MODES)[number];\n\nexport const RENDER_STATUSES = ['queued', 'rendering', 'succeeded', 'failed'] as const;\nexport type RenderStatus = (typeof RENDER_STATUSES)[number];\n\nexport const RENDER_SOURCES = ['html', 'url'] as const;\nexport type RenderSource = (typeof RENDER_SOURCES)[number];\n\nexport const ACCOUNT_STATUSES = ['active', 'past_due', 'cancelled'] as const;\nexport type AccountStatus = (typeof ACCOUNT_STATUSES)[number];\n\nexport interface Cookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n}\n\nexport interface RenderRequest {\n /** Exactly one of html or url. */\n html?: string;\n url?: string;\n options?: RenderOptions;\n output?: OutputMode;\n filename?: string;\n /** url input only: extra request headers, so an authenticated page can be rendered. */\n headers?: Record<string, string>;\n /** url input only: cookies to seed the context with. */\n cookies?: Cookie[];\n}\n\nexport interface AsyncRenderRequest extends RenderRequest {\n callback_url: string;\n}\n\nexport interface RenderUrlResponse {\n id: string;\n url: string;\n expires_at: string;\n pages: number;\n bytes: number;\n duration_ms: number;\n}\n\nexport interface AsyncRenderAccepted {\n id: string;\n status: 'queued';\n}\n\nexport interface RenderStatusResponse {\n id: string;\n status: RenderStatus;\n url?: string;\n expires_at?: string;\n pages?: number;\n bytes?: number;\n duration_ms?: number;\n error?: { code: string; message: string };\n}\n\nexport interface UsageResponse {\n used: number;\n limit: number;\n overage_count: number;\n period_start: string;\n resets_at: string;\n}\n\n/** Body sent to callback_url when an async render settles. */\nexport interface WebhookPayload {\n id: string;\n status: 'succeeded' | 'failed';\n url?: string;\n pages?: number;\n bytes?: number;\n duration_ms: number;\n error?: { code: string; message: string };\n}\n\n/** Top-level request fields, for the generated docs reference. */\nexport const REQUEST_FIELDS_SPEC = [\n {\n name: 'html',\n type: { kind: 'string', maxLength: 5_000_000 },\n description: 'The document to render. Mutually exclusive with url; exactly one is required.',\n },\n {\n name: 'url',\n type: { kind: 'string', maxLength: 2000 },\n description: 'A public http(s) URL to render. Mutually exclusive with html.',\n },\n {\n name: 'output',\n type: { kind: 'enum', values: OUTPUT_MODES },\n default: 'binary',\n description: '\"binary\" streams application/pdf back; \"url\" uploads and returns a signed link.',\n },\n {\n name: 'filename',\n type: { kind: 'string', maxLength: 255 },\n default: 'document.pdf',\n description: 'Used for Content-Disposition on binary output and in the signed URL.',\n },\n {\n name: 'headers',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Extra request headers, e.g. an Authorization header.',\n },\n {\n name: 'cookies',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Array of {name, value, domain?, path?} seeded into the context.',\n },\n] as const satisfies readonly OptionField[];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AA6BA,0BAaC;AAvCD,6EAA6E;AAC7E,MAAa,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAA8B;IAClC,MAAM,CAAS;IACf,OAAO,CAAgB;IACvB,SAAS,CAAU;IAE5B,YACE,IAAiC,EACjC,OAAe,EACf,MAAc,EACd,UAAyB,IAAI;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,eAAe,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;IAC/E,CAAC;CACF;AAnBD,sCAmBC;AAMD,SAAgB,OAAO,CAAC,MAAc,EAAE,IAAY;IAClD,IAAI,MAAM,GAAc,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IACD,OAAO,IAAI,aAAa,CACrB,MAAM,CAAC,KAAK,EAAE,IAAkB,IAAI,gBAAgB,EACrD,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,sBAAsB,MAAM,EAAE,EACvD,MAAM,EACN,MAAM,CAAC,KAAK,EAAE,QAAQ,IAAI,IAAI,CAC/B,CAAC;AACJ,CAAC","sourcesContent":["// packages/sdk/src/errors.ts\nimport type { ErrorCode } from './contract/index.js';\n\n/** Every failure from the API arrives as one of these. Branch on `.code`. */\nexport class PDFCraftError extends Error {\n readonly code: ErrorCode | 'network_error';\n readonly status: number;\n readonly docsUrl: string | null;\n readonly retryable: boolean;\n\n constructor(\n code: ErrorCode | 'network_error',\n message: string,\n status: number,\n docsUrl: string | null = null,\n ) {\n super(message);\n this.name = 'PDFCraftError';\n this.code = code;\n this.status = status;\n this.docsUrl = docsUrl;\n this.retryable = code === 'network_error' || status === 429 || status >= 500;\n }\n}\n\ninterface WireError {\n error?: { code?: string; message?: string; docs_url?: string };\n}\n\nexport function toError(status: number, body: string): PDFCraftError {\n let parsed: WireError = {};\n try {\n parsed = JSON.parse(body) as WireError;\n } catch {\n // Non-JSON body (a proxy error page, say) — fall through to the defaults.\n }\n return new PDFCraftError(\n (parsed.error?.code as ErrorCode) ?? 'internal_error',\n parsed.error?.message ?? `PDFCraft responded ${status}`,\n status,\n parsed.error?.docs_url ?? null,\n );\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":";;;AA6BA,0BAaC;AAvCD,6EAA6E;AAC7E,MAAa,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAA8B;IAClC,MAAM,CAAS;IACf,OAAO,CAAgB;IACvB,SAAS,CAAU;IAE5B,YACE,IAAiC,EACjC,OAAe,EACf,MAAc,EACd,UAAyB,IAAI;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,eAAe,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;IAC/E,CAAC;CACF;AAnBD,sCAmBC;AAMD,SAAgB,OAAO,CAAC,MAAc,EAAE,IAAY;IAClD,IAAI,MAAM,GAAc,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IACD,OAAO,IAAI,aAAa,CACrB,MAAM,CAAC,KAAK,EAAE,IAAkB,IAAI,gBAAgB,EACrD,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,sBAAsB,MAAM,EAAE,EACvD,MAAM,EACN,MAAM,CAAC,KAAK,EAAE,QAAQ,IAAI,IAAI,CAC/B,CAAC;AACJ,CAAC","sourcesContent":["// src/errors.ts\nimport type { ErrorCode } from './contract/index.js';\n\n/** Every failure from the API arrives as one of these. Branch on `.code`. */\nexport class PDFCraftError extends Error {\n readonly code: ErrorCode | 'network_error';\n readonly status: number;\n readonly docsUrl: string | null;\n readonly retryable: boolean;\n\n constructor(\n code: ErrorCode | 'network_error',\n message: string,\n status: number,\n docsUrl: string | null = null,\n ) {\n super(message);\n this.name = 'PDFCraftError';\n this.code = code;\n this.status = status;\n this.docsUrl = docsUrl;\n this.retryable = code === 'network_error' || status === 429 || status >= 500;\n }\n}\n\ninterface WireError {\n error?: { code?: string; message?: string; docs_url?: string };\n}\n\nexport function toError(status: number, body: string): PDFCraftError {\n let parsed: WireError = {};\n try {\n parsed = JSON.parse(body) as WireError;\n } catch {\n // Non-JSON body (a proxy error page, say) — fall through to the defaults.\n }\n return new PDFCraftError(\n (parsed.error?.code as ErrorCode) ?? 'internal_error',\n parsed.error?.message ?? `PDFCraft responded ${status}`,\n status,\n parsed.error?.docs_url ?? null,\n );\n}\n"]}
package/dist/cjs/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.PDFCraftError = exports.Renderer = void 0;
4
- // packages/sdk/src/index.ts
4
+ // src/index.ts
5
5
  var client_js_1 = require("./client.js");
6
6
  Object.defineProperty(exports, "Renderer", { enumerable: true, get: function () { return client_js_1.Renderer; } });
7
7
  var errors_js_1 = require("./errors.js");
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,4BAA4B;AAC5B,yCAKqB;AAJnB,qGAAA,QAAQ,OAAA;AAKV,yCAA4C;AAAnC,0GAAA,aAAa,OAAA","sourcesContent":["// packages/sdk/src/index.ts\nexport {\n Renderer,\n type AsyncRenderInput,\n type RenderInput,\n type RendererOptions,\n} from './client.js';\nexport { PDFCraftError } from './errors.js';\nexport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n Cookie,\n ErrorCode,\n Margin,\n OutputMode,\n RenderOptions,\n RenderRequest,\n RenderStatus,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n WaitFor,\n WebhookPayload,\n} from './contract/index.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,eAAe;AACf,yCAKqB;AAJnB,qGAAA,QAAQ,OAAA;AAKV,yCAA4C;AAAnC,0GAAA,aAAa,OAAA","sourcesContent":["// src/index.ts\nexport {\n Renderer,\n type AsyncRenderInput,\n type RenderInput,\n type RendererOptions,\n} from './client.js';\nexport { PDFCraftError } from './errors.js';\nexport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n Cookie,\n ErrorCode,\n Margin,\n OutputMode,\n RenderOptions,\n RenderRequest,\n RenderStatus,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n WaitFor,\n WebhookPayload,\n} from './contract/index.js';\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAYrD,MAAM,QAAQ,GAAG;IACf,OAAO,EAAE,0BAA0B;IACnC,UAAU,EAAE,CAAC;IACb,SAAS,EAAE,OAAO;CACnB,CAAC;AAWF,MAAM,OAAO,QAAQ;IACF,MAAM,CAAS;IACf,OAAO,CAAS;IAChB,UAAU,CAAS;IACnB,SAAS,CAAS;IAClB,OAAO,CAA0B;IAElD,YAAY,MAAc,EAAE,UAA2B,EAAE;QACvD,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,aAAa,CAAC,iBAAiB,EAAE,yBAAyB,EAAE,GAAG,CAAC,CAAC;QACxF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACzE,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,QAAQ,CAAC,UAAU,CAAC;QAC5D,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,QAAQ,CAAC,SAAS,CAAC;QACzD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,MAAM,CAAC,KAAkB,EAAE,cAAuB;QACtD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,cAAc,CAAC,CAAC;QAC/F,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QAC3D,OAAO,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACpE,CAAC;IAED,sEAAsE;IACtE,KAAK,CAAC,WAAW,CAAC,KAAkB,EAAE,cAAuB;QAC3D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,GAAG,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,cAAc,CAAC,CAAC;QAC5F,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAsB,CAAC;IACtD,CAAC;IAED,wDAAwD;IACxD,KAAK,CAAC,WAAW,CACf,KAAuB,EACvB,cAAuB;QAEvB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,kBAAkB,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC;QAC5E,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAwB,CAAC;IACxD,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,EAAU;QACxB,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,eAAe,kBAAkB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QAChG,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAyB,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAkB,CAAC;IAClD,CAAC;IAEO,IAAI,CAAC,IAAY,EAAE,IAAa,EAAE,cAAuB;QAC/D,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE;YACxB,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,GAAG,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACjE;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;SAC3B,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,IAAiB;QACnD,IAAI,SAAS,GAAyB,IAAI,CAAC;QAC3C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC,UAAU,EAAE,OAAO,IAAI,CAAC,EAAE,CAAC;YAC/D,IAAI,QAAkB,CAAC;YACvB,IAAI,CAAC;gBACH,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;oBACtD,GAAG,IAAI;oBACP,OAAO,EAAE;wBACP,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;wBACtC,YAAY,EAAE,uBAAuB;wBACrC,GAAI,IAAI,CAAC,OAA8C;qBACxD;oBACD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC;iBAC5C,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,SAAS,GAAG,IAAI,aAAa,CAAC,eAAe,EAAE,6BAA6B,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC;gBACxF,IAAI,OAAO,KAAK,IAAI,CAAC,UAAU;oBAAE,MAAM,SAAS,CAAC;gBACjD,MAAM,KAAK,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;gBAChC,SAAS;YACX,CAAC;YAED,IAAI,QAAQ,CAAC,EAAE;gBAAE,OAAO,QAAQ,CAAC;YAEjC,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;YAC9D,4EAA4E;YAC5E,IAAI,CAAC,KAAK,CAAC,SAAS,IAAI,OAAO,KAAK,IAAI,CAAC,UAAU;gBAAE,MAAM,KAAK,CAAC;YACjE,SAAS,GAAG,KAAK,CAAC;YAClB,MAAM,KAAK,CAAC,YAAY,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5D,CAAC;QACD,MAAM,SAAS,IAAI,IAAI,aAAa,CAAC,gBAAgB,EAAE,iBAAiB,EAAE,GAAG,CAAC,CAAC;IACjF,CAAC;CACF;AAED,SAAS,SAAS,CAAC,OAAe;IAChC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC;AACvE,CAAC;AAED,SAAS,YAAY,CAAC,QAAkB;IACtC,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACvE,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAC3D,CAAC","sourcesContent":["// packages/sdk/src/client.ts\nimport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n RenderRequest,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n} from './contract/index.js';\nimport { PDFCraftError, toError } from './errors.js';\n\nexport interface RendererOptions {\n /** Override for testing or a self-hosted gateway. */\n baseUrl?: string;\n /** Retries on 429 and 5xx only. Default 3. */\n maxRetries?: number;\n /** Per-request timeout in milliseconds. Default 130000, just past the API's own ceiling. */\n timeoutMs?: number;\n fetch?: typeof globalThis.fetch;\n}\n\nconst DEFAULTS = {\n baseUrl: 'https://api.pdfcraft.dev',\n maxRetries: 3,\n timeoutMs: 130_000,\n};\n\n/**\n * The method you call decides the output mode, so passing `output` yourself\n * could only ever contradict it. Excluded from the type rather than ignored at\n * runtime: `render({ output: 'url' })` returning bytes is the kind of silent\n * surprise that costs someone an afternoon.\n */\nexport type RenderInput = Omit<RenderRequest, 'output'>;\nexport type AsyncRenderInput = Omit<AsyncRenderRequest, 'output'>;\n\nexport class Renderer {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly doFetch: typeof globalThis.fetch;\n\n constructor(apiKey: string, options: RendererOptions = {}) {\n if (!apiKey) throw new PDFCraftError('invalid_api_key', 'An API key is required.', 401);\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULTS.baseUrl).replace(/\\/+$/, '');\n this.maxRetries = options.maxRetries ?? DEFAULTS.maxRetries;\n this.timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs;\n this.doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The PDF bytes. In Node this is a Buffer, which is a Uint8Array. */\n async render(input: RenderInput, idempotencyKey?: string): Promise<Uint8Array> {\n const response = await this.send('/v1/render', { ...input, output: 'binary' }, idempotencyKey);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return typeof Buffer === 'undefined' ? bytes : Buffer.from(bytes);\n }\n\n /** Uploads the PDF and returns a signed link instead of the bytes. */\n async renderToUrl(input: RenderInput, idempotencyKey?: string): Promise<RenderUrlResponse> {\n const response = await this.send('/v1/render', { ...input, output: 'url' }, idempotencyKey);\n return (await response.json()) as RenderUrlResponse;\n }\n\n /** Queues the render and calls back when it settles. */\n async renderAsync(\n input: AsyncRenderInput,\n idempotencyKey?: string,\n ): Promise<AsyncRenderAccepted> {\n const response = await this.send('/v1/render/async', input, idempotencyKey);\n return (await response.json()) as AsyncRenderAccepted;\n }\n\n async getRender(id: string): Promise<RenderStatusResponse> {\n const response = await this.request(`/v1/renders/${encodeURIComponent(id)}`, { method: 'GET' });\n return (await response.json()) as RenderStatusResponse;\n }\n\n async usage(): Promise<UsageResponse> {\n const response = await this.request('/v1/usage', { method: 'GET' });\n return (await response.json()) as UsageResponse;\n }\n\n private send(path: string, body: unknown, idempotencyKey?: string): Promise<Response> {\n return this.request(path, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(idempotencyKey ? { 'idempotency-key': idempotencyKey } : {}),\n },\n body: JSON.stringify(body),\n });\n }\n\n private async request(path: string, init: RequestInit): Promise<Response> {\n let lastError: PDFCraftError | null = null;\n for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {\n let response: Response;\n try {\n response = await this.doFetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n authorization: `Bearer ${this.apiKey}`,\n 'user-agent': 'pdfcraft-sdk-js/1.0.0',\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n } catch (cause) {\n lastError = new PDFCraftError('network_error', `Could not reach PDFCraft: ${cause}`, 0);\n if (attempt === this.maxRetries) throw lastError;\n await sleep(backoffMs(attempt));\n continue;\n }\n\n if (response.ok) return response;\n\n const error = toError(response.status, await response.text());\n // 4xx other than 429 will fail identically no matter how many times we ask.\n if (!error.retryable || attempt === this.maxRetries) throw error;\n lastError = error;\n await sleep(retryAfterMs(response) ?? backoffMs(attempt));\n }\n throw lastError ?? new PDFCraftError('internal_error', 'Request failed.', 500);\n }\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.round(500 * 2 ** attempt * (0.75 + Math.random() * 0.5));\n}\n\nfunction retryAfterMs(response: Response): number | null {\n const header = response.headers.get('retry-after');\n if (!header) return null;\n const seconds = Number(header);\n return Number.isFinite(seconds) ? Math.max(0, seconds) * 1000 : null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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","sourcesContent":["// src/client.ts\nimport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n RenderRequest,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n} from './contract/index.js';\nimport { PDFCraftError, toError } from './errors.js';\n\nexport interface RendererOptions {\n /** Override for testing or a self-hosted gateway. */\n baseUrl?: string;\n /** Retries on 429 and 5xx only. Default 3. */\n maxRetries?: number;\n /** Per-request timeout in milliseconds. Default 130000, just past the API's own ceiling. */\n timeoutMs?: number;\n fetch?: typeof globalThis.fetch;\n}\n\nconst DEFAULTS = {\n baseUrl: 'https://api.pdfcraft.dev',\n maxRetries: 3,\n timeoutMs: 130_000,\n};\n\n/**\n * The method you call decides the output mode, so passing `output` yourself\n * could only ever contradict it. Excluded from the type rather than ignored at\n * runtime: `render({ output: 'url' })` returning bytes is the kind of silent\n * surprise that costs someone an afternoon.\n */\nexport type RenderInput = Omit<RenderRequest, 'output'>;\nexport type AsyncRenderInput = Omit<AsyncRenderRequest, 'output'>;\n\nexport class Renderer {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly maxRetries: number;\n private readonly timeoutMs: number;\n private readonly doFetch: typeof globalThis.fetch;\n\n constructor(apiKey: string, options: RendererOptions = {}) {\n if (!apiKey) throw new PDFCraftError('invalid_api_key', 'An API key is required.', 401);\n this.apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? DEFAULTS.baseUrl).replace(/\\/+$/, '');\n this.maxRetries = options.maxRetries ?? DEFAULTS.maxRetries;\n this.timeoutMs = options.timeoutMs ?? DEFAULTS.timeoutMs;\n this.doFetch = options.fetch ?? globalThis.fetch.bind(globalThis);\n }\n\n /** The PDF bytes. In Node this is a Buffer, which is a Uint8Array. */\n async render(input: RenderInput, idempotencyKey?: string): Promise<Uint8Array> {\n const response = await this.send('/v1/render', { ...input, output: 'binary' }, idempotencyKey);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return typeof Buffer === 'undefined' ? bytes : Buffer.from(bytes);\n }\n\n /** Uploads the PDF and returns a signed link instead of the bytes. */\n async renderToUrl(input: RenderInput, idempotencyKey?: string): Promise<RenderUrlResponse> {\n const response = await this.send('/v1/render', { ...input, output: 'url' }, idempotencyKey);\n return (await response.json()) as RenderUrlResponse;\n }\n\n /** Queues the render and calls back when it settles. */\n async renderAsync(\n input: AsyncRenderInput,\n idempotencyKey?: string,\n ): Promise<AsyncRenderAccepted> {\n const response = await this.send('/v1/render/async', input, idempotencyKey);\n return (await response.json()) as AsyncRenderAccepted;\n }\n\n async getRender(id: string): Promise<RenderStatusResponse> {\n const response = await this.request(`/v1/renders/${encodeURIComponent(id)}`, { method: 'GET' });\n return (await response.json()) as RenderStatusResponse;\n }\n\n async usage(): Promise<UsageResponse> {\n const response = await this.request('/v1/usage', { method: 'GET' });\n return (await response.json()) as UsageResponse;\n }\n\n private send(path: string, body: unknown, idempotencyKey?: string): Promise<Response> {\n return this.request(path, {\n method: 'POST',\n headers: {\n 'content-type': 'application/json',\n ...(idempotencyKey ? { 'idempotency-key': idempotencyKey } : {}),\n },\n body: JSON.stringify(body),\n });\n }\n\n private async request(path: string, init: RequestInit): Promise<Response> {\n let lastError: PDFCraftError | null = null;\n for (let attempt = 0; attempt <= this.maxRetries; attempt += 1) {\n let response: Response;\n try {\n response = await this.doFetch(`${this.baseUrl}${path}`, {\n ...init,\n headers: {\n authorization: `Bearer ${this.apiKey}`,\n 'user-agent': 'pdfcraft-sdk-js/1.0.0',\n ...(init.headers as Record<string, string> | undefined),\n },\n signal: AbortSignal.timeout(this.timeoutMs),\n });\n } catch (cause) {\n lastError = new PDFCraftError('network_error', `Could not reach PDFCraft: ${cause}`, 0);\n if (attempt === this.maxRetries) throw lastError;\n await sleep(backoffMs(attempt));\n continue;\n }\n\n if (response.ok) return response;\n\n const error = toError(response.status, await response.text());\n // 4xx other than 429 will fail identically no matter how many times we ask.\n if (!error.retryable || attempt === this.maxRetries) throw error;\n lastError = error;\n await sleep(retryAfterMs(response) ?? backoffMs(attempt));\n }\n throw lastError ?? new PDFCraftError('internal_error', 'Request failed.', 500);\n }\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.round(500 * 2 ** attempt * (0.75 + Math.random() * 0.5));\n}\n\nfunction retryAfterMs(response: Response): number | null {\n const header = response.headers.get('retry-after');\n if (!header) return null;\n const seconds = Number(header);\n return Number.isFinite(seconds) ? Math.max(0, seconds) * 1000 : null;\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n"]}
@@ -1,4 +1,4 @@
1
- // packages/contract/src/errors.ts
1
+ // src/contract/errors.ts — generated; see index.ts
2
2
  //
3
3
  // Every error the API can return. The exception filter maps domain errors onto
4
4
  // this table, the SDK exposes `.code` from it, and the docs error reference is
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/contract/errors.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;AAE3E,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,gBAAgB;CACR,CAAC;AAaX,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,4EAA4E;QAClF,QAAQ,EAAE,mFAAmF;KAC9F;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8EAA8E;QACpF,QAAQ,EAAE,+EAA+E;KAC1F;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,mEAAmE;QACzE,QAAQ,EAAE,qFAAqF;KAChG;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,iDAAiD;QACvD,QAAQ,EACN,8FAA8F;KACjG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gEAAgE;QACtE,QAAQ,EACN,wGAAwG;KAC3G;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,yFAAyF;QAC/F,QAAQ,EACN,yFAAyF;KAC5F;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gDAAgD;QACtD,QAAQ,EAAE,wEAAwE;KACnF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,qEAAqE;QAC3E,QAAQ,EACN,qGAAqG;KACxG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8BAA8B;QACpC,QAAQ,EAAE,0EAA0E;KACrF;CACsC,CAAC;AAE1C,MAAM,CAAC,MAAM,kBAAkB,GAA2C,MAAM,CAAC,WAAW,CAC1F,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACb,CAAC;AAElC,MAAM,UAAU,UAAU,CAAC,IAAe;IACxC,OAAO,GAAG,WAAW,WAAW,IAAI,EAAE,CAAC;AACzC,CAAC","sourcesContent":["// packages/contract/src/errors.ts\n//\n// Every error the API can return. The exception filter maps domain errors onto\n// this table, the SDK exposes `.code` from it, and the docs error reference is\n// generated from it — each anchor matches the docs_url the API hands back.\n\nexport const DOCS_ORIGIN = 'https://pdfcraft.dev';\n\nexport const ERROR_CODES = [\n 'invalid_request',\n 'invalid_api_key',\n 'payment_required',\n 'not_found',\n 'render_timeout',\n 'render_failed',\n 'rate_limited',\n 'quota_exceeded',\n 'internal_error',\n] as const;\n\nexport type ErrorCode = (typeof ERROR_CODES)[number];\n\nexport interface ErrorSpec {\n readonly code: ErrorCode;\n readonly status: number;\n /** True when Chromium actually ran, which is what makes a render billable. */\n readonly billable: boolean;\n readonly when: string;\n readonly whatToDo: string;\n}\n\nexport const ERROR_TABLE = [\n {\n code: 'invalid_request',\n status: 400,\n billable: false,\n when: 'Both html and url were supplied, or neither, or an option is out of range.',\n whatToDo: 'Read the message — it names the offending field. Send exactly one of html or url.',\n },\n {\n code: 'invalid_api_key',\n status: 401,\n billable: false,\n when: 'The Authorization header is missing, malformed, or the key has been revoked.',\n whatToDo: 'Send \"Authorization: Bearer sk_live_…\". Issue a fresh key from the dashboard.',\n },\n {\n code: 'payment_required',\n status: 402,\n billable: false,\n when: 'The last subscription payment failed, so the account is past_due.',\n whatToDo: 'Update the card on the billing portal. Rendering resumes the moment payment clears.',\n },\n {\n code: 'not_found',\n status: 404,\n billable: false,\n when: 'No render with that id belongs to your account.',\n whatToDo:\n 'Check the id. Ids from another account also return 404, never 403, so they cannot be probed.',\n },\n {\n code: 'render_timeout',\n status: 408,\n billable: false,\n when: 'The page did not finish within timeoutMs and was force-closed.',\n whatToDo:\n 'Raise timeoutMs (max 120000), or relax waitFor — networkIdle on a page with a long-poll never settles.',\n },\n {\n code: 'render_failed',\n status: 422,\n billable: true,\n when: 'Chromium ran but the page threw, navigation failed, or waitFor.selector never appeared.',\n whatToDo:\n 'Load the same HTML in a browser. This one is billable because the browser did the work.',\n },\n {\n code: 'rate_limited',\n status: 429,\n billable: false,\n when: 'More requests per second than the plan allows.',\n whatToDo: 'Honour the Retry-After header and back off. Paid plans allow 20 req/s.',\n },\n {\n code: 'quota_exceeded',\n status: 429,\n billable: false,\n when: 'A free-plan account has used all 100 renders in the current period.',\n whatToDo:\n 'Upgrade, or wait for resets_at from GET /v1/usage. Paid plans never hard-stop; they accrue overage.',\n },\n {\n code: 'internal_error',\n status: 500,\n billable: false,\n when: 'Something on our side broke.',\n whatToDo: 'Retry with backoff. Never billed. If it persists, send us the render id.',\n },\n] as const satisfies readonly ErrorSpec[];\n\nexport const ERROR_SPEC_BY_CODE: Readonly<Record<ErrorCode, ErrorSpec>> = Object.fromEntries(\n ERROR_TABLE.map((spec) => [spec.code, spec]),\n) as Record<ErrorCode, ErrorSpec>;\n\nexport function docsUrlFor(code: ErrorCode): string {\n return `${DOCS_ORIGIN}/errors#${code}`;\n}\n\nexport interface ApiErrorBody {\n error: {\n code: ErrorCode;\n message: string;\n docs_url: string;\n };\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/contract/errors.ts"],"names":[],"mappings":"AAAA,mDAAmD;AACnD,EAAE;AACF,+EAA+E;AAC/E,+EAA+E;AAC/E,2EAA2E;AAE3E,MAAM,CAAC,MAAM,WAAW,GAAG,sBAAsB,CAAC;AAElD,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,iBAAiB;IACjB,iBAAiB;IACjB,kBAAkB;IAClB,WAAW;IACX,gBAAgB;IAChB,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,gBAAgB;CACR,CAAC;AAaX,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,4EAA4E;QAClF,QAAQ,EAAE,mFAAmF;KAC9F;IACD;QACE,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8EAA8E;QACpF,QAAQ,EAAE,+EAA+E;KAC1F;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,mEAAmE;QACzE,QAAQ,EAAE,qFAAqF;KAChG;IACD;QACE,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,iDAAiD;QACvD,QAAQ,EACN,8FAA8F;KACjG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gEAAgE;QACtE,QAAQ,EACN,wGAAwG;KAC3G;IACD;QACE,IAAI,EAAE,eAAe;QACrB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE,yFAAyF;QAC/F,QAAQ,EACN,yFAAyF;KAC5F;IACD;QACE,IAAI,EAAE,cAAc;QACpB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,gDAAgD;QACtD,QAAQ,EAAE,wEAAwE;KACnF;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,qEAAqE;QAC3E,QAAQ,EACN,qGAAqG;KACxG;IACD;QACE,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,GAAG;QACX,QAAQ,EAAE,KAAK;QACf,IAAI,EAAE,8BAA8B;QACpC,QAAQ,EAAE,0EAA0E;KACrF;CACsC,CAAC;AAE1C,MAAM,CAAC,MAAM,kBAAkB,GAA2C,MAAM,CAAC,WAAW,CAC1F,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CACb,CAAC;AAElC,MAAM,UAAU,UAAU,CAAC,IAAe;IACxC,OAAO,GAAG,WAAW,WAAW,IAAI,EAAE,CAAC;AACzC,CAAC","sourcesContent":["// src/contract/errors.ts — generated; see index.ts\n//\n// Every error the API can return. The exception filter maps domain errors onto\n// this table, the SDK exposes `.code` from it, and the docs error reference is\n// generated from it — each anchor matches the docs_url the API hands back.\n\nexport const DOCS_ORIGIN = 'https://pdfcraft.dev';\n\nexport const ERROR_CODES = [\n 'invalid_request',\n 'invalid_api_key',\n 'payment_required',\n 'not_found',\n 'render_timeout',\n 'render_failed',\n 'rate_limited',\n 'quota_exceeded',\n 'internal_error',\n] as const;\n\nexport type ErrorCode = (typeof ERROR_CODES)[number];\n\nexport interface ErrorSpec {\n readonly code: ErrorCode;\n readonly status: number;\n /** True when Chromium actually ran, which is what makes a render billable. */\n readonly billable: boolean;\n readonly when: string;\n readonly whatToDo: string;\n}\n\nexport const ERROR_TABLE = [\n {\n code: 'invalid_request',\n status: 400,\n billable: false,\n when: 'Both html and url were supplied, or neither, or an option is out of range.',\n whatToDo: 'Read the message — it names the offending field. Send exactly one of html or url.',\n },\n {\n code: 'invalid_api_key',\n status: 401,\n billable: false,\n when: 'The Authorization header is missing, malformed, or the key has been revoked.',\n whatToDo: 'Send \"Authorization: Bearer sk_live_…\". Issue a fresh key from the dashboard.',\n },\n {\n code: 'payment_required',\n status: 402,\n billable: false,\n when: 'The last subscription payment failed, so the account is past_due.',\n whatToDo: 'Update the card on the billing portal. Rendering resumes the moment payment clears.',\n },\n {\n code: 'not_found',\n status: 404,\n billable: false,\n when: 'No render with that id belongs to your account.',\n whatToDo:\n 'Check the id. Ids from another account also return 404, never 403, so they cannot be probed.',\n },\n {\n code: 'render_timeout',\n status: 408,\n billable: false,\n when: 'The page did not finish within timeoutMs and was force-closed.',\n whatToDo:\n 'Raise timeoutMs (max 120000), or relax waitFor — networkIdle on a page with a long-poll never settles.',\n },\n {\n code: 'render_failed',\n status: 422,\n billable: true,\n when: 'Chromium ran but the page threw, navigation failed, or waitFor.selector never appeared.',\n whatToDo:\n 'Load the same HTML in a browser. This one is billable because the browser did the work.',\n },\n {\n code: 'rate_limited',\n status: 429,\n billable: false,\n when: 'More requests per second than the plan allows.',\n whatToDo: 'Honour the Retry-After header and back off. Paid plans allow 20 req/s.',\n },\n {\n code: 'quota_exceeded',\n status: 429,\n billable: false,\n when: 'A free-plan account has used all 100 renders in the current period.',\n whatToDo:\n 'Upgrade, or wait for resets_at from GET /v1/usage. Paid plans never hard-stop; they accrue overage.',\n },\n {\n code: 'internal_error',\n status: 500,\n billable: false,\n when: 'Something on our side broke.',\n whatToDo: 'Retry with backoff. Never billed. If it persists, send us the render id.',\n },\n] as const satisfies readonly ErrorSpec[];\n\nexport const ERROR_SPEC_BY_CODE: Readonly<Record<ErrorCode, ErrorSpec>> = Object.fromEntries(\n ERROR_TABLE.map((spec) => [spec.code, spec]),\n) as Record<ErrorCode, ErrorSpec>;\n\nexport function docsUrlFor(code: ErrorCode): string {\n return `${DOCS_ORIGIN}/errors#${code}`;\n}\n\nexport interface ApiErrorBody {\n error: {\n code: ErrorCode;\n message: string;\n docs_url: string;\n };\n}\n"]}
@@ -1,9 +1,10 @@
1
- // packages/contract/src/render-options.ts
1
+ // src/contract/render-options.ts — generated; see index.ts
2
2
  //
3
3
  // The one description of the render option surface. The API builds its validator
4
4
  // from RENDER_OPTIONS_SPEC and the docs site builds its reference table from the
5
- // same constant, so the two cannot drift. The SDK vendors this file verbatim at
6
- // build time (see packages/sdk/scripts/vendor-contract.mjs) to stay dependency-free.
5
+ // same constant, so the two cannot drift. The SDK, which lives in its own repo,
6
+ // keeps a copy written by scripts/sync-sdk.mjs so it can stay dependency-free
7
+ // apps/api/test/contract-sync.spec.ts fails when this file changes without it.
7
8
  export const PAGE_FORMATS = ['A4', 'A3', 'A5', 'Letter', 'Legal', 'Tabloid'];
8
9
  export const EMULATE_MEDIA = ['print', 'screen'];
9
10
  export const MAX_TIMEOUT_MS = 120_000;
@@ -1 +1 @@
1
- {"version":3,"file":"render-options.js","sourceRoot":"","sources":["../../../src/contract/render-options.ts"],"names":[],"mappings":"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","sourcesContent":["// packages/contract/src/render-options.ts\n//\n// The one description of the render option surface. The API builds its validator\n// from RENDER_OPTIONS_SPEC and the docs site builds its reference table from the\n// same constant, so the two cannot drift. The SDK vendors this file verbatim at\n// build time (see packages/sdk/scripts/vendor-contract.mjs) to stay dependency-free.\n\nexport type OptionKind =\n | { readonly kind: 'enum'; readonly values: readonly string[] }\n | { readonly kind: 'boolean' }\n | { readonly kind: 'number'; readonly min: number; readonly max: number }\n | { readonly kind: 'integer'; readonly min: number; readonly max: number }\n | { readonly kind: 'string'; readonly maxLength: number; readonly pattern?: string }\n | { readonly kind: 'css-length' }\n | { readonly kind: 'object'; readonly fields: readonly OptionField[] };\n\nexport interface OptionField {\n readonly name: string;\n readonly type: OptionKind;\n readonly default?: string | number | boolean;\n readonly description: string;\n}\n\nexport const PAGE_FORMATS = ['A4', 'A3', 'A5', 'Letter', 'Legal', 'Tabloid'] as const;\nexport const EMULATE_MEDIA = ['print', 'screen'] as const;\n\nexport const MAX_TIMEOUT_MS = 120_000;\nexport const DEFAULT_TIMEOUT_MS = 30_000;\nexport const MAX_HTML_BYTES = 5_000_000;\n\nexport const RENDER_OPTIONS_SPEC = [\n {\n name: 'format',\n type: { kind: 'enum', values: PAGE_FORMATS },\n default: 'A4',\n description: 'Paper size. Ignored if the page CSS declares its own @page size.',\n },\n {\n name: 'landscape',\n type: { kind: 'boolean' },\n default: false,\n description: 'Rotate the paper to landscape orientation.',\n },\n {\n name: 'margin',\n type: {\n kind: 'object',\n fields: [\n { name: 'top', type: { kind: 'css-length' }, description: 'e.g. \"20mm\", \"1in\", \"72px\".' },\n { name: 'right', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n { name: 'bottom', type: { kind: 'css-length' }, description: 'e.g. \"20mm\".' },\n { name: 'left', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n ],\n },\n description: 'Page margins. Any side may be omitted; omitted sides default to 0.',\n },\n {\n name: 'scale',\n type: { kind: 'number', min: 0.1, max: 2 },\n default: 1,\n description: 'Rendering scale factor.',\n },\n {\n name: 'printBackground',\n type: { kind: 'boolean' },\n default: true,\n description:\n 'Print background colours and images. Off by default in browsers; on by default here.',\n },\n {\n name: 'pageRanges',\n type: { kind: 'string', maxLength: 100, pattern: '^[0-9,\\\\-\\\\s]+$' },\n description: 'Subset of pages to keep, e.g. \"1-5\" or \"1,4,7-9\". Empty means all pages.',\n },\n {\n name: 'headerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description:\n 'HTML for the running header. Supports Chromium print classes: date, title, url, pageNumber, totalPages. Needs a top margin to be visible.',\n },\n {\n name: 'footerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description: 'HTML for the running footer. Same classes as headerHtml; needs a bottom margin.',\n },\n {\n name: 'waitFor',\n type: {\n kind: 'object',\n fields: [\n {\n name: 'selector',\n type: { kind: 'string', maxLength: 500 },\n description: 'Wait until this CSS selector is attached to the DOM.',\n },\n {\n name: 'networkIdle',\n type: { kind: 'boolean' },\n default: false,\n description: 'Wait until there have been no network connections for 500 ms.',\n },\n {\n name: 'delayMs',\n type: { kind: 'integer', min: 0, max: 30_000 },\n default: 0,\n description: 'Fixed pause after the other wait conditions are satisfied.',\n },\n ],\n },\n description: 'Conditions to satisfy before the PDF is taken. All of them apply, in order.',\n },\n {\n name: 'emulateMedia',\n type: { kind: 'enum', values: EMULATE_MEDIA },\n default: 'print',\n description: 'Which CSS media type the page sees.',\n },\n {\n name: 'timeoutMs',\n type: { kind: 'integer', min: 1000, max: MAX_TIMEOUT_MS },\n default: DEFAULT_TIMEOUT_MS,\n description: 'Hard ceiling on the whole render. Exceeding it returns 408 render_timeout.',\n },\n] as const satisfies readonly OptionField[];\n\nexport interface Margin {\n top?: string;\n right?: string;\n bottom?: string;\n left?: string;\n}\n\nexport interface WaitFor {\n selector?: string;\n networkIdle?: boolean;\n delayMs?: number;\n}\n\nexport interface RenderOptions {\n format?: (typeof PAGE_FORMATS)[number];\n landscape?: boolean;\n margin?: Margin;\n scale?: number;\n printBackground?: boolean;\n pageRanges?: string;\n headerHtml?: string;\n footerHtml?: string;\n waitFor?: WaitFor;\n emulateMedia?: (typeof EMULATE_MEDIA)[number];\n timeoutMs?: number;\n}\n\ntype SpecFieldName = (typeof RENDER_OPTIONS_SPEC)[number]['name'];\n\n// Compile-time drift guard: this assignment stops type-checking the moment\n// RENDER_OPTIONS_SPEC and RenderOptions describe different sets of options.\nconst driftCheck: [Exclude<keyof RenderOptions, SpecFieldName>] extends [never]\n ? [Exclude<SpecFieldName, keyof RenderOptions>] extends [never]\n ? true\n : never\n : never = true;\n\nexport const SPEC_MATCHES_TYPES: boolean = driftCheck;\n"]}
1
+ {"version":3,"file":"render-options.js","sourceRoot":"","sources":["../../../src/contract/render-options.ts"],"names":[],"mappings":"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","sourcesContent":["// src/contract/render-options.ts — generated; see index.ts\n//\n// The one description of the render option surface. The API builds its validator\n// from RENDER_OPTIONS_SPEC and the docs site builds its reference table from the\n// same constant, so the two cannot drift. The SDK, which lives in its own repo,\n// keeps a copy written by scripts/sync-sdk.mjs so it can stay dependency-free —\n// apps/api/test/contract-sync.spec.ts fails when this file changes without it.\n\nexport type OptionKind =\n | { readonly kind: 'enum'; readonly values: readonly string[] }\n | { readonly kind: 'boolean' }\n | { readonly kind: 'number'; readonly min: number; readonly max: number }\n | { readonly kind: 'integer'; readonly min: number; readonly max: number }\n | { readonly kind: 'string'; readonly maxLength: number; readonly pattern?: string }\n | { readonly kind: 'css-length' }\n | { readonly kind: 'object'; readonly fields: readonly OptionField[] };\n\nexport interface OptionField {\n readonly name: string;\n readonly type: OptionKind;\n readonly default?: string | number | boolean;\n readonly description: string;\n}\n\nexport const PAGE_FORMATS = ['A4', 'A3', 'A5', 'Letter', 'Legal', 'Tabloid'] as const;\nexport const EMULATE_MEDIA = ['print', 'screen'] as const;\n\nexport const MAX_TIMEOUT_MS = 120_000;\nexport const DEFAULT_TIMEOUT_MS = 30_000;\nexport const MAX_HTML_BYTES = 5_000_000;\n\nexport const RENDER_OPTIONS_SPEC = [\n {\n name: 'format',\n type: { kind: 'enum', values: PAGE_FORMATS },\n default: 'A4',\n description: 'Paper size. Ignored if the page CSS declares its own @page size.',\n },\n {\n name: 'landscape',\n type: { kind: 'boolean' },\n default: false,\n description: 'Rotate the paper to landscape orientation.',\n },\n {\n name: 'margin',\n type: {\n kind: 'object',\n fields: [\n { name: 'top', type: { kind: 'css-length' }, description: 'e.g. \"20mm\", \"1in\", \"72px\".' },\n { name: 'right', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n { name: 'bottom', type: { kind: 'css-length' }, description: 'e.g. \"20mm\".' },\n { name: 'left', type: { kind: 'css-length' }, description: 'e.g. \"15mm\".' },\n ],\n },\n description: 'Page margins. Any side may be omitted; omitted sides default to 0.',\n },\n {\n name: 'scale',\n type: { kind: 'number', min: 0.1, max: 2 },\n default: 1,\n description: 'Rendering scale factor.',\n },\n {\n name: 'printBackground',\n type: { kind: 'boolean' },\n default: true,\n description:\n 'Print background colours and images. Off by default in browsers; on by default here.',\n },\n {\n name: 'pageRanges',\n type: { kind: 'string', maxLength: 100, pattern: '^[0-9,\\\\-\\\\s]+$' },\n description: 'Subset of pages to keep, e.g. \"1-5\" or \"1,4,7-9\". Empty means all pages.',\n },\n {\n name: 'headerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description:\n 'HTML for the running header. Supports Chromium print classes: date, title, url, pageNumber, totalPages. Needs a top margin to be visible.',\n },\n {\n name: 'footerHtml',\n type: { kind: 'string', maxLength: 50_000 },\n description: 'HTML for the running footer. Same classes as headerHtml; needs a bottom margin.',\n },\n {\n name: 'waitFor',\n type: {\n kind: 'object',\n fields: [\n {\n name: 'selector',\n type: { kind: 'string', maxLength: 500 },\n description: 'Wait until this CSS selector is attached to the DOM.',\n },\n {\n name: 'networkIdle',\n type: { kind: 'boolean' },\n default: false,\n description: 'Wait until there have been no network connections for 500 ms.',\n },\n {\n name: 'delayMs',\n type: { kind: 'integer', min: 0, max: 30_000 },\n default: 0,\n description: 'Fixed pause after the other wait conditions are satisfied.',\n },\n ],\n },\n description: 'Conditions to satisfy before the PDF is taken. All of them apply, in order.',\n },\n {\n name: 'emulateMedia',\n type: { kind: 'enum', values: EMULATE_MEDIA },\n default: 'print',\n description: 'Which CSS media type the page sees.',\n },\n {\n name: 'timeoutMs',\n type: { kind: 'integer', min: 1000, max: MAX_TIMEOUT_MS },\n default: DEFAULT_TIMEOUT_MS,\n description: 'Hard ceiling on the whole render. Exceeding it returns 408 render_timeout.',\n },\n] as const satisfies readonly OptionField[];\n\nexport interface Margin {\n top?: string;\n right?: string;\n bottom?: string;\n left?: string;\n}\n\nexport interface WaitFor {\n selector?: string;\n networkIdle?: boolean;\n delayMs?: number;\n}\n\nexport interface RenderOptions {\n format?: (typeof PAGE_FORMATS)[number];\n landscape?: boolean;\n margin?: Margin;\n scale?: number;\n printBackground?: boolean;\n pageRanges?: string;\n headerHtml?: string;\n footerHtml?: string;\n waitFor?: WaitFor;\n emulateMedia?: (typeof EMULATE_MEDIA)[number];\n timeoutMs?: number;\n}\n\ntype SpecFieldName = (typeof RENDER_OPTIONS_SPEC)[number]['name'];\n\n// Compile-time drift guard: this assignment stops type-checking the moment\n// RENDER_OPTIONS_SPEC and RenderOptions describe different sets of options.\nconst driftCheck: [Exclude<keyof RenderOptions, SpecFieldName>] extends [never]\n ? [Exclude<SpecFieldName, keyof RenderOptions>] extends [never]\n ? true\n : never\n : never = true;\n\nexport const SPEC_MATCHES_TYPES: boolean = driftCheck;\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/contract/request.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAC;AAGvD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAGvF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,KAAK,CAAU,CAAC;AAGvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAuE7E,kEAAkE;AAClE,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;QAC9C,WAAW,EAAE,+EAA+E;KAC7F;IACD;QACE,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;QACzC,WAAW,EAAE,+DAA+D;KAC7E;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE;QAC5C,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,iFAAiF;KAC/F;IACD;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE;QACxC,OAAO,EAAE,cAAc;QACvB,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,iFAAiF;KAC/F;CACwC,CAAC","sourcesContent":["// packages/contract/src/request.ts\nimport { type OptionField, type RenderOptions } from './render-options.js';\n\nexport const OUTPUT_MODES = ['binary', 'url'] as const;\nexport type OutputMode = (typeof OUTPUT_MODES)[number];\n\nexport const RENDER_STATUSES = ['queued', 'rendering', 'succeeded', 'failed'] as const;\nexport type RenderStatus = (typeof RENDER_STATUSES)[number];\n\nexport const RENDER_SOURCES = ['html', 'url'] as const;\nexport type RenderSource = (typeof RENDER_SOURCES)[number];\n\nexport const ACCOUNT_STATUSES = ['active', 'past_due', 'cancelled'] as const;\nexport type AccountStatus = (typeof ACCOUNT_STATUSES)[number];\n\nexport interface Cookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n}\n\nexport interface RenderRequest {\n /** Exactly one of html or url. */\n html?: string;\n url?: string;\n options?: RenderOptions;\n output?: OutputMode;\n filename?: string;\n /** url input only: extra request headers, so an authenticated page can be rendered. */\n headers?: Record<string, string>;\n /** url input only: cookies to seed the context with. */\n cookies?: Cookie[];\n}\n\nexport interface AsyncRenderRequest extends RenderRequest {\n callback_url: string;\n}\n\nexport interface RenderUrlResponse {\n id: string;\n url: string;\n expires_at: string;\n pages: number;\n bytes: number;\n duration_ms: number;\n}\n\nexport interface AsyncRenderAccepted {\n id: string;\n status: 'queued';\n}\n\nexport interface RenderStatusResponse {\n id: string;\n status: RenderStatus;\n url?: string;\n expires_at?: string;\n pages?: number;\n bytes?: number;\n duration_ms?: number;\n error?: { code: string; message: string };\n}\n\nexport interface UsageResponse {\n used: number;\n limit: number;\n overage_count: number;\n period_start: string;\n resets_at: string;\n}\n\n/** Body sent to callback_url when an async render settles. */\nexport interface WebhookPayload {\n id: string;\n status: 'succeeded' | 'failed';\n url?: string;\n pages?: number;\n bytes?: number;\n duration_ms: number;\n error?: { code: string; message: string };\n}\n\n/** Top-level request fields, for the generated docs reference. */\nexport const REQUEST_FIELDS_SPEC = [\n {\n name: 'html',\n type: { kind: 'string', maxLength: 5_000_000 },\n description: 'The document to render. Mutually exclusive with url; exactly one is required.',\n },\n {\n name: 'url',\n type: { kind: 'string', maxLength: 2000 },\n description: 'A public http(s) URL to render. Mutually exclusive with html.',\n },\n {\n name: 'output',\n type: { kind: 'enum', values: OUTPUT_MODES },\n default: 'binary',\n description: '\"binary\" streams application/pdf back; \"url\" uploads and returns a signed link.',\n },\n {\n name: 'filename',\n type: { kind: 'string', maxLength: 255 },\n default: 'document.pdf',\n description: 'Used for Content-Disposition on binary output and in the signed URL.',\n },\n {\n name: 'headers',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Extra request headers, e.g. an Authorization header.',\n },\n {\n name: 'cookies',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Array of {name, value, domain?, path?} seeded into the context.',\n },\n] as const satisfies readonly OptionField[];\n"]}
1
+ {"version":3,"file":"request.js","sourceRoot":"","sources":["../../../src/contract/request.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAU,CAAC;AAGvD,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAC;AAGvF,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,KAAK,CAAU,CAAC;AAGvD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,CAAU,CAAC;AAuE7E,kEAAkE;AAClE,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC;QACE,IAAI,EAAE,MAAM;QACZ,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE;QAC9C,WAAW,EAAE,+EAA+E;KAC7F;IACD;QACE,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE;QACzC,WAAW,EAAE,+DAA+D;KAC7E;IACD;QACE,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE;QAC5C,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,iFAAiF;KAC/F;IACD;QACE,IAAI,EAAE,UAAU;QAChB,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,EAAE;QACxC,OAAO,EAAE,cAAc;QACvB,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,sEAAsE;KACpF;IACD;QACE,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE;QACpC,WAAW,EAAE,iFAAiF;KAC/F;CACwC,CAAC","sourcesContent":["// src/contract/request.ts — generated; see index.ts\nimport { type OptionField, type RenderOptions } from './render-options.js';\n\nexport const OUTPUT_MODES = ['binary', 'url'] as const;\nexport type OutputMode = (typeof OUTPUT_MODES)[number];\n\nexport const RENDER_STATUSES = ['queued', 'rendering', 'succeeded', 'failed'] as const;\nexport type RenderStatus = (typeof RENDER_STATUSES)[number];\n\nexport const RENDER_SOURCES = ['html', 'url'] as const;\nexport type RenderSource = (typeof RENDER_SOURCES)[number];\n\nexport const ACCOUNT_STATUSES = ['active', 'past_due', 'cancelled'] as const;\nexport type AccountStatus = (typeof ACCOUNT_STATUSES)[number];\n\nexport interface Cookie {\n name: string;\n value: string;\n domain?: string;\n path?: string;\n}\n\nexport interface RenderRequest {\n /** Exactly one of html or url. */\n html?: string;\n url?: string;\n options?: RenderOptions;\n output?: OutputMode;\n filename?: string;\n /** url input only: extra request headers, so an authenticated page can be rendered. */\n headers?: Record<string, string>;\n /** url input only: cookies to seed the context with. */\n cookies?: Cookie[];\n}\n\nexport interface AsyncRenderRequest extends RenderRequest {\n callback_url: string;\n}\n\nexport interface RenderUrlResponse {\n id: string;\n url: string;\n expires_at: string;\n pages: number;\n bytes: number;\n duration_ms: number;\n}\n\nexport interface AsyncRenderAccepted {\n id: string;\n status: 'queued';\n}\n\nexport interface RenderStatusResponse {\n id: string;\n status: RenderStatus;\n url?: string;\n expires_at?: string;\n pages?: number;\n bytes?: number;\n duration_ms?: number;\n error?: { code: string; message: string };\n}\n\nexport interface UsageResponse {\n used: number;\n limit: number;\n overage_count: number;\n period_start: string;\n resets_at: string;\n}\n\n/** Body sent to callback_url when an async render settles. */\nexport interface WebhookPayload {\n id: string;\n status: 'succeeded' | 'failed';\n url?: string;\n pages?: number;\n bytes?: number;\n duration_ms: number;\n error?: { code: string; message: string };\n}\n\n/** Top-level request fields, for the generated docs reference. */\nexport const REQUEST_FIELDS_SPEC = [\n {\n name: 'html',\n type: { kind: 'string', maxLength: 5_000_000 },\n description: 'The document to render. Mutually exclusive with url; exactly one is required.',\n },\n {\n name: 'url',\n type: { kind: 'string', maxLength: 2000 },\n description: 'A public http(s) URL to render. Mutually exclusive with html.',\n },\n {\n name: 'output',\n type: { kind: 'enum', values: OUTPUT_MODES },\n default: 'binary',\n description: '\"binary\" streams application/pdf back; \"url\" uploads and returns a signed link.',\n },\n {\n name: 'filename',\n type: { kind: 'string', maxLength: 255 },\n default: 'document.pdf',\n description: 'Used for Content-Disposition on binary output and in the signed URL.',\n },\n {\n name: 'headers',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Extra request headers, e.g. an Authorization header.',\n },\n {\n name: 'cookies',\n type: { kind: 'object', fields: [] },\n description: 'url input only. Array of {name, value, domain?, path?} seeded into the context.',\n },\n] as const satisfies readonly OptionField[];\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAGA,6EAA6E;AAC7E,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAA8B;IAClC,MAAM,CAAS;IACf,OAAO,CAAgB;IACvB,SAAS,CAAU;IAE5B,YACE,IAAiC,EACjC,OAAe,EACf,MAAc,EACd,UAAyB,IAAI;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,eAAe,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;IAC/E,CAAC;CACF;AAMD,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,IAAY;IAClD,IAAI,MAAM,GAAc,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IACD,OAAO,IAAI,aAAa,CACrB,MAAM,CAAC,KAAK,EAAE,IAAkB,IAAI,gBAAgB,EACrD,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,sBAAsB,MAAM,EAAE,EACvD,MAAM,EACN,MAAM,CAAC,KAAK,EAAE,QAAQ,IAAI,IAAI,CAC/B,CAAC;AACJ,CAAC","sourcesContent":["// packages/sdk/src/errors.ts\nimport type { ErrorCode } from './contract/index.js';\n\n/** Every failure from the API arrives as one of these. Branch on `.code`. */\nexport class PDFCraftError extends Error {\n readonly code: ErrorCode | 'network_error';\n readonly status: number;\n readonly docsUrl: string | null;\n readonly retryable: boolean;\n\n constructor(\n code: ErrorCode | 'network_error',\n message: string,\n status: number,\n docsUrl: string | null = null,\n ) {\n super(message);\n this.name = 'PDFCraftError';\n this.code = code;\n this.status = status;\n this.docsUrl = docsUrl;\n this.retryable = code === 'network_error' || status === 429 || status >= 500;\n }\n}\n\ninterface WireError {\n error?: { code?: string; message?: string; docs_url?: string };\n}\n\nexport function toError(status: number, body: string): PDFCraftError {\n let parsed: WireError = {};\n try {\n parsed = JSON.parse(body) as WireError;\n } catch {\n // Non-JSON body (a proxy error page, say) — fall through to the defaults.\n }\n return new PDFCraftError(\n (parsed.error?.code as ErrorCode) ?? 'internal_error',\n parsed.error?.message ?? `PDFCraft responded ${status}`,\n status,\n parsed.error?.docs_url ?? null,\n );\n}\n"]}
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAGA,6EAA6E;AAC7E,MAAM,OAAO,aAAc,SAAQ,KAAK;IAC7B,IAAI,CAA8B;IAClC,MAAM,CAAS;IACf,OAAO,CAAgB;IACvB,SAAS,CAAU;IAE5B,YACE,IAAiC,EACjC,OAAe,EACf,MAAc,EACd,UAAyB,IAAI;QAE7B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,IAAI,KAAK,eAAe,IAAI,MAAM,KAAK,GAAG,IAAI,MAAM,IAAI,GAAG,CAAC;IAC/E,CAAC;CACF;AAMD,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,IAAY;IAClD,IAAI,MAAM,GAAc,EAAE,CAAC;IAC3B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAc,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IACD,OAAO,IAAI,aAAa,CACrB,MAAM,CAAC,KAAK,EAAE,IAAkB,IAAI,gBAAgB,EACrD,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,sBAAsB,MAAM,EAAE,EACvD,MAAM,EACN,MAAM,CAAC,KAAK,EAAE,QAAQ,IAAI,IAAI,CAC/B,CAAC;AACJ,CAAC","sourcesContent":["// src/errors.ts\nimport type { ErrorCode } from './contract/index.js';\n\n/** Every failure from the API arrives as one of these. Branch on `.code`. */\nexport class PDFCraftError extends Error {\n readonly code: ErrorCode | 'network_error';\n readonly status: number;\n readonly docsUrl: string | null;\n readonly retryable: boolean;\n\n constructor(\n code: ErrorCode | 'network_error',\n message: string,\n status: number,\n docsUrl: string | null = null,\n ) {\n super(message);\n this.name = 'PDFCraftError';\n this.code = code;\n this.status = status;\n this.docsUrl = docsUrl;\n this.retryable = code === 'network_error' || status === 429 || status >= 500;\n }\n}\n\ninterface WireError {\n error?: { code?: string; message?: string; docs_url?: string };\n}\n\nexport function toError(status: number, body: string): PDFCraftError {\n let parsed: WireError = {};\n try {\n parsed = JSON.parse(body) as WireError;\n } catch {\n // Non-JSON body (a proxy error page, say) — fall through to the defaults.\n }\n return new PDFCraftError(\n (parsed.error?.code as ErrorCode) ?? 'internal_error',\n parsed.error?.message ?? `PDFCraft responded ${status}`,\n status,\n parsed.error?.docs_url ?? null,\n );\n}\n"]}
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- // packages/sdk/src/index.ts
1
+ // src/index.ts
2
2
  export { Renderer, } from './client.js';
3
3
  export { PDFCraftError } from './errors.js';
4
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,4BAA4B;AAC5B,OAAO,EACL,QAAQ,GAIT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC","sourcesContent":["// packages/sdk/src/index.ts\nexport {\n Renderer,\n type AsyncRenderInput,\n type RenderInput,\n type RendererOptions,\n} from './client.js';\nexport { PDFCraftError } from './errors.js';\nexport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n Cookie,\n ErrorCode,\n Margin,\n OutputMode,\n RenderOptions,\n RenderRequest,\n RenderStatus,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n WaitFor,\n WebhookPayload,\n} from './contract/index.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,eAAe;AACf,OAAO,EACL,QAAQ,GAIT,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC","sourcesContent":["// src/index.ts\nexport {\n Renderer,\n type AsyncRenderInput,\n type RenderInput,\n type RendererOptions,\n} from './client.js';\nexport { PDFCraftError } from './errors.js';\nexport type {\n AsyncRenderAccepted,\n AsyncRenderRequest,\n Cookie,\n ErrorCode,\n Margin,\n OutputMode,\n RenderOptions,\n RenderRequest,\n RenderStatus,\n RenderStatusResponse,\n RenderUrlResponse,\n UsageResponse,\n WaitFor,\n WebhookPayload,\n} from './contract/index.js';\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pdfcraft-dev/pdf",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "HTML to PDF in one call. The official PDFCraft SDK.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://pdfcraft.dev",