@popcraft/cli 0.58.0 → 0.59.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.
- package/dist/popcraft.mjs +105 -33
- package/package.json +2 -2
package/dist/popcraft.mjs
CHANGED
|
@@ -1198,7 +1198,7 @@ function operations(spec = openapi) {
|
|
|
1198
1198
|
}
|
|
1199
1199
|
async function call(target2, method, path, opts = {}) {
|
|
1200
1200
|
const qs = new URLSearchParams(opts.query ?? {}).toString();
|
|
1201
|
-
const headers = { "user-agent": `popcraft-cli/${"0.
|
|
1201
|
+
const headers = { "user-agent": `popcraft-cli/${"0.59.0"}`, ...opts.headers };
|
|
1202
1202
|
if (target2.token) headers.authorization = `Bearer ${target2.token}`;
|
|
1203
1203
|
if (opts.contentType) headers["content-type"] = opts.contentType;
|
|
1204
1204
|
try {
|
|
@@ -29244,7 +29244,6 @@ function selectionWorldBounds(nodes, ids2, scrollState) {
|
|
|
29244
29244
|
}
|
|
29245
29245
|
var init_selection_bounds = __esm({
|
|
29246
29246
|
"lib/editor/selection-bounds.ts"() {
|
|
29247
|
-
"use strict";
|
|
29248
29247
|
init_scene_graph();
|
|
29249
29248
|
init_transform();
|
|
29250
29249
|
}
|
|
@@ -252585,6 +252584,7 @@ function hasMessage(key5) {
|
|
|
252585
252584
|
var current3, loading2, listeners2, formats, asts;
|
|
252586
252585
|
var init_runtime = __esm({
|
|
252587
252586
|
"lib/i18n/runtime.ts"() {
|
|
252587
|
+
"use strict";
|
|
252588
252588
|
init_intl_messageformat();
|
|
252589
252589
|
init_icu_messageformat_parser();
|
|
252590
252590
|
init_catalogs();
|
|
@@ -254384,6 +254384,7 @@ function repairDocumentPaints(doc2) {
|
|
|
254384
254384
|
var broken;
|
|
254385
254385
|
var init_paint_repair = __esm({
|
|
254386
254386
|
"lib/document/paint-repair.ts"() {
|
|
254387
|
+
"use strict";
|
|
254387
254388
|
init_shader_graph();
|
|
254388
254389
|
broken = (p2) => {
|
|
254389
254390
|
if (!p2 || typeof p2 !== "object") return false;
|
|
@@ -260666,7 +260667,6 @@ function repairFx(raw) {
|
|
|
260666
260667
|
var isObj5, finite6, optFinite, isVec2, TIMELINE_COLOR_IDS, TIMELINE_COLORS, UNITS, ORDERS, PROP_KEYS, ANIMATOR_ID, MOTION_TYPES, TRANSITIONS, isFraction, MEDIA_HASH, LAYER_KINDS, ADJUSTMENT_TYPES, OPACITY_PROPERTY, CAPTION_PRESET_NAMES, inRange;
|
|
260667
260668
|
var init_invariants = __esm({
|
|
260668
260669
|
"lib/motion/invariants.ts"() {
|
|
260669
|
-
"use strict";
|
|
260670
260670
|
init_adjustments();
|
|
260671
260671
|
init_captions();
|
|
260672
260672
|
init_lut();
|
|
@@ -260773,7 +260773,6 @@ function resyncText(doc2, ids2) {
|
|
|
260773
260773
|
var isVirtualId;
|
|
260774
260774
|
var init_invariants2 = __esm({
|
|
260775
260775
|
"lib/document/invariants.ts"() {
|
|
260776
|
-
"use strict";
|
|
260777
260776
|
init_auto_layout();
|
|
260778
260777
|
init_scene_graph();
|
|
260779
260778
|
init_text_bounds();
|
|
@@ -261805,7 +261804,6 @@ function beforeWrite() {
|
|
|
261805
261804
|
var leave;
|
|
261806
261805
|
var init_read_only = __esm({
|
|
261807
261806
|
"lib/editor/modes/read-only.ts"() {
|
|
261808
|
-
"use strict";
|
|
261809
261807
|
leave = null;
|
|
261810
261808
|
}
|
|
261811
261809
|
});
|
|
@@ -263477,7 +263475,6 @@ function resizeWindow(doc2, target2, rect) {
|
|
|
263477
263475
|
}
|
|
263478
263476
|
var init_crop = __esm({
|
|
263479
263477
|
"lib/editor/crop.ts"() {
|
|
263480
|
-
"use strict";
|
|
263481
263478
|
init_dist_node();
|
|
263482
263479
|
init_scene_graph();
|
|
263483
263480
|
init_photo_frames();
|
|
@@ -267059,6 +267056,7 @@ function mergeFonts(fonts, incoming) {
|
|
|
267059
267056
|
var fontWeightOf, fontStyleOf, sameSlot, hashOf, documentFontHashes;
|
|
267060
267057
|
var init_document_fonts = __esm({
|
|
267061
267058
|
"lib/fonts/document-fonts.ts"() {
|
|
267059
|
+
"use strict";
|
|
267062
267060
|
init_media_store();
|
|
267063
267061
|
init_media_hash();
|
|
267064
267062
|
fontWeightOf = (f2) => f2.weight ?? 400;
|
|
@@ -267471,7 +267469,6 @@ function followPeers(peers) {
|
|
|
267471
267469
|
var PALETTE, usePresence, awareness, CURSOR_SEND_MS, VIEWPORT_SEND_MS, cursorTimer, pendingCursor, sentCursor, EMOTE_MS, lastFollowCamera;
|
|
267472
267470
|
var init_presence = __esm({
|
|
267473
267471
|
"lib/collab/presence.ts"() {
|
|
267474
|
-
"use strict";
|
|
267475
267472
|
init_esm();
|
|
267476
267473
|
init_editor_store();
|
|
267477
267474
|
init_status_announcements();
|
|
@@ -273394,6 +273391,16 @@ var init_plugin_store = __esm({
|
|
|
273394
273391
|
toasts: [],
|
|
273395
273392
|
permissionPrompt: null,
|
|
273396
273393
|
managerOpen: false,
|
|
273394
|
+
panelIcons: {},
|
|
273395
|
+
setPanelIcon: (tab, icon) => set4((st3) => {
|
|
273396
|
+
const next2 = { ...st3.panelIcons };
|
|
273397
|
+
if (icon) next2[tab] = icon;
|
|
273398
|
+
else delete next2[tab];
|
|
273399
|
+
return { panelIcons: next2 };
|
|
273400
|
+
}),
|
|
273401
|
+
clearPanelIcons: (pluginId) => set4((st3) => ({
|
|
273402
|
+
panelIcons: Object.fromEntries(Object.entries(st3.panelIcons).filter(([, v]) => v.pluginId !== pluginId))
|
|
273403
|
+
})),
|
|
273397
273404
|
setInstalled: (installed4) => set4({ installed: installed4 }),
|
|
273398
273405
|
setManagerOpen: (managerOpen) => set4({ managerOpen }),
|
|
273399
273406
|
upsertSession: (s) => set4((st3) => ({ sessions: [...st3.sessions.filter((x2) => x2.sessionId !== s.sessionId), s] })),
|
|
@@ -273791,7 +273798,6 @@ function planEntryAction({ home }) {
|
|
|
273791
273798
|
var STORAGE_KEY2, useHyperyTeam, TEAM_PROMPT_ENABLED, TEAM_PROMPTED_KEY, PROMPTED_KEY, useTeamPrompt, started;
|
|
273792
273799
|
var init_team = __esm({
|
|
273793
273800
|
"lib/client/cloud/team.ts"() {
|
|
273794
|
-
"use strict";
|
|
273795
273801
|
init_esm();
|
|
273796
273802
|
init_api4();
|
|
273797
273803
|
init_session();
|
|
@@ -317458,7 +317464,6 @@ function decodeSource(key5, label3) {
|
|
|
317458
317464
|
var DECODE_CACHE_BYTES, cache7, pending4, held, sizeOf, lengths, decodedLengths, DECODE_TIMEOUT_MS, decodedAudio, decodedSource, pcmOf;
|
|
317459
317465
|
var init_audio_decode = __esm({
|
|
317460
317466
|
"lib/motion/audio-decode.ts"() {
|
|
317461
|
-
"use strict";
|
|
317462
317467
|
init_media_store();
|
|
317463
317468
|
init_audio_plan();
|
|
317464
317469
|
init_time_stretch();
|
|
@@ -322651,6 +322656,7 @@ function startCloudSync() {
|
|
|
322651
322656
|
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, SEEN_KEY, started2;
|
|
322652
322657
|
var init_sync2 = __esm({
|
|
322653
322658
|
"lib/client/cloud/sync.ts"() {
|
|
322659
|
+
"use strict";
|
|
322654
322660
|
init_kinds();
|
|
322655
322661
|
init_paint_repair();
|
|
322656
322662
|
init_migrate();
|
|
@@ -323261,6 +323267,7 @@ function creditLine(c2) {
|
|
|
323261
323267
|
var MAX_PHOTO_PAGE, MAX_PHOTO_QUERY, UUID, isPhotoId, photoImagePath;
|
|
323262
323268
|
var init_stock = __esm({
|
|
323263
323269
|
"lib/photos/stock.ts"() {
|
|
323270
|
+
"use strict";
|
|
323264
323271
|
MAX_PHOTO_PAGE = 12;
|
|
323265
323272
|
MAX_PHOTO_QUERY = 200;
|
|
323266
323273
|
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -339075,7 +339082,7 @@ var init_package = __esm({
|
|
|
339075
339082
|
"packages/runtime/package.json"() {
|
|
339076
339083
|
package_default = {
|
|
339077
339084
|
name: "@popcraft/runtime",
|
|
339078
|
-
version: "0.
|
|
339085
|
+
version: "0.59.0",
|
|
339079
339086
|
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.",
|
|
339080
339087
|
license: "MIT",
|
|
339081
339088
|
homepage: "https://popcraft.app/docs/exporting/nextjs",
|
|
@@ -363741,6 +363748,7 @@ function exportsOf(source3) {
|
|
|
363741
363748
|
var CODE_LIMITS, packageOf;
|
|
363742
363749
|
var init_source2 = __esm({
|
|
363743
363750
|
"lib/code/source.ts"() {
|
|
363751
|
+
"use strict";
|
|
363744
363752
|
CODE_LIMITS = { modules: 100, sourceLength: 2e5, packages: 12 };
|
|
363745
363753
|
packageOf = (spec) => spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).join("/");
|
|
363746
363754
|
}
|
|
@@ -363783,6 +363791,7 @@ function compileModule(module2) {
|
|
|
363783
363791
|
var import_sucrase, BUILT_IN, memo7;
|
|
363784
363792
|
var init_compile2 = __esm({
|
|
363785
363793
|
"lib/code/compile.ts"() {
|
|
363794
|
+
"use strict";
|
|
363786
363795
|
import_sucrase = __toESM(require_dist2());
|
|
363787
363796
|
init_source2();
|
|
363788
363797
|
init_source2();
|
|
@@ -369944,6 +369953,7 @@ var init_sequence2 = __esm({
|
|
|
369944
369953
|
length: external_exports.number().min(500).max(6e5).optional().describe("ms, default 3000.")
|
|
369945
369954
|
}),
|
|
369946
369955
|
expose: {
|
|
369956
|
+
plugin: { method: "addTitle" },
|
|
369947
369957
|
ui: { label: "Add a title", keywords: ["title", "text", "lower third", "subtitle", "caption", "name"], enabled: (c2) => inEdit(c2) },
|
|
369948
369958
|
agent: { name: "add_title", description: "Put a title on a sequence: a new transparent frame (the sequence's size) with the text in a look \u2014 a big centred title, a lower third or a subtitle line \u2014 placed as a clip on a track above V1. Restyle or animate it in its frame like any text; change its words with set_text." }
|
|
369949
369959
|
},
|
|
@@ -370004,6 +370014,7 @@ var init_sequence2 = __esm({
|
|
|
370004
370014
|
clip: external_exports.string().optional().describe("The multicam clip (default: the picked one).")
|
|
370005
370015
|
}),
|
|
370006
370016
|
expose: {
|
|
370017
|
+
plugin: { method: "syncAngles" },
|
|
370007
370018
|
ui: { label: "Sync angles by sound", keywords: ["multicam", "sync", "align", "audio", "clap", "angles"], enabled: (c2) => withPicked(c2) },
|
|
370008
370019
|
agent: { name: "sync_angles", description: "Line up a multicam clip's camera angles by their sound: each angle's audio is matched against the first one's (a clap, speech or music works) and moved so the same moment plays together. Runs in the editor (it decodes the sound)." }
|
|
370009
370020
|
},
|
|
@@ -370077,6 +370088,7 @@ var init_sequence2 = __esm({
|
|
|
370077
370088
|
multicam: external_exports.boolean().optional().describe("A multicam clip: each track of the picked clips is a camera angle (in sync as placed), and the clip shows one at a time \u2014 the first to start with; cut between them with edit_sequence `angle`.")
|
|
370078
370089
|
}),
|
|
370079
370090
|
expose: {
|
|
370091
|
+
plugin: { method: "nestClips" },
|
|
370080
370092
|
ui: { label: "Nest clips", keywords: ["nest", "precompose", "group", "sequence", "compound clip"], enabled: (c2) => withPicked(c2) },
|
|
370081
370093
|
agent: { name: "nest_clips", description: "Nest clips on V2 and up into a new sequence (a precomp / compound clip), replaced by one clip of it on the lowest of their tracks. Its picture and sound play as before; open the new sequence to edit inside it." }
|
|
370082
370094
|
},
|
|
@@ -370155,6 +370167,7 @@ var init_sequence2 = __esm({
|
|
|
370155
370167
|
to: external_exports.number().min(-24).max(0).optional().describe("Peak level, dBFS (default \u22121).")
|
|
370156
370168
|
}),
|
|
370157
370169
|
expose: {
|
|
370170
|
+
plugin: { method: "normalizeAudio" },
|
|
370158
370171
|
ui: { label: "Normalize audio", keywords: ["normalize", "loudness", "level", "peak", "volume", "gain"], enabled: (c2) => inEdit(c2) },
|
|
370159
370172
|
agent: { name: "normalize_audio", description: "Bring audio clips to one peak level (default \u22121 dBFS): each clip's level is scaled so its loudest sample reaches it. Runs in the editor (it reads the sound files)." }
|
|
370160
370173
|
},
|
|
@@ -380983,16 +380996,16 @@ var init_api5 = __esm({
|
|
|
380983
380996
|
}
|
|
380984
380997
|
});
|
|
380985
380998
|
|
|
380986
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
380999
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/generated/runtime.js
|
|
380987
381000
|
var MAIN_RUNTIME, UI_RUNTIME;
|
|
380988
381001
|
var init_runtime6 = __esm({
|
|
380989
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
380990
|
-
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 /**\n * Sequences (Edit mode): a composition as a multi-track timeline \u2014 V1 main scenes, V2\u2026 layered scenes / videos / stills,\n * A1\u2026 audio. `editSequence({ id, op })` cuts, trims, slips, rolls, slides, places, stretches, blends, mixes and ducks\n * (docs/plugins/methods.md); `getSequence({ id? })` reads it by track.\n */\n editSequence: (opts) => rpc.call("editSequence", opts || {}),\n getSequence: (opts) => rpc.call("getSequence", 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})();';
|
|
381002
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
|
|
381003
|
+
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 /**\n * Sequences (Edit mode): a composition as a multi-track timeline \u2014 V1 main scenes, V2\u2026 layered scenes / videos / stills,\n * A1\u2026 audio. `editSequence({ id, op })` cuts, trims, slips, rolls, slides, places, stretches, blends, mixes and ducks\n * (docs/plugins/methods.md); `getSequence({ id? })` reads it by track.\n */\n editSequence: (opts) => rpc.call("editSequence", opts || {}),\n getSequence: (opts) => rpc.call("getSequence", opts || {}),\n /** A title, lower third or subtitle as a clip on a track above V1 (`{ id?, text, style?, track?, start?, length? }`). */\n addTitle: (opts) => rpc.call("addTitle", opts || {}),\n /** Clips on V2 and up nested into a new sequence; `multicam: true` makes them camera angles (`{ id?, clips, multicam? }`). */\n nestClips: (opts) => rpc.call("nestClips", opts || {}),\n /** A multicam clip\'s angles lined up by their sound (`{ id?, clip }`). */\n syncAngles: (opts) => rpc.call("syncAngles", opts || {}),\n /** Audio clips brought to one peak level (`{ id?, clips?, to? }`, dBFS, default \u22121). */\n normalizeAudio: (opts) => rpc.call("normalizeAudio", 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 /**\n * Change the rail icon of one of this plugin\'s panels while it runs, e.g. to show a connection\'s state. Reset when\n * the plugin stops.\n */\n setPanelIcon: (options) => rpc.call("setPanelIcon", options || {}),\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})();';
|
|
380991
381004
|
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})();';
|
|
380992
381005
|
}
|
|
380993
381006
|
});
|
|
380994
381007
|
|
|
380995
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381008
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/host.js
|
|
380996
381009
|
function csp(network) {
|
|
380997
381010
|
const connect2 = network ? "connect-src * data: blob:;" : "connect-src 'none';";
|
|
380998
381011
|
const img = network ? "img-src * data: blob:;" : "img-src data: blob:;";
|
|
@@ -381020,40 +381033,40 @@ function buildUIDocument(uiHtml, network) {
|
|
|
381020
381033
|
}
|
|
381021
381034
|
var escapeScript;
|
|
381022
381035
|
var init_host2 = __esm({
|
|
381023
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381036
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/host.js"() {
|
|
381024
381037
|
init_runtime6();
|
|
381025
381038
|
escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
|
|
381026
381039
|
}
|
|
381027
381040
|
});
|
|
381028
381041
|
|
|
381029
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381042
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/rpc.js
|
|
381030
381043
|
var init_rpc = __esm({
|
|
381031
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381044
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
|
|
381032
381045
|
}
|
|
381033
381046
|
});
|
|
381034
381047
|
|
|
381035
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381048
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/main.js
|
|
381036
381049
|
var init_main = __esm({
|
|
381037
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381050
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
|
|
381038
381051
|
init_rpc();
|
|
381039
381052
|
}
|
|
381040
381053
|
});
|
|
381041
381054
|
|
|
381042
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381055
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/types.js
|
|
381043
381056
|
var init_types10 = __esm({
|
|
381044
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381057
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/types.js"() {
|
|
381045
381058
|
}
|
|
381046
381059
|
});
|
|
381047
381060
|
|
|
381048
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381061
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/widget.js
|
|
381049
381062
|
var init_widget = __esm({
|
|
381050
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381063
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/widget.js"() {
|
|
381051
381064
|
}
|
|
381052
381065
|
});
|
|
381053
381066
|
|
|
381054
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381067
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/index.js
|
|
381055
381068
|
var init_dist = __esm({
|
|
381056
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381069
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/index.js"() {
|
|
381057
381070
|
init_host2();
|
|
381058
381071
|
init_main();
|
|
381059
381072
|
init_runtime6();
|
|
@@ -381206,6 +381219,7 @@ function validateManifest(raw) {
|
|
|
381206
381219
|
if (typeof pp.title !== "string" || !pp.title.trim()) throw new PluginPackageError(`${at5}.title must be a non-empty string`);
|
|
381207
381220
|
if (pp.side !== void 0 && pp.side !== "left" && pp.side !== "right") throw new PluginPackageError(`${at5}.side must be "left" or "right"`);
|
|
381208
381221
|
if (pp.command !== void 0 && typeof pp.command !== "string") throw new PluginPackageError(`${at5}.command must be a string`);
|
|
381222
|
+
if (pp.autostart !== void 0 && typeof pp.autostart !== "boolean") throw new PluginPackageError(`${at5}.autostart must be true or false`);
|
|
381209
381223
|
if (pp.icon !== void 0 && (typeof pp.icon !== "string" || !(DATA_ICON_RE.test(pp.icon) || ICON_PATH_RE.test(pp.icon)))) {
|
|
381210
381224
|
throw new PluginPackageError(`${at5}.icon must be a data:image URL or the path of an .svg, .png or .webp file in the package`);
|
|
381211
381225
|
}
|
|
@@ -381214,9 +381228,11 @@ function validateManifest(raw) {
|
|
|
381214
381228
|
title: pp.title.trim(),
|
|
381215
381229
|
...pp.icon !== void 0 && { icon: pp.icon },
|
|
381216
381230
|
...pp.side !== void 0 && { side: pp.side },
|
|
381217
|
-
...pp.command !== void 0 && { command: pp.command }
|
|
381231
|
+
...pp.command !== void 0 && { command: pp.command },
|
|
381232
|
+
...pp.autostart === true && { autostart: true }
|
|
381218
381233
|
};
|
|
381219
381234
|
});
|
|
381235
|
+
if (panels.filter((p2) => p2.autostart).length > 1) throw new PluginPackageError("manifest.contributes.panels: at most one panel may autostart");
|
|
381220
381236
|
contributes = { ...contributes, panels };
|
|
381221
381237
|
}
|
|
381222
381238
|
if (c2.importers !== void 0) {
|
|
@@ -411139,6 +411155,7 @@ var init_plugin_import = __esm({
|
|
|
411139
411155
|
var host_exports2 = {};
|
|
411140
411156
|
__export(host_exports2, {
|
|
411141
411157
|
attachPluginUI: () => attachPluginUI,
|
|
411158
|
+
autostartPluginPanels: () => autostartPluginPanels,
|
|
411142
411159
|
closeSession: () => closeSession,
|
|
411143
411160
|
dispatchWidgetClick: () => dispatchWidgetClick,
|
|
411144
411161
|
exportFileName: () => exportFileName2,
|
|
@@ -411274,6 +411291,13 @@ async function runPlugin(pluginId, commandId, opts = {}) {
|
|
|
411274
411291
|
}
|
|
411275
411292
|
}),
|
|
411276
411293
|
hideUI: () => usePluginStore.getState().patchSession(sessionId, { ui: null }),
|
|
411294
|
+
setPanelIcon: (o) => {
|
|
411295
|
+
const panels = plugin.manifest.contributes?.panels ?? [];
|
|
411296
|
+
const panel = o.panel ? panels.find((x2) => x2.id === o.panel) : panels[0];
|
|
411297
|
+
if (!panel) throw new Error(o.panel ? `No panel "${o.panel}" in manifest.contributes.panels` : "This plugin has no panels in manifest.contributes.panels");
|
|
411298
|
+
const tab = pluginPanelTab(pluginId, panel.id);
|
|
411299
|
+
usePluginStore.getState().setPanelIcon(tab, o.icon ? { pluginId, icon: o.icon, color: !!o.color } : null);
|
|
411300
|
+
},
|
|
411277
411301
|
close: (message) => {
|
|
411278
411302
|
const sel = message ? [...useEditorStore.getState().selection] : [];
|
|
411279
411303
|
closeSession(sessionId);
|
|
@@ -411462,6 +411486,15 @@ function closeSession(sessionId) {
|
|
|
411462
411486
|
s.uiPort?.close();
|
|
411463
411487
|
s.iframe.remove();
|
|
411464
411488
|
usePluginStore.getState().removeSession(sessionId);
|
|
411489
|
+
usePluginStore.getState().clearPanelIcons(s.plugin.manifest.id);
|
|
411490
|
+
}
|
|
411491
|
+
function autostartPluginPanels(installed4) {
|
|
411492
|
+
for (const p2 of installed4) {
|
|
411493
|
+
if (!p2.enabled || p2.granted === null || !p2.manifest.main) continue;
|
|
411494
|
+
const panel = p2.manifest.contributes?.panels?.find((x2) => x2.autostart);
|
|
411495
|
+
if (!panel || runningSessionFor(p2.manifest.id)) continue;
|
|
411496
|
+
void runPlugin(p2.manifest.id, panel.command ?? panel.id, { dock: pluginPanelTab(p2.manifest.id, panel.id) });
|
|
411497
|
+
}
|
|
411465
411498
|
}
|
|
411466
411499
|
var running3;
|
|
411467
411500
|
var init_host3 = __esm({
|
|
@@ -411593,7 +411626,7 @@ function pluginContext(env) {
|
|
|
411593
411626
|
return out;
|
|
411594
411627
|
},
|
|
411595
411628
|
storage: { get: env.effects.storageGet, set: env.effects.storageSet },
|
|
411596
|
-
panel: { showUI: env.effects.showUI, hideUI: env.effects.hideUI, close: env.effects.close }
|
|
411629
|
+
panel: { showUI: env.effects.showUI, hideUI: env.effects.hideUI, close: env.effects.close, setPanelIcon: env.effects.setPanelIcon }
|
|
411597
411630
|
};
|
|
411598
411631
|
const st3 = () => env.getState();
|
|
411599
411632
|
return {
|
|
@@ -411641,7 +411674,7 @@ function dispatchPluginCall(env, method, params2 = {}) {
|
|
|
411641
411674
|
}
|
|
411642
411675
|
});
|
|
411643
411676
|
}
|
|
411644
|
-
var PLUGIN_CAPABILITIES, pluginCommandId, empty, MAX_UPLOAD_BYTES, MAX_UPLOAD_REPLY_CHARS, commands, pluginRun, registered;
|
|
411677
|
+
var PLUGIN_CAPABILITIES, pluginCommandId, empty, MAX_PANEL_ICON_CHARS, MAX_UPLOAD_BYTES, MAX_UPLOAD_REPLY_CHARS, commands, pluginRun, registered;
|
|
411645
411678
|
var init_plugin = __esm({
|
|
411646
411679
|
"lib/commands/plugin.ts"() {
|
|
411647
411680
|
init_zod();
|
|
@@ -411657,6 +411690,7 @@ var init_plugin = __esm({
|
|
|
411657
411690
|
PLUGIN_CAPABILITIES = ["render", "storage", "panel"];
|
|
411658
411691
|
pluginCommandId = (method) => `plugin.${method}`;
|
|
411659
411692
|
empty = external_exports.object({});
|
|
411693
|
+
MAX_PANEL_ICON_CHARS = 64 * 1024;
|
|
411660
411694
|
MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
|
|
411661
411695
|
MAX_UPLOAD_REPLY_CHARS = 1024 * 1024;
|
|
411662
411696
|
commands = [
|
|
@@ -411801,6 +411835,33 @@ var init_plugin = __esm({
|
|
|
411801
411835
|
return { summary: "UI shown" };
|
|
411802
411836
|
}
|
|
411803
411837
|
}),
|
|
411838
|
+
defineCommand({
|
|
411839
|
+
id: pluginCommandId("setPanelIcon"),
|
|
411840
|
+
title: "Set panel icon",
|
|
411841
|
+
domain: "ui",
|
|
411842
|
+
params: external_exports.object({
|
|
411843
|
+
panel: external_exports.string().optional(),
|
|
411844
|
+
icon: external_exports.string().nullable().optional(),
|
|
411845
|
+
color: external_exports.boolean().optional()
|
|
411846
|
+
}),
|
|
411847
|
+
effect: "none",
|
|
411848
|
+
permission: null,
|
|
411849
|
+
needs: ["panel"],
|
|
411850
|
+
expose: { plugin: { method: "setPanelIcon" } },
|
|
411851
|
+
run: (p2, ctx2) => {
|
|
411852
|
+
const icon = p2.icon ?? null;
|
|
411853
|
+
if (icon !== null && !/^data:image\/(svg\+xml|png|webp)[;,]/.test(icon)) {
|
|
411854
|
+
throw new PluginApiError("icon must be a data:image/svg+xml, png or webp URL", "invalid_params");
|
|
411855
|
+
}
|
|
411856
|
+
if (icon !== null && icon.length > MAX_PANEL_ICON_CHARS) {
|
|
411857
|
+
throw new PluginApiError(`icon is limited to ${MAX_PANEL_ICON_CHARS} characters`, "invalid_params");
|
|
411858
|
+
}
|
|
411859
|
+
const set4 = ctx2.use("panel").setPanelIcon;
|
|
411860
|
+
if (!set4) throw new PluginApiError("Panel icons are not available here");
|
|
411861
|
+
set4({ panel: p2.panel, icon, color: p2.color });
|
|
411862
|
+
return { summary: icon ? "Panel icon set" : "Panel icon reset" };
|
|
411863
|
+
}
|
|
411864
|
+
}),
|
|
411804
411865
|
defineCommand({
|
|
411805
411866
|
id: pluginCommandId("hideUI"),
|
|
411806
411867
|
title: "Hide plugin UI",
|
|
@@ -415148,8 +415209,8 @@ function themeCommand(themes) {
|
|
|
415148
415209
|
});
|
|
415149
415210
|
}
|
|
415150
415211
|
function pluginCommand(plugins) {
|
|
415151
|
-
const variants = plugins.filter((p2) => p2.enabled
|
|
415152
|
-
const commands2 = p2.manifest.commands?.length ? p2.manifest.commands : [{ id: "run", label: "Run" }];
|
|
415212
|
+
const variants = plugins.filter((p2) => p2.enabled).flatMap((p2) => {
|
|
415213
|
+
const commands2 = p2.manifest.commands?.length ? p2.manifest.commands : p2.manifest.contributes?.panels?.length ? [] : [{ id: "run", label: "Run" }];
|
|
415153
415214
|
return commands2.map((c2) => ({ id: `${p2.manifest.id}:${c2.id}`, label: `${p2.manifest.name}: ${c2.label}`, params: { pluginId: p2.manifest.id, commandId: c2.id } }));
|
|
415154
415215
|
});
|
|
415155
415216
|
return defineCommand({
|
|
@@ -424949,9 +425010,14 @@ async function launch2(headful) {
|
|
|
424949
425010
|
const profile = await mkdtemp(join5(tmpdir(), "popcraft-cli-"));
|
|
424950
425011
|
const browser = await puppeteer.launch({
|
|
424951
425012
|
headless: !headful,
|
|
425013
|
+
// A long export on a software renderer outlasts puppeteer's 180 s default for one page.evaluate.
|
|
425014
|
+
protocolTimeout: 0,
|
|
424952
425015
|
userDataDir: profile,
|
|
424953
425016
|
// The same switches as the docs screenshots: WebGPU on a software adapter, so a machine with no GPU still renders.
|
|
424954
|
-
|
|
425017
|
+
// Linux with no GPU (containers, CI, cloud workers): a WebGPU canvas crashes the GPU process on its first present
|
|
425018
|
+
// ("Could not find SharedImageBackingFactory … WebgpuSwapChainTexture", then "A valid external Instance reference
|
|
425019
|
+
// no longer exists") unless the compositor runs ANGLE on Vulkan, which can share the swap-chain image.
|
|
425020
|
+
args: ["--enable-unsafe-webgpu", ...process.platform === "linux" ? ["--enable-features=Vulkan,DefaultANGLEVulkan,VulkanFromANGLE", "--use-angle=vulkan"] : ["--enable-features=Vulkan"], "--enable-unsafe-swiftshader", "--hide-scrollbars", "--mute-audio", "--autoplay-policy=no-user-gesture-required", ...process.env.CI ? ["--no-sandbox"] : []]
|
|
424955
425021
|
});
|
|
424956
425022
|
return { browser, close: async () => {
|
|
424957
425023
|
await browser.close();
|
|
@@ -425775,7 +425841,10 @@ async function openEditor(base, o = {}) {
|
|
|
425775
425841
|
userDataDir: profile,
|
|
425776
425842
|
// A film export is one evaluate that runs for minutes (the hero, the trailer): puppeteer's 3-minute default cut it.
|
|
425777
425843
|
protocolTimeout: 15 * 6e4,
|
|
425778
|
-
|
|
425844
|
+
// Linux with no GPU (containers, CI, cloud workers): a WebGPU canvas crashes the GPU process on its first present
|
|
425845
|
+
// ("Could not find SharedImageBackingFactory … WebgpuSwapChainTexture", then "A valid external Instance reference
|
|
425846
|
+
// no longer exists") unless the compositor runs ANGLE on Vulkan, which can share the swap-chain image.
|
|
425847
|
+
args: ["--enable-unsafe-webgpu", ...process.platform === "linux" ? ["--enable-features=Vulkan,DefaultANGLEVulkan,VulkanFromANGLE", "--use-angle=vulkan"] : ["--enable-features=Vulkan"], "--enable-unsafe-swiftshader", "--hide-scrollbars", ...process.env.CI ? ["--no-sandbox"] : []]
|
|
425779
425848
|
});
|
|
425780
425849
|
let page;
|
|
425781
425850
|
const newTab = async () => {
|
|
@@ -426384,6 +426453,9 @@ async function runPluginHeadless(plugin, opts) {
|
|
|
426384
426453
|
showUI: () => fail3(app("opens a panel")),
|
|
426385
426454
|
hideUI: () => {
|
|
426386
426455
|
},
|
|
426456
|
+
// No rails headless: a panel icon has nowhere to show.
|
|
426457
|
+
setPanelIcon: () => {
|
|
426458
|
+
},
|
|
426387
426459
|
close: (message) => finish3({ closed: true, message, errors: errors2 }),
|
|
426388
426460
|
storageGet: async (key5) => storage[key5],
|
|
426389
426461
|
storageSet: async (key5, value3) => {
|
|
@@ -426573,7 +426645,7 @@ init_resources();
|
|
|
426573
426645
|
init_desktop();
|
|
426574
426646
|
init_hypery();
|
|
426575
426647
|
import { createInterface } from "node:readline";
|
|
426576
|
-
var VERSION2 = "0.
|
|
426648
|
+
var VERSION2 = "0.59.0";
|
|
426577
426649
|
var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
|
|
426578
426650
|
|
|
426579
426651
|
Files (headless, on .popcraft files):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@popcraft/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.59.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.
|
|
37
|
+
"@popcraft/kit": "0.59.0"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node build.mjs",
|