Les plugins sandboxés s’exécutent dans un runtime isolé fourni par un runner de sandbox. Les installations du marketplace et du registre s’exécutent toujours en sandbox, tout comme les plugins listés sous sandboxed: [] dans l’intégration emdash(). Les plugins listés sous plugins: [] s’exécutent dans le processus serveur et n’utilisent pas le runner.
Le runner dépend de la plateforme de déploiement. Sur Cloudflare Workers, chaque plugin s’exécute en tant que Dynamic Worker créé via le binding Worker Loader. Sur Node.js, le serveur lance workerd, le runtime Workers open-source, en tant que processus enfant et exécute chaque plugin comme un service à l’intérieur. L’option sandboxRunner de emdash() sélectionne le runner. Sans elle, les plugins sous sandboxed: [] ne sont jamais chargés, et un marketplace configuré fait échouer le build avec « Marketplace requires sandboxRunner to be configured ».
Le tableau suivant résume ce que chaque runner nécessite et applique.
| Cloudflare Workers | Node.js | |
|---|---|---|
sandboxRunner | sandbox() de @emdash-cms/cloudflare | "@emdash-cms/sandbox-workerd/sandbox" |
| Prérequis | Plan Workers Paid, un binding worker_loaders, PluginBridge exporté depuis le point d’entrée du Worker | Le package workerd |
| Accès BD | Le binding D1 DB, indépendant de l’adaptateur configuré | La base de données configurée |
| Limites appliquées | Temps CPU, sous-requêtes, wall time | Wall time |
Cloudflare Workers
Les Dynamic Workers sont disponibles sur le plan Workers Paid. Le runner nécessite le binding et l’export du point d’entrée ci-dessous ; les templates *-cloudflare fournissent les deux.
-
Ajoutez le binding Worker Loader à
wrangler.jsonc. Le runner le lit sous le nomLOADER:{ "worker_loaders": [ { "binding": "LOADER", }, ], } -
Exportez
PluginBridgedepuis le point d’entrée du Worker, et pointezmainvers ce fichier.PluginBridgeest le point d’entrée par lequel les plugins sandboxés accèdent au contenu, aux médias, au stockage et à l’email ; le runner le cherche dans les exports du module d’entrée :import handler, { createScheduledHandler, PluginBridge } from "@emdash-cms/cloudflare/worker"; export { PluginBridge }; export default { ...handler, scheduled: createScheduledHandler(), } satisfies ExportedHandler;{ "main": "./src/worker.ts", } -
Sélectionnez le runner dans l’intégration
emdash():import { d1, r2, sandbox } from "@emdash-cms/cloudflare"; emdash({ database: d1({ binding: "DB" }), storage: r2({ binding: "MEDIA" }), sandboxRunner: sandbox(), });
Node.js
-
Installez le runner avec
workerd, qui est une dépendance peer :npm install @emdash-cms/sandbox-workerd workerdLe package
workerdinstalle le binaire pour la plateforme courante (Linux, macOS et Windows sur x64 ; Linux et macOS sur arm64) via une dépendance optionnelle. Installez avec les dépendances optionnelles activées, sur la plateforme où le serveur s’exécute. Dans un build Docker multi-stage, exécutez l’installation dans une étape avec la même plateforme que l’étape runtime. -
Sélectionnez le runner dans l’intégration
emdash():import { sqlite } from "emdash/db"; emdash({ database: sqlite({ url: "file:./data/emdash.db" }), sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox", }); -
Pour le développement, installez
miniflarecomme dépendance de développement :npm install -D miniflareLorsque
NODE_ENVestdevelopment, ce queastro devdéfinit, et queminiflareest installé, le runner transmet les plugins à Miniflare, qui gère son propre processusworkerd; la politique de crash ci-dessous ne s’applique pas.astro previewdéfinitNODE_ENVàproductionetnode ./dist/server/entry.mjsle laisse non défini ; les deux utilisentworkerd.
Comment le processus workerd fonctionne
EmDash démarre workerd lors de l’initialisation à la première requête vers le site, une fois les plugins sandboxés chargés, et attend jusqu’à 10 secondes que les services de plugins répondent. L’installation ou la mise à jour d’un plugin depuis l’admin le redémarre. Tout ce que workerd écrit sur stdout ou stderr apparaît dans la sortie du serveur avec le préfixe [emdash:workerd].
Les services de plugins écoutent sur 127.0.0.1, et le canal retour vers le serveur est un socket de domaine Unix (un port TCP 127.0.0.1 sous Windows). Aucun port entrant n’a besoin d’être ouvert.
Le processus enfant ne reçoit que PATH, HOME, TMPDIR, TMP, TEMP, LANG et LC_ALL de l’environnement du serveur, de sorte que les secrets dans l’environnement du serveur restent hors du sandbox. Pour passer plus de variables, définissez EMDASH_WORKERD_PASSTHROUGH_ENV avec une liste de noms de variables séparés par des virgules.
Si workerd se termine de manière inattendue, le runner journalise [emdash:workerd] workerd exited with <reason> et le redémarre à la prochaine invocation, avec un délai qui commence à 1 seconde et double jusqu’à 30 secondes. Lorsque workerd plante plus de cinq fois en 60 secondes, le runner arrête de le redémarrer et journalise [emdash:workerd] workerd crashed 5 times in 60 seconds, giving up. À partir de là, chaque hook et route de plugin sandboxé échoue avec Plugin sandbox unavailable for <plugin>: workerd is not running jusqu’au redémarrage du serveur. Un SIGTERM envoyé au serveur termine workerd avec lui.
Limites de ressources
Chaque runner applique le même ensemble de limites par invocation de plugin. Les limites sont fixes ; l’intégration emdash() n’a pas d’option pour les modifier.
| Limite | Valeur | Cloudflare Workers | Node.js |
|---|---|---|---|
| Temps CPU | 50 ms | Appliqué par le Worker Loader ; le plugin lève une erreur à la limite | Non appliqué |
| Sous-requêtes | 10 | Appliqué par le Worker Loader ; le plugin lève une erreur à la limite | Non appliqué |
| Mémoire | 128 Mo | Non appliqué par plugin ; le plafond mémoire des isolats de la plateforme s’applique | Non appliqué |
| Wall time | 30 s | Appliqué par le runner | Appliqué par le runner |
Lorsqu’un hook ou une route dépasse la limite de wall-time, l’invocation échoue avec Plugin <id> exceeded wall-time limit of 30000ms during hook:<name> (ou route:<name>). Pour un hook, EmDash journalise l’échec avec le préfixe EmDash: Sandboxed plugin <id> et poursuit la requête sans le résultat de ce plugin. Une route de plugin qui dépasse la limite échoue pour son appelant.
Lorsque le runner n’est pas disponible
Un runner configuré peut être indisponible : sur Cloudflare Workers quand le binding worker_loaders ou l’export PluginBridge est manquant, sur Node.js quand workerd n’est pas installé ou que son binaire ne s’exécute pas. EmDash journalise alors l’avertissement suivant au démarrage du runtime :
EmDash: Plugin sandbox is configured but not available on this platform. Sandboxed plugins will not be loaded. If using @emdash-cms/sandbox-workerd/sandbox, ensure workerd is installed.
Les plugins sous sandboxed: [] ne sont pas chargés, les plugins installés du marketplace et du registre ne s’exécutent pas, et une nouvelle installation depuis l’admin échoue avec le code d’erreur SANDBOX_NOT_AVAILABLE. Le reste du site n’est pas affecté.
Exécuter les plugins sandboxés dans le processus
Définissez sandbox: false dans emdash() pour exécuter les plugins sous sandboxed: [] et les plugins installés du marketplace dans le processus serveur, sans isolation ni limites. C’est une option de débogage qui distingue un bug dans un plugin d’un bug dans le sandbox. La configuration suivante désactive le sandbox sur un site Node.js :
emdash({
sandboxRunner: "@emdash-cms/sandbox-workerd/sandbox",
sandbox: false,
});
Sur Cloudflare Workers, le runtime refuse de démarrer avec sandbox: false is not supported in Cloudflare Workers.
Dépannage
Chaque entrée est précédée du message tel que le serveur le journalise, ou du code d’erreur retourné par l’admin.
”Plugin sandbox is configured but not available on this platform”
Sur Cloudflare Workers, vérifiez les deux prérequis : wrangler.jsonc a un binding worker_loaders nommé LOADER, et main pointe vers un fichier qui exporte PluginBridge. Le déploiement du binding nécessite le plan Workers Paid.
Sur Node.js, exécutez le binaire que le runner utilise :
npx workerd --version
Si la commande échoue, workerd est absent de node_modules ou le binaire installé ne s’exécute pas sur cette plateforme. Réinstallez sur la plateforme cible avec les dépendances optionnelles activées.
”workerd failed to start within 10 seconds”
Le processus enfant a démarré, mais ses services de plugins n’ont pas répondu dans les 10 secondes. Les lignes préfixées [emdash:workerd] avant ce message contiennent la sortie de workerd lui-même, y compris les erreurs de configuration et de démarrage. Le runner réessaie à la prochaine invocation.
”workerd crashed 5 times in 60 seconds, giving up”
Le runner a cessé de redémarrer workerd. Les lignes [emdash:workerd] workerd exited with <reason> avant ce message nomment le code de sortie ou le signal de chaque crash. Corrigez la cause, puis redémarrez le serveur.
SANDBOX_NOT_AVAILABLE lors de l’installation d’un plugin
La demande d’installation de l’admin a été refusée parce que le runner est manquant ou indisponible. Configurez le runner pour la plateforme, ou corrigez la cause de l’avertissement de démarrage ci-dessus, et redéployez.