Node.js SDK für Dateikonvertierung#
@enconvert/node-sdk ist der offizielle JavaScript- und TypeScript-Client für die EnConvert-API. Dreizehn typisierte Konvertierungsmethoden bilden REST-Endpunkte wie POST /v1/convert/url-to-pdf 1:1 ab, und ein zweiter Namensraum, client.v2, ergänzt Web-Intelligenz: eine URL in agentenfertige Artefakte überführen (perceive), die URLs einer Site ermitteln (discover), eine Websuche ausführen (lookup), strukturierte Daten destillieren (distill), eine Site als RAG-fertiges JSONL ingestieren (ingest) und Seiten auf Änderungen überwachen (watch). Das SDK zielt auf Node.js 18+ ohne Laufzeit-Abhängigkeiten, baut auf nativem fetch, FormData und node:stream auf und erholt sich transparent von Reverse-Proxy-Timeouts, indem es den Job-Status abfragt. Es wird mit dualen ESM- und CJS-Builds sowie vollständigen TypeScript-Deklarationen ausgeliefert.
@enconvert/node-sdk · Quelle: enconvert/node-sdk · Node: 18+
Installation#
npm install @enconvert/node-sdk
pnpm add @enconvert/node-sdk
yarn add @enconvert/node-sdk
Schnellstart#
import { Enconvert } from "@enconvert/node-sdk";
const client = new Enconvert({ apiKey: process.env.ENCONVERT_API_KEY! });
// V1: Eine URL in ein PDF konvertieren und auf die Festplatte streamen.
const result = await client.convertUrlToPdf("https://example.com", {
saveTo: "page.pdf",
});
console.log(result.presignedUrl);
// V2: Eine Seite so lesen, wie dein Agent es tun sollte, mit angehängtem Qualitätswert.
const op = await client.v2.perceive("https://example.com", {
outputs: ["markdown", "structured"],
});
console.log(op.outputs.markdown.url, op.renderQuality); // z. B. 0.93
Das SDK läuft in jeder modernen Node-Runtime (Node 18+, Bun, Deno über den npm-Spezifizierer). Es ist ausschließlich serverseitig, bündle deinen privaten API-Schlüssel also niemals in eine Browser-Anwendung.
Was der Client bereitstellt#
Ein Client, zwei Oberflächen. Beide sind über dieselbe Enconvert-Instanz erreichbar und teilen sich einen API-Schlüssel.
| Oberfläche | Erreichbar über | Was sie abdeckt |
|---|---|---|
| Dateikonvertierung | client.convertUrlToPdf(...), client.convertImage(...) und so weiter |
Dreizehn typisierte Methoden für URL-Rendering, Bildkonvertierung, Bildkomprimierung, Dokumentkonvertierung sowie Job- und Website-Batch-Polling. Siehe Dateikonvertierung. |
| Web-Intelligenz (V2) | client.v2.perceive(...), client.v2.distill(...) und so weiter |
Dreiundzwanzig Methoden über sechs Fähigkeiten hinweg: perceive, discover, lookup, distill, ingest, watch. Siehe Web-Intelligenz (V2). |
V2-Endpunkte verlangen einen privaten API-Schlüssel (sk_...); öffentliche Schlüssel werden abgelehnt. Wie sich die beiden Schlüsseltypen unterscheiden, steht unter Authentifizierung, und die REST-Oberfläche hinter client.v2 beschreibt die V1 und V2.
Dateikonvertierung#
Die Konvertierungs-Oberfläche stellt dreizehn Methoden bereit, die die REST-API 1:1 abbilden:
| Methode | Endpunkt | Rückgabe |
|---|---|---|
convertUrlToPdf(url, options?) |
POST /v1/convert/url-to-pdf |
ConversionResult |
convertUrlToScreenshot(url, options?) |
POST /v1/convert/url-to-screenshot |
ConversionResult |
convertUrlToMarkdown(url, options?) |
POST /v1/convert/url-to-markdown |
ConversionResult |
convertImage(file, options) |
POST /v1/convert/{from}-to-{to} |
ConversionResult |
convertDocument(file, options?) |
POST /v1/convert/{from}-to-{to} |
ConversionResult |
compressImage(file, options?) |
POST /v1/convert/compress-image |
ConversionResult |
convertToMarkdown(file, options?) |
POST /v1/convert/anything-to-markdown |
ConversionResult |
convertToPdf(file, options?) |
POST /v1/convert/anything-to-pdf |
ConversionResult |
getJobStatus(jobId) |
GET /v1/convert/status/{jobId} |
JobStatus |
convertWebsiteToPdf(url, options?) |
POST /v1/convert/website-to-pdf |
BatchSubmission |
convertWebsiteToScreenshot(url, options?) |
POST /v1/convert/website-to-screenshot |
BatchSubmission |
getBatchStatus(batchId) |
GET /v1/convert/batch/{batchId} |
BatchStatus |
waitForBatch(batchId, options?) |
GET /v1/convert/batch/{batchId} (per Polling) |
BatchStatus |
Jede Methode liefert ein typisiertes Promise. Alle Optionsfelder sind optional, sofern nicht anders vermerkt. Die letzten vier sind Batch-Helfer für ganze Websites: Sie reichen asynchrone Jobs ein und fragen sie ab, geben also eine BatchSubmission oder einen BatchStatus zurück statt eines ConversionResult.
convertUrlToPdf#
Rendert jede öffentliche URL als PDF.
const result = await client.convertUrlToPdf("https://example.com", {
pdfOptions: { pageSize: "A4", orientation: "landscape" },
singlePage: false,
viewportWidth: 1440,
saveTo: "report.pdf",
});
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
saveTo |
string |
-- | Lokaler Pfad, auf den das PDF gestreamt wird. Übergeordnete Verzeichnisse werden automatisch angelegt. |
singlePage |
boolean |
true |
true erzeugt eine durchgehende Seite. false paginiert anhand von pdfOptions.pageSize. |
pdfOptions |
PdfOptions |
-- | Seitengröße, Ausrichtung, Ränder, Skalierung, Graustufen, Kopf- und Fußzeile. Siehe PDF-Optionen. |
viewportWidth |
number |
1920 |
Breite des Browser-Viewports in Pixeln. |
viewportHeight |
number |
1080 |
Höhe des Browser-Viewports in Pixeln. |
loadMedia |
boolean |
true |
Wartet vor der Aufnahme auf Bilder und Videos. |
enableScroll |
boolean |
true |
Scrollt von oben nach unten, um Lazy Loader auszulösen. |
outputFilename |
string |
auto | Überschreibt den generierten Dateinamen. .pdf wird ergänzt, falls es fehlt. |
convertUrlToScreenshot#
Nimmt ein ganzseitiges PNG einer beliebigen URL auf.
const result = await client.convertUrlToScreenshot("https://example.com", {
viewportWidth: 1440,
saveTo: "screenshot.png",
});
Akzeptiert dieselben Optionen für Viewport, Medien, Scrollen und Dateinamen wie convertUrlToPdf (ohne singlePage und pdfOptions).
convertUrlToMarkdown#
Extrahiert sauberes GitHub-Flavored Markdown aus jeder URL. Der Konverter entfernt Navigation, Fußzeilen, Werbung und Skripte, behält den Hauptartikeltext und stellt YAML-Frontmatter voran (title, description, url, links, images).
const result = await client.convertUrlToMarkdown("https://example.com/article", {
saveTo: "article.md",
});
Nützlich, um RAG-Pipelines zu bauen, fremde Inhalte in ein CMS zu importieren oder Trainingsdaten zu erzeugen. Wenn du zusätzlich zum Markdown einen Render-Qualitätswert möchtest, nimm stattdessen client.v2.perceive.
convertImage#
Konvertiert zwischen jpeg, png, svg, heic und webp.
// Aus einem Pfad
await client.convertImage("photo.heic", {
outputFormat: "webp",
saveTo: "photo.webp",
});
// Aus Bytes
import { readFile } from "node:fs/promises";
const buf = await readFile("photo.heic");
await client.convertImage(
{ data: buf, filename: "photo.heic" },
{ outputFormat: "webp", saveTo: "photo.webp" },
);
// Ein SVG mit fester Breite rastern
await client.convertImage("logo.svg", { outputFormat: "png", width: 512, saveTo: "logo.png" });
Das Eingabeformat wird aus der Endung des Pfads bzw. Dateinamens erkannt. Das Ausgabeformat ist erforderlich.
| Option | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
outputFormat |
string |
Ja | Zielformat: jpeg, png, svg, heic oder webp (und jpeg bei einer .pdf-Eingabe). Die Aliase jpg, yml, htm und md werden normalisiert. Nicht unterstützte Paare werfen einen Fehler, bevor die Anfrage rausgeht. |
saveTo |
string |
-- | Lokaler Pfad, auf den das Ergebnis gestreamt wird. |
outputFilename |
string |
-- | Überschreibt den generierten Dateinamen. |
width |
number |
-- | Nur bei SVG-Eingabe (svg-to-png, svg-to-jpeg, svg-to-webp), 1 bis 10000. Allein gesetzt skaliert der Wert proportional und übernimmt die Höhe aus dem Seitenverhältnis des SVG. |
height |
number |
-- | Nur bei SVG-Eingabe (svg-to-png, svg-to-jpeg, svg-to-webp), 1 bis 10000. Allein gesetzt skaliert der Wert proportional und übernimmt die Breite aus dem Seitenverhältnis des SVG. |
Setze width und height gemeinsam, um eine exakte Leinwand festzulegen, was das Seitenverhältnis verändern kann. Lässt du beide weg, behält die Ausgabe die intrinsische Breite, Höhe oder viewBox des SVG. Die Gesamtzahl der Ausgabepixel ist auf 25.000.000 begrenzt. Keine der beiden Optionen wird von svg-to-heic akzeptiert, und das SDK wirft einen Fehler, bevor es die Anfrage sendet, wenn du sie einer anderen Konvertierung übergibst.
convertDocument#
Konvertiert Dokumente und Datenformate. Der Standardwert von outputFormat ist "pdf".
// docx zu pdf
await client.convertDocument("report.docx", { saveTo: "report.pdf" });
// json zu yaml
await client.convertDocument("data.json", {
outputFormat: "yaml",
saveTo: "data.yaml",
});
// markdown zu pdf mit eigenem Seitenlayout
await client.convertDocument("README.md", {
outputFormat: "pdf",
pdfOptions: { pageSize: "A4", margins: { top: 20, bottom: 20, left: 25, right: 25 } },
saveTo: "readme.pdf",
});
Unterstützte Eingaben: doc, docx, xls, xlsx, ppt, pptx, html, htm, odt, ods, odp, ots, pages, numbers, markdown (.md, .markdown), csv, json, xml, yaml (.yaml, .yml), toml.
Für EPUB gibt es kein eigenes Dokumentkonvertierungs-Paar. Schicke .epub-Dateien stattdessen durch convertToPdf oder convertToMarkdown.
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
outputFormat |
string |
"pdf" |
Zielformat. |
saveTo |
string |
-- | Lokaler Pfad, auf den das Ergebnis gestreamt wird. |
outputFilename |
string |
-- | Überschreibt den generierten Dateinamen. |
pdfOptions |
PdfOptions |
-- | Seitenlayout. Wird nur berücksichtigt, wenn die Ausgabe ein PDF ist. |
compressImage#
Verkleinert ein PNG, JPEG oder WebP, ohne das Format zu ändern.
// Nur der verlustfreie Durchgang
const result = await client.compressImage("photo.jpg", { saveTo: "photo-small.jpg" });
// Auf ein Budget von 200 KB zielen
const capped = await client.compressImage("photo.jpg", {
targetSizeKb: 200,
saveTo: "photo-capped.jpg",
});
console.log(capped.fileSize);
Unterstützte Eingaben: .png, .jpg, .jpeg, .webp.
Die Ausgabe behält Format und Endung der Eingabe, es gibt hier also kein Ausgabeformat zu wählen. Die erste Stufe ist verlustfrei: Metadaten werden entfernt, ICC-Profil und EXIF-Ausrichtung bleiben erhalten, und das Ergebnis ist nie größer als die Eingabe. targetSizeKb ergänzt eine zweite Stufe, die bei gesperrtem Seitenverhältnis herunterskaliert, bis das Budget erreicht ist. Dieses Ziel gilt als Best Effort: Ein unerreichbares Budget liefert die kleinste erzielte Datei statt eines Fehlers, prüfe also result.fileSize. Animierte APNG- und animierte WebP-Dateien werden mit 400 abgelehnt, und die dekodierte Leinwand ist auf 40.000.000 Pixel begrenzt.
| Option | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
targetSizeKb |
number |
-- | Größenbudget in KB, ganzzahlig, Minimum 1. Weglassen, um nur den verlustfreien Durchgang auszuführen. |
saveTo |
string |
-- | Lokaler Pfad, auf den das Ergebnis gestreamt wird. |
outputFilename |
string |
-- | Überschreibt den generierten Dateinamen. Die Eingabe-Endung bleibt erhalten. |
convertToMarkdown#
Konvertiert jede unterstützte Dokument-, Tabellen-, Präsentations-, E-Book-, Web- oder Klartextdatei nach Markdown.
await client.convertToMarkdown("handbook.docx", {
saveTo: "handbook.md",
});
Unterstützte Eingaben (22): .csv, .doc, .docx, .epub, .htm, .html, .markdown, .md, .mdown, .mkd, .odp, .ods, .odt, .pdf, .ppt, .pptx, .rtf, .text, .txt, .xhtml, .xls, .xlsx.
Die Ausgabe ist eine einzelne, überschriftenbewusste .md-Datei, gebaut für RAG-Chunking: Die Überschriftenhierarchie des Dokuments übersteht die Konvertierung, sodass ein semantischer Chunker an Überschriften trennen kann statt an willkürlichen Zeichenzahlen. Dieser Endpunkt kennt keine PDF-Optionen. Jede andere Endung wirft einen Fehler, bevor eine Anfrage gestellt wird.
| Option | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
saveTo |
string |
-- | Lokaler Pfad, auf den das Markdown gestreamt wird. |
outputFilename |
string |
-- | Überschreibt den generierten Dateinamen. |
Wenn das Chunking gleich mit erledigt werden soll, übergib dieselben Dateien an client.v2.ingestFiles.
convertToPdf#
Konvertiert jede unterstützte Dokument-, Bild-, E-Book-, Web- oder Klartextdatei nach PDF.
// docx zu pdf
await client.convertToPdf("contract.docx", { saveTo: "contract.pdf" });
// html zu pdf mit vollständiger Seitengeometrie
await client.convertToPdf("invoice.html", {
pdfOptions: { pageSize: "A4", margins: { top: 15, bottom: 15, left: 15, right: 15 } },
saveTo: "invoice.pdf",
});
// pdf zu Graustufen-pdf (Durchreichen)
await client.convertToPdf("scan.pdf", {
pdfOptions: { grayscale: true },
saveTo: "scan-gray.pdf",
});
Unterstützte Eingaben (36): .bmp, .csv, .doc, .docx, .epub, .gif, .heic, .heif, .htm, .html, .jpeg, .jpg, .markdown, .md, .mdown, .mkd, .numbers, .odp, .ods, .odt, .ots, .pages, .pdf, .png, .ppt, .pptx, .rtf, .svg, .text, .tif, .tiff, .txt, .webp, .xhtml, .xls, .xlsx.
Eine .pdf-Eingabe wird akzeptiert und durchgereicht, mit pdfOptions: { grayscale: true } dient diese Methode also zugleich als PDF-Normalisierungspfad. EPUB wird ebenfalls hier abgewickelt, da es kein eigenes Dokumentkonvertierungs-Paar hat. Jede andere Endung wirft einen Fehler, bevor eine Anfrage gestellt wird.
.html, .htm, .xhtml), Markdown, Klartext, EPUB, Bild- und SVG-Eingaben berücksichtigt. Office-, ODF-, iWork-, RTF- und CSV-Eingaben sowie das Durchreichen von PDFs unterstützen nur grayscale und antworten mit 400, wenn eine explizite Geometrie-Option gesetzt ist. grayscale selbst wird bei jeder Eingabe berücksichtigt.
| Option | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
saveTo |
string |
-- | Lokaler Pfad, auf den das PDF gestreamt wird. |
outputFilename |
string |
-- | Überschreibt den generierten Dateinamen. .pdf wird ergänzt, falls es fehlt. |
pdfOptions |
PdfOptions |
-- | Seitenlayout. Siehe den Hinweis oben dazu, welche Eingaben die Geometrie berücksichtigen. |
getJobStatus#
Fragt den Status eines asynchronen oder wiederhergestellten Jobs ab.
const status = await client.getJobStatus("job_abc123");
if (status.status === "success") {
console.log(status.presignedUrl);
} else if (status.status === "failed") {
console.error(status.error);
}
Liefert { status: "processing" | "success" | "failed", presignedUrl?, objectKey?, error? }.
Batch-Helfer für ganze Websites#
convertWebsiteToPdf und convertWebsiteToScreenshot ermitteln die Seiten einer Website, stellen sie alle in die Warteschlange und bündeln die Ausgaben in einem ZIP. Beide liefern sofort eine BatchSubmission; frage anschließend mit getBatchStatus ab oder blockiere mit waitForBatch. Gemeinsame Optionen sind crawlMode ("auto", "sitemap" oder "full"), includePatterns, excludePatterns, notificationEmail und callbackUrl; convertWebsiteToPdf ergänzt singlePage und pdfOptions.
const batch = await client.convertWebsiteToPdf("https://example.com", {
crawlMode: "sitemap",
excludePatterns: ["/tag/"],
});
const done = await client.waitForBatch(batch.batchId, { saveTo: "site.zip" });
console.log(done.status, done.completed, done.failed, done.zipDownloadUrl);
waitForBatch akzeptiert intervalMs (Standard 5_000), timeoutMs (Standard 1_800_000, also dreißig Minuten) und saveTo. Wird die Frist überschritten, wirft es APIError(504, ...). Die REST-Oberfläche beschreibt die Endpunkt-Übersicht.
Web-Intelligenz (V2)#
Alles unterhalb von client.v2 liefert Daten, denen ein Agent vertrauen kann, denn jedes V2-Rendering trägt einen renderQuality-Wert zwischen 0.0 und 1.0. Eine blockierte Seite, eine Bot-Challenge, eine Login-Schranke, eine HTTP-Fehlerseite, ein Soft-404 oder eine leere SPA-Hülle kommt mit niedrigem Wert samt benannten deductions und warnings zurück und wird damit markiert, statt für echten Inhalt gehalten zu werden. Der Inhalt wird trotzdem zurückgegeben; was du damit machst, entscheidest du. Werte unterhalb von etwa 0.40 bedeuten, dass das Rendering in keinem sinnvollen Sinn geglückt ist.
Dreiundzwanzig Methoden über sechs Fähigkeiten hinweg:
| Methode | Endpunkt | Rückgabe |
|---|---|---|
v2.perceive(url, options?) |
POST /v2/perceive |
PerceiveResult |
v2.perceiveDirect(url, options?) |
POST /v2/perceive |
PerceiveDirectResult |
v2.getPerceiveOperation(operationId) |
GET /v2/perceive/{operationId} |
PerceiveResult |
v2.downloadPerceiveArtifact(operationId, output?) |
GET /v2/perceive/{operationId} |
PerceiveDirectResult |
v2.perceiveBatch(urls, options?) |
POST /v2/perceive/batch |
PerceiveBatchResult |
v2.getPerceiveBatch(jobId) |
GET /v2/perceive/batch/{jobId} |
PerceiveBatchResult |
v2.discover(url, options?) |
POST /v2/discover |
DiscoverResult |
v2.lookup(query, options?) |
POST /v2/lookup |
LookupResult |
v2.distill(options) |
POST /v2/distill |
DistillResult |
v2.ingest(options) |
POST /v2/ingest |
IngestJob |
v2.ingestFiles(files, options?) |
POST /v2/ingest/files |
IngestJob |
v2.listIngestJobs(options?) |
GET /v2/ingest |
IngestJobList |
v2.getIngestJob(jobId) |
GET /v2/ingest/{jobId} |
IngestJob |
v2.cancelIngestJob(jobId) |
DELETE /v2/ingest/{jobId} |
IngestJob |
v2.retryIngestWebhook(jobId) |
POST /v2/ingest/{jobId}/retry-webhook |
WebhookRetryResult |
v2.getWebhookSecret() |
GET /v2/ingest/webhook-secret |
WebhookSecret |
v2.rotateWebhookSecret() |
POST /v2/ingest/webhook-secret/rotate |
WebhookSecret |
v2.createWatcher(url, options?) |
POST /v2/watch |
Watcher |
v2.listWatchers(options?) |
GET /v2/watch |
WatcherList |
v2.getWatcher(watcherId) |
GET /v2/watch/{watcherId} |
Watcher |
v2.getWatcherSnapshots(watcherId, options?) |
GET /v2/watch/{watcherId}/snapshots |
WatcherSnapshotList |
v2.updateWatcher(watcherId, updates) |
PATCH /v2/watch/{watcherId} |
Watcher |
v2.deleteWatcher(watcherId) |
DELETE /v2/watch/{watcherId} |
Watcher |
Optionen sind auf der SDK-Oberfläche in camelCase und werden in das snake_case-Wire-Format der API serialisiert; Antworten werden zurück nach camelCase abgebildet. Deine eigenen Payloads (Extraktionsschemata, extrahierte Daten, verfolgte Felder, Diff-Einträge) werden unverändert durchgereicht.
Perceive#
Rendert eine URL in die Artefakte, die du anforderst: Markdown, bereinigtes oder rohes HTML, einen Viewport- oder Ganzseiten-Screenshot, ein PDF, eine Linkliste, eine Bildliste oder strukturierte Daten. perceive arbeitet synchron und liefert die abgeschlossene Operation mit 15 Minuten gültigen signierten Artefakt-URLs. Vollständige Referenz: Perceive.
const op = await client.v2.perceive("https://example.com", {
outputs: ["markdown", "screenshot", "structured"],
extract: ["tables", "metadata"],
onlyMainContent: true,
waitFor: "css:.article-body",
viewport: { width: 1440, height: 900 },
});
console.log(op.renderQuality); // 0.0 bis 1.0
console.log(op.deductions); // z. B. { http_error: 0.7 }
console.log(op.outputs.markdown.url); // 15 Minuten gültige signierte URL
console.log(op.structured);
if ((op.renderQuality ?? 0) < 0.4) {
console.warn("Bad read, do not feed this to the model:", op.warnings);
}
// Artefakt-URLs später neu signieren, ohne erneut zu rendern:
const again = await client.v2.getPerceiveOperation(op.operationId);
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
outputs |
PerceiveOutputName[] |
["markdown", "structured"] |
Beliebige aus markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. |
extract |
PerceiveExtractName[] |
-- | Heuristische Ziele: tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all. |
onlyMainContent |
boolean |
true |
Entfernt Navigation, Header, Footer und Cookie-Banner aus der Markdown-Ausgabe, abgesichert durch einen Fidelity-Guard. false liefert die vollständige Seite unangetastet. |
schema |
Record<string, unknown> |
-- | JSON-Schema für die strukturierte Extraktion auf der LLM-Stufe. |
waitFor |
string |
-- | CSS-Selektor (optional als "css:...") oder "js:<expr>", auf den vor der Aufnahme gewartet wird. |
waitTimeoutMs |
number |
30000 |
0 bis 60000. |
jsCode |
string |
-- | JavaScript, das nach der Navigation ausgeführt wird. Maximal 20000 Zeichen. |
viewport |
{ width?, height? } |
1920 x 1080 |
Breite 320 bis 3840, Höhe 240 bis 2160. |
headers |
Record<string, string> |
-- | Zusätzliche Request-Header. |
cookies |
BrowserCookie[] |
-- | Cookies, die vor dem Rendern gesetzt werden. Jedes braucht name, value und entweder domain oder url. |
auth |
{ username, password } |
-- | HTTP Basic Auth. |
cacheMode |
"enabled" \| "bypass" \| "refresh" |
"enabled" |
Cache für eine Stunde. bypass überspringt ihn, refresh erzwingt ein neues Rendering. |
pdfOptions |
PdfOptions |
-- | Nur sinnvoll, wenn outputs den Wert "pdf" enthält. Siehe PDF-Optionen. |
blockResources |
PerceiveResourceType[] |
-- | Ressourcentypen, die der Browser nicht laden soll, zum Beispiel ["image", "font", "media"]. |
respectRobots |
boolean |
-- | Beachtet die Robots-Regeln der Website. |
mobile |
boolean |
-- | Rendert mit einem mobilen Profil. |
directDownload |
boolean |
-- | Nur bei perceive. Nimm besser perceiveDirect, das die Option für dich setzt. |
proxyUrl, geolocation und actionChain sind auf PerceiveOptions typisiert, werden serverseitig aber derzeit mit 422 abgelehnt. Sie sind reserviert, nicht nutzbar.
Direkter Download. perceiveDirect spart den Umweg über die signierte URL: Der HTTP-Antwortkörper enthält die Artefakt-Bytes, und die Metadaten reisen in den Headern mit. Es verlangt genau eine artefakterzeugende Ausgabe, und das SDK wirft lokal einen Fehler vor dem Senden, wenn das nicht der Fall ist ("structured" darf mitfahren, bleibt aber serverseitig inline und wird nicht zurückgegeben).
import { writeFile } from "node:fs/promises";
const direct = await client.v2.perceiveDirect("https://example.com", { outputs: ["markdown"] });
console.log(direct.contentType, direct.renderQuality, direct.sourceStatusCode);
await writeFile(direct.filename ?? "page.md", direct.content);
// Ein gespeichertes Artefakt einer früheren Operation erneut als rohe Bytes laden.
// `output` darf entfallen, wenn die Operation genau ein Artefakt erzeugt hat.
const raw = await client.v2.downloadPerceiveArtifact(op.operationId, "markdown");
downloadPerceiveArtifact liefert 410, sobald das gespeicherte Artefakt abgelaufen ist, und 400 (mit Auflistung der verfügbaren Ausgaben), wenn die Operation mehr als ein Artefakt erzeugt hat und du output weggelassen hast.
Batches. perceiveBatch nimmt bis zu 1000 URLs mit einem gemeinsamen Optionsblock entgegen. Kleine Batches laufen inline und kommen fertig zurück; größere liefern den Status "queued", frage sie also mit der zurückgegebenen jobId über getPerceiveBatch ab.
const batch = await client.v2.perceiveBatch(["https://example.com/a", "https://example.com/b"], {
outputs: ["markdown"],
outputMode: "zip",
});
let job = await client.v2.getPerceiveBatch(batch.jobId);
while (job.status === "queued" || job.status === "processing") {
await new Promise((r) => setTimeout(r, 3000));
job = await client.v2.getPerceiveBatch(batch.jobId);
}
console.log(job.completed, job.failed, job.zip?.url);
outputMode ist "manifest" (Standard, ein Eintrag pro URL in items) oder "zip" (jedes erfolgreiche Artefakt wird gebündelt, sobald der Job fertig ist). Der Batch-Endpunkt lehnt directDownload ab; nutze stattdessen outputMode: "zip".
Discover#
Listet die URLs einer Website auf, ohne etwas zu rendern. Es ist kein Browser beteiligt, das macht es schnell und günstig im Vergleich dazu, jede Seite wahrzunehmen. Vollständige Referenz: Discover.
const found = await client.v2.discover("https://example.com", {
mode: "hybrid",
maxUrls: 200,
maxDepth: 3,
excludePatterns: ["/tag/", "/author/"],
sameDomainOnly: true,
});
console.log(found.total, found.truncated, found.sources); // z. B. { sitemap: 42, crawl: 30 }
for (const url of found.urls) console.log(url);
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
mode |
"sitemap" \| "crawl" \| "hybrid" |
"hybrid" |
Nur Sitemap, nur HTTP-Crawl oder beides. |
maxUrls |
number |
100 |
1 bis 1000. truncated ist true, wenn es mehr URLs gab, als dieses Limit zuließ. |
maxDepth |
number |
2 |
1 bis 5. Crawl-Tiefe ab der Start-URL. |
includePatterns |
string[] |
-- | Regex-Positivliste, maximal 50 Einträge. |
excludePatterns |
string[] |
-- | Regex-Negativliste, angewandt nach includePatterns, maximal 50 Einträge. |
sameDomainOnly |
boolean |
true |
Hält den Crawl auf der Start-Domain. |
respectRobots |
boolean |
-- | Beachtet die Robots-Regeln der Website. robotsRespected im Ergebnis meldet, was tatsächlich passiert ist. |
Lookup#
Führt eine kategorisierte Websuche aus und nimmt auf Wunsch die besten Treffer automatisch wahr, sodass jeder Treffer sein eigenes vollständiges PerceiveResult inline mitbringt. Vollständige Referenz: Lookup.
const search = await client.v2.lookup("best static site generators", {
category: "web",
numResults: 10,
country: "us",
locale: "en",
timeFilter: "month",
perceiveTop: 3,
});
for (const hit of search.results) {
console.log(hit.position, hit.title, hit.url);
if (hit.perceive) {
console.log(" quality:", hit.perceive.renderQuality);
console.log(" markdown:", hit.perceive.outputs.markdown?.url);
}
}
console.log(search.answerBox, search.knowledgeGraph);
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
category |
"web" \| "news" \| "images" \| "scholar" \| "patents" \| "maps" |
"web" |
Suchvertikale. |
country |
string |
-- | Google-gl-Ländercode, zum Beispiel "us" oder "in". |
locale |
string |
-- | Google-hl-Oberflächensprache, zum Beispiel "en". |
timeFilter |
"hour" \| "day" \| "week" \| "month" \| "year" |
-- | Aktualitätsfenster. |
numResults |
number |
10 |
1 bis 100. |
page |
number |
1 |
1 bis 10. |
location |
string |
-- | Freitext-Ort, zum Beispiel "Austin, Texas". |
autocorrect |
boolean |
true |
Lässt den Anbieter offensichtliche Tippfehler korrigieren. |
perceiveTop |
number |
0 |
0 bis 10. Rendert die Top-N-Ergebnis-URLs automatisch; jede davon ist ein vollständiges Browser-Rendering. |
perceiveTop im Ergebnis meldet, wie viele Treffer tatsächlich wahrgenommen wurden, was weniger sein kann als angefordert, und perceiveOperationIds liefert dir die Operations-IDs zum späteren Neusignieren.
Distill#
Schemagesteuerte strukturierte Extraktion. Gib eine Form und eine Menge URLs vor (oder eine Website, die zuerst ermittelt werden soll), und du bekommst Datensätze in dieser Form zurück. Ein optionales cssSchema beantwortet alles, was es über Selektoren kann, bevor irgendetwas auf die LLM-Stufe eskaliert. Vollständige Referenz: Distill.
const extraction = await client.v2.distill({
urls: ["https://example.com/pricing"],
schema: { plans: "list of plan names with monthly prices" },
cssSchema: {
baseSelector: ".plan-card",
fields: [
{ name: "name", type: "text", selector: "h3" },
{ name: "price", type: "text", selector: ".price" },
{ name: "url", type: "attribute", selector: "a", attribute: "href" },
],
},
});
const first = extraction.results[0];
console.log(first.data);
console.log(first.extractionTier); // "css" | "llm" | "mixed" | "none"
console.log(first.fieldsFromCss, first.fieldsFromLlm, first.renderQuality);
Übergib genau eines von urls oder discoverFrom; das SDK wirft lokal einen Fehler, wenn du beides oder keines übergibst, und ebenso, wenn schema fehlt oder kein Objekt ist.
// Zuerst eine Website ermitteln, dann jede gefundene Seite destillieren.
await client.v2.distill({
discoverFrom: { url: "https://example.com", mode: "sitemap", maxPages: 10 },
schema: { title: "page title", summary: "one-line summary" },
});
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
urls |
string[] |
-- | Explizite URLs zum Destillieren, maximal 50. Schließt discoverFrom aus. |
discoverFrom |
{ url, mode?, maxPages? } |
-- | Erst ermitteln, dann destillieren. maxPages liegt zwischen 1 und 50, Standard 10, und begrenzt sowohl Ermittlung als auch Destillation. |
schema |
Record<string, unknown> |
erforderlich | Ein JSON-Schema-Objekt ({ type: "object", properties: {...} }) oder eine flache { field: description }-Zuordnung. |
cssSchema |
CssSchema |
-- | Kostenloser Selektor-Durchgang vor jeder LLM-Eskalation. |
waitFor |
string |
-- | CSS-Selektor oder "js:<expr>", auf den gewartet wird. |
waitTimeoutMs |
number |
30000 |
0 bis 60000. |
headers |
Record<string, string> |
-- | Zusätzliche Request-Header. |
cookies |
BrowserCookie[] |
-- | Cookies, die vor dem Rendern gesetzt werden. |
respectRobots |
boolean |
-- | Beachtet die Robots-Regeln der Website. |
Ein CssSchema besitzt einen baseSelector (den sich wiederholenden Container, ein Datensatz pro Treffer), eine fields-Liste, einen optionalen name und ein optionales targetField, das die Eigenschaft des Ausgabeschemas benennt, welche die Datensätze füllen. Jedes Feld hat die Form { name, type, selector?, attribute?, pattern?, default?, transform?, fields? }, wobei type einer der Werte text, attribute, html, regex, nested, list, nested_list ist. attribute ist bei attribute-Feldern erforderlich, pattern bei regex-Feldern und ein nicht leeres fields-Array bei den verschachtelten Typen (maximale Tiefe 5).
Ingest#
Verwandelt eine Website oder einen Stapel hochgeladener Dokumente in gechunktes, RAG-fertiges JSONL. Ingest läuft immer asynchron: Beide Einstiegspunkte liefern einen eingereihten IngestJob, und du fragst ihn entweder ab oder richtest einen Webhook ein. Vollständige Referenz: Ingest.
// Von einer Website.
const job = await client.v2.ingest({
mode: "sitemap",
url: "https://docs.example.com",
maxPages: 100,
chunk: { maxWords: 512, sentenceOverlap: 1 },
webhookUrl: "https://my.app/hooks/enconvert",
});
// Von hochgeladenen Dateien: PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT/MD
// sowie alte oder ODF-Office-Dokumente.
const fileJob = await client.v2.ingestFiles(["handbook.pdf", "notes.docx"], {
chunk: { maxWords: 512, sentenceOverlap: 1 },
});
// Beide werden gleich abgefragt. Nicht-terminale Zustände: queued, discovering, processing.
let status = await client.v2.getIngestJob(job.jobId);
while (!["completed", "failed", "canceled"].includes(status.status)) {
await new Promise((r) => setTimeout(r, 5000));
status = await client.v2.getIngestJob(job.jobId);
}
console.log(status.totalChunks, status.outputUrl, status.errorMessage);
const page = await client.v2.listIngestJobs({ limit: 20, skip: 0 });
console.log(page.jobs.length, page.hasMore);
await client.v2.cancelIngestJob(job.jobId); // idempotent
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
mode |
"urls" \| "sitemap" \| "crawl" |
"urls" |
"urls" braucht urls und lehnt url ab. "sitemap" und "crawl" brauchen eine Start-url und lehnen urls ab. Beide Regeln werden lokal vor der Anfrage geprüft. Die IngestMode-Union kennt außerdem "files", was ingestFiles bei seinem Job meldet; übergib es hier nicht. |
url |
string |
-- | Start-URL für sitemap und crawl. |
urls |
string[] |
-- | Explizite URLs für den Modus "urls", maximal 1000. |
maxPages |
number |
50 |
Ermittlungs-Limit für sitemap und crawl, 1 bis 1000. |
maxDepth |
number |
2 |
1 bis 5. |
sameDomainOnly |
boolean |
true |
Hält den Crawl auf der Start-Domain. |
includePatterns / excludePatterns |
string[] |
-- | Regex-Positiv- und Negativliste. |
respectRobots |
boolean |
-- | Beachtet die Robots-Regeln der Website. |
waitFor / waitTimeoutMs |
string / number |
-- / 30000 |
Wartezeit pro Seite beim Rendern. |
chunk |
{ maxWords?, sentenceOverlap? } |
512 / 1 |
maxWords liegt zwischen 32 und 4000, sentenceOverlap zwischen 0 und 10. |
webhookUrl |
string |
-- | Webhook bei Fertigstellung, HMAC-signiert. |
ingestFiles nimmt ein FileInput[] entgegen, also Pfad-Strings, Uint8Array / Buffer oder { data, filename, contentType? }-Objekte in beliebiger Mischung. Es akzeptiert nur chunk und webhookUrl und wirft bei einer leeren Liste lokal einen Fehler.
Webhook-Signierung. Webhooks bei Fertigstellung sind HMAC-signiert. Hole das Secret (es wird beim ersten Aufruf erzeugt), um Zustellungen zu prüfen, rotiere es bei Bedarf und stelle einen Webhook erneut zu, den dein Endpunkt verpasst hat.
const secret = await client.v2.getWebhookSecret();
console.log(secret.signatureHeader, secret.timestampHeader);
console.log(secret.signatureScheme, secret.replayToleranceSeconds);
// Rotieren macht Signaturen des vorherigen Secrets sofort ungültig.
const rotated = await client.v2.rotateWebhookSecret();
// Den Webhook eines abgeschlossenen Jobs erneut zustellen.
const retry = await client.v2.retryIngestWebhook(job.jobId);
console.log(retry.delivered, retry.attempts, retry.statusCode, retry.detail);
retryIngestWebhook liefert 409, wenn der Job nicht abgeschlossen ist, und 400, wenn für den Job kein Webhook konfiguriert wurde.
Watch#
Erstellt einen Watcher, der eine URL in festem Takt neu rendert und dich benachrichtigt, wenn sich die Seite ändert: per E-Mail, per Webhook oder beides. Vollständige Referenz: Watch.
const watcher = await client.v2.createWatcher("https://example.com/pricing", {
frequencyMinutes: 60,
diffMode: "auto",
webhookUrl: "https://my.app/hooks/changes",
notifyEmail: true,
});
console.log(watcher.watcherId, watcher.nextCheckAt);
const list = await client.v2.listWatchers({ limit: 20 });
const one = await client.v2.getWatcher(watcher.watcherId);
const history = await client.v2.getWatcherSnapshots(watcher.watcherId, { limit: 10 });
for (const snap of history.snapshots) {
console.log(snap.checkedAt, snap.hasChanges, snap.similarity, snap.changeCount);
}
await client.v2.updateWatcher(watcher.watcherId, { status: "paused" });
await client.v2.updateWatcher(watcher.watcherId, { webhookUrl: "" }); // löscht den Webhook
await client.v2.deleteWatcher(watcher.watcherId); // Soft Delete, idempotent
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
frequencyMinutes |
number |
60 |
Minuten zwischen zwei Prüfungen, 60 bis 43200. Die Stundengrenze ist hart. |
diffMode |
"auto" \| "text" \| "structured" \| "tables" \| "metadata" |
"auto" |
"auto" lässt die Diff-Engine nach Inhaltstyp entscheiden. |
trackFields |
Record<string, unknown> |
-- | Feld- oder Selektor-Auswahl, um den Diff einzugrenzen. |
webhookUrl |
string |
-- | Webhook für Änderungsbenachrichtigungen, HMAC-signiert. |
notifyEmail |
boolean |
true |
Benachrichtigt den Projektinhaber bei Änderungen per E-Mail. |
updateWatcher nimmt dieselben Felder plus status ("active" oder "paused") und verlangt mindestens eines davon; bei einem leeren Update wirft das SDK lokal einen Fehler. webhookUrl: "" löscht den Webhook explizit. Das Löschen ist ein Soft Delete: deleteWatcher liefert den stillgelegten Watcher mit Status "deleted" zurück, und ein gelöschter Watcher antwortet bei getWatcher mit 404.
Jeder Snapshot trägt checkedAt, hasChanges, similarity (0.0 bis 1.0 gegenüber der vorherigen Aufnahme), renderQuality, changeCount und ein changes-Array.
snapshot.changes stammen direkt von der überwachten Seite. Escape sie, bevor du sie in HTML renderst oder in einen Log-Viewer schreibst.
PDF-Optionen#
Werden über das Feld pdfOptions an convertUrlToPdf, convertDocument, convertToPdf, convertWebsiteToPdf und client.v2.perceive übergeben (bei letzterem, wenn outputs den Wert "pdf" enthält).
const result = await client.convertUrlToPdf("https://example.com", {
pdfOptions: {
pageSize: "A4",
orientation: "landscape",
margins: { top: 10, bottom: 10, left: 15, right: 15 },
scale: 0.9,
grayscale: false,
},
saveTo: "report.pdf",
});
| Feld | Typ | Beschreibung |
|---|---|---|
pageSize |
string |
"A4", "A3", "Letter", "Legal" usw. |
pageWidth / pageHeight |
number |
Explizite Seitengeometrie als Alternative zu pageSize. |
orientation |
"portrait" \| "landscape" |
Standard ist Hochformat. |
margins |
{ top, bottom, left, right } (mm) |
Alle vier sind optional. |
scale |
number |
Render-Skalierung, z. B. 0.9 für 90 %. |
grayscale |
boolean |
Wandelt das PDF per Ghostscript-Nachbearbeitung in Graustufen um. |
header |
PdfHeaderFooter |
{ content?, height? }. content ist auf 2000 Zeichen begrenzt. |
footer |
PdfHeaderFooter |
Gleiche Form wie header. |
Jeder Parameter ist vollständig unter Synchrone und asynchrone Jobs beschrieben.
Fehlerbehandlung#
Fehler sind typisierte Exception-Klassen, die du per instanceof abgleichen kannst. Dieselbe Hierarchie deckt sowohl die Konvertierungsmethoden als auch client.v2 ab.
import {
Enconvert,
APIError,
AuthenticationError,
QuotaError,
RateLimitError,
} from "@enconvert/node-sdk";
try {
await client.v2.perceive("https://example.com", { outputs: ["markdown"] });
} catch (e) {
if (e instanceof AuthenticationError) {
console.error("Invalid API key. Check ENCONVERT_API_KEY.");
} else if (e instanceof QuotaError) {
console.error("Request rejected with 402.");
} else if (e instanceof RateLimitError) {
console.error("Too many requests. Back off and retry.");
} else if (e instanceof APIError) {
console.error(`API error [${e.statusCode}]: ${e.message}`);
} else {
throw e;
}
}
| Klasse | Ausgelöst bei | Statuscode |
|---|---|---|
AuthenticationError |
Ungültiger, fehlender oder widerrufener Schlüssel | 401, 403 (beide melden statusCode 401) |
QuotaError |
Wird bei HTTP 402 ausgelöst | 402 |
RateLimitError |
Zu viele Anfragen | 429 |
APIError |
Jeder andere 4xx-/5xx-Fehler | der tatsächliche Code |
EnconvertError |
Basisklasse für alle oben genannten | -- |
QuotaError und RateLimitError erweitern beide APIError, das wiederum EnconvertError erweitert. Ordne deine instanceof-Prüfungen also von spezifisch nach allgemein. Jeder APIError trägt ein Feld statusCode.
Manche Fehler erreichen das Netzwerk nie: eine nicht unterstützte Dateiendung, ein distill-Aufruf mit urls und discoverFrom gleichzeitig, ein ingest-Aufruf, dessen Modus und Argumente nicht zusammenpassen, ein perceiveDirect-Aufruf mit mehr als einer Artefakt-Ausgabe oder ein updateWatcher-Aufruf ohne Felder. Diese werfen lokal einen einfachen Error, damit du den Fehler in der Entwicklung findest.
Die vollständige Zuordnung der Fehlermeldungen steht in der Referenz Fehlercodes.
Timeout-Recovery#
Lange URL-zu-PDF-Vorgänge oder große Dokumentkonvertierungen können das Reverse-Proxy-Timeout von 60 bis 120 Sekunden überschreiten, selbst wenn die Konvertierung auf dem Server am Ende gelingt. Das SDK erledigt das bei den V1-Konvertierungsmethoden transparent:
- Vor jeder Anfrage erzeugt das SDK eine UUID und sendet sie als
job_idim Request-Body. - Liefert die ursprüngliche Anfrage 5xx, wechselt das SDK still auf Polling von
GET /v1/convert/status/{job_id}alle 3 Sekunden. - Sobald der Job als
successverbucht ist, gibt das SDK das Ergebnis zurück. Sobald er alsfailedverbucht ist, wirft das SDKAPIError. - Die Polling-Frist beträgt 5 Minuten. Wird sie überschritten, wirft das SDK
APIError(504, "Conversion timed out").
Dafür musst du keine Zeile Code schreiben, es funktioniert einfach. Setze timeout im Konstruktor, wenn du die erste Anfrage begrenzen willst.
V2 nutzt statt impliziter Recovery explizite Job-Objekte: perceiveBatch und ingest liefern eine ID, die du mit getPerceiveBatch bzw. getIngestJob abfragst, und ingest kann stattdessen einen Webhook aufrufen.
Konfiguration#
const client = new Enconvert({
apiKey: process.env.ENCONVERT_API_KEY!,
timeout: 300_000, // ms, Standard 5 Min.
baseUrl: "https://api.enconvert.com", // für selbst gehostete Gateways überschreiben
});
| Option | Typ | Standard | Beschreibung |
|---|---|---|---|
apiKey |
string |
-- (erforderlich) | Privater API-Schlüssel (sk_...). Der Konstruktor wirft sofort einen Fehler, wenn er fehlt. |
timeout |
number |
300_000 |
Request-Timeout in ms. Bricht das zugrunde liegende fetch über AbortController ab. |
baseUrl |
string |
https://api.enconvert.com |
Basis-URL der API. Schrägstriche am Ende werden entfernt. |
Der Schlüssel reist bei jeder Anfrage als X-API-Key-Header mit, bei V1 wie bei V2. client.v2 wird für dich konstruiert und teilt sich Schlüssel, Basis-URL und Timeout des Clients, es gibt also nichts zusätzlich zu konfigurieren.
Form des Ergebnisses#
Jede Konvertierungsmethode liefert ein ConversionResult:
interface ConversionResult {
presignedUrl: string; // signierte URL zum Download der Ausgabe (1 Stunde)
objectKey: string; // Objektschlüssel im Speicher
filename: string; // serverseitiger Dateiname
fileSize?: number; // Bytes
conversionTimeSeconds?: number;
jobId?: string; // vorhanden, wenn die Timeout-Recovery abgefragt hat
}
Die vorsignierte URL ist eine Stunde lang gültig. Brauchst du dauerhaften Zugriff, lade die Datei herunter (per saveTo oder indem du die URL selbst abrufst) und lege sie in deinem eigenen Bucket ab.
V2-Ergebnisse sind anders aufgebaut. Ein PerceiveResult trägt operationId, status, url, urlFinal, contentHash, renderQuality, statusCode, deductions, cacheHit, eine nach Ausgabenamen geschlüsselte outputs-Zuordnung, structured, extractionTier, tokens, costCents, durationMs, optionsEcho, error und warnings. Jeder Eintrag in outputs ist ein V2OutputArtifact der Form { url?, objectKey, sizeBytes, contentType, expiresIn }, wobei expiresIn in Sekunden angegeben ist und standardmäßig 900 beträgt. V2-Artefakt-URLs halten also 15 Minuten statt einer Stunde und werden bei jedem Lesen neu signiert. Ein erneuter Aufruf von getPerceiveOperation(operationId) liefert dir daher frische Links, ohne die Seite neu zu rendern.
TypeScript#
Die Typdefinitionen werden mit dem Paket ausgeliefert, eine @types/...-Installation ist also nicht nötig. Das Paket wird dual veröffentlicht (ESM + CJS) mit sauberen exports, types sowie .d.ts / .d.cts, sodass es unter jedem Node-Modulauflösungsmodus funktioniert.
import type {
ClientOptions,
CompressImageOptions,
ConversionResult,
ConvertDocumentOptions,
ConvertImageOptions,
ConvertToMarkdownOptions,
ConvertToPdfOptions,
FileInput,
JobStatus,
PdfOptions,
UrlToMarkdownOptions,
UrlToPdfOptions,
UrlToScreenshotOptions,
// Die V2-Typen kommen aus demselben Einstiegspunkt.
DiscoverOptions, DiscoverResult,
DistillOptions, DistillResult,
IngestJob, IngestOptions,
LookupOptions, LookupResult,
PerceiveOptions, PerceiveResult, PerceiveOutputName,
PerceiveBatchResult, PerceiveDirectResult,
Watcher, WatcherSnapshotList,
} from "@enconvert/node-sdk";
Die Klasse EnconvertV2 selbst wird ebenfalls exportiert, falls du einen Funktionsparameter als V2-Namensraum typisieren willst.
Aktualisieren#
Das Paket bringt eine kleine CLI mit, enconvert-sdk, um sich selbst aktuell zu halten.
npx enconvert-sdk upgrade
npx enconvert-sdk upgrade --dry-run
npx enconvert-sdk version
upgrade erkennt npm, pnpm, yarn oder bun aus der Umgebung und gibt den exakten Installationsbefehl immer aus, bevor es ihn ausführt. So passiert mit deiner Lockfile nichts unbemerkt. --dry-run gibt diesen Befehl aus und hört dann auf. version meldet die installierte SDK-Version.
Quellcode und Issues#
- npm: @enconvert/node-sdk
- GitHub: enconvert/node-sdk
- Lizenz: MIT
- Andere Sprachen: Alle SDKs
Häufig gestellte Fragen#
Wie konvertiere ich Dateien in Node.js mit einem npm-Paket?#
Installiere @enconvert/node-sdk, erzeuge einen Client mit deinem API-Schlüssel (new Enconvert({ apiKey: process.env.ENCONVERT_API_KEY! })) und rufe eine typisierte Methode wie convertUrlToPdf, convertImage oder convertDocument auf. Übergib saveTo, um das Ergebnis direkt auf die Festplatte zu streamen.
Wie lese ich eine Webseite in Node.js als sauberes Markdown aus?#
Rufe client.v2.perceive(url, { outputs: ["markdown"] }) auf. Du bekommst in op.outputs.markdown.url eine 15 Minuten gültige signierte URL zum Markdown sowie einen renderQuality-Wert für den Lesevorgang. Willst du stattdessen direkt die Bytes, rufe client.v2.perceiveDirect(url, { outputs: ["markdown"] }) auf und lies result.content.
Was ist renderQuality und warum ist das wichtig?#
renderQuality ist ein Wert zwischen 0.0 und 1.0, der an jedem V2-Rendering hängt. Eine Bot-Challenge, eine Login-Schranke, eine HTTP-Fehlerseite, ein Soft-404 oder eine leere SPA-Hülle erhalten alle einen niedrigen Wert und kommen mit benannten deductions und warnings zurück. So wird ein schlechter Lesevorgang markiert, statt still als echte Seite in den Kontext deines Agenten zu wandern. Werte unterhalb von etwa 0.40 bedeuten, dass das Rendering praktisch fehlgeschlagen ist, auch wenn die Anfrage 200 geliefert hat.
Wie konvertiere ich HEIC in Node.js nach WebP?#
Rufe convertImage mit der HEIC-Datei (ein Pfad oder ein { data, filename }-Buffer-Objekt) und outputFormat: "webp" auf. Das SDK konvertiert zwischen jpeg, png, svg, heic und webp; das Eingabeformat wird aus der Dateiendung erkannt.
Wie komprimiere ich in Node.js ein Bild, ohne das Format zu ändern?#
Rufe compressImage mit einer .png-, .jpg-, .jpeg- oder .webp-Datei auf. Die Ausgabe behält Format und Endung der Eingabe, entfernt Metadaten und bewahrt dabei ICC-Profil und EXIF-Ausrichtung, und ist nie größer als die Eingabe. Ergänze targetSizeKb, um in Richtung eines Größenbudgets herunterzuskalieren; das Ziel gilt als Best Effort, lies also result.fileSize, um zu sehen, was tatsächlich erreicht wurde.
Wie konvertiere ich ein beliebiges Dokument für eine RAG-Pipeline nach Markdown?#
Rufe convertToMarkdown mit der Datei auf und übergib saveTo, um die .md-Datei direkt auf die Festplatte zu schreiben. Die Methode akzeptiert 22 Endungen aus Office, OpenDocument, PDF, EPUB, HTML, CSV und Klartext und liefert eine überschriftenbewusste Markdown-Datei zurück, sodass dein Chunker an den Überschriften des Dokuments trennen kann statt an willkürlichen Zeichenzahlen.
Wie verwandle ich in Node.js eine ganze Website in RAG-fertige Chunks?#
Rufe client.v2.ingest({ mode: "sitemap", url, maxPages, chunk: { maxWords: 512, sentenceOverlap: 1 } }) auf. Ingest läuft immer asynchron, frage also client.v2.getIngestJob(job.jobId) ab, bis status den Wert "completed" hat, und lies outputUrl für das signierte JSONL. Alternativ setzt du webhookUrl und lässt dich vom Fertigstellungs-Webhook informieren. Für lokale Dokumente statt einer Website durchläuft client.v2.ingestFiles([...]) dieselbe Pipeline.
Wie extrahiere ich in Node.js strukturiertes JSON aus einer Seite?#
Rufe client.v2.distill({ urls, schema }) auf, wobei schema entweder ein JSON-Schema-Objekt oder eine flache { field: description }-Zuordnung ist. Ergänze ein cssSchema, dann beantwortet der Selektor-Durchgang alles, was er kann, bevor irgendetwas auf die LLM-Stufe eskaliert; result.extractionTier, fieldsFromCss und fieldsFromLlm verraten dir, welche Stufe die Arbeit erledigt hat.
Wie überwache ich in Node.js eine Webseite auf Änderungen?#
Rufe client.v2.createWatcher(url, { frequencyMinutes: 60, diffMode: "auto", webhookUrl }) auf. Die Stundengrenze ist hart, 60 ist also der kleinste Takt. Die Historie liest du mit getWatcherSnapshots, pausieren kannst du mit updateWatcher(id, { status: "paused" }), und entfernen mit deleteWatcher, was ein idempotenter Soft Delete ist.
Wie geht das SDK mit langen Konvertierungen um, die ins Reverse-Proxy-Timeout laufen?#
Vor jeder V1-Konvertierungsanfrage erzeugt das SDK eine UUID und sendet sie als job_id; liefert die Anfrage 5xx, fragt es still alle 3 Sekunden GET /v1/convert/status/{job_id} ab, bis der Job success oder failed meldet. Die Polling-Frist beträgt 5 Minuten, danach wirft es APIError(504, "Conversion timed out"). V2 nutzt stattdessen explizite Job-IDs, die mit getPerceiveBatch oder getIngestJob abgefragt werden.
Kann ich das Node.js-SDK in einer Browser-Anwendung verwenden?#
Nein, das SDK ist ausschließlich serverseitig, weil es sich mit einem privaten API-Schlüssel (sk_...) authentifiziert, der niemals in clientseitigen Code gebündelt werden darf. Es läuft in Node 18+, Bun und Deno über den npm-Spezifizierer.
Wie lange ist die vorsignierte Download-URL gültig?#
Die presignedUrl in jedem ConversionResult ist eine Stunde lang gültig. V2-Artefakt-URLs gelten 15 Minuten und werden bei jedem Lesen neu signiert, getPerceiveOperation(operationId) liefert dir also frische Links. Für dauerhaften Zugriff lade die Datei herunter und lege sie in deinem eigenen Bucket ab.