SDK Node.js de conversion de fichiers#
@enconvert/node-sdk est le client JavaScript et TypeScript officiel de l'API EnConvert. Treize méthodes de conversion typées sont mappées 1:1 sur des endpoints REST comme POST /v1/convert/url-to-pdf, et un second espace de noms, client.v2, ajoute la web intelligence : percevoir une URL sous forme d'artefacts prêts pour un agent, découvrir les URL d'un site, lancer une recherche web, extraire des données structurées, ingérer un site en JSONL prêt pour le RAG, et surveiller les changements d'une page. Il cible Node.js 18+ sans aucune dépendance runtime, s'appuie sur les fetch, FormData et node:stream natifs, et récupère de façon transparente après un timeout du reverse proxy en interrogeant le statut de la tâche. Livré en builds ESM et CJS avec des déclarations TypeScript complètes.
@enconvert/node-sdk · Source : enconvert/node-sdk · Node : 18+
Installation#
npm install @enconvert/node-sdk
pnpm add @enconvert/node-sdk
yarn add @enconvert/node-sdk
Démarrage rapide#
import { Enconvert } from "@enconvert/node-sdk";
const client = new Enconvert({ apiKey: process.env.ENCONVERT_API_KEY! });
// V1 : convertit une URL en PDF et l'écrit en flux sur le disque.
const result = await client.convertUrlToPdf("https://example.com", {
saveTo: "page.pdf",
});
console.log(result.presignedUrl);
// V2 : lit une page comme votre agent devrait le faire, avec un score de qualité attaché.
const op = await client.v2.perceive("https://example.com", {
outputs: ["markdown", "structured"],
});
console.log(op.outputs.markdown.url, op.renderQuality); // par ex. 0.93
Le SDK fonctionne dans tous les runtimes Node modernes (Node 18+, Bun, Deno via le spécificateur npm). Il est exclusivement côté serveur : n'embarquez donc jamais votre clé API privée dans une application navigateur.
Ce que le client expose#
Un seul client, deux surfaces. Les deux sont atteintes depuis la même instance Enconvert et partagent une seule clé API.
| Surface | Atteinte via | Ce qu'elle couvre |
|---|---|---|
| Conversion de fichiers | client.convertUrlToPdf(...), client.convertImage(...), et ainsi de suite |
Treize méthodes typées pour le rendu d'URL, la conversion d'images, la compression d'images, la conversion de documents, plus l'interrogation des tâches et des lots de site entier. Voir Conversion de fichiers. |
| Web intelligence (V2) | client.v2.perceive(...), client.v2.distill(...), et ainsi de suite |
Vingt-trois méthodes réparties sur six capacités : perceive, discover, lookup, distill, ingest, watch. Voir Web intelligence (V2). |
Les endpoints V2 exigent une clé API privée (sk_...) ; les clés publiques sont rejetées. Voir Authentification pour comprendre ce qui distingue les deux types de clés, et la V1 et V2 pour la surface REST derrière client.v2.
Conversion de fichiers#
La surface de conversion expose treize méthodes mappées 1:1 sur l'API REST :
| Méthode | Endpoint | Renvoie |
|---|---|---|
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} (interrogé) |
BatchStatus |
Chaque méthode renvoie une promesse typée. Tous les champs d'options sont facultatifs sauf indication contraire. Les quatre dernières sont des utilitaires de lot pour un site entier : elles soumettent et interrogent des tâches asynchrones, et renvoient donc un BatchSubmission ou un BatchStatus plutôt qu'un ConversionResult.
convertUrlToPdf#
Rendez n'importe quelle URL publique en PDF.
const result = await client.convertUrlToPdf("https://example.com", {
pdfOptions: { pageSize: "A4", orientation: "landscape" },
singlePage: false,
viewportWidth: 1440,
saveTo: "report.pdf",
});
| Option | Type | Défaut | Description |
|---|---|---|---|
saveTo |
string |
-- | Chemin local vers lequel écrire le PDF en flux. Les répertoires parents sont créés automatiquement. |
singlePage |
boolean |
true |
true produit une seule page continue. false pagine en utilisant pdfOptions.pageSize. |
pdfOptions |
PdfOptions |
-- | Format de page, orientation, marges, échelle, niveaux de gris, en-tête et pied de page. Voir Options PDF. |
viewportWidth |
number |
1920 |
Largeur de la fenêtre du navigateur, en pixels. |
viewportHeight |
number |
1080 |
Hauteur de la fenêtre du navigateur, en pixels. |
loadMedia |
boolean |
true |
Attend les images et les vidéos avant la capture. |
enableScroll |
boolean |
true |
Fait défiler la page de haut en bas pour déclencher les chargements différés. |
outputFilename |
string |
auto | Remplace le nom de fichier généré. .pdf est ajouté s'il manque. |
convertUrlToScreenshot#
Capturez un PNG pleine page de n'importe quelle URL.
const result = await client.convertUrlToScreenshot("https://example.com", {
viewportWidth: 1440,
saveTo: "screenshot.png",
});
Accepte les mêmes options de fenêtre, de médias, de défilement et de nom de fichier que convertUrlToPdf (sans singlePage ni pdfOptions).
convertUrlToMarkdown#
Extrayez du Markdown GitHub-Flavored propre depuis n'importe quelle URL. Le convertisseur supprime la navigation, les pieds de page, les publicités et les scripts, conserve le corps principal de l'article, et ajoute en tête un frontmatter YAML (titre, description, url, liens, images).
const result = await client.convertUrlToMarkdown("https://example.com/article", {
saveTo: "article.md",
});
Pratique pour construire des pipelines RAG, importer du contenu tiers dans un CMS, ou générer des données d'entraînement. Si vous voulez un score de qualité de rendu à côté du Markdown, utilisez plutôt client.v2.perceive.
convertImage#
Convertissez entre jpeg, png, svg, heic et webp.
// Depuis un chemin
await client.convertImage("photo.heic", {
outputFormat: "webp",
saveTo: "photo.webp",
});
// Depuis des octets
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" },
);
// Rastérise un SVG à une largeur fixe
await client.convertImage("logo.svg", { outputFormat: "png", width: 512, saveTo: "logo.png" });
Le format d'entrée est détecté à partir de l'extension du chemin ou du nom de fichier. Le format de sortie est obligatoire.
| Option | Type | Obligatoire | Description |
|---|---|---|---|
outputFormat |
string |
Oui | Format cible : jpeg, png, svg, heic ou webp (et jpeg pour une entrée .pdf). Les alias jpg, yml, htm et md sont normalisés. Les paires non prises en charge lèvent une erreur avant l'envoi de la requête. |
saveTo |
string |
-- | Chemin local vers lequel écrire le résultat en flux. |
outputFilename |
string |
-- | Remplace le nom de fichier généré. |
width |
number |
-- | Entrée SVG uniquement (svg-to-png, svg-to-jpeg, svg-to-webp), de 1 à 10000. Seule, cette option met à l'échelle proportionnellement, la hauteur étant déduite du ratio du SVG. |
height |
number |
-- | Entrée SVG uniquement (svg-to-png, svg-to-jpeg, svg-to-webp), de 1 à 10000. Seule, cette option met à l'échelle proportionnellement, la largeur étant déduite du ratio du SVG. |
Définissez width et height ensemble pour fixer un canevas exact, ce qui peut modifier le ratio d'aspect. Omettez les deux et la sortie conserve la largeur, la hauteur ou le viewBox intrinsèque du SVG. Le nombre total de pixels de sortie est plafonné à 25 000 000. Aucune de ces deux options n'est acceptée par svg-to-heic, et le SDK lève une erreur avant l'envoi de la requête si vous les passez à une autre conversion.
convertDocument#
Convertissez des documents et des formats de données. Le outputFormat par défaut est "pdf".
// docx vers pdf
await client.convertDocument("report.docx", { saveTo: "report.pdf" });
// json vers yaml
await client.convertDocument("data.json", {
outputFormat: "yaml",
saveTo: "data.yaml",
});
// markdown vers pdf avec une mise en page personnalisée
await client.convertDocument("README.md", {
outputFormat: "pdf",
pdfOptions: { pageSize: "A4", margins: { top: 20, bottom: 20, left: 25, right: 25 } },
saveTo: "readme.pdf",
});
Entrées prises en charge : doc, docx, xls, xlsx, ppt, pptx, html, htm, odt, ods, odp, ots, pages, numbers, markdown (.md, .markdown), csv, json, xml, yaml (.yaml, .yml), toml.
EPUB n'a pas de paire de conversion de document dédiée. Faites plutôt passer les fichiers .epub par convertToPdf ou convertToMarkdown.
| Option | Type | Défaut | Description |
|---|---|---|---|
outputFormat |
string |
"pdf" |
Format cible. |
saveTo |
string |
-- | Chemin local vers lequel écrire le résultat en flux. |
outputFilename |
string |
-- | Remplace le nom de fichier généré. |
pdfOptions |
PdfOptions |
-- | Mise en page. Pris en compte uniquement lorsque la sortie est un PDF. |
compressImage#
Réduisez un PNG, un JPEG ou un WebP sans changer son format.
// Passe sans perte uniquement
const result = await client.compressImage("photo.jpg", { saveTo: "photo-small.jpg" });
// Vise un budget de 200 Ko
const capped = await client.compressImage("photo.jpg", {
targetSizeKb: 200,
saveTo: "photo-capped.jpg",
});
console.log(capped.fileSize);
Entrées prises en charge : .png, .jpg, .jpeg, .webp.
La sortie conserve le format et l'extension de l'entrée : il n'y a donc pas de format de sortie à choisir. La première étape est sans perte : les métadonnées sont supprimées, le profil ICC et l'orientation EXIF sont préservés, et le résultat n'est jamais plus volumineux que l'entrée. Définir targetSizeKb ajoute une seconde étape qui réduit la taille avec le ratio d'aspect verrouillé jusqu'à atteindre le budget. Cette cible est au mieux : un budget inatteignable renvoie le plus petit fichier obtenu au lieu d'une erreur, alors vérifiez result.fileSize. Les APNG et WebP animés sont rejetés avec un 400, et le canevas décodé est plafonné à 40 000 000 pixels.
| Option | Type | Obligatoire | Description |
|---|---|---|---|
targetSizeKb |
number |
-- | Budget de taille en Ko, entier, minimum 1. Omettez-le pour n'exécuter que la passe sans perte. |
saveTo |
string |
-- | Chemin local vers lequel écrire le résultat en flux. |
outputFilename |
string |
-- | Remplace le nom de fichier généré. L'extension d'entrée est conservée. |
convertToMarkdown#
Convertissez en Markdown n'importe quel document, tableur, présentation, ebook, fichier web ou fichier texte pris en charge.
await client.convertToMarkdown("handbook.docx", {
saveTo: "handbook.md",
});
Entrées prises en charge (22) : .csv, .doc, .docx, .epub, .htm, .html, .markdown, .md, .mdown, .mkd, .odp, .ods, .odt, .pdf, .ppt, .pptx, .rtf, .text, .txt, .xhtml, .xls, .xlsx.
La sortie est un unique fichier .md conscient des titres, conçu pour le découpage RAG : la hiérarchie de titres du document survit à la conversion, si bien qu'un découpeur sémantique peut segmenter sur les titres plutôt que sur un nombre arbitraire de caractères. Cet endpoint n'a aucune option PDF. Toute autre extension lève une erreur avant qu'une requête ne soit envoyée.
| Option | Type | Obligatoire | Description |
|---|---|---|---|
saveTo |
string |
-- | Chemin local vers lequel écrire le Markdown en flux. |
outputFilename |
string |
-- | Remplace le nom de fichier généré. |
Si vous voulez aussi que le découpage soit fait pour vous, confiez les mêmes fichiers à client.v2.ingestFiles.
convertToPdf#
Convertissez en PDF n'importe quel document, image, ebook, fichier web ou fichier texte pris en charge.
// docx vers pdf
await client.convertToPdf("contract.docx", { saveTo: "contract.pdf" });
// html vers pdf avec une géométrie de page complète
await client.convertToPdf("invoice.html", {
pdfOptions: { pageSize: "A4", margins: { top: 15, bottom: 15, left: 15, right: 15 } },
saveTo: "invoice.pdf",
});
// pdf vers pdf en niveaux de gris (passthrough)
await client.convertToPdf("scan.pdf", {
pdfOptions: { grayscale: true },
saveTo: "scan-gray.pdf",
});
Entrées prises en charge (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.
Une entrée .pdf est acceptée et transmise telle quelle : avec pdfOptions: { grayscale: true }, cette méthode fait donc aussi office de chemin de normalisation PDF. EPUB est également géré ici, puisqu'il n'a pas de paire de conversion de document dédiée. Toute autre extension lève une erreur avant qu'une requête ne soit envoyée.
.html, .htm, .xhtml), Markdown, texte brut, EPUB, image et SVG. Les entrées Office, ODF, iWork, RTF et CSV ainsi que le passthrough PDF ne prennent en charge que grayscale, et renvoient 400 si une option de géométrie explicite est définie. grayscale lui-même est pris en compte pour toutes les entrées.
| Option | Type | Obligatoire | Description |
|---|---|---|---|
saveTo |
string |
-- | Chemin local vers lequel écrire le PDF en flux. |
outputFilename |
string |
-- | Remplace le nom de fichier généré. .pdf est ajouté s'il manque. |
pdfOptions |
PdfOptions |
-- | Mise en page. Voir la réserve ci-dessus pour savoir quelles entrées prennent en compte la géométrie. |
getJobStatus#
Interrogez le statut d'une tâche asynchrone ou récupérée.
const status = await client.getJobStatus("job_abc123");
if (status.status === "success") {
console.log(status.presignedUrl);
} else if (status.status === "failed") {
console.error(status.error);
}
Renvoie { status: "processing" | "success" | "failed", presignedUrl?, objectKey?, error? }.
Utilitaires de lot pour un site entier#
convertWebsiteToPdf et convertWebsiteToScreenshot découvrent les pages d'un site, les mettent toutes en file d'attente, et regroupent les sorties dans un seul ZIP. Les deux renvoient immédiatement un BatchSubmission ; interrogez avec getBatchStatus ou bloquez avec waitForBatch. Les options partagées sont crawlMode ("auto", "sitemap" ou "full"), includePatterns, excludePatterns, notificationEmail et callbackUrl ; convertWebsiteToPdf ajoute singlePage et 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 accepte intervalMs (défaut 5_000), timeoutMs (défaut 1_800_000, soit trente minutes) et saveTo. Il lève APIError(504, ...) si l'échéance est dépassée. Voir la vue d'ensemble des endpoints pour la surface REST.
Web intelligence (V2)#
Tout ce qui se trouve sous client.v2 renvoie des données auxquelles un agent peut se fier, parce que chaque rendu V2 porte un score renderQuality compris entre 0.0 et 1.0. Une page bloquée, un défi anti-bot, un mur de connexion, une page d'erreur HTTP, un soft 404 ou une coquille vide d'application monopage revient avec un score bas plus des deductions et des warnings nommés : elle est donc signalée au lieu d'être prise pour du vrai contenu. Le contenu est tout de même renvoyé ; c'est vous qui décidez quoi en faire. Un score inférieur à environ 0,40 signifie que le rendu n'a réussi en aucun sens utile.
Vingt-trois méthodes réparties sur six capacités :
| Méthode | Endpoint | Renvoie |
|---|---|---|
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 |
Les options sont en camelCase sur la surface du SDK et sérialisées vers le format de transport snake_case de l'API ; les réponses sont retraduites en camelCase. Vos propres charges utiles (schémas d'extraction, données extraites, champs suivis, entrées de diff) passent intactes.
Perceive#
Rendez une URL sous forme des artefacts que vous demandez : Markdown, HTML nettoyé ou brut, une capture d'écran de la fenêtre ou de la page entière, un PDF, une liste de liens, une liste d'images, ou des données structurées. perceive est synchrone et renvoie l'opération terminée avec des URL d'artefacts signées pour 15 minutes. Référence complète : 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); // de 0.0 à 1.0
console.log(op.deductions); // par ex. { http_error: 0.7 }
console.log(op.outputs.markdown.url); // URL signée, 15 minutes
console.log(op.structured);
if ((op.renderQuality ?? 0) < 0.4) {
console.warn("Bad read, do not feed this to the model:", op.warnings);
}
// Resignez les URL d'artefacts plus tard, sans refaire le rendu :
const again = await client.v2.getPerceiveOperation(op.operationId);
| Option | Type | Défaut | Description |
|---|---|---|---|
outputs |
PerceiveOutputName[] |
["markdown", "structured"] |
Au choix parmi markdown, html_cleaned, html_raw, screenshot, screenshot_full_page, pdf, links, images, structured. |
extract |
PerceiveExtractName[] |
-- | Cibles heuristiques : tables, prices, contacts, metadata, main_content, headings, structured_data, technologies, all. |
onlyMainContent |
boolean |
true |
Supprime la navigation, l'en-tête, le pied de page et les bandeaux de cookies de la sortie Markdown, derrière un garde-fou de fidélité. false renvoie la page entière intacte. |
schema |
Record<string, unknown> |
-- | Schéma JSON pour l'extraction structurée au niveau LLM. |
waitFor |
string |
-- | Sélecteur CSS (éventuellement "css:...") ou "js:<expr>" à attendre avant la capture. |
waitTimeoutMs |
number |
30000 |
De 0 à 60000. |
jsCode |
string |
-- | JavaScript exécuté après la navigation. 20000 caractères maximum. |
viewport |
{ width?, height? } |
1920 x 1080 |
Largeur de 320 à 3840, hauteur de 240 à 2160. |
headers |
Record<string, string> |
-- | En-têtes de requête supplémentaires. |
cookies |
BrowserCookie[] |
-- | Cookies injectés avant le rendu. Chacun a besoin de name, value, et soit domain, soit url. |
auth |
{ username, password } |
-- | Authentification HTTP Basic. |
cacheMode |
"enabled" \| "bypass" \| "refresh" |
"enabled" |
Cache d'une heure. bypass l'ignore, refresh force un nouveau rendu. |
pdfOptions |
PdfOptions |
-- | N'a de sens que lorsque outputs inclut "pdf". Voir Options PDF. |
blockResources |
PerceiveResourceType[] |
-- | Types de ressources que le navigateur ne doit pas charger, par exemple ["image", "font", "media"]. |
respectRobots |
boolean |
-- | Respecte les règles robots du site. |
mobile |
boolean |
-- | Effectue le rendu avec un profil mobile. |
directDownload |
boolean |
-- | perceive uniquement. Préférez perceiveDirect, qui le définit pour vous. |
proxyUrl, geolocation et actionChain sont typées sur PerceiveOptions mais actuellement rejetées côté serveur avec un 422. Elles sont réservées, pas utilisables.
Téléchargement direct. perceiveDirect évite l'aller-retour par URL signée : le corps de la réponse HTTP contient les octets de l'artefact et les métadonnées voyagent dans les en-têtes. Cette méthode exige exactement une sortie produisant un artefact, et le SDK lève une erreur localement avant l'envoi si ce n'est pas le cas ("structured" peut accompagner la demande, mais il reste en ligne côté serveur et n'est pas renvoyé).
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);
// Retélécharge un artefact stocké lors d'une opération antérieure, en octets bruts.
// `output` peut être omis lorsque l'opération n'a produit qu'un seul artefact.
const raw = await client.v2.downloadPerceiveArtifact(op.operationId, "markdown");
downloadPerceiveArtifact renvoie 410 une fois l'artefact stocké expiré, et 400 (en listant les sorties disponibles) si l'opération a produit plus d'un artefact et que vous avez omis output.
Lots. perceiveBatch prend jusqu'à 1000 URL avec un seul bloc d'options partagé. Les petits lots s'exécutent en ligne et reviennent terminés ; les plus gros renvoient le statut "queued", alors interrogez getPerceiveBatch avec le jobId renvoyé.
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 vaut "manifest" (défaut, une entrée par URL dans items) ou "zip" (tous les artefacts réussis regroupés une fois la tâche terminée). L'endpoint de lot rejette directDownload ; utilisez outputMode: "zip" à la place.
Discover#
Listez les URL d'un site sans rien rendre. Aucun navigateur n'intervient : c'est donc rapide et peu coûteux comparé au fait de percevoir chaque page. Référence complète : 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); // par ex. { sitemap: 42, crawl: 30 }
for (const url of found.urls) console.log(url);
| Option | Type | Défaut | Description |
|---|---|---|---|
mode |
"sitemap" \| "crawl" \| "hybrid" |
"hybrid" |
Sitemap seul, crawl HTTP seul, ou les deux. |
maxUrls |
number |
100 |
De 1 à 1000. truncated vaut true lorsqu'il existait plus d'URL que ce plafond ne le permettait. |
maxDepth |
number |
2 |
De 1 à 5. Profondeur de crawl depuis l'URL de départ. |
includePatterns |
string[] |
-- | Liste d'autorisation par regex, 50 entrées maximum. |
excludePatterns |
string[] |
-- | Liste de refus par regex appliquée après includePatterns, 50 entrées maximum. |
sameDomainOnly |
boolean |
true |
Maintient le crawl sur le domaine de départ. |
respectRobots |
boolean |
-- | Respecte les règles robots du site. robotsRespected dans le résultat indique ce qui s'est passé. |
Lookup#
Lancez une recherche web catégorisée, et faites éventuellement percevoir automatiquement les meilleurs résultats pour que chaque occurrence porte son propre PerceiveResult complet en ligne. Référence complète : 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 | Type | Défaut | Description |
|---|---|---|---|
category |
"web" \| "news" \| "images" \| "scholar" \| "patents" \| "maps" |
"web" |
Verticale de recherche. |
country |
string |
-- | Code pays Google gl, par exemple "us" ou "in". |
locale |
string |
-- | Langue d'interface Google hl, par exemple "en". |
timeFilter |
"hour" \| "day" \| "week" \| "month" \| "year" |
-- | Fenêtre de fraîcheur. |
numResults |
number |
10 |
De 1 à 100. |
page |
number |
1 |
De 1 à 10. |
location |
string |
-- | Localisation en texte libre, par exemple "Austin, Texas". |
autocorrect |
boolean |
true |
Laisse le fournisseur corriger les fautes de frappe évidentes. |
perceiveTop |
number |
0 |
De 0 à 10. Rend automatiquement les N premières URL de résultats ; chacune est un rendu navigateur complet. |
perceiveTop dans le résultat indique combien de résultats ont réellement été perçus, ce qui peut être inférieur à ce que vous avez demandé, et perceiveOperationIds vous donne les identifiants d'opérations pour resigner plus tard.
Distill#
Extraction structurée pilotée par schéma. Donnez-lui une forme et un ensemble d'URL (ou un site à découvrir d'abord) et il renvoie des enregistrements correspondant à cette forme. Un cssSchema facultatif répond à tout ce qu'il peut à partir de sélecteurs avant toute escalade vers le niveau LLM. Référence complète : 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);
Passez exactement l'un de urls ou discoverFrom ; le SDK lève une erreur localement si vous passez les deux ou aucun, et il lève aussi une erreur si schema est absent ou n'est pas un objet.
// Découvre d'abord un site, puis extrait de chaque page trouvée.
await client.v2.distill({
discoverFrom: { url: "https://example.com", mode: "sitemap", maxPages: 10 },
schema: { title: "page title", summary: "one-line summary" },
});
| Option | Type | Défaut | Description |
|---|---|---|---|
urls |
string[] |
-- | URL explicites à traiter, 50 maximum. Mutuellement exclusif avec discoverFrom. |
discoverFrom |
{ url, mode?, maxPages? } |
-- | Découvre d'abord, puis extrait. maxPages va de 1 à 50, vaut 10 par défaut, et plafonne à la fois la découverte et l'extraction. |
schema |
Record<string, unknown> |
obligatoire | Un objet JSON-Schema ({ type: "object", properties: {...} }) ou une table plate { champ: description }. |
cssSchema |
CssSchema |
-- | Passe de sélecteurs gratuite exécutée avant toute escalade LLM. |
waitFor |
string |
-- | Sélecteur CSS ou "js:<expr>" à attendre. |
waitTimeoutMs |
number |
30000 |
De 0 à 60000. |
headers |
Record<string, string> |
-- | En-têtes de requête supplémentaires. |
cookies |
BrowserCookie[] |
-- | Cookies injectés avant le rendu. |
respectRobots |
boolean |
-- | Respecte les règles robots du site. |
Un CssSchema possède un baseSelector (le conteneur répété, un enregistrement par correspondance), une liste fields, un name facultatif, et un targetField facultatif nommant la propriété du schéma de sortie que les enregistrements remplissent. Chaque champ s'écrit { name, type, selector?, attribute?, pattern?, default?, transform?, fields? } où type vaut text, attribute, html, regex, nested, list ou nested_list. attribute est obligatoire pour les champs attribute, pattern pour les champs regex, et un tableau fields non vide pour les types imbriqués (profondeur maximale de 5).
Ingest#
Transformez un site, ou un lot de documents téléversés, en JSONL découpé et prêt pour le RAG. Ingest est toujours asynchrone : les deux points d'entrée renvoient un IngestJob en file d'attente, et vous l'interrogez ou vous configurez un webhook. Référence complète : Ingest.
// Depuis un site.
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",
});
// Depuis des fichiers téléversés : PDF, DOCX, PPTX, XLSX, CSV, HTML, EPUB, TXT/MD,
// ainsi que les documents bureautiques anciens ou ODF.
const fileJob = await client.v2.ingestFiles(["handbook.pdf", "notes.docx"], {
chunk: { maxWords: 512, sentenceOverlap: 1 },
});
// Interrogez l'un ou l'autre de la même façon. États non terminaux : 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 | Type | Défaut | Description |
|---|---|---|---|
mode |
"urls" \| "sitemap" \| "crawl" |
"urls" |
"urls" a besoin de urls et rejette url. "sitemap" et "crawl" ont besoin d'une url de départ et rejettent urls. Les deux règles sont vérifiées localement avant la requête. L'union IngestMode contient aussi "files", que ingestFiles renseigne sur sa tâche ; ne le passez pas ici. |
url |
string |
-- | URL de départ pour sitemap et crawl. |
urls |
string[] |
-- | URL explicites pour le mode "urls", 1000 maximum. |
maxPages |
number |
50 |
Plafond de découverte pour sitemap et crawl, de 1 à 1000. |
maxDepth |
number |
2 |
De 1 à 5. |
sameDomainOnly |
boolean |
true |
Maintient le crawl sur le domaine de départ. |
includePatterns / excludePatterns |
string[] |
-- | Liste d'autorisation et liste de refus par regex. |
respectRobots |
boolean |
-- | Respecte les règles robots du site. |
waitFor / waitTimeoutMs |
string / number |
-- / 30000 |
Attente de rendu par page. |
chunk |
{ maxWords?, sentenceOverlap? } |
512 / 1 |
maxWords va de 32 à 4000, sentenceOverlap de 0 à 10. |
webhookUrl |
string |
-- | Webhook de fin, signé en HMAC. |
ingestFiles accepte un FileInput[], c'est-à-dire des chaînes de chemin, des Uint8Array / Buffer, ou des objets { data, filename, contentType? }, dans n'importe quel mélange. Il ne prend que chunk et webhookUrl, et lève une erreur localement sur une liste vide.
Signature des webhooks. Les webhooks de fin sont signés en HMAC. Récupérez le secret (il est créé au premier appel) pour vérifier les livraisons, faites-le tourner quand vous en avez besoin, et relivrez un webhook que votre endpoint a manqué.
const secret = await client.v2.getWebhookSecret();
console.log(secret.signatureHeader, secret.timestampHeader);
console.log(secret.signatureScheme, secret.replayToleranceSeconds);
// La rotation invalide immédiatement les signatures faites avec le secret précédent.
const rotated = await client.v2.rotateWebhookSecret();
// Relivre le webhook d'une tâche terminée.
const retry = await client.v2.retryIngestWebhook(job.jobId);
console.log(retry.delivered, retry.attempts, retry.statusCode, retry.detail);
retryIngestWebhook renvoie 409 lorsque la tâche n'est pas terminée et 400 lorsque la tâche n'a aucun webhook configuré.
Watch#
Créez un observateur qui refait le rendu d'une URL à une cadence fixe et vous prévient lorsque la page change, par e-mail, par webhook, ou les deux. Référence complète : 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: "" }); // efface le webhook
await client.v2.deleteWatcher(watcher.watcherId); // suppression douce, idempotente
| Option | Type | Défaut | Description |
|---|---|---|---|
frequencyMinutes |
number |
60 |
Minutes entre deux vérifications, de 60 à 43200. Le plancher horaire est strict. |
diffMode |
"auto" \| "text" \| "structured" \| "tables" \| "metadata" |
"auto" |
"auto" laisse le moteur de diff choisir selon le type de contenu. |
trackFields |
Record<string, unknown> |
-- | Sous-ensemble de champs ou de sélecteurs pour restreindre le diff. |
webhookUrl |
string |
-- | Webhook de notification de changement, signé en HMAC. |
notifyEmail |
boolean |
true |
Envoie un e-mail au propriétaire du projet en cas de changement. |
updateWatcher prend les mêmes champs plus status ("active" ou "paused") et en exige au moins un ; le SDK lève une erreur localement sur une mise à jour vide. Passer webhookUrl: "" efface explicitement le webhook. La suppression est une suppression douce : deleteWatcher renvoie l'observateur marqué supprimé avec le statut "deleted", et un observateur supprimé répond 404 depuis getWatcher.
Chaque instantané porte checkedAt, hasChanges, similarity (de 0.0 à 1.0 par rapport à la capture précédente), renderQuality, changeCount, et un tableau changes.
snapshot.changes viennent directement de la page surveillée. Échappez-les avant de les afficher en HTML ou de les écrire dans un visualiseur de logs.
Options PDF#
Passées via le champ pdfOptions sur convertUrlToPdf, convertDocument, convertToPdf, convertWebsiteToPdf et client.v2.perceive (lorsque outputs inclut "pdf").
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",
});
| Champ | Type | Description |
|---|---|---|
pageSize |
string |
"A4", "A3", "Letter", "Legal", etc. |
pageWidth / pageHeight |
number |
Géométrie de page explicite, en remplacement de pageSize. |
orientation |
"portrait" \| "landscape" |
Portrait par défaut. |
margins |
{ top, bottom, left, right } (mm) |
Les quatre sont facultatifs. |
scale |
number |
Échelle de rendu, par ex. 0.9 pour 90 %. |
grayscale |
boolean |
Post-traite le PDF via Ghostscript pour le passer en niveaux de gris. |
header |
PdfHeaderFooter |
{ content?, height? }. content est plafonné à 2000 caractères. |
footer |
PdfHeaderFooter |
Même forme que header. |
Chaque paramètre est décrit en détail dans Tâches synchrones et asynchrones.
Gestion des erreurs#
Les erreurs sont des classes d'exception typées que vous pouvez filtrer avec instanceof. La même hiérarchie couvre à la fois les méthodes de conversion et client.v2.
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;
}
}
| Classe | Levée sur | Code de statut |
|---|---|---|
AuthenticationError |
Clé invalide, manquante ou révoquée | 401, 403 (les deux rapportent statusCode 401) |
QuotaError |
Levée sur un HTTP 402 | 402 |
RateLimitError |
Trop de requêtes | 429 |
APIError |
Toute autre 4xx / 5xx | le code réel |
EnconvertError |
Classe de base de toutes les précédentes | -- |
QuotaError et RateLimitError étendent toutes deux APIError, qui étend EnconvertError : ordonnez donc vos vérifications instanceof de la plus spécifique à la plus générale. Chaque APIError porte un champ statusCode.
Certaines défaillances n'atteignent jamais le réseau : une extension de fichier non prise en charge, un appel distill avec à la fois urls et discoverFrom, un appel ingest dont le mode et les arguments se contredisent, un appel perceiveDirect avec plus d'une sortie d'artefact, ou un appel updateWatcher sans aucun champ. Ceux-là lèvent une Error ordinaire localement, pour que vous trouviez l'erreur en développement.
La table complète des messages d'erreur se trouve dans la référence Codes d'erreur.
Récupération après timeout#
Les conversions URL vers PDF longues ou les documents volumineux peuvent dépasser la limite de timeout de 60 à 120 secondes du reverse proxy, même quand la conversion finit par réussir côté serveur. Le SDK gère cela de façon transparente sur les méthodes de conversion V1 :
- Avant chaque requête, le SDK génère un UUID et l'envoie comme
job_iddans le corps de la requête. - Si la requête initiale renvoie une 5xx, le SDK bascule discrètement sur l'interrogation de
GET /v1/convert/status/{job_id}toutes les 3 secondes. - Dès que la tâche est enregistrée comme
success, le SDK renvoie le résultat. Dès qu'elle est enregistrée commefailed, le SDK lèveAPIError. - L'échéance d'interrogation est de 5 minutes. Si elle est dépassée, le SDK lève
APIError(504, "Conversion timed out").
Vous n'avez aucun code à écrire pour cela, ça fonctionne tout seul. Définissez timeout sur le constructeur si vous voulez borner la requête initiale.
La V2 utilise des objets de tâche explicites plutôt qu'une récupération implicite : perceiveBatch et ingest renvoient un identifiant que vous interrogez avec getPerceiveBatch et getIngestJob, et ingest peut appeler un webhook à la place.
Configuration#
const client = new Enconvert({
apiKey: process.env.ENCONVERT_API_KEY!,
timeout: 300_000, // ms, 5 min par défaut
baseUrl: "https://api.enconvert.com", // à surcharger pour des passerelles auto-hébergées
});
| Option | Type | Défaut | Description |
|---|---|---|---|
apiKey |
string |
-- (obligatoire) | Clé API privée (sk_...). Le constructeur lève une erreur immédiatement si elle manque. |
timeout |
number |
300_000 |
Timeout de requête en ms. Interrompt le fetch sous-jacent via AbortController. |
baseUrl |
string |
https://api.enconvert.com |
URL de base de l'API. Les barres obliques finales sont supprimées. |
La clé voyage dans un en-tête X-API-Key sur chaque requête, en V1 comme en V2. client.v2 est construit pour vous et partage la clé, l'URL de base et le timeout du client : il n'y a donc rien de plus à configurer.
Forme du résultat#
Chaque méthode de conversion renvoie un ConversionResult :
interface ConversionResult {
presignedUrl: string; // URL signée pour télécharger la sortie (1 heure)
objectKey: string; // clé de l'objet de stockage
filename: string; // nom de fichier côté serveur
fileSize?: number; // octets
conversionTimeSeconds?: number;
jobId?: string; // présent lorsque la récupération après timeout a interrogé
}
L'URL pré-signée est valable une heure. Si vous avez besoin d'un accès permanent, téléchargez le fichier (utilisez saveTo, ou récupérez l'URL vous-même) et stockez-le dans votre propre bucket.
Les résultats V2 ont une forme différente. Un PerceiveResult porte operationId, status, url, urlFinal, contentHash, renderQuality, statusCode, deductions, cacheHit, une table outputs indexée par nom de sortie, structured, extractionTier, tokens, costCents, durationMs, optionsEcho, error et warnings. Chaque entrée de outputs est un V2OutputArtifact de la forme { url?, objectKey, sizeBytes, contentType, expiresIn }, où expiresIn est en secondes et vaut 900 par défaut. Les URL d'artefacts V2 durent donc 15 minutes plutôt qu'une heure, et elles sont resignées à chaque lecture : rappeler getPerceiveOperation(operationId) vous donne donc des liens frais sans refaire le rendu de la page.
TypeScript#
Les définitions de types sont livrées avec le package : aucune installation @types/... n'est nécessaire. Le package est publié en double (ESM + CJS) avec des exports, types et .d.ts / .d.cts corrects, si bien qu'il fonctionne sous n'importe quel mode de résolution de modules Node.
import type {
ClientOptions,
CompressImageOptions,
ConversionResult,
ConvertDocumentOptions,
ConvertImageOptions,
ConvertToMarkdownOptions,
ConvertToPdfOptions,
FileInput,
JobStatus,
PdfOptions,
UrlToMarkdownOptions,
UrlToPdfOptions,
UrlToScreenshotOptions,
// Les types V2 proviennent du même point d'entrée.
DiscoverOptions, DiscoverResult,
DistillOptions, DistillResult,
IngestJob, IngestOptions,
LookupOptions, LookupResult,
PerceiveOptions, PerceiveResult, PerceiveOutputName,
PerceiveBatchResult, PerceiveDirectResult,
Watcher, WatcherSnapshotList,
} from "@enconvert/node-sdk";
La classe EnconvertV2 elle-même est également exportée, si vous voulez typer un paramètre de fonction comme étant l'espace de noms V2.
Mise à jour#
Le package embarque une petite CLI, enconvert-sdk, pour se maintenir à jour.
npx enconvert-sdk upgrade
npx enconvert-sdk upgrade --dry-run
npx enconvert-sdk version
upgrade détecte npm, pnpm, yarn ou bun à partir du gestionnaire de paquets ambiant et affiche toujours la commande d'installation exacte avant de l'exécuter : rien n'arrive donc à votre lockfile sans que vous le voyiez. --dry-run affiche cette commande et s'arrête. version indique la version du SDK installée.
Source et tickets#
- npm : @enconvert/node-sdk
- GitHub : enconvert/node-sdk
- Licence : MIT
- Autres langages : Tous les SDK
Questions fréquentes#
Comment convertir des fichiers en Node.js avec un package npm ?#
Installez @enconvert/node-sdk, créez un client avec votre clé API (new Enconvert({ apiKey: process.env.ENCONVERT_API_KEY! })), et appelez une méthode typée comme convertUrlToPdf, convertImage ou convertDocument. Passez saveTo pour écrire le résultat en flux directement sur le disque.
Comment récupérer une page web en Markdown propre avec Node.js ?#
Appelez client.v2.perceive(url, { outputs: ["markdown"] }). Vous obtenez une URL signée pour 15 minutes vers le Markdown dans op.outputs.markdown.url, plus un score renderQuality pour la lecture. Si vous voulez les octets directement au lieu d'une URL, appelez client.v2.perceiveDirect(url, { outputs: ["markdown"] }) et lisez result.content.
Qu'est-ce que renderQuality et pourquoi est-ce important ?#
renderQuality est un score de 0.0 à 1.0 attaché à chaque rendu V2. Un défi anti-bot, un mur de connexion, une page d'erreur HTTP, un soft 404 ou une coquille vide d'application monopage obtiennent tous un score bas et reviennent avec des deductions et des warnings nommés : une mauvaise lecture est donc signalée au lieu d'entrer discrètement dans le contexte de votre agent comme s'il s'agissait de la vraie page. Un score inférieur à environ 0,40 signifie que le rendu a échoué en pratique, même si la requête a renvoyé 200.
Comment convertir du HEIC en WebP en Node.js ?#
Appelez convertImage avec le fichier HEIC (un chemin ou un objet buffer { data, filename }) et outputFormat: "webp". Le SDK convertit entre jpeg, png, svg, heic et webp ; le format d'entrée est détecté à partir de l'extension du nom de fichier.
Comment compresser une image en Node.js sans changer son format ?#
Appelez compressImage avec un fichier .png, .jpg, .jpeg ou .webp. La sortie conserve le format et l'extension de l'entrée, supprime les métadonnées tout en préservant le profil ICC et l'orientation EXIF, et n'est jamais plus volumineuse que l'entrée. Ajoutez targetSizeKb pour réduire la taille vers un budget donné ; la cible est au mieux, alors lisez result.fileSize pour voir ce qui a réellement été atteint.
Comment convertir n'importe quel document en Markdown pour un pipeline RAG ?#
Appelez convertToMarkdown avec le fichier et passez saveTo pour écrire le .md directement sur le disque. Il accepte 22 extensions couvrant Office, OpenDocument, PDF, EPUB, HTML, CSV et texte brut, et renvoie un seul fichier Markdown conscient des titres : votre découpeur peut donc segmenter sur les titres du document plutôt que sur un nombre arbitraire de caractères.
Comment transformer un site web entier en chunks prêts pour le RAG avec Node.js ?#
Appelez client.v2.ingest({ mode: "sitemap", url, maxPages, chunk: { maxWords: 512, sentenceOverlap: 1 } }). Ingest est toujours asynchrone : interrogez donc client.v2.getIngestJob(job.jobId) jusqu'à ce que status vaille "completed" et lisez outputUrl pour le JSONL signé, ou définissez webhookUrl et laissez le webhook de fin vous prévenir. Pour des documents locaux plutôt qu'un site, client.v2.ingestFiles([...]) exécute le même pipeline.
Comment extraire du JSON structuré depuis une page en Node.js ?#
Appelez client.v2.distill({ urls, schema }) où schema est soit un objet JSON-Schema, soit une table plate { champ: description }. Ajoutez un cssSchema et la passe de sélecteurs répond à tout ce qu'elle peut avant toute escalade vers le niveau LLM ; result.extractionTier, fieldsFromCss et fieldsFromLlm vous disent quel niveau a fait le travail.
Comment surveiller les changements d'une page web en Node.js ?#
Appelez client.v2.createWatcher(url, { frequencyMinutes: 60, diffMode: "auto", webhookUrl }). Le plancher horaire est strict, donc 60 est la cadence minimale. Lisez l'historique avec getWatcherSnapshots, mettez en pause avec updateWatcher(id, { status: "paused" }), et supprimez avec deleteWatcher, qui est une suppression douce et idempotente.
Comment le SDK gère-t-il les conversions longues qui atteignent le timeout du reverse proxy ?#
Avant chaque requête de conversion V1, le SDK génère un UUID et l'envoie comme job_id ; si la requête renvoie une 5xx, il interroge discrètement GET /v1/convert/status/{job_id} toutes les 3 secondes jusqu'à ce que la tâche soit success ou failed. L'échéance d'interrogation est de 5 minutes, après quoi il lève APIError(504, "Conversion timed out"). La V2 utilise plutôt des identifiants de tâche explicites, interrogés avec getPerceiveBatch ou getIngestJob.
Puis-je utiliser le SDK Node.js dans une application navigateur ?#
Non, le SDK est exclusivement côté serveur, parce qu'il s'authentifie avec une clé API privée (sk_...) qui ne doit jamais être embarquée dans du code côté client. Il fonctionne sous Node 18+, Bun et Deno via le spécificateur npm.
Combien de temps l'URL de téléchargement pré-signée reste-t-elle valable ?#
Le presignedUrl de chaque ConversionResult est valable une heure. Les URL d'artefacts V2 sont valables 15 minutes et sont resignées à chaque lecture : getPerceiveOperation(operationId) vous remet donc des liens frais. Pour un accès permanent, téléchargez le fichier et stockez-le dans votre propre bucket.