Remote Plugins
Gehostete Tools fuer den Live-Editor
Uebersicht
Remote Plugins sind gehostete Web-Apps, die im confBuild Editor als iframe geoeffnet werden. Sie kommunizieren per Message Bridge mit dem Editor und koennen Projektdaten oder Sheet-Daten lesen, kontrollierte Sheet-Updates schreiben, registrierte Script-Actions starten und eine eigene Oberflaeche anzeigen.
Eigenes Hosting
Deployen Sie das Plugin auf einer eigenen HTTPS-Domain und fuegen Sie es unter Project Settings > Plugins hinzu.
Sheet-Zugriff
Nutzen Sie Methoden wie sheet.getActive, sheet.getRange, sheet.setCell und sheet.applyOperation.
Toolbar und Scripts
Platzieren Sie Plugins in Topbar, Editor-Toolbar, Tools-Toolbar oder Tools-Dropdown und oeffnen Sie sie mit API.openPlugin().
Plugin Manifest
Project Settings > Plugins speichert Plugin-Definitionen in project.plugins. Jedes Plugin deklariert iframe-URL, vertrauenswuerdige Origin, Menue-Platzierung und Berechtigungen.
project.plugins = [
{
id: "bom-helper",
name: "BOM Helper",
iframeUrl: "https://plugins.example.com/bom/index.html",
allowedOrigin: "https://plugins.example.com",
icon: "fa-solid fa-table",
placement: "project-settings",
permissions: ["project:read", "sheet:read", "sheet:write", "script:run-action"],
order: 20,
enabled: true
}
];topbarIm Szenen-Header links neben dem Project Type Buttontools-toolbarNeben Tools wie BOM, CAM und Floor Planproject-settingsIm Tools-Dropdown oben rechts nahe Project SettingsPlugins verwalten
Oeffnen Sie Project Settings > Plugins, um Remote Plugins ohne direkte JSON-Bearbeitung hinzuzufuegen, zu duplizieren, zu entfernen, zu deaktivieren, zu sortieren, zu importieren, zu exportieren und zu validieren.
- Nutzen Sie Catalog, um verifizierte confBuild Plugin-Listings in das aktuelle Projekt zu installieren.
- Lassen Sie Origin leer, um sie aus der iframe-URL abzuleiten, oder tragen Sie die exakte URL-Origin manuell ein.
- Waehlen Sie, wo der Start-Button erscheint: Main Menu, Tools Toolbar oder Project Settings Menu.
- Vergeben Sie nur die Berechtigungen, die die Remote-App benoetigt.
- Nutzen Sie die JSON-Ansicht, um das aktuelle Manifest zu exportieren oder ein einzelnes Plugin, ein Array, eine Object Map,
{ "plugins": [...] }oder{ "installed": [...] }zu importieren. - Speichern wird blockiert, wenn ein Plugin eine ungueltige ID, doppelte ID, unsichere URL, abweichende Origin, nicht unterstuetzte Platzierung, ungueltiges Icon oder ungueltige Dialoggroesse hat.
Plugin Catalog
Der Catalog Button in Project Settings > Plugins zeigt veroeffentlichte Plugin Store Listings, die mit einem Klick in das Projekt installiert werden koennen. Eine Catalog-Installation speichert dieselbe Manifest-Struktur wie ein manuell hinzugefuegtes Plugin. Dadurch gelten dieselben Berechtigungspruefungen, Freigabe-Dialoge, Toolbar-Platzierungen und Script-Zugriffe.
Verifizierte Listings
Listings werden im Admin Plugin Store kuratiert und enthalten vertrauenswuerdige iframe-Origin, benoetigte Berechtigungen, Platzierung, Groesse und gehostete URL.
Projektbezogen
Ein Catalog-Plugin wird zum project.plugins Array des aktuellen Projekts hinzugefuegt. Andere Projekte bleiben unveraendert.
Gleiche Runtime API
Catalog-Plugins nutzen dieselbe iframe Bridge, Sheet API, Freigabepruefung, Audit-Anzeige und API.openPlugin() Script Hooks.
Admin Plugin Store
Admins verwalten Catalog Listings unter /admin/plugin-store. Veroeffentlichte Listings erscheinen im Project Settings Catalog; unveroeffentlichte Listings bleiben fuer Nutzer verborgen.
- Listings mit Publisher, Version, Kategorie, Tags und Summary erstellen oder bearbeiten.
- iframe-URL, exakte Allowed Origin, Platzierung, Icon, Dialoggroesse und Berechtigungen setzen.
- Mit Seed Built-ins die gebuendelten Beispiel-Listings im Store anlegen.
- Nur Admins koennen Listings erstellen, bearbeiten, unveroeffentlichen oder loeschen.
Beispiel-Plugins
Die Docs-Site enthaelt statische Beispiel-Plugins, die Sie als Remote Plugins registrieren oder aus dem Plugin Catalog installieren koennen. Die gehostete Beispiel-Liste ist unter /assets/plugins/ verfuegbar.
{
"id": "sheet-inspector-example",
"name": "Sheet Inspector Example",
"iframeUrl": "https://confbuild.com/assets/plugins/sheet-inspector-example/",
"allowedOrigin": "https://confbuild.com",
"icon": "fa-solid fa-table",
"placement": "project-settings",
"permissions": ["project:read", "sheet:read", "sheet:write", "script:run-action"],
"order": 30,
"enabled": true,
"width": "1180px",
"height": "820px"
}Das Beispiel liest Projekt- und Sheet-Daten, schreibt eine einzelne Zelle, startet eine Script Action, zeigt einen Toast, schliesst sich selbst und verarbeitet Host Calls von API.callPlugin().
{
"id": "cut-list-planner-example",
"name": "Cut List Planner Example",
"iframeUrl": "https://confbuild.com/assets/plugins/cut-list-planner-example/",
"allowedOrigin": "https://confbuild.com",
"icon": "fa-solid fa-ruler-combined",
"placement": "tools-toolbar",
"permissions": ["project:read", "sheet:read", "sheet:write"],
"order": 35,
"enabled": true,
"width": "1240px",
"height": "860px"
}Das Cut List Planner Beispiel liest Sheet-Zeilen, gruppiert Materialverbrauch, schaetzt Plattenanzahl und Kosten, schreibt eine Summary-Zelle und verarbeitet Host Calls fuer Refresh, Fokus, Pricing und Export.
API.openPlugin("sheet-inspector-example");
await API.callPlugin("sheet-inspector-example", "setMessage", {
message: "Called from a project script"
});
await API.callPlugin("sheet-inspector-example", "highlightRows", {
rowIndexes: [0, 3],
outputIds: ["plate_1"]
});
API.openPlugin("cut-list-planner-example");
await API.callPlugin("cut-list-planner-example", "focusMaterial", {
material: "birch plywood"
});
const cutPlan = await API.callPlugin("cut-list-planner-example", "exportPlan");AI Coding Prompt
Kopieren Sie diesen Prompt in Ihren Coding-Assistenten, um eine bestehende App in ein externes Plugin mit iframe-Verbindung, Manifest-Dateien, CAD-Zeilen-Schreiblogik und Test-Checkliste umzubauen.
You are an expert frontend engineer adapting an existing frontend app into a confBuild remote plugin.
Goal:
Adapt the existing app in this repository into a hosted iframe plugin for confBuild: [DESCRIBE_THE_PLUGIN].
Existing app: [DESCRIBE_THE_EXISTING_APP, for example "an I-beam sizing/configurator app"].
Preserve the app's current purpose, user workflow, UI structure, styling, framework, build system, components, and business logic unless a specific change is required for confBuild integration.
Hard adaptation rules:
- First inspect the existing files and identify the current entry point, framework, state model, UI controls, and build/deploy commands.
- Do not create a new app, new project folder, fresh scaffold, unrelated demo, or replacement UI unless this repository is empty or I explicitly ask for a fresh app.
- Do not replace the existing app with a generic confBuild sample. Add the confBuild bridge, manifest/discovery metadata, and sheet-writing workflow to the existing app.
- Keep existing domain-specific behavior. For example, if this is an I-beam app, keep the I-beam controls/calculations and map its outputs to confBuild ibeam rows.
- Make the smallest coherent edits needed. Reuse existing buttons/forms where possible; add plugin actions beside the existing workflow.
- Use the existing app's tech stack and package setup. Use plain HTML, CSS, and JavaScript only when no framework/build setup already exists.
- Keep the app runnable standalone outside confBuild with realistic demo data.
confBuild plugin facts:
- The plugin runs inside a sandboxed iframe and communicates with the confBuild editor through a postMessage bridge.
- Prefer loading https://confbuild.com/js/confbuild-plugin-client.js and creating the client with ConfBuildPluginClient.create({ pluginId: "[PLUGIN_ID]" }).
- Development may use http://localhost:[PORT]/. Production iframe URLs must use HTTPS.
- The manifest allowedOrigin must exactly match the iframeUrl origin.
- Manifest fields: id, name, iframeUrl, allowedOrigin, icon, placement, permissions, order, enabled, width, height, description.
- Project Settings > Plugins can import a plugin from a pasted URL if that URL returns manifest JSON or an HTML page with discovery metadata.
- To support URL import, publish a production plugin-manifest.json next to the plugin and add <link rel="confbuild-plugin-manifest" href="./plugin-manifest.json"> to index.html.
- If a separate manifest file is not available, include <script type="application/confbuild-plugin+json">...</script> or meta tags for confbuild:plugin-id, confbuild:plugin-name, confbuild:plugin-url, confbuild:plugin-origin, confbuild:plugin-icon, confbuild:plugin-description, confbuild:plugin-placement, confbuild:plugin-permissions, confbuild:plugin-order, confbuild:plugin-width, and confbuild:plugin-height.
- Always expose a plugin description for URL import. confBuild reads it from plugin-manifest.json description, embedded plugin JSON description, or HTML metadata. Include at least <meta name="confbuild:plugin-description" content="[PLUGIN_DESCRIPTION]">; also include <meta name="description" content="[PLUGIN_DESCRIPTION]"> for normal SEO/browser previews. Accepted description metadata names include confbuild:plugin-description, confbuild-plugin-description, description, og:description, and twitter:description.
- Plugin hosts must allow cross-origin reads for the page or manifest so browser-based URL import can read the metadata.
- Placements: topbar, tools-toolbar, project-settings.
- Permissions: project:read, sheet:read, sheet:write, script:run-action, app-action:run. Request only the permissions needed.
- Helper methods: ready, getCapabilities, getProjectSummary, getActiveSheet, getSheetData, getRange, getCell, setCell, applyOperation, runScriptAction, runAppAction, toast, close, onHostCall.
- Sheet writes, applyOperation, script actions, and app actions require edit mode and trigger a confBuild approval dialog.
- If you implement postMessage manually instead of using the helper, validate event.source and event.origin.
Before finishing, verify confBuild plugin installability:
- Publish a real /plugin-manifest.json next to the app and link it with <link rel="confbuild-plugin-manifest" href="./plugin-manifest.json">.
- Ensure the manifest iframeUrl is the final canonical deployed URL, not a preview/stale Cloud Run URL.
- Ensure allowedOrigin and confbuild:plugin-origin are exact iframe origins. Use localhost origins for local dev, such as http://localhost:5173.
- Add HTML fallback metadata for id, name, description, placement, permissions, width, and height.
- Serve HTML and manifest with CORS readable from confBuild, at minimum Access-Control-Allow-Origin: https://app.confbuild.com or * for public static metadata.
- Load https://confbuild.com/js/confbuild-plugin-client.js.
- Wait for ready robustly: const session = await (typeof client.ready === "function" ? client.ready() : client.ready);.
- In standalone mode, keep export simulated/demo-only. In confBuild mode, label the action Write to confBuild.
- For writes, show a preview, then call sheet.applyOperation using append_after_marker and marker OUTPUTID.
- Test in an iframe host: plugin emits confbuild:plugin:ready, receives confbuild:plugin:init, and sends confbuild:plugin:request.
- Test localhost import using http://localhost:[PORT]/ without requiring HTTPS.
confBuild sheet/CAD row facts:
- Geometry is spreadsheet-driven. Output rows live below an OUTPUTID marker.
- A geometry block starts with a header row whose first cell is "#", second cell is "type", and remaining cells are parameter names.
- Data rows under that header use first cell as output id, second cell as row type, then values matching the header.
- Do not mix row types under one header. When switching type, write a new "#" header.
- Position and rotation columns should be last as x, y, z, rx, ry, rz. Units are millimeters and degrees unless noted.
- Material strings can be "#RRGGBB" or "physicalMaterialId;#RRGGBB;roughness;metalness;reflectivity;opacity".
- Prefer SnippetManager-compatible headers because cadnodeengine maps rows by header names.
- For new straight profile members (ibeam, uprofile, tprofile, lprofile, squaretube, roundtube, aluprofile), prefer global startPoint/endPoint columns when endpoints, nodes, contact faces, or spans are known. The renderer derives length and aligns local +Z from start to end; use length/x/y/z/rx/ry/rz mainly for legacy headers or special local rotation.
- Use sheet.applyOperation with append_after_marker, insert_before_marker, replace_range, replace_sheet, or batch. For generated geometry, append_after_marker after OUTPUTID is usually safest.
Common geometry row schemas from cadnodeengine/SnippetManager:
- preferred straight profile endpoint schemas:
ibeam/uprofile/tprofile/lprofile/squaretube/roundtube: ["#", "type", "profile", "material", "startPoint", "endPoint"]
aluprofile: ["#", "type", "series", "size", "material", "startPoint", "endPoint"]
- cube: ["#", "type", "width", "length", "height", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- cylinder: ["#", "type", "radiusTop", "radiusBottom", "height", "radialSegments", "heightSegments", "openEnded", "hollow", "wallWidth", "thetaStart", "thetaLength", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- cone: ["#", "type", "radius", "height", "radialSegments", "heightSegments", "openEnded", "thetaStart", "thetaLength", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- sphere: ["#", "type", "radius", "widthSegments", "heightSegments", "phiStart", "phiLength", "thetaStart", "thetaLength", "material", "x", "y", "z", "rx", "ry", "rz"]
- plate: ["#", "type", "width", "length", "height", "baseplane", "extrusionvector", "gridsize", "material", "edges", "x", "y", "z", "rx", "ry", "rz"]
- wall: ["#", "type", "width", "depth", "height", "gridsize", "material", "edges", "x", "y", "z", "rx", "ry", "rz"]
- extrusion: ["#", "type", "baseplane", "extrusionvector", "material", "bevelwidth", "bevelsegments", "edges", "x", "y", "z", "rx", "ry", "rz"]
- shape: ["#", "type", "points", "splinePath", "splineDivisions", "depth", "material", "edges", "x", "y", "z", "rx", "ry", "rz"]
- nurbs: ["#", "type", "controlPoints", "rows", "cols", "degreeU", "degreeV", "segments", "depth", "material", "x", "y", "z", "rx", "ry", "rz", "showControlPoints", "showControlGrid"]
- sheetmetal: ["#", "type", "contour", "thickness", "innerRadius", "kFactor", "bends", "stampings", "sheetMetalKernel", "renderMode", "showFlatPattern", "material", "x", "y", "z", "rx", "ry", "rz"]
- tube: ["#", "type", "path", "radius", "bendradiusfactor", "material", "x", "y", "z", "rx", "ry", "rz"]
- line: ["#", "type", "p1", "p2", "width", "material", "x", "y", "z", "rx", "ry", "rz"]
- ring: ["#", "type", "outerRadius", "innerRadius", "depth", "material", "edges", "x", "y", "z", "rx", "ry", "rz"]
- spring: ["#", "type", "radius", "pitch", "turns", "wireRadius", "length", "material", "x", "y", "z", "rx", "ry", "rz"]
- ibeam/uprofile/tprofile: ["#", "type", "profile", "width", "height", "length", "flangeThickness", "webThickness", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- lprofile: ["#", "type", "profile", "width", "height", "length", "thickness", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- squaretube: ["#", "type", "profile", "outerWidth", "outerHeight", "length", "wallThickness", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- roundtube: ["#", "type", "profile", "outerDiameter", "length", "wallThickness", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"]
- aluprofile: ["#", "type", "series", "size", "length", "material", "edges", "price_per_meter", "total_price", "supplier", "currency", "weight_per_meter", "estimated_price", "cross_section_area", "x", "y", "z", "rx", "ry", "rz"]
- dinpart: ["#", "type", "partType", "diameter", "length", "material", "hostOutputId", "seatFace", "axis", "entryDirection", "throughHole", "x", "y", "z", "rx", "ry", "rz"]
- subtraction: ["#", "type", "cuttedoutputids", "cutoutputids", "x", "y", "z", "rx", "ry", "rz"]
- union: ["#", "type", "mergedoutputids", "x", "y", "z", "rx", "ry", "rz"]
- connector: ["#", "type", "label", "type", "activator", "inparent", "context", "refpos", "refrot", "x", "y", "z", "rx", "ry", "rz", "sx", "sy", "sz"]
- dimensionline: ["#", "type", "p1", "p2", "width", "material", "orthogonalLength", "orthogonalOffset", "dashed", "rotation", "textSize", "textBackground", "editcell", "targetOutputId", "targetSeries", "refpos", "x", "y", "z", "rx", "ry", "rz"]
- 3dlabel: ["#", "type", "text", "position", "target", "background", "color", "borderColor", "borderWidth", "lineColor", "lineWidth", "fontSize", "padding", "align"]
- arrow: ["#", "type", "start", "end", "width", "material", "headLength", "headWidth", "x", "y", "z", "rx", "ry", "rz"]
- ledstrip: ["#", "type", "path", "ledspacing", "ledsize", "ledcolor", "glowintensity", "glowradius", "pcbwidth", "pcbheight", "pcbcolor", "x", "y", "z", "rx", "ry", "rz"]
Geometry selection rules:
- Use cube only for true rectangular prisms or simple mitered ends via startSlope/endSlope.
- Use extrusion or plate with baseplane for triangular gussets, trapezoids, brackets, non-rectangular panels, holes, slots, and constant-thickness custom outlines.
- Use cylinder/cone/sphere/ring/tube/spring for native round or path-based forms.
- Use ibeam, uprofile, tprofile, lprofile, squaretube, roundtube, or aluprofile for standard structural/profile members instead of approximating them with cubes.
- For plugin-generated structural/profile members, use endpoint rows first when you know start/end nodes. Example: ["beam_1", "ibeam", "IPE 200", "#708090", "(0,0,2800)", "(6000,0,2800)"].
- Use dinpart for standard purchased hardware such as screws, nuts, washers, bearings, springs, fittings, rails, and furniture connectors.
- For holes and cutouts, create visible or hidden cutter rows first, then add a subtraction row. Keep subtraction x/y/z/rx/ry/rz at 0 and position the cutter rows.
- Use nurbs only for smooth freeform skins. Do not use NURBS for ordinary chamfers or prismatic brackets.
- For sheet metal, use sheetmetal with contour, bends JSON, and stampings JSON rather than many loose plates.
If the plugin includes a prompt box for users:
- Convert the user's natural-language request into previewable confBuild rows using the schemas above.
- Show a row preview and a human summary before calling applyOperation.
- Never send sheet/project data to an external AI service unless the user configured that service and explicitly triggers generation.
- Do not put API keys in browser code. If external AI is required, call a user-owned backend.
- Validate every generated row before writing: unique output ids, known type, matching header length, sensible dimensions, and no mixed types under one header.
Example geometry write:
await confbuild.applyOperation({
operation: {
mode: "append_after_marker",
marker: "OUTPUTID",
data: [
["#", "type", "width", "length", "height", "material", "edges", "startSlope", "endSlope", "x", "y", "z", "rx", "ry", "rz"],
["plugin_base", "cube", 420, 240, 30, "steel_s235;#6f7c85;0.35;0.85;0.8;1", true, 0, 0, 0, 0, 15, 0, 0, 0],
["#", "type", "baseplane", "extrusionvector", "material", "bevelwidth", "bevelsegments", "edges", "x", "y", "z", "rx", "ry", "rz"],
["plugin_gusset", "extrusion", "(0,0);(160,0);(0,120)", "(0,0,8)", "steel_s235;#4f6f7a;0.35;0.8;0.8;1", 1, 1, true, -120, 0, 30, 0, 0, 0]
]
}
});
Requirements:
1. Adapt the existing app UI for [FEATURES_AND_WORKFLOW] instead of replacing it with a new plugin UI.
2. Include loading, connected, standalone demo, empty, and error states without breaking the existing app flow.
3. On startup, wait for confbuild.ready, read getCapabilities(), and enable only actions allowed by granted permissions.
4. If not running inside confBuild within 2 seconds, use realistic demo data so the UI can be developed standalone.
5. Read sheet data with getActiveSheet({ includeFormulas: true }), getRange(), getCell(), or getSheetData() as appropriate.
6. For writes, use the smallest safe operation: setCell for one cell, applyOperation for structured multi-cell updates.
7. Before any write/action button runs, show the user exactly what will change.
8. Register host-call handlers with confbuild.onHostCall() for [HOST_CALLS_OR_NONE].
9. Use responsive, accessible UI. Avoid external dependencies unless necessary.
10. Do not store secrets, tokens, project data, or sheet data in localStorage.
11. Catch bridge errors and show clear messages. Use toast() for successful writes when available.
12. Make the production URL self-describing for Project Settings URL import with either the manifest link, embedded JSON manifest, or confBuild meta tags above.
Plugin config:
- id: [PLUGIN_ID]
- name: [PLUGIN_NAME]
- description: [PLUGIN_DESCRIPTION]
- dev iframeUrl: http://localhost:[PORT]/
- production iframeUrl: [HTTPS_PLUGIN_URL]
- placement: [PLACEMENT]
- permissions: [PERMISSIONS]
- icon: [FONT_AWESOME_ICON_CLASS]
- dialog size: [WIDTH] x [HEIGHT]
Deliverables:
- index.html
- Optional styles.css and app.js if the code is easier to maintain split into files
- plugin-manifest.dev.json
- plugin-manifest.production.json
- index.html discovery metadata: either a confBuild manifest link, embedded application/confbuild-plugin+json, or confBuild plugin meta tags
- README with hosting and Project Settings > Plugins installation steps
- Manual test checklist covering open, read, write, approval cancel, host call response, error state, and close dialog
Before coding, make reasonable defaults for any missing placeholder, list those defaults, then write the files.Client Helper
Remote Plugins koennen den kleinen Browser-Helper ueber https://confbuild.com/js/confbuild-plugin-client.js laden oder in das eigene Bundle kopieren. Er verwaltet Init, Capabilities, Requests, Timeouts und Host-to-Plugin Calls.
<script src="https://confbuild.com/js/confbuild-plugin-client.js"></script>
<script>
const confbuild = ConfBuildPluginClient.create({ pluginId: "bom-helper" });
async function main() {
const session = await confbuild.ready;
const capabilities = await confbuild.getCapabilities();
const activeSheet = await confbuild.getActiveSheet({ includeFormulas: true });
console.log("Verfuegbare Bridge-Methoden", capabilities.methods);
await confbuild.setCell({
address: "B2",
value: "Updated from plugin"
});
}
confbuild.onHostCall("highlightRows", async payload => {
return { highlighted: payload.outputIds?.length || 0 };
});
main().catch(error => console.error(error));
</script>Message Bridge
Der Helper kapselt dieses Protokoll. Wenn Sie die Bridge selbst implementieren, sendet der Editor eine Init-Nachricht an das iframe, und das Plugin schickt typisierte Requests an das Parent-Fenster. Die Init-Nachricht enthaelt Capabilities fuer die aktuelle Session; Projektsummary-Daten sind nur enthalten, wenn das Plugin project:read besitzt.
let confbuildOrigin = "";
let session = null;
const pending = new Map();
window.addEventListener("message", event => {
const message = event.data;
if (message?.type === "confbuild:plugin:init") {
confbuildOrigin = event.origin;
session = message;
return;
}
if (message?.type === "confbuild:plugin:response") {
const callbacks = pending.get(message.requestId);
if (!callbacks) return;
pending.delete(message.requestId);
message.ok ? callbacks.resolve(message.result) : callbacks.reject(new Error(message.error));
}
});
parent.postMessage({
type: "confbuild:plugin:ready",
pluginId: "bom-helper"
}, "*");
function request(method, payload = {}) {
if (!session) throw new Error("Plugin session is not ready yet.");
if (!confbuildOrigin) throw new Error("confBuild origin is unknown.");
const requestId = crypto.randomUUID();
parent.postMessage({
type: "confbuild:plugin:request",
version: 1,
sessionId: session.sessionId,
pluginId: session.pluginId,
requestId,
method,
payload
}, confbuildOrigin);
return new Promise((resolve, reject) => pending.set(requestId, { resolve, reject }));
}Sheets lesen und schreiben
Lesen benoetigt sheet:read. Schreiben benoetigt sheet:write und den Edit-Modus.
const activeSheet = await request("sheet.getActive", { includeFormulas: true });
const priceRange = await request("sheet.getRange", { range: "A1:D20" });
await request("sheet.setCell", {
address: "B2",
value: "Updated from plugin"
});
await request("sheet.applyOperation", {
operation: {
mode: "replace_range",
range: "A10:C11",
data: [
["plugin_part", "cube", 120],
["plugin_plate", "cube", 40]
]
}
});Aus Scripts oeffnen
Plugins koennen ueber die VBA-aehnliche Scripting API gestartet werden. Host-to-Plugin Calls funktionieren, wenn das iframe bereits offen ist und die Remote-App einen Response-Handler implementiert.
API.registerAction({
id: "openBomHelper",
label: "Open BOM Helper",
run: async () => API.openPlugin("bom-helper", { source: "script-action" })
});
await API.callPlugin("bom-helper", "highlightRows", {
outputIds: ["plate_1", "plate_2"]
});Sicherheitsregeln
- Nutzen Sie HTTPS fuer gehostete Plugins. Localhost-HTTP ist nur fuer Entwicklung erlaubt.
allowedOriginmuss exakt zur iframe-URL-Origin passen.- Der Editor prueft iframe-Fenster und Origin, bevor eine Message akzeptiert wird.
- Vergeben Sie nur die Berechtigungen, die das Plugin wirklich braucht.
- Sheet-Writes, strukturierte Sheet-Operationen, Script-Actions und App-Actions zeigen einmal pro Methode einen strukturierten Freigabe-Dialog, solange der Plugin-Dialog geoeffnet ist.
- Der Plugin-Dialog fuehrt pro Session ein kompaktes Audit-Protokoll zu eingehenden Bridge-Methoden und ausgehenden Host-Calls, ohne Request-Payloads zu speichern.
- Vermeiden Sie nicht vertrauenswuerdige Same-Origin-Pluginseiten, weil die iframe-Sandbox dort schwaecher isoliert.