@layoutor/sdk
v1.0.1
Published
TypeScript client for Layoutor's PDF layout-preservation and text-rewrite service
Readme
@layoutor/sdk
TypeScript client for Layoutor, a layout-preservation service, not a translation engine. It extracts a PDF's text as units for your callback to rewrite, then re-typesets your submitted text so the PDF looks like the original. Change register or tone, simplify or correct text, apply a glossary, or translate; Layoutor never writes, translates, or judges text itself. targetLang is the language of the text your callback submits, so use the source language for same-language edits.
Install
npm install @layoutor/sdkNode.js 20 or newer and modern browsers are supported. The package includes ESM, CommonJS, and TypeScript declarations.
Authentication
Pass an API key explicitly:
import { LayoutorClient } from "@layoutor/sdk";
const client = new LayoutorClient({ apiKey: "lk_live_..." });In Node.js, LAYOUTOR_API_KEY is used when apiKey is omitted. Do not put an API key in browser source or a public frontend bundle. Obtain it from your own trusted backend at runtime, or call Layoutor from that backend.
API keys must be lk_live_ followed by exactly 43 URL-safe characters (A-Z, a-z, 0-9, _, or -).
Every other value, including the empty string, produces invalid_api_key; an unspecified key produces
invalid_request. Error messages and request IDs redact every occurrence of the configured key,
including occurrences embedded in a longer string. They also redact every string matching
lk_live_[A-Za-z0-9_-]{43}. A non-key identifier with that exact shape is therefore intentionally redacted as a
false positive. Error codes are never redacted.
Translate a document
import { readFile, writeFile } from "node:fs/promises";
import { LayoutorClient } from "@layoutor/sdk";
const client = new LayoutorClient();
const source = await readFile("source.pdf");
const result = await client.translateDocument({
file: source,
fileName: "source.pdf",
sourceLang: "en",
targetLang: "ja",
async translate(units, { notes, document }) {
console.log(notes);
console.log(`Translate before ${document.expires_at}`);
return {
units: await myTranslator(units.filter((unit) => unit.translate))
};
}
});
await writeFile("translated.pdf", result.pdf);The callback receives readonly Unit[] and { notes, document }. It may return a UnitsSubmission object or its units array. It must return exactly one known ID for every unit whose translate property is true. The SDK always submits source text for translate: false units.
Ready documents are retained for only 10 minutes. The deadline is available as document.expires_at in the callback context. If submission happens after it, the API error is thrown as LayoutorError and the PDF must be uploaded again.
The SDK uses a deterministic idempotency key for each file and language pair. If document creation replays an earlier run that is already composing, completed, failed, or expired, the SDK obtains a new signed upload and recreates the document once with a randomized suffix. If a caller-supplied idempotencyKey was used, or the recreation is also a replay, it instead throws LayoutorError with code document_replayed and includes the replayed status in the message.
The result is { documentId, document, submission, pdf }, where pdf is a Uint8Array.
If submit transport is ambiguous but polling proves acceptance, submission.acceptedWithoutResult is true and result counters are undefined because no submit response was retrieved.
Low-level API
LayoutorClient exposes the workflow operations implemented by this SDK:
createUpload(input, options?)
putUpload(uploadUrl, file, options?)
createDocument(input, options?)
getDocument(id, options?)
deleteDocument(id, options?)
getDocumentUnits(id, options?)
getDocumentUnitsXliff(id, options?)
submitDocumentUnits(id, submission, options?)
submitDocumentUnitsXliff(id, xliff, options?)
getDocumentPdf(id, options?)
getCurrentAccount(options?)The generated paths type covers every OpenAPI operation, including download URLs, leases, and unauthenticated
downloads, for use with an openapi-fetch low-level client:
import createClient from "openapi-fetch";
import type { paths } from "@layoutor/sdk";
const client = createClient<paths>({ baseUrl: "https://api.layoutor.ai" });
await client.POST("/v1/documents/{id}/lease", {
params: { path: { id: "doc_123" }, header: { "User-Agent": "integration/1.0" } }
});All authenticated Node.js requests use layoutor-sdk/1.0.0 (+https://layoutor.ai/contact) by default. Set userAgent in the constructor to identify your integration. Native browsers retain their browser-controlled User-Agent.
LayoutorError exposes code, optional status, requestId, retryAfter, and cause. Caller cancellation remains an AbortError.
Request retries and upload/submit recovery use a 180-second deadline by default; retry.maxElapsedMs changes it.
After the deadline, the SDK starts no new request or retry wait and throws LayoutorError with code
retry_exhausted when recovery would need one. A request started before the deadline may finish afterward, and its
response remains valid; a successful response is still treated as successful.
Custom baseUrl values must use HTTPS; HTTP is accepted only for localhost, IPv4 127.0.0.0/8, and IPv6
[::1] loopback development endpoints.
