@popcraft/cli 0.58.1 → 0.59.1
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 +116 -53
- 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.1"}`, ...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 {
|
|
@@ -29290,6 +29290,30 @@ var init_cell_text = __esm({
|
|
|
29290
29290
|
}
|
|
29291
29291
|
});
|
|
29292
29292
|
|
|
29293
|
+
// lib/engine/canvas-dpr.ts
|
|
29294
|
+
function isAppleMobile() {
|
|
29295
|
+
if (typeof navigator === "undefined") return false;
|
|
29296
|
+
return /iPad|iPhone|iPod/.test(navigator.userAgent) || /Mac/.test(navigator.platform) && navigator.maxTouchPoints > 1;
|
|
29297
|
+
}
|
|
29298
|
+
function canvasDpr() {
|
|
29299
|
+
if (typeof window === "undefined") return 1;
|
|
29300
|
+
const dpr = window.devicePixelRatio || 1;
|
|
29301
|
+
return dpr > 1 ? Math.max(1, dpr * renderScale) : dpr;
|
|
29302
|
+
}
|
|
29303
|
+
var renderScale;
|
|
29304
|
+
var init_canvas_dpr = __esm({
|
|
29305
|
+
"lib/engine/canvas-dpr.ts"() {
|
|
29306
|
+
renderScale = 1;
|
|
29307
|
+
}
|
|
29308
|
+
});
|
|
29309
|
+
|
|
29310
|
+
// lib/editor/handle-reach.ts
|
|
29311
|
+
var init_handle_reach = __esm({
|
|
29312
|
+
"lib/editor/handle-reach.ts"() {
|
|
29313
|
+
init_canvas_dpr();
|
|
29314
|
+
}
|
|
29315
|
+
});
|
|
29316
|
+
|
|
29293
29317
|
// lib/document/scale-geometry.ts
|
|
29294
29318
|
function scaleVectorPaths(paths, sx, sy, rebuild) {
|
|
29295
29319
|
if (!paths?.length || sx === 1 && sy === 1) return paths;
|
|
@@ -29379,23 +29403,6 @@ var init_resize_children = __esm({
|
|
|
29379
29403
|
}
|
|
29380
29404
|
});
|
|
29381
29405
|
|
|
29382
|
-
// lib/engine/canvas-dpr.ts
|
|
29383
|
-
function isAppleMobile() {
|
|
29384
|
-
if (typeof navigator === "undefined") return false;
|
|
29385
|
-
return /iPad|iPhone|iPod/.test(navigator.userAgent) || /Mac/.test(navigator.platform) && navigator.maxTouchPoints > 1;
|
|
29386
|
-
}
|
|
29387
|
-
function canvasDpr() {
|
|
29388
|
-
if (typeof window === "undefined") return 1;
|
|
29389
|
-
const dpr = window.devicePixelRatio || 1;
|
|
29390
|
-
return dpr > 1 ? Math.max(1, dpr * renderScale) : dpr;
|
|
29391
|
-
}
|
|
29392
|
-
var renderScale;
|
|
29393
|
-
var init_canvas_dpr = __esm({
|
|
29394
|
-
"lib/engine/canvas-dpr.ts"() {
|
|
29395
|
-
renderScale = 1;
|
|
29396
|
-
}
|
|
29397
|
-
});
|
|
29398
|
-
|
|
29399
29406
|
// lib/editor/pointer/move/snap.ts
|
|
29400
29407
|
var init_snap = __esm({
|
|
29401
29408
|
"lib/editor/pointer/move/snap.ts"() {
|
|
@@ -29407,6 +29414,7 @@ var init_snap = __esm({
|
|
|
29407
29414
|
// lib/editor/pointer/move/group-resize.ts
|
|
29408
29415
|
var init_group_resize = __esm({
|
|
29409
29416
|
"lib/editor/pointer/move/group-resize.ts"() {
|
|
29417
|
+
init_handle_reach();
|
|
29410
29418
|
init_resize_children();
|
|
29411
29419
|
init_scene_graph();
|
|
29412
29420
|
init_selection_bounds();
|
|
@@ -176240,7 +176248,6 @@ var init_frame_labels = __esm({
|
|
|
176240
176248
|
var MODE_PROFILES, isTimelineMode, FOCUS_PROFILES, MODE_LIST, FOCUS_BY_PRECEDENCE;
|
|
176241
176249
|
var init_registry2 = __esm({
|
|
176242
176250
|
"lib/editor/modes/registry.ts"() {
|
|
176243
|
-
"use strict";
|
|
176244
176251
|
MODE_PROFILES = {
|
|
176245
176252
|
DESIGN: {
|
|
176246
176253
|
id: "DESIGN",
|
|
@@ -180354,6 +180361,7 @@ var init_hit_test = __esm({
|
|
|
180354
180361
|
init_layout_access();
|
|
180355
180362
|
init_glyph_linear();
|
|
180356
180363
|
init_canvas_dpr();
|
|
180364
|
+
init_handle_reach();
|
|
180357
180365
|
init_frame_labels();
|
|
180358
180366
|
init_stage_view();
|
|
180359
180367
|
init_paths();
|
|
@@ -252584,7 +252592,6 @@ function hasMessage(key5) {
|
|
|
252584
252592
|
var current3, loading2, listeners2, formats, asts;
|
|
252585
252593
|
var init_runtime = __esm({
|
|
252586
252594
|
"lib/i18n/runtime.ts"() {
|
|
252587
|
-
"use strict";
|
|
252588
252595
|
init_intl_messageformat();
|
|
252589
252596
|
init_icu_messageformat_parser();
|
|
252590
252597
|
init_catalogs();
|
|
@@ -254983,7 +254990,6 @@ function relinkCopies(doc2, copies) {
|
|
|
254983
254990
|
var TEXT_PATH_SOURCE_TYPES, isPathSource;
|
|
254984
254991
|
var init_text_links = __esm({
|
|
254985
254992
|
"lib/document/text-links.ts"() {
|
|
254986
|
-
"use strict";
|
|
254987
254993
|
init_transform();
|
|
254988
254994
|
TEXT_PATH_SOURCE_TYPES = ["VECTOR", "ELLIPSE", "RECTANGLE", "POLYGON", "STAR", "LINE", "ARROW", "FRAME"];
|
|
254989
254995
|
isPathSource = (n) => !!n && TEXT_PATH_SOURCE_TYPES.includes(n.type);
|
|
@@ -263475,7 +263481,6 @@ function resizeWindow(doc2, target2, rect) {
|
|
|
263475
263481
|
}
|
|
263476
263482
|
var init_crop = __esm({
|
|
263477
263483
|
"lib/editor/crop.ts"() {
|
|
263478
|
-
"use strict";
|
|
263479
263484
|
init_dist_node();
|
|
263480
263485
|
init_scene_graph();
|
|
263481
263486
|
init_photo_frames();
|
|
@@ -263726,7 +263731,6 @@ function getActiveRenderer() {
|
|
|
263726
263731
|
var active;
|
|
263727
263732
|
var init_renderer_registry = __esm({
|
|
263728
263733
|
"lib/engine/renderer-registry.ts"() {
|
|
263729
|
-
"use strict";
|
|
263730
263734
|
active = null;
|
|
263731
263735
|
}
|
|
263732
263736
|
});
|
|
@@ -266506,7 +266510,6 @@ fn shade(uv: vec2<f32>, res: vec2<f32>, tm: f32) -> vec4<f32> {
|
|
|
266506
266510
|
var SHADER_PRESETS, shaderPreset, legacyPresetOf, DEFAULT_SHADER_PRESET, DEFAULT_TEXTURE_PARAMS, f, vec4, NOISE_LIB;
|
|
266507
266511
|
var init_shader_presets = __esm({
|
|
266508
266512
|
"lib/engine/shader-presets.ts"() {
|
|
266509
|
-
"use strict";
|
|
266510
266513
|
init_shader_graph();
|
|
266511
266514
|
init_shader_graph_presets();
|
|
266512
266515
|
init_shader_presets_legacy();
|
|
@@ -273392,6 +273395,16 @@ var init_plugin_store = __esm({
|
|
|
273392
273395
|
toasts: [],
|
|
273393
273396
|
permissionPrompt: null,
|
|
273394
273397
|
managerOpen: false,
|
|
273398
|
+
panelIcons: {},
|
|
273399
|
+
setPanelIcon: (tab, icon) => set4((st3) => {
|
|
273400
|
+
const next2 = { ...st3.panelIcons };
|
|
273401
|
+
if (icon) next2[tab] = icon;
|
|
273402
|
+
else delete next2[tab];
|
|
273403
|
+
return { panelIcons: next2 };
|
|
273404
|
+
}),
|
|
273405
|
+
clearPanelIcons: (pluginId) => set4((st3) => ({
|
|
273406
|
+
panelIcons: Object.fromEntries(Object.entries(st3.panelIcons).filter(([, v]) => v.pluginId !== pluginId))
|
|
273407
|
+
})),
|
|
273395
273408
|
setInstalled: (installed4) => set4({ installed: installed4 }),
|
|
273396
273409
|
setManagerOpen: (managerOpen) => set4({ managerOpen }),
|
|
273397
273410
|
upsertSession: (s) => set4((st3) => ({ sessions: [...st3.sessions.filter((x2) => x2.sessionId !== s.sessionId), s] })),
|
|
@@ -273789,6 +273802,7 @@ function planEntryAction({ home }) {
|
|
|
273789
273802
|
var STORAGE_KEY2, useHyperyTeam, TEAM_PROMPT_ENABLED, TEAM_PROMPTED_KEY, PROMPTED_KEY, useTeamPrompt, started;
|
|
273790
273803
|
var init_team = __esm({
|
|
273791
273804
|
"lib/client/cloud/team.ts"() {
|
|
273805
|
+
"use strict";
|
|
273792
273806
|
init_esm();
|
|
273793
273807
|
init_api4();
|
|
273794
273808
|
init_session();
|
|
@@ -322648,6 +322662,7 @@ function startCloudSync() {
|
|
|
322648
322662
|
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;
|
|
322649
322663
|
var init_sync2 = __esm({
|
|
322650
322664
|
"lib/client/cloud/sync.ts"() {
|
|
322665
|
+
"use strict";
|
|
322651
322666
|
init_kinds();
|
|
322652
322667
|
init_paint_repair();
|
|
322653
322668
|
init_migrate();
|
|
@@ -323258,7 +323273,6 @@ function creditLine(c2) {
|
|
|
323258
323273
|
var MAX_PHOTO_PAGE, MAX_PHOTO_QUERY, UUID, isPhotoId, photoImagePath;
|
|
323259
323274
|
var init_stock = __esm({
|
|
323260
323275
|
"lib/photos/stock.ts"() {
|
|
323261
|
-
"use strict";
|
|
323262
323276
|
MAX_PHOTO_PAGE = 12;
|
|
323263
323277
|
MAX_PHOTO_QUERY = 200;
|
|
323264
323278
|
UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -323920,7 +323934,6 @@ function applyTextPath(layout2, path, tp, rebase = true) {
|
|
|
323920
323934
|
var defaultCircleRadius, ownsPath, mapPoint;
|
|
323921
323935
|
var init_text_path = __esm({
|
|
323922
323936
|
"lib/engine/text/text-path.ts"() {
|
|
323923
|
-
"use strict";
|
|
323924
323937
|
init_scene_graph();
|
|
323925
323938
|
init_transform();
|
|
323926
323939
|
init_shape_to_path();
|
|
@@ -324038,7 +324051,6 @@ function areaBounds(rings) {
|
|
|
324038
324051
|
}
|
|
324039
324052
|
var init_text_area = __esm({
|
|
324040
324053
|
"lib/engine/text/text-area.ts"() {
|
|
324041
|
-
"use strict";
|
|
324042
324054
|
}
|
|
324043
324055
|
});
|
|
324044
324056
|
|
|
@@ -328079,7 +328091,6 @@ async function exportSettingFile(renderer, node2, setting, doc2, styles) {
|
|
|
328079
328091
|
var MIME, DEFAULT_EXPORT, exportSettingsOf;
|
|
328080
328092
|
var init_export = __esm({
|
|
328081
328093
|
"lib/io/export.ts"() {
|
|
328082
|
-
"use strict";
|
|
328083
328094
|
init_download();
|
|
328084
328095
|
init_scene_graph();
|
|
328085
328096
|
init_codecs();
|
|
@@ -328171,7 +328182,6 @@ async function selectionReferenceImages(doc2, selection, opts = {}) {
|
|
|
328171
328182
|
var FIT_QUALITIES, FIT_SCALES, blobToDataUrl;
|
|
328172
328183
|
var init_reference_images = __esm({
|
|
328173
328184
|
"lib/ai/reference-images.ts"() {
|
|
328174
|
-
"use strict";
|
|
328175
328185
|
init_export();
|
|
328176
328186
|
init_selection_bounds();
|
|
328177
328187
|
init_renderer_registry();
|
|
@@ -339074,7 +339084,7 @@ var init_package = __esm({
|
|
|
339074
339084
|
"packages/runtime/package.json"() {
|
|
339075
339085
|
package_default = {
|
|
339076
339086
|
name: "@popcraft/runtime",
|
|
339077
|
-
version: "0.
|
|
339087
|
+
version: "0.59.1",
|
|
339078
339088
|
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.",
|
|
339079
339089
|
license: "MIT",
|
|
339080
339090
|
homepage: "https://popcraft.app/docs/exporting/nextjs",
|
|
@@ -363740,7 +363750,6 @@ function exportsOf(source3) {
|
|
|
363740
363750
|
var CODE_LIMITS, packageOf;
|
|
363741
363751
|
var init_source2 = __esm({
|
|
363742
363752
|
"lib/code/source.ts"() {
|
|
363743
|
-
"use strict";
|
|
363744
363753
|
CODE_LIMITS = { modules: 100, sourceLength: 2e5, packages: 12 };
|
|
363745
363754
|
packageOf = (spec) => spec.split("/").slice(0, spec.startsWith("@") ? 2 : 1).join("/");
|
|
363746
363755
|
}
|
|
@@ -363783,7 +363792,6 @@ function compileModule(module2) {
|
|
|
363783
363792
|
var import_sucrase, BUILT_IN, memo7;
|
|
363784
363793
|
var init_compile2 = __esm({
|
|
363785
363794
|
"lib/code/compile.ts"() {
|
|
363786
|
-
"use strict";
|
|
363787
363795
|
import_sucrase = __toESM(require_dist2());
|
|
363788
363796
|
init_source2();
|
|
363789
363797
|
init_source2();
|
|
@@ -369945,6 +369953,7 @@ var init_sequence2 = __esm({
|
|
|
369945
369953
|
length: external_exports.number().min(500).max(6e5).optional().describe("ms, default 3000.")
|
|
369946
369954
|
}),
|
|
369947
369955
|
expose: {
|
|
369956
|
+
plugin: { method: "addTitle" },
|
|
369948
369957
|
ui: { label: "Add a title", keywords: ["title", "text", "lower third", "subtitle", "caption", "name"], enabled: (c2) => inEdit(c2) },
|
|
369949
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." }
|
|
369950
369959
|
},
|
|
@@ -370005,6 +370014,7 @@ var init_sequence2 = __esm({
|
|
|
370005
370014
|
clip: external_exports.string().optional().describe("The multicam clip (default: the picked one).")
|
|
370006
370015
|
}),
|
|
370007
370016
|
expose: {
|
|
370017
|
+
plugin: { method: "syncAngles" },
|
|
370008
370018
|
ui: { label: "Sync angles by sound", keywords: ["multicam", "sync", "align", "audio", "clap", "angles"], enabled: (c2) => withPicked(c2) },
|
|
370009
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)." }
|
|
370010
370020
|
},
|
|
@@ -370078,6 +370088,7 @@ var init_sequence2 = __esm({
|
|
|
370078
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`.")
|
|
370079
370089
|
}),
|
|
370080
370090
|
expose: {
|
|
370091
|
+
plugin: { method: "nestClips" },
|
|
370081
370092
|
ui: { label: "Nest clips", keywords: ["nest", "precompose", "group", "sequence", "compound clip"], enabled: (c2) => withPicked(c2) },
|
|
370082
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." }
|
|
370083
370094
|
},
|
|
@@ -370156,6 +370167,7 @@ var init_sequence2 = __esm({
|
|
|
370156
370167
|
to: external_exports.number().min(-24).max(0).optional().describe("Peak level, dBFS (default \u22121).")
|
|
370157
370168
|
}),
|
|
370158
370169
|
expose: {
|
|
370170
|
+
plugin: { method: "normalizeAudio" },
|
|
370159
370171
|
ui: { label: "Normalize audio", keywords: ["normalize", "loudness", "level", "peak", "volume", "gain"], enabled: (c2) => inEdit(c2) },
|
|
370160
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)." }
|
|
370161
370173
|
},
|
|
@@ -380984,16 +380996,16 @@ var init_api5 = __esm({
|
|
|
380984
380996
|
}
|
|
380985
380997
|
});
|
|
380986
380998
|
|
|
380987
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
380999
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/generated/runtime.js
|
|
380988
381000
|
var MAIN_RUNTIME, UI_RUNTIME;
|
|
380989
381001
|
var init_runtime6 = __esm({
|
|
380990
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
380991
|
-
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})();';
|
|
380992
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})();';
|
|
380993
381005
|
}
|
|
380994
381006
|
});
|
|
380995
381007
|
|
|
380996
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381008
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/host.js
|
|
380997
381009
|
function csp(network) {
|
|
380998
381010
|
const connect2 = network ? "connect-src * data: blob:;" : "connect-src 'none';";
|
|
380999
381011
|
const img = network ? "img-src * data: blob:;" : "img-src data: blob:;";
|
|
@@ -381021,40 +381033,40 @@ function buildUIDocument(uiHtml, network) {
|
|
|
381021
381033
|
}
|
|
381022
381034
|
var escapeScript;
|
|
381023
381035
|
var init_host2 = __esm({
|
|
381024
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381036
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/host.js"() {
|
|
381025
381037
|
init_runtime6();
|
|
381026
381038
|
escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
|
|
381027
381039
|
}
|
|
381028
381040
|
});
|
|
381029
381041
|
|
|
381030
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381042
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/rpc.js
|
|
381031
381043
|
var init_rpc = __esm({
|
|
381032
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381044
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/rpc.js"() {
|
|
381033
381045
|
}
|
|
381034
381046
|
});
|
|
381035
381047
|
|
|
381036
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381048
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/main.js
|
|
381037
381049
|
var init_main = __esm({
|
|
381038
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381050
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/runtime/main.js"() {
|
|
381039
381051
|
init_rpc();
|
|
381040
381052
|
}
|
|
381041
381053
|
});
|
|
381042
381054
|
|
|
381043
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381055
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/types.js
|
|
381044
381056
|
var init_types10 = __esm({
|
|
381045
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381057
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/types.js"() {
|
|
381046
381058
|
}
|
|
381047
381059
|
});
|
|
381048
381060
|
|
|
381049
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381061
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/widget.js
|
|
381050
381062
|
var init_widget = __esm({
|
|
381051
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381063
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/widget.js"() {
|
|
381052
381064
|
}
|
|
381053
381065
|
});
|
|
381054
381066
|
|
|
381055
|
-
// node_modules/.pnpm/@popcraft+plugins@1.
|
|
381067
|
+
// node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/index.js
|
|
381056
381068
|
var init_dist = __esm({
|
|
381057
|
-
"node_modules/.pnpm/@popcraft+plugins@1.
|
|
381069
|
+
"node_modules/.pnpm/@popcraft+plugins@1.6.1/node_modules/@popcraft/plugins/dist/index.js"() {
|
|
381058
381070
|
init_host2();
|
|
381059
381071
|
init_main();
|
|
381060
381072
|
init_runtime6();
|
|
@@ -381207,6 +381219,7 @@ function validateManifest(raw) {
|
|
|
381207
381219
|
if (typeof pp.title !== "string" || !pp.title.trim()) throw new PluginPackageError(`${at5}.title must be a non-empty string`);
|
|
381208
381220
|
if (pp.side !== void 0 && pp.side !== "left" && pp.side !== "right") throw new PluginPackageError(`${at5}.side must be "left" or "right"`);
|
|
381209
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`);
|
|
381210
381223
|
if (pp.icon !== void 0 && (typeof pp.icon !== "string" || !(DATA_ICON_RE.test(pp.icon) || ICON_PATH_RE.test(pp.icon)))) {
|
|
381211
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`);
|
|
381212
381225
|
}
|
|
@@ -381215,9 +381228,11 @@ function validateManifest(raw) {
|
|
|
381215
381228
|
title: pp.title.trim(),
|
|
381216
381229
|
...pp.icon !== void 0 && { icon: pp.icon },
|
|
381217
381230
|
...pp.side !== void 0 && { side: pp.side },
|
|
381218
|
-
...pp.command !== void 0 && { command: pp.command }
|
|
381231
|
+
...pp.command !== void 0 && { command: pp.command },
|
|
381232
|
+
...pp.autostart === true && { autostart: true }
|
|
381219
381233
|
};
|
|
381220
381234
|
});
|
|
381235
|
+
if (panels.filter((p2) => p2.autostart).length > 1) throw new PluginPackageError("manifest.contributes.panels: at most one panel may autostart");
|
|
381221
381236
|
contributes = { ...contributes, panels };
|
|
381222
381237
|
}
|
|
381223
381238
|
if (c2.importers !== void 0) {
|
|
@@ -411140,6 +411155,7 @@ var init_plugin_import = __esm({
|
|
|
411140
411155
|
var host_exports2 = {};
|
|
411141
411156
|
__export(host_exports2, {
|
|
411142
411157
|
attachPluginUI: () => attachPluginUI,
|
|
411158
|
+
autostartPluginPanels: () => autostartPluginPanels,
|
|
411143
411159
|
closeSession: () => closeSession,
|
|
411144
411160
|
dispatchWidgetClick: () => dispatchWidgetClick,
|
|
411145
411161
|
exportFileName: () => exportFileName2,
|
|
@@ -411275,6 +411291,13 @@ async function runPlugin(pluginId, commandId, opts = {}) {
|
|
|
411275
411291
|
}
|
|
411276
411292
|
}),
|
|
411277
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
|
+
},
|
|
411278
411301
|
close: (message) => {
|
|
411279
411302
|
const sel = message ? [...useEditorStore.getState().selection] : [];
|
|
411280
411303
|
closeSession(sessionId);
|
|
@@ -411463,6 +411486,15 @@ function closeSession(sessionId) {
|
|
|
411463
411486
|
s.uiPort?.close();
|
|
411464
411487
|
s.iframe.remove();
|
|
411465
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
|
+
}
|
|
411466
411498
|
}
|
|
411467
411499
|
var running3;
|
|
411468
411500
|
var init_host3 = __esm({
|
|
@@ -411594,7 +411626,7 @@ function pluginContext(env) {
|
|
|
411594
411626
|
return out;
|
|
411595
411627
|
},
|
|
411596
411628
|
storage: { get: env.effects.storageGet, set: env.effects.storageSet },
|
|
411597
|
-
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 }
|
|
411598
411630
|
};
|
|
411599
411631
|
const st3 = () => env.getState();
|
|
411600
411632
|
return {
|
|
@@ -411642,7 +411674,7 @@ function dispatchPluginCall(env, method, params2 = {}) {
|
|
|
411642
411674
|
}
|
|
411643
411675
|
});
|
|
411644
411676
|
}
|
|
411645
|
-
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;
|
|
411646
411678
|
var init_plugin = __esm({
|
|
411647
411679
|
"lib/commands/plugin.ts"() {
|
|
411648
411680
|
init_zod();
|
|
@@ -411658,6 +411690,7 @@ var init_plugin = __esm({
|
|
|
411658
411690
|
PLUGIN_CAPABILITIES = ["render", "storage", "panel"];
|
|
411659
411691
|
pluginCommandId = (method) => `plugin.${method}`;
|
|
411660
411692
|
empty = external_exports.object({});
|
|
411693
|
+
MAX_PANEL_ICON_CHARS = 64 * 1024;
|
|
411661
411694
|
MAX_UPLOAD_BYTES = 500 * 1024 * 1024;
|
|
411662
411695
|
MAX_UPLOAD_REPLY_CHARS = 1024 * 1024;
|
|
411663
411696
|
commands = [
|
|
@@ -411802,6 +411835,33 @@ var init_plugin = __esm({
|
|
|
411802
411835
|
return { summary: "UI shown" };
|
|
411803
411836
|
}
|
|
411804
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
|
+
}),
|
|
411805
411865
|
defineCommand({
|
|
411806
411866
|
id: pluginCommandId("hideUI"),
|
|
411807
411867
|
title: "Hide plugin UI",
|
|
@@ -415149,8 +415209,8 @@ function themeCommand(themes) {
|
|
|
415149
415209
|
});
|
|
415150
415210
|
}
|
|
415151
415211
|
function pluginCommand(plugins) {
|
|
415152
|
-
const variants = plugins.filter((p2) => p2.enabled
|
|
415153
|
-
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" }];
|
|
415154
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 } }));
|
|
415155
415215
|
});
|
|
415156
415216
|
return defineCommand({
|
|
@@ -426393,6 +426453,9 @@ async function runPluginHeadless(plugin, opts) {
|
|
|
426393
426453
|
showUI: () => fail3(app("opens a panel")),
|
|
426394
426454
|
hideUI: () => {
|
|
426395
426455
|
},
|
|
426456
|
+
// No rails headless: a panel icon has nowhere to show.
|
|
426457
|
+
setPanelIcon: () => {
|
|
426458
|
+
},
|
|
426396
426459
|
close: (message) => finish3({ closed: true, message, errors: errors2 }),
|
|
426397
426460
|
storageGet: async (key5) => storage[key5],
|
|
426398
426461
|
storageSet: async (key5, value3) => {
|
|
@@ -426582,7 +426645,7 @@ init_resources();
|
|
|
426582
426645
|
init_desktop();
|
|
426583
426646
|
init_hypery();
|
|
426584
426647
|
import { createInterface } from "node:readline";
|
|
426585
|
-
var VERSION2 = "0.
|
|
426648
|
+
var VERSION2 = "0.59.1";
|
|
426586
426649
|
var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
|
|
426587
426650
|
|
|
426588
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.1",
|
|
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.1"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "node build.mjs",
|