@popcraft/cli 0.52.0 → 0.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/popcraft.mjs +72 -26
  2. package/package.json +2 -2
package/dist/popcraft.mjs CHANGED
@@ -1196,7 +1196,7 @@ function operations(spec = openapi) {
1196
1196
  }
1197
1197
  async function call(target2, method, path, opts = {}) {
1198
1198
  const qs = new URLSearchParams(opts.query ?? {}).toString();
1199
- const headers = { "user-agent": `popcraft-cli/${"0.52.0"}`, ...opts.headers };
1199
+ const headers = { "user-agent": `popcraft-cli/${"0.53.0"}`, ...opts.headers };
1200
1200
  if (target2.token) headers.authorization = `Bearer ${target2.token}`;
1201
1201
  if (opts.contentType) headers["content-type"] = opts.contentType;
1202
1202
  try {
@@ -94509,7 +94509,6 @@ function hasMessage(key5) {
94509
94509
  var current2, loading, listeners, formats, asts;
94510
94510
  var init_runtime = __esm({
94511
94511
  "lib/i18n/runtime.ts"() {
94512
- "use strict";
94513
94512
  init_intl_messageformat();
94514
94513
  init_icu_messageformat_parser();
94515
94514
  init_catalogs();
@@ -96212,7 +96211,6 @@ function repairDocumentPaints(doc2) {
96212
96211
  var broken;
96213
96212
  var init_paint_repair = __esm({
96214
96213
  "lib/document/paint-repair.ts"() {
96215
- "use strict";
96216
96214
  init_shader_graph();
96217
96215
  broken = (p2) => {
96218
96216
  if (!p2 || typeof p2 !== "object") return false;
@@ -96870,6 +96868,7 @@ function releaseMediaMemory(hash3) {
96870
96868
  var key2, peaksKey, objectUrls, sourceKey, remoteResolver, MEDIA_FETCH_TIMEOUT_MS, SHIPPED_MEDIA_PATH, notShipped, MEDIA_SCHEME, isImageDataUrl, memory, pendingLoads, sourceAliases, PAINT_KEYS, URL_KEYS;
96871
96869
  var init_media_store = __esm({
96872
96870
  "lib/storage/media-store.ts"() {
96871
+ "use strict";
96873
96872
  init_media_types();
96874
96873
  init_idb();
96875
96874
  init_media_hash();
@@ -97578,6 +97577,7 @@ function relinkCopies(doc2, copies) {
97578
97577
  var TEXT_PATH_SOURCE_TYPES, isPathSource;
97579
97578
  var init_text_links = __esm({
97580
97579
  "lib/document/text-links.ts"() {
97580
+ "use strict";
97581
97581
  init_transform();
97582
97582
  TEXT_PATH_SOURCE_TYPES = ["VECTOR", "ELLIPSE", "RECTANGLE", "POLYGON", "STAR", "LINE", "ARROW", "FRAME"];
97583
97583
  isPathSource = (n) => !!n && TEXT_PATH_SOURCE_TYPES.includes(n.type);
@@ -248026,6 +248026,7 @@ function repairCompositions(comps, nodes) {
248026
248026
  var isObj5, finite6, optFinite, isVec2, TIMELINE_COLOR_IDS, TIMELINE_COLORS, UNITS, ORDERS, PROP_KEYS, ANIMATOR_ID, MOTION_TYPES, TRANSITIONS, isFraction, MEDIA_HASH;
248027
248027
  var init_invariants = __esm({
248028
248028
  "lib/motion/invariants.ts"() {
248029
+ "use strict";
248029
248030
  init_easing();
248030
248031
  init_properties();
248031
248032
  init_markers();
@@ -249003,6 +249004,7 @@ function fillPhotoFrame(doc2, groupId, imageUrl, size6, name2 = "Photo", credit)
249003
249004
  var isPhotoFrame;
249004
249005
  var init_photo_frames = __esm({
249005
249006
  "lib/document/photo-frames.ts"() {
249007
+ "use strict";
249006
249008
  init_dist_node();
249007
249009
  init_scene_graph();
249008
249010
  init_types();
@@ -249147,6 +249149,7 @@ function beforeWrite() {
249147
249149
  var leave;
249148
249150
  var init_read_only = __esm({
249149
249151
  "lib/editor/modes/read-only.ts"() {
249152
+ "use strict";
249150
249153
  leave = null;
249151
249154
  }
249152
249155
  });
@@ -252588,6 +252591,7 @@ function resizeWindow(doc2, target2, rect) {
252588
252591
  }
252589
252592
  var init_crop = __esm({
252590
252593
  "lib/editor/crop.ts"() {
252594
+ "use strict";
252591
252595
  init_dist_node();
252592
252596
  init_scene_graph();
252593
252597
  init_photo_frames();
@@ -257084,6 +257088,7 @@ function followPeers(peers) {
257084
257088
  var PALETTE, usePresence, awareness, CURSOR_SEND_MS, VIEWPORT_SEND_MS, cursorTimer, pendingCursor, sentCursor, EMOTE_MS, lastFollowCamera;
257085
257089
  var init_presence = __esm({
257086
257090
  "lib/collab/presence.ts"() {
257091
+ "use strict";
257087
257092
  init_esm();
257088
257093
  init_editor_store();
257089
257094
  init_status_announcements();
@@ -311651,7 +311656,6 @@ function startCloudSync() {
311651
311656
  var status, readOnlyDoc, activeLink, statusListeners, notice, urlArmed, opening, syncStatus, canEdit, uploaded, MEDIA_UPLOAD_PARALLEL, pushTimer, pushing, dirty, pendingMedia, collab, collabSession, collabAnonymous, uploadedThumbs, thumbCheckedAt, THUMB_EVERY_MS, THUMB_MIN_GAP_MS, putThumbnail, openingFiles, mediaHealed, started2;
311652
311657
  var init_sync2 = __esm({
311653
311658
  "lib/client/cloud/sync.ts"() {
311654
- "use strict";
311655
311659
  init_paint_repair();
311656
311660
  init_migrate();
311657
311661
  init_view();
@@ -311861,7 +311865,6 @@ async function dispatchShaped(key5, options) {
311861
311865
  var onViolation;
311862
311866
  var init_dispatch = __esm({
311863
311867
  "lib/commands/dispatch.ts"() {
311864
- "use strict";
311865
311868
  init_errors();
311866
311869
  init_registry();
311867
311870
  init_confirm();
@@ -312923,6 +312926,7 @@ function applyTextPath(layout2, path, tp, rebase = true) {
312923
312926
  var defaultCircleRadius, ownsPath, mapPoint;
312924
312927
  var init_text_path = __esm({
312925
312928
  "lib/engine/text/text-path.ts"() {
312929
+ "use strict";
312926
312930
  init_scene_graph();
312927
312931
  init_transform();
312928
312932
  init_shape_to_path();
@@ -313040,6 +313044,7 @@ function areaBounds(rings) {
313040
313044
  }
313041
313045
  var init_text_area = __esm({
313042
313046
  "lib/engine/text/text-area.ts"() {
313047
+ "use strict";
313043
313048
  }
313044
313049
  });
313045
313050
 
@@ -318318,7 +318323,6 @@ function agentToolList() {
318318
318323
  var AGENT_CAPABILITIES, legacyCommandId, legacyTools, blobToDataUrl3, provided, legacyTool, legacyToolList;
318319
318324
  var init_agent = __esm({
318320
318325
  "lib/commands/agent.ts"() {
318321
- "use strict";
318322
318326
  init_types5();
318323
318327
  init_registry();
318324
318328
  init_errors();
@@ -328473,7 +328477,7 @@ var init_package = __esm({
328473
328477
  "packages/runtime/package.json"() {
328474
328478
  package_default = {
328475
328479
  name: "@popcraft/runtime",
328476
- version: "0.52.0",
328480
+ version: "0.53.0",
328477
328481
  description: "What code exported from PopCraft shares: the meaning of expressions (operators and functions) and, as it grows, the parts of a design's behaviour that are common code rather than generated React.",
328478
328482
  license: "MIT",
328479
328483
  homepage: "https://popcraft.app/docs/exporting/nextjs",
@@ -362225,7 +362229,6 @@ var init_delete_current_file = __esm({
362225
362229
  var storeOpsSeam;
362226
362230
  var init_seams = __esm({
362227
362231
  "lib/commands/seams.ts"() {
362228
- "use strict";
362229
362232
  storeOpsSeam = (st) => ({
362230
362233
  booleanOperation: (op4) => st().booleanOperation(op4),
362231
362234
  flatten: () => st().flattenSelection(),
@@ -368587,16 +368590,16 @@ var init_api5 = __esm({
368587
368590
  }
368588
368591
  });
368589
368592
 
368590
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/generated/runtime.js
368593
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/generated/runtime.js
368591
368594
  var MAIN_RUNTIME, UI_RUNTIME;
368592
368595
  var init_runtime6 = __esm({
368593
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
368594
- MAIN_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/main.ts\n function clone(v) {\n return v === void 0 ? {} : JSON.parse(JSON.stringify(v));\n }\n function createMainApi(rpc = createRpcClient()) {\n const uiHandlers = [];\n let uiOnMessage = null;\n const uiQueue = [];\n function deliverUI(msg) {\n for (const cb of uiHandlers) {\n try {\n cb(msg);\n } catch (e) {\n console.error(e);\n }\n }\n if (typeof uiOnMessage === "function") {\n try {\n uiOnMessage(msg);\n } catch (e) {\n console.error(e);\n }\n }\n }\n function flushUI() {\n if (uiHandlers.length || typeof uiOnMessage === "function") uiQueue.splice(0).forEach(deliverUI);\n }\n rpc.on("uimessage", (msg) => {\n if (!uiHandlers.length && typeof uiOnMessage !== "function") uiQueue.push(msg);\n else deliverUI(msg);\n });\n let widgetDef = null;\n const widgetQueue = [];\n function renderWidget(state) {\n const handlers = {};\n function walk(el, path) {\n if (!el || typeof el !== "object") return el;\n const out = {};\n for (const k of Object.keys(el)) {\n const v = el[k];\n if (k === "children") {\n out.children = (Array.isArray(v) ? v : [v]).filter((c) => c !== null && c !== void 0 && c !== false).map((c, i) => walk(c, path + "." + i));\n } else if (k === "onClick" && typeof v === "function") {\n handlers[path] = v;\n out.onClick = path;\n } else {\n out[k] = v;\n }\n }\n return out;\n }\n return { tree: walk(widgetDef.render(state), "root"), handlers };\n }\n function initialWidgetState() {\n const s = widgetDef && widgetDef.initialState;\n return clone(typeof s === "function" ? s() : s);\n }\n function commitWidget(nodeId, state) {\n return rpc.call("widgetUpdate", { id: nodeId, state, tree: renderWidget(clone(state)).tree });\n }\n function handleWidgetClick(e) {\n Promise.resolve().then(() => {\n const state = clone(e.state);\n const rendered = renderWidget(state);\n const h = rendered.handlers[e.handler] || widgetDef.handlers && widgetDef.handlers[e.handler];\n if (typeof h !== "function") return;\n return Promise.resolve(h(state, { nodeId: e.nodeId })).then((ret) => commitWidget(e.nodeId, ret === void 0 ? state : ret));\n }).catch((err) => rpc.send({ kind: "error", message: String((err == null ? void 0 : err.message) || err) }));\n }\n rpc.on("widgetclick", (e) => {\n if (widgetDef) handleWidgetClick(e);\n else widgetQueue.push(e);\n });\n const popcraft = {\n /** Which menu command the user picked, or null when the plugin ran some other way. */\n command: null,\n /** Host import mode when launched as an importer, else null. */\n importMode: null,\n /** Pending import file when the host handed one over, else null. */\n importFile: null,\n /** Pending export request (File \u2192 Export \u2192 this plugin\'s format), else null. */\n exportRequest: null,\n getSelection: () => rpc.call("getSelection"),\n setSelection: (ids) => rpc.call("setSelection", { ids }),\n getNode: (id) => rpc.call("getNode", { id }),\n findNodes: (query) => rpc.call("findNodes", query || {}),\n getCurrentPage: () => rpc.call("getCurrentPage"),\n createNode: (type, props) => rpc.call("createNode", { type, props: props || {} }),\n updateNode: (id, props) => rpc.call("updateNode", { id, props }),\n deleteNode: (id) => rpc.call("deleteNode", { id }),\n setText: (id, characters) => rpc.call("setText", { id, characters }),\n /** Put TEXT layers on a path (another layer\'s outline, or their own arc, circle or wave), or tune one: brackets, alignment, placement, effect, overflow. */\n setTextPath: (opts) => rpc.call("setTextPath", opts || {}),\n /** Area type: flow a TEXT layer inside a closed shape, kept `inset` px in. */\n flowTextIntoShape: (opts) => rpc.call("flowTextIntoShape", opts || {}),\n /** Take TEXT layers off their path or out of their shape (or free every text linked to a path / shape). */\n detachText: (opts) => rpc.call("detachText", opts || {}),\n /** Auto-size TEXT layers\' type to their box, shape or path. */\n setTextFit: (opts) => rpc.call("setTextFit", opts || {}),\n createPage: (name) => rpc.call("createPage", name != null ? { name: String(name) } : {}),\n setCurrentPage: (pageId) => rpc.call("setCurrentPage", { pageId }),\n createImage: (opts) => rpc.call("createImage", opts || {}),\n createDocument: (opts) => rpc.call("createDocument", opts || {}),\n getImportMode: () => rpc.call("getImportMode"),\n getImportFile: () => rpc.call("getImportFile"),\n /**\n * The open page as a storefront design in a neutral form, for an exporter that writes its own store\'s templates:\n * each page\'s HTML with the store\'s data marked (`{{page.title}}`, `{{item.price}}`, `<!-- pc:each \u2026 -->` lists,\n * `data-pc-action` forms), and its collections with their commerce schema and sample records.\n */\n getStorefront: () => rpc.call("getStorefront"),\n /**\n * A design\'s data (docs: Collections): a collection and its fields (`schema`: what it stands for, e.g.\n * `commerce.product`, whose fields are made for it), its records, and reading them.\n */\n editCollection: (opts) => rpc.call("editCollection", opts || {}),\n editRecords: (opts) => rpc.call("editRecords", opts || {}),\n getRecords: (opts) => rpc.call("getRecords", opts || {}),\n /** A layer as a web page\'s form control (a FORM\'s `formAction`, an INPUT\'s name and value), repeated per record, a page\'s address, its semantics. */\n setControl: (opts) => rpc.call("setControl", opts || {}),\n setRepeat: (opts) => rpc.call("setRepeat", opts || {}),\n setRoute: (opts) => rpc.call("setRoute", opts || {}),\n setSemantics: (opts) => rpc.call("setSemantics", opts || {}),\n /** Which record layers are about (one product, picked from a collection), and which of its fields a layer\'s words, picture or an instance\'s properties follow. */\n setRecord: (opts) => rpc.call("setRecord", opts || {}),\n bindField: (opts) => rpc.call("bindField", opts || {}),\n /** The site\'s environment: public settings its host reads by name when it is deployed (never a secret: the file keeps them). */\n getSiteEnvironment: () => rpc.call("getSiteEnvironment"),\n setSiteEnvironment: (set) => rpc.call("setSiteEnvironment", { set }),\n /** What this plugin keeps with the open file (its settings for this design), under its own id; JSON only. */\n getFileData: (key) => rpc.call("getFileData", { key }),\n setFileData: (key, value) => rpc.call("setFileData", { key, value }),\n /** A store\'s project built from the open page, zipped (needs `export`): what an exporter saves with `saveExport`. */\n getStorefrontFiles: (target) => rpc.call("getStorefrontFiles", { target }),\n getExportRequest: () => rpc.call("getExportRequest"),\n /** Save the exporter\'s file (once per export request); the host enforces the contributed extension. */\n saveExport: (file) => rpc.call("saveExport", file || {}),\n /**\n * Presentation audio (docs/plugins/presentation-audio.md): the deck\'s slides, notes, narration and timing; the\n * soundtrack\'s settings, bed and stinger.\n */\n getPresentationAudio: (opts) => rpc.call("getPresentationAudio", opts || {}),\n /** Change the soundtrack\'s settings (voice, style, mood, loudness, beat alignment, levels) and re-time it. */\n setPresentationAudioSettings: (opts) => rpc.call("setPresentationAudioSettings", opts || {}),\n /** Put a sound in (a slide\'s narration, the bed or the stinger): bytes are normalised to the soundtrack\'s target and stored. */\n setPresentationAudioClip: (opts) => rpc.call("setPresentationAudioClip", opts || {}),\n removePresentationAudioClip: (opts) => rpc.call("removePresentationAudioClip", opts || {}),\n /** Re-time: fixed slide lengths (ms, null clears) and beat-aligned changes. */\n setPresentationTiming: (opts) => rpc.call("setPresentationTiming", opts || {}),\n /** The mix as the export carries it: loudness, true peak, and (wav: true) the 48 kHz stereo WAV. */\n getPresentationMix: (opts) => rpc.call("getPresentationMix", opts || {}),\n /** Ask the user to generate with AI (the panel opens with the request filled in; the user decides). */\n requestPresentationAudio: (opts) => rpc.call("requestPresentationAudio", opts || {}),\n /** Editor commands: each takes the arguments documented in docs/plugins/methods.md (the agent tool of the same purpose). */\n moveNodes: (opts) => rpc.call("moveNodes", opts || {}),\n resizeNodes: (opts) => rpc.call("resizeNodes", opts || {}),\n renameNodes: (opts) => rpc.call("renameNodes", opts || {}),\n reparentNodes: (opts) => rpc.call("reparentNodes", opts || {}),\n duplicateNodes: (opts) => rpc.call("duplicateNodes", opts || {}),\n groupNodes: (opts) => rpc.call("groupNodes", opts || {}),\n ungroupNodes: (opts) => rpc.call("ungroupNodes", opts || {}),\n alignNodes: (opts) => rpc.call("alignNodes", opts || {}),\n distributeNodes: (opts) => rpc.call("distributeNodes", opts || {}),\n flipNodes: (opts) => rpc.call("flipNodes", opts || {}),\n rotateNodes: (opts) => rpc.call("rotateNodes", opts || {}),\n reorderNodes: (opts) => rpc.call("reorderNodes", opts || {}),\n setLocked: (opts) => rpc.call("setLocked", opts || {}),\n setVisible: (opts) => rpc.call("setVisible", opts || {}),\n setAutoLayout: (opts) => rpc.call("setAutoLayout", opts || {}),\n importSvg: (opts) => rpc.call("importSvg", opts || {}),\n measureNodes: (opts) => rpc.call("measureNodes", opts || {}),\n setFills: (opts) => rpc.call("setFills", opts || {}),\n setStrokes: (opts) => rpc.call("setStrokes", opts || {}),\n setEffects: (opts) => rpc.call("setEffects", opts || {}),\n replaceColor: (opts) => rpc.call("replaceColor", opts || {}),\n setTypography: (opts) => rpc.call("setTypography", opts || {}),\n applyStyle: (opts) => rpc.call("applyStyle", opts || {}),\n createComponent: (opts) => rpc.call("createComponent", opts || {}),\n createInstance: (opts) => rpc.call("createInstance", opts || {}),\n renamePage: (opts) => rpc.call("renamePage", opts || {}),\n getDocumentOutline: (opts) => rpc.call("getDocumentOutline", opts || {}),\n setPageSetup: (opts) => rpc.call("setPageSetup", opts || {}),\n setShowAdvance: (opts) => rpc.call("setShowAdvance", opts || {}),\n booleanOperation: (opts) => rpc.call("booleanOperation", opts || {}),\n flattenNodes: (opts) => rpc.call("flattenNodes", opts || {}),\n outlineStroke: (opts) => rpc.call("outlineStroke", opts || {}),\n setMask: (opts) => rpc.call("setMask", opts || {}),\n setMaskType: (opts) => rpc.call("setMaskType", opts || {}),\n shapeBuilder: (opts) => rpc.call("shapeBuilder", opts || {}),\n setKeyframes: (opts) => rpc.call("setKeyframes", opts || {}),\n getAnimation: (opts) => rpc.call("getAnimation", opts || {}),\n getCompositions: (opts) => rpc.call("getCompositions", opts || {}),\n editBehaviours: (opts) => rpc.call("editBehaviours", opts || {}),\n setTimeline: (opts) => rpc.call("setTimeline", opts || {}),\n setLayerTiming: (opts) => rpc.call("setLayerTiming", opts || {}),\n editTextAnimation: (opts) => rpc.call("editTextAnimation", opts || {}),\n edit3DScene: (opts) => rpc.call("edit3DScene", opts || {}),\n setInstancePlayback: (opts) => rpc.call("setInstancePlayback", opts || {}),\n editComponentProperty: (opts) => rpc.call("editComponentProperty", opts || {}),\n setShaderFill: (opts) => rpc.call("setShaderFill", opts || {}),\n createComposition: (opts) => rpc.call("createComposition", opts || {}),\n editComposition: (opts) => rpc.call("editComposition", opts || {}),\n editStateMachine: (opts) => rpc.call("editStateMachine", opts || {}),\n getStateMachine: (opts) => rpc.call("getStateMachine", opts || {}),\n applyMotionPreset: (opts) => rpc.call("applyMotionPreset", opts || {}),\n staggerMotion: (opts) => rpc.call("staggerMotion", opts || {}),\n createMotionComponent: (opts) => rpc.call("createMotionComponent", opts || {}),\n addAudio: (opts) => rpc.call("addAudio", opts || {}),\n editFrameAudio: (opts) => rpc.call("editFrameAudio", opts || {}),\n editVideoClip: (opts) => rpc.call("editVideoClip", opts || {}),\n detectAudioOnsets: (opts) => rpc.call("detectAudioOnsets", opts || {}),\n cutToBeat: (opts) => rpc.call("cutToBeat", opts || {}),\n editPrototype: (opts) => rpc.call("editPrototype", opts || {}),\n usePresentationFallbackAudio: (opts) => rpc.call("usePresentationFallbackAudio", opts || {}),\n /** Bring a Lottie, PDF or PopCraft file into the open document (the `importFile` field is the file an importer was handed). */\n importDocumentFile: (opts) => rpc.call("importDocumentFile", opts || {}),\n getStyles: () => rpc.call("getStyles"),\n createPaintStyle: (name, paints) => rpc.call("createPaintStyle", { name, paints }),\n getVariables: () => rpc.call("getVariables"),\n setVariableValue: (variableId, modeId, value) => rpc.call("setVariableValue", { variableId, modeId, value }),\n exportNode: (id, options) => rpc.call("exportNode", { id, options: options || {} }),\n openExternal: (url) => rpc.call("openExternal", { url }),\n notify: (message, options) => rpc.call("notify", { message: String(message), error: !!(options && options.error) }),\n showUI: (options) => rpc.call("showUI", options || {}),\n hideUI: () => rpc.call("hideUI"),\n /** Ends the run. The optional message is shown as a notification. */\n closePlugin: (message) => rpc.call("closePlugin", { message }),\n storage: {\n get: (key) => rpc.call("storageGet", { key }),\n set: (key, value) => rpc.call("storageSet", { key, value })\n },\n ui: {\n get onmessage() {\n return uiOnMessage;\n },\n set onmessage(cb) {\n uiOnMessage = cb;\n flushUI();\n },\n postMessage: (msg) => rpc.send({ kind: "toUI", data: msg }),\n on: (cb) => {\n uiHandlers.push(cb);\n flushUI();\n }\n },\n widget: {\n register(def) {\n if (!def || typeof def.render !== "function") throw new Error("popcraft.widget.register needs a render(state) function");\n widgetDef = def;\n widgetQueue.splice(0).forEach(handleWidgetClick);\n },\n insert(options) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n const o = options || {};\n const state = o.state !== void 0 ? clone(o.state) : initialWidgetState();\n return rpc.call("widgetInsert", { state, tree: renderWidget(state).tree, x: o.x, y: o.y });\n },\n getState: (nodeId) => rpc.call("widgetGet", { id: nodeId }),\n setState(nodeId, state) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n return commitWidget(nodeId, clone(state));\n }\n },\n on: (event, cb) => rpc.on(event, cb),\n off: (event, cb) => rpc.off(event, cb)\n };\n rpc.on("init", (data) => {\n var _a, _b, _c;\n popcraft.command = data.command;\n popcraft.importMode = (_a = data.importMode) != null ? _a : null;\n popcraft.importFile = (_b = data.importFile) != null ? _b : null;\n popcraft.exportRequest = (_c = data.exportRequest) != null ? _c : null;\n });\n return popcraft;\n }\n function installMainApi() {\n const rpc = createRpcClient();\n const api = createMainApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n window.addEventListener("error", (e) => rpc.send({ kind: "error", message: String(e.message || e) }));\n window.addEventListener("unhandledrejection", (e) => rpc.send({ kind: "error", message: String(e.reason && e.reason.message || e.reason) }));\n return api;\n }\n\n // src/runtime/main.entry.ts\n installMainApi();\n})();';
368596
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
368597
+ MAIN_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/main.ts\n function clone(v) {\n return v === void 0 ? {} : JSON.parse(JSON.stringify(v));\n }\n function createMainApi(rpc = createRpcClient()) {\n const uiHandlers = [];\n let uiOnMessage = null;\n const uiQueue = [];\n function deliverUI(msg) {\n for (const cb of uiHandlers) {\n try {\n cb(msg);\n } catch (e) {\n console.error(e);\n }\n }\n if (typeof uiOnMessage === "function") {\n try {\n uiOnMessage(msg);\n } catch (e) {\n console.error(e);\n }\n }\n }\n function flushUI() {\n if (uiHandlers.length || typeof uiOnMessage === "function") uiQueue.splice(0).forEach(deliverUI);\n }\n rpc.on("uimessage", (msg) => {\n if (!uiHandlers.length && typeof uiOnMessage !== "function") uiQueue.push(msg);\n else deliverUI(msg);\n });\n let widgetDef = null;\n const widgetQueue = [];\n function renderWidget(state) {\n const handlers = {};\n function walk(el, path) {\n if (!el || typeof el !== "object") return el;\n const out = {};\n for (const k of Object.keys(el)) {\n const v = el[k];\n if (k === "children") {\n out.children = (Array.isArray(v) ? v : [v]).filter((c) => c !== null && c !== void 0 && c !== false).map((c, i) => walk(c, path + "." + i));\n } else if (k === "onClick" && typeof v === "function") {\n handlers[path] = v;\n out.onClick = path;\n } else {\n out[k] = v;\n }\n }\n return out;\n }\n return { tree: walk(widgetDef.render(state), "root"), handlers };\n }\n function initialWidgetState() {\n const s = widgetDef && widgetDef.initialState;\n return clone(typeof s === "function" ? s() : s);\n }\n function commitWidget(nodeId, state) {\n return rpc.call("widgetUpdate", { id: nodeId, state, tree: renderWidget(clone(state)).tree });\n }\n function handleWidgetClick(e) {\n Promise.resolve().then(() => {\n const state = clone(e.state);\n const rendered = renderWidget(state);\n const h = rendered.handlers[e.handler] || widgetDef.handlers && widgetDef.handlers[e.handler];\n if (typeof h !== "function") return;\n return Promise.resolve(h(state, { nodeId: e.nodeId })).then((ret) => commitWidget(e.nodeId, ret === void 0 ? state : ret));\n }).catch((err) => rpc.send({ kind: "error", message: String((err == null ? void 0 : err.message) || err) }));\n }\n rpc.on("widgetclick", (e) => {\n if (widgetDef) handleWidgetClick(e);\n else widgetQueue.push(e);\n });\n const popcraft = {\n /** Which menu command the user picked, or null when the plugin ran some other way. */\n command: null,\n /** Host import mode when launched as an importer, else null. */\n importMode: null,\n /** Pending import file when the host handed one over, else null. */\n importFile: null,\n /** Pending export request (File \u2192 Export \u2192 this plugin\'s format), else null. */\n exportRequest: null,\n getSelection: () => rpc.call("getSelection"),\n setSelection: (ids) => rpc.call("setSelection", { ids }),\n getNode: (id) => rpc.call("getNode", { id }),\n findNodes: (query) => rpc.call("findNodes", query || {}),\n getCurrentPage: () => rpc.call("getCurrentPage"),\n createNode: (type, props) => rpc.call("createNode", { type, props: props || {} }),\n updateNode: (id, props) => rpc.call("updateNode", { id, props }),\n deleteNode: (id) => rpc.call("deleteNode", { id }),\n setText: (id, characters) => rpc.call("setText", { id, characters }),\n /** Put TEXT layers on a path (another layer\'s outline, or their own arc, circle or wave), or tune one: brackets, alignment, placement, effect, overflow. */\n setTextPath: (opts) => rpc.call("setTextPath", opts || {}),\n /** Area type: flow a TEXT layer inside a closed shape, kept `inset` px in. */\n flowTextIntoShape: (opts) => rpc.call("flowTextIntoShape", opts || {}),\n /** Take TEXT layers off their path or out of their shape (or free every text linked to a path / shape). */\n detachText: (opts) => rpc.call("detachText", opts || {}),\n /** Auto-size TEXT layers\' type to their box, shape or path. */\n setTextFit: (opts) => rpc.call("setTextFit", opts || {}),\n createPage: (name) => rpc.call("createPage", name != null ? { name: String(name) } : {}),\n setCurrentPage: (pageId) => rpc.call("setCurrentPage", { pageId }),\n createImage: (opts) => rpc.call("createImage", opts || {}),\n createDocument: (opts) => rpc.call("createDocument", opts || {}),\n getImportMode: () => rpc.call("getImportMode"),\n getImportFile: () => rpc.call("getImportFile"),\n /**\n * The open page as a storefront design in a neutral form, for an exporter that writes its own store\'s templates:\n * each page\'s HTML with the store\'s data marked (`{{page.title}}`, `{{item.price}}`, `<!-- pc:each \u2026 -->` lists,\n * `data-pc-action` forms), and its collections with their commerce schema and sample records.\n */\n getStorefront: () => rpc.call("getStorefront"),\n /**\n * A design\'s data (docs: Collections): a collection and its fields (`schema`: what it stands for, e.g.\n * `commerce.product`, whose fields are made for it), its records, and reading them.\n */\n editCollection: (opts) => rpc.call("editCollection", opts || {}),\n editRecords: (opts) => rpc.call("editRecords", opts || {}),\n getRecords: (opts) => rpc.call("getRecords", opts || {}),\n /** A layer as a web page\'s form control (a FORM\'s `formAction`, an INPUT\'s name and value), repeated per record, a page\'s address, its semantics. */\n setControl: (opts) => rpc.call("setControl", opts || {}),\n setRepeat: (opts) => rpc.call("setRepeat", opts || {}),\n setRoute: (opts) => rpc.call("setRoute", opts || {}),\n setSemantics: (opts) => rpc.call("setSemantics", opts || {}),\n /** Which record layers are about (one product, picked from a collection), and which of its fields a layer\'s words, picture or an instance\'s properties follow. */\n setRecord: (opts) => rpc.call("setRecord", opts || {}),\n bindField: (opts) => rpc.call("bindField", opts || {}),\n /** The site\'s environment: public settings its host reads by name when it is deployed (never a secret: the file keeps them). */\n getSiteEnvironment: () => rpc.call("getSiteEnvironment"),\n setSiteEnvironment: (set) => rpc.call("setSiteEnvironment", { set }),\n /** What this plugin keeps with the open file (its settings for this design), under its own id; JSON only. */\n getFileData: (key) => rpc.call("getFileData", { key }),\n setFileData: (key, value) => rpc.call("setFileData", { key, value }),\n /** A store\'s project built from the open page, zipped (needs `export`): what an exporter saves with `saveExport`. */\n getStorefrontFiles: (target) => rpc.call("getStorefrontFiles", { target }),\n getExportRequest: () => rpc.call("getExportRequest"),\n /** Save the exporter\'s file (once per export request); the host enforces the contributed extension. */\n saveExport: (file) => rpc.call("saveExport", file || {}),\n /**\n * Presentation audio (docs/plugins/presentation-audio.md): the deck\'s slides, notes, narration and timing; the\n * soundtrack\'s settings, bed and stinger.\n */\n getPresentationAudio: (opts) => rpc.call("getPresentationAudio", opts || {}),\n /** Change the soundtrack\'s settings (voice, style, mood, loudness, beat alignment, levels) and re-time it. */\n setPresentationAudioSettings: (opts) => rpc.call("setPresentationAudioSettings", opts || {}),\n /** Put a sound in (a slide\'s narration, the bed or the stinger): bytes are normalised to the soundtrack\'s target and stored. */\n setPresentationAudioClip: (opts) => rpc.call("setPresentationAudioClip", opts || {}),\n removePresentationAudioClip: (opts) => rpc.call("removePresentationAudioClip", opts || {}),\n /** Re-time: fixed slide lengths (ms, null clears) and beat-aligned changes. */\n setPresentationTiming: (opts) => rpc.call("setPresentationTiming", opts || {}),\n /** The mix as the export carries it: loudness, true peak, and (wav: true) the 48 kHz stereo WAV. */\n getPresentationMix: (opts) => rpc.call("getPresentationMix", opts || {}),\n /** Ask the user to generate with AI (the panel opens with the request filled in; the user decides). */\n requestPresentationAudio: (opts) => rpc.call("requestPresentationAudio", opts || {}),\n /** Editor commands: each takes the arguments documented in docs/plugins/methods.md (the agent tool of the same purpose). */\n moveNodes: (opts) => rpc.call("moveNodes", opts || {}),\n resizeNodes: (opts) => rpc.call("resizeNodes", opts || {}),\n renameNodes: (opts) => rpc.call("renameNodes", opts || {}),\n reparentNodes: (opts) => rpc.call("reparentNodes", opts || {}),\n duplicateNodes: (opts) => rpc.call("duplicateNodes", opts || {}),\n groupNodes: (opts) => rpc.call("groupNodes", opts || {}),\n ungroupNodes: (opts) => rpc.call("ungroupNodes", opts || {}),\n alignNodes: (opts) => rpc.call("alignNodes", opts || {}),\n distributeNodes: (opts) => rpc.call("distributeNodes", opts || {}),\n flipNodes: (opts) => rpc.call("flipNodes", opts || {}),\n rotateNodes: (opts) => rpc.call("rotateNodes", opts || {}),\n reorderNodes: (opts) => rpc.call("reorderNodes", opts || {}),\n setLocked: (opts) => rpc.call("setLocked", opts || {}),\n setVisible: (opts) => rpc.call("setVisible", opts || {}),\n setAutoLayout: (opts) => rpc.call("setAutoLayout", opts || {}),\n importSvg: (opts) => rpc.call("importSvg", opts || {}),\n measureNodes: (opts) => rpc.call("measureNodes", opts || {}),\n setFills: (opts) => rpc.call("setFills", opts || {}),\n setStrokes: (opts) => rpc.call("setStrokes", opts || {}),\n setEffects: (opts) => rpc.call("setEffects", opts || {}),\n replaceColor: (opts) => rpc.call("replaceColor", opts || {}),\n setTypography: (opts) => rpc.call("setTypography", opts || {}),\n applyStyle: (opts) => rpc.call("applyStyle", opts || {}),\n createComponent: (opts) => rpc.call("createComponent", opts || {}),\n createInstance: (opts) => rpc.call("createInstance", opts || {}),\n renamePage: (opts) => rpc.call("renamePage", opts || {}),\n getDocumentOutline: (opts) => rpc.call("getDocumentOutline", opts || {}),\n setPageSetup: (opts) => rpc.call("setPageSetup", opts || {}),\n setShowAdvance: (opts) => rpc.call("setShowAdvance", opts || {}),\n booleanOperation: (opts) => rpc.call("booleanOperation", opts || {}),\n flattenNodes: (opts) => rpc.call("flattenNodes", opts || {}),\n outlineStroke: (opts) => rpc.call("outlineStroke", opts || {}),\n setMask: (opts) => rpc.call("setMask", opts || {}),\n setMaskType: (opts) => rpc.call("setMaskType", opts || {}),\n shapeBuilder: (opts) => rpc.call("shapeBuilder", opts || {}),\n setKeyframes: (opts) => rpc.call("setKeyframes", opts || {}),\n getAnimation: (opts) => rpc.call("getAnimation", opts || {}),\n getCompositions: (opts) => rpc.call("getCompositions", opts || {}),\n editBehaviours: (opts) => rpc.call("editBehaviours", opts || {}),\n setTimeline: (opts) => rpc.call("setTimeline", opts || {}),\n setLayerTiming: (opts) => rpc.call("setLayerTiming", opts || {}),\n editTextAnimation: (opts) => rpc.call("editTextAnimation", opts || {}),\n edit3DScene: (opts) => rpc.call("edit3DScene", opts || {}),\n setInstancePlayback: (opts) => rpc.call("setInstancePlayback", opts || {}),\n editComponentProperty: (opts) => rpc.call("editComponentProperty", opts || {}),\n setShaderFill: (opts) => rpc.call("setShaderFill", opts || {}),\n createComposition: (opts) => rpc.call("createComposition", opts || {}),\n editComposition: (opts) => rpc.call("editComposition", opts || {}),\n editStateMachine: (opts) => rpc.call("editStateMachine", opts || {}),\n getStateMachine: (opts) => rpc.call("getStateMachine", opts || {}),\n applyMotionPreset: (opts) => rpc.call("applyMotionPreset", opts || {}),\n staggerMotion: (opts) => rpc.call("staggerMotion", opts || {}),\n createMotionComponent: (opts) => rpc.call("createMotionComponent", opts || {}),\n addAudio: (opts) => rpc.call("addAudio", opts || {}),\n editFrameAudio: (opts) => rpc.call("editFrameAudio", opts || {}),\n editVideoClip: (opts) => rpc.call("editVideoClip", opts || {}),\n detectAudioOnsets: (opts) => rpc.call("detectAudioOnsets", opts || {}),\n cutToBeat: (opts) => rpc.call("cutToBeat", opts || {}),\n editPrototype: (opts) => rpc.call("editPrototype", opts || {}),\n usePresentationFallbackAudio: (opts) => rpc.call("usePresentationFallbackAudio", opts || {}),\n /** Bring a Lottie, PDF or PopCraft file into the open document (the `importFile` field is the file an importer was handed). */\n importDocumentFile: (opts) => rpc.call("importDocumentFile", opts || {}),\n getStyles: () => rpc.call("getStyles"),\n createPaintStyle: (name, paints) => rpc.call("createPaintStyle", { name, paints }),\n getVariables: () => rpc.call("getVariables"),\n setVariableValue: (variableId, modeId, value) => rpc.call("setVariableValue", { variableId, modeId, value }),\n exportNode: (id, options) => rpc.call("exportNode", { id, options: options || {} }),\n openExternal: (url) => rpc.call("openExternal", { url }),\n /**\n * Send a file to an https URL. PopCraft makes the request, not the sandbox, so it works for files of\n * any size the server accepts, including straight to a presigned storage URL. Needs `network`.\n */\n upload: (url, options) => {\n const body = options.body instanceof ArrayBuffer ? new Uint8Array(options.body) : options.body;\n return rpc.call("upload", {\n url,\n body,\n method: options.method,\n contentType: options.contentType,\n headers: options.headers\n });\n },\n notify: (message, options) => rpc.call("notify", { message: String(message), error: !!(options && options.error) }),\n showUI: (options) => rpc.call("showUI", options || {}),\n hideUI: () => rpc.call("hideUI"),\n /** Ends the run. The optional message is shown as a notification. */\n closePlugin: (message) => rpc.call("closePlugin", { message }),\n storage: {\n get: (key) => rpc.call("storageGet", { key }),\n set: (key, value) => rpc.call("storageSet", { key, value })\n },\n ui: {\n get onmessage() {\n return uiOnMessage;\n },\n set onmessage(cb) {\n uiOnMessage = cb;\n flushUI();\n },\n postMessage: (msg) => rpc.send({ kind: "toUI", data: msg }),\n on: (cb) => {\n uiHandlers.push(cb);\n flushUI();\n }\n },\n widget: {\n register(def) {\n if (!def || typeof def.render !== "function") throw new Error("popcraft.widget.register needs a render(state) function");\n widgetDef = def;\n widgetQueue.splice(0).forEach(handleWidgetClick);\n },\n insert(options) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n const o = options || {};\n const state = o.state !== void 0 ? clone(o.state) : initialWidgetState();\n return rpc.call("widgetInsert", { state, tree: renderWidget(state).tree, x: o.x, y: o.y });\n },\n getState: (nodeId) => rpc.call("widgetGet", { id: nodeId }),\n setState(nodeId, state) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n return commitWidget(nodeId, clone(state));\n }\n },\n on: (event, cb) => rpc.on(event, cb),\n off: (event, cb) => rpc.off(event, cb)\n };\n rpc.on("init", (data) => {\n var _a, _b, _c;\n popcraft.command = data.command;\n popcraft.importMode = (_a = data.importMode) != null ? _a : null;\n popcraft.importFile = (_b = data.importFile) != null ? _b : null;\n popcraft.exportRequest = (_c = data.exportRequest) != null ? _c : null;\n });\n return popcraft;\n }\n function installMainApi() {\n const rpc = createRpcClient();\n const api = createMainApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n window.addEventListener("error", (e) => rpc.send({ kind: "error", message: String(e.message || e) }));\n window.addEventListener("unhandledrejection", (e) => rpc.send({ kind: "error", message: String(e.reason && e.reason.message || e.reason) }));\n return api;\n }\n\n // src/runtime/main.entry.ts\n installMainApi();\n})();';
368595
368598
  UI_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/ui.ts\n function createUiApi(rpc = createRpcClient()) {\n const popcraft = {\n onmessage: null,\n postMessage: (msg) => rpc.send({ kind: "fromUI", data: msg }),\n close: () => rpc.send({ kind: "closeUI" })\n };\n rpc.on("message", (msg) => {\n if (typeof popcraft.onmessage === "function") popcraft.onmessage(msg);\n window.dispatchEvent(new MessageEvent("message", { data: { pluginMessage: msg } }));\n });\n return popcraft;\n }\n function installUiApi() {\n const rpc = createRpcClient();\n const api = createUiApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n return api;\n }\n\n // src/runtime/ui.entry.ts\n installUiApi();\n})();';
368596
368599
  }
368597
368600
  });
368598
368601
 
368599
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/host.js
368602
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/host.js
368600
368603
  function csp(network) {
368601
368604
  const connect2 = network ? "connect-src * data: blob:;" : "connect-src 'none';";
368602
368605
  const img = network ? "img-src * data: blob:;" : "img-src data: blob:;";
@@ -368624,40 +368627,40 @@ function buildUIDocument(uiHtml, network) {
368624
368627
  }
368625
368628
  var escapeScript;
368626
368629
  var init_host2 = __esm({
368627
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/host.js"() {
368630
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/host.js"() {
368628
368631
  init_runtime6();
368629
368632
  escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
368630
368633
  }
368631
368634
  });
368632
368635
 
368633
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/rpc.js
368636
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/runtime/rpc.js
368634
368637
  var init_rpc = __esm({
368635
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
368638
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
368636
368639
  }
368637
368640
  });
368638
368641
 
368639
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/main.js
368642
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/runtime/main.js
368640
368643
  var init_main = __esm({
368641
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
368644
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
368642
368645
  init_rpc();
368643
368646
  }
368644
368647
  });
368645
368648
 
368646
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/types.js
368649
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/types.js
368647
368650
  var init_types10 = __esm({
368648
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/types.js"() {
368651
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/types.js"() {
368649
368652
  }
368650
368653
  });
368651
368654
 
368652
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/widget.js
368655
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/widget.js
368653
368656
  var init_widget = __esm({
368654
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/widget.js"() {
368657
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/widget.js"() {
368655
368658
  }
368656
368659
  });
368657
368660
 
368658
- // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/index.js
368661
+ // node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/index.js
368659
368662
  var init_dist = __esm({
368660
- "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/index.js"() {
368663
+ "node_modules/.pnpm/@popcraft+plugins@1.3.0/node_modules/@popcraft/plugins/dist/index.js"() {
368661
368664
  init_host2();
368662
368665
  init_main();
368663
368666
  init_runtime6();
@@ -399245,7 +399248,7 @@ function dispatchPluginCall(env, method, params2 = {}) {
399245
399248
  }
399246
399249
  });
399247
399250
  }
399248
- var PLUGIN_CAPABILITIES, pluginCommandId, empty, commands, pluginRun, registered;
399251
+ var PLUGIN_CAPABILITIES, pluginCommandId, empty, MAX_UPLOAD_BYTES, MAX_UPLOAD_REPLY_CHARS, commands, pluginRun, registered;
399249
399252
  var init_plugin = __esm({
399250
399253
  "lib/commands/plugin.ts"() {
399251
399254
  init_zod();
@@ -399261,6 +399264,8 @@ var init_plugin = __esm({
399261
399264
  PLUGIN_CAPABILITIES = ["render", "storage", "panel"];
399262
399265
  pluginCommandId = (method) => `plugin.${method}`;
399263
399266
  empty = external_exports.object({});
399267
+ MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
399268
+ MAX_UPLOAD_REPLY_CHARS = 1024 * 1024;
399264
399269
  commands = [
399265
399270
  defineCommand({
399266
399271
  id: pluginCommandId("getVariables"),
@@ -399340,6 +399345,46 @@ var init_plugin = __esm({
399340
399345
  return { summary: "Opened link" };
399341
399346
  }
399342
399347
  }),
399348
+ defineCommand({
399349
+ id: pluginCommandId("upload"),
399350
+ title: "Upload a file",
399351
+ domain: "ui",
399352
+ // The sandbox's own fetch is fine for small requests; a book-sized export goes through here so it can be
399353
+ // PUT straight onto a presigned storage URL rather than through a server that caps its request body.
399354
+ params: external_exports.object({
399355
+ url: external_exports.string().refine(isOpenableUrl, { error: "url must be https, or http on localhost" }),
399356
+ body: external_exports.union([external_exports.instanceof(Uint8Array), external_exports.string()]),
399357
+ method: external_exports.enum(["PUT", "POST"]).optional(),
399358
+ contentType: external_exports.string().max(200).optional(),
399359
+ headers: external_exports.record(external_exports.string(), external_exports.string()).optional()
399360
+ }),
399361
+ effect: "none",
399362
+ permission: "network",
399363
+ expose: { plugin: { method: "upload", shape: (r) => r.data } },
399364
+ run: async (p2) => {
399365
+ const size6 = typeof p2.body === "string" ? p2.body.length : p2.body.byteLength;
399366
+ if (size6 > MAX_UPLOAD_BYTES) throw new PluginApiError(`upload is limited to ${MAX_UPLOAD_BYTES / 1024 / 1024} MB`, "invalid_params");
399367
+ if (typeof location !== "undefined" && new URL(p2.url).origin === location.origin) {
399368
+ throw new PluginApiError("upload cannot send to PopCraft itself", "invalid_params");
399369
+ }
399370
+ const headers = new Headers(p2.headers ?? {});
399371
+ if (p2.contentType) headers.set("content-type", p2.contentType);
399372
+ let res;
399373
+ try {
399374
+ res = await fetch(p2.url, { method: p2.method ?? "PUT", body: p2.body, headers, credentials: "omit", mode: "cors" });
399375
+ } catch (err2) {
399376
+ throw new PluginApiError(`Could not reach ${new URL(p2.url).origin}: ${err2 instanceof Error ? err2.message : String(err2)}`, "unsupported");
399377
+ }
399378
+ const text = await res.text();
399379
+ const data = {
399380
+ ok: res.ok,
399381
+ status: res.status,
399382
+ headers: Object.fromEntries(res.headers.entries()),
399383
+ body: text.length > MAX_UPLOAD_REPLY_CHARS ? text.slice(0, MAX_UPLOAD_REPLY_CHARS) : text
399384
+ };
399385
+ return { summary: `Uploaded ${size6} bytes (${res.status})`, data };
399386
+ }
399387
+ }),
399343
399388
  defineCommand({
399344
399389
  id: pluginCommandId("showUI"),
399345
399390
  title: "Show plugin UI",
@@ -401239,6 +401284,7 @@ function placeDesign(doc2, built, source3, size6, name2, at4) {
401239
401284
  var DESIGN_NAMESPACES, DERIVED2, templateOfBuild;
401240
401285
  var init_build3 = __esm({
401241
401286
  "lib/agent/design-script/build.ts"() {
401287
+ "use strict";
401242
401288
  init_hash();
401243
401289
  init_scene_graph();
401244
401290
  init_libraries();
@@ -401268,6 +401314,7 @@ function designFrameOf(doc2, id3) {
401268
401314
  }
401269
401315
  var init_locate = __esm({
401270
401316
  "lib/agent/design-script/locate.ts"() {
401317
+ "use strict";
401271
401318
  }
401272
401319
  });
401273
401320
 
@@ -406449,7 +406496,6 @@ function registerBuiltinCommands() {
406449
406496
  var builtinCommands, uiOnlyCommands;
406450
406497
  var init_builtin4 = __esm({
406451
406498
  "lib/commands/builtin.ts"() {
406452
- "use strict";
406453
406499
  init_registry();
406454
406500
  init_node();
406455
406501
  init_node();
@@ -414054,7 +414100,7 @@ init_resources();
414054
414100
  init_desktop();
414055
414101
  init_hypery();
414056
414102
  import { createInterface } from "node:readline";
414057
- var VERSION2 = "0.52.0";
414103
+ var VERSION2 = "0.53.0";
414058
414104
  var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
414059
414105
 
414060
414106
  Files (headless, on .popcraft files):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popcraft/cli",
3
- "version": "0.52.0",
3
+ "version": "0.53.0",
4
4
  "description": "The PopCraft command line: edit .popcraft files headlessly, call the REST API, publish to the marketplace and manage the desktop app's local plugins, themes, fonts, skills and agents.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://popcraft.app/docs/api/cli",
@@ -34,7 +34,7 @@
34
34
  "esbuild": "0.28.2"
35
35
  },
36
36
  "dependencies": {
37
- "@popcraft/kit": "0.52.0"
37
+ "@popcraft/kit": "0.53.0"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "node build.mjs",