@cesdk/node-native 1.77.0 → 1.77.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/lib/index.js CHANGED
@@ -579,6 +579,133 @@ async function downloadAndCheckLicense(config, fetchImpl = globalThis.fetch) {
579
579
  );
580
580
  }
581
581
 
582
+ // ../wasm/js_web/src/EngineActions.ts
583
+ var EngineActions = class {
584
+ /** @internal */
585
+ #ubq;
586
+ /**
587
+ * Settlers for in-flight `run()` calls so {@link dispose} can reject them
588
+ * instead of leaking forever-pending promises.
589
+ * @internal
590
+ */
591
+ #pending = /* @__PURE__ */ new Set();
592
+ /** @internal */
593
+ #disposed = false;
594
+ /** @internal */
595
+ constructor(ubq) {
596
+ this.#ubq = ubq;
597
+ }
598
+ register(id, fn) {
599
+ const trampoline = (jsonArgs) => {
600
+ let args;
601
+ try {
602
+ const parsed = JSON.parse(jsonArgs);
603
+ args = Array.isArray(parsed) ? parsed : [parsed];
604
+ } catch {
605
+ args = [];
606
+ }
607
+ try {
608
+ const result = fn(...args);
609
+ if (result != null && typeof result.then === "function") {
610
+ return result.then(
611
+ (value) => JSON.stringify(value ?? null)
612
+ );
613
+ }
614
+ return JSON.stringify(result ?? null);
615
+ } catch (error) {
616
+ return Promise.reject(
617
+ error instanceof Error ? error : new Error(String(error))
618
+ );
619
+ }
620
+ };
621
+ this.#ubq.actionsRegister(id, trampoline, fn);
622
+ }
623
+ get(id) {
624
+ return this.#ubq.actionsGetLocal(id);
625
+ }
626
+ run(id, ...args) {
627
+ if (this.#disposed) {
628
+ return Promise.reject(new Error("Engine has been disposed."));
629
+ }
630
+ const local = this.#ubq.actionsGetLocal(id);
631
+ if (local !== void 0) {
632
+ return new Promise((resolve, reject) => {
633
+ const settle = (reason) => {
634
+ this.#pending.delete(settle);
635
+ reject(reason);
636
+ };
637
+ this.#pending.add(settle);
638
+ let result;
639
+ try {
640
+ result = local(...args);
641
+ } catch (error) {
642
+ this.#pending.delete(settle);
643
+ reject(error instanceof Error ? error : new Error(String(error)));
644
+ return;
645
+ }
646
+ Promise.resolve(result).then(
647
+ (value) => {
648
+ this.#pending.delete(settle);
649
+ resolve(value);
650
+ },
651
+ (error) => {
652
+ this.#pending.delete(settle);
653
+ reject(error instanceof Error ? error : new Error(String(error)));
654
+ }
655
+ );
656
+ });
657
+ }
658
+ return new Promise((resolve, reject) => {
659
+ const settle = (reason) => {
660
+ this.#pending.delete(settle);
661
+ reject(reason);
662
+ };
663
+ this.#pending.add(settle);
664
+ this.#ubq.actionsRun(
665
+ id,
666
+ JSON.stringify(args),
667
+ (jsonResult) => {
668
+ this.#pending.delete(settle);
669
+ try {
670
+ resolve(jsonResult === "" ? void 0 : JSON.parse(jsonResult));
671
+ } catch (error) {
672
+ reject(error instanceof Error ? error : new Error(String(error)));
673
+ }
674
+ },
675
+ (error) => settle(new Error(error))
676
+ );
677
+ });
678
+ }
679
+ /** Whether an action with this id is registered (host or engine default). */
680
+ has(id) {
681
+ return this.#ubq.actionsHas(id);
682
+ }
683
+ /**
684
+ * Remove a host action, or revert an overridden engine default to its built-in.
685
+ *
686
+ * If you override an engine default (such as `select` or `undo`), unregistering the id restores
687
+ * the default rather than leaving it unhandled. A custom id you registered yourself is removed
688
+ * entirely. Returns `false` only when the id is unknown.
689
+ */
690
+ unregister(id) {
691
+ return this.#ubq.actionsUnregister(id);
692
+ }
693
+ /** List registered actions, optionally filtered by a `*` glob matcher on the id. */
694
+ list(options) {
695
+ return this.#ubq.actionsList(options?.matcher ?? null);
696
+ }
697
+ /**
698
+ * Reject all in-flight `run()` promises. Called by the engine's `dispose()`.
699
+ * @internal
700
+ */
701
+ dispose() {
702
+ this.#disposed = true;
703
+ const pending = [...this.#pending];
704
+ this.#pending.clear();
705
+ pending.forEach((settle) => settle(new Error("Engine has been disposed.")));
706
+ }
707
+ };
708
+
582
709
  // ts/src/CreativeEngine.ts
583
710
  function isRGBAColor2(color) {
584
711
  return "r" in color && "a" in color && color.r !== void 0 && color.a !== void 0;
@@ -1277,9 +1404,9 @@ var BlockAPI = class {
1277
1404
  "Color is not in sRGB color space. Use getColor() for non-RGBA colors."
1278
1405
  );
1279
1406
  }
1280
- return { r: color.r, g: color.g, b: color.b, a: color.a };
1407
+ return [color.r, color.g, color.b, color.a];
1281
1408
  }
1282
- setColorRGBA(block, property, r, g, b, a) {
1409
+ setColorRGBA(block, property, r, g, b, a = 1) {
1283
1410
  this.setColor(block, property, { r, g, b, a });
1284
1411
  }
1285
1412
  getEnum(block, property) {
@@ -1316,8 +1443,8 @@ var BlockAPI = class {
1316
1443
  getWidth(block) {
1317
1444
  return this.#engine.getWidth(block);
1318
1445
  }
1319
- setWidth(block, value) {
1320
- this.#engine.setWidth(block, value);
1446
+ setWidth(block, value, maintainCrop) {
1447
+ this.#engine.setWidth(block, value, maintainCrop ?? false);
1321
1448
  }
1322
1449
  getWidthMode(block) {
1323
1450
  return this.#engine.getWidthMode(block);
@@ -1328,8 +1455,8 @@ var BlockAPI = class {
1328
1455
  getHeight(block) {
1329
1456
  return this.#engine.getHeight(block);
1330
1457
  }
1331
- setHeight(block, value) {
1332
- this.#engine.setHeight(block, value);
1458
+ setHeight(block, value, maintainCrop) {
1459
+ this.#engine.setHeight(block, value, maintainCrop ?? false);
1333
1460
  }
1334
1461
  getHeightMode(block) {
1335
1462
  return this.#engine.getHeightMode(block);
@@ -1381,7 +1508,7 @@ var BlockAPI = class {
1381
1508
  this.#engine.fillParent(block);
1382
1509
  }
1383
1510
  resizeContentAware(blocks, width, height) {
1384
- return this.#engine.resizeContentAware(blocks, width, height);
1511
+ this.#engine.resizeContentAware(blocks, width, height);
1385
1512
  }
1386
1513
  // Global bounding box
1387
1514
  getGlobalBoundingBoxX(block) {
@@ -1416,15 +1543,15 @@ var BlockAPI = class {
1416
1543
  this.#engine.setFillEnabled(block, enabled);
1417
1544
  }
1418
1545
  getFillColorRGBA(block) {
1419
- const color = this.getFillSolidColor(block);
1546
+ const color = this.#engine.getFillSolidColor(block);
1420
1547
  if (!isRGBAColor2(color)) {
1421
1548
  throw new Error(
1422
1549
  "Fill color is not in sRGB color space. Use getFillSolidColor() for non-RGBA colors."
1423
1550
  );
1424
1551
  }
1425
- return { r: color.r, g: color.g, b: color.b, a: color.a };
1552
+ return [color.r, color.g, color.b, color.a];
1426
1553
  }
1427
- setFillColorRGBA(block, r, g, b, a) {
1554
+ setFillColorRGBA(block, r, g, b, a = 1) {
1428
1555
  this.setFillSolidColor(block, r, g, b, a);
1429
1556
  }
1430
1557
  getFill(block) {
@@ -1433,9 +1560,6 @@ var BlockAPI = class {
1433
1560
  setFill(block, fill) {
1434
1561
  this.#engine.setFill(block, fill);
1435
1562
  }
1436
- getFillEnabled(block) {
1437
- return this.#engine.getFillEnabled(block);
1438
- }
1439
1563
  isFillEnabled(block) {
1440
1564
  return this.#engine.getFillEnabled(block);
1441
1565
  }
@@ -1443,7 +1567,8 @@ var BlockAPI = class {
1443
1567
  this.#engine.setFillEnabled(block, enabled);
1444
1568
  }
1445
1569
  getFillSolidColor(block) {
1446
- return this.#engine.getFillSolidColor(block);
1570
+ const c = this.#engine.getFillSolidColor(block);
1571
+ return [c.r, c.g, c.b, c.a];
1447
1572
  }
1448
1573
  setFillSolidColor(block, r, g, b, a = 1) {
1449
1574
  this.#engine.setFillSolidColor(block, { r, g, b, a });
@@ -1469,15 +1594,9 @@ var BlockAPI = class {
1469
1594
  hasStroke(block) {
1470
1595
  return this.#engine.hasStroke(block);
1471
1596
  }
1472
- getStroke(block) {
1473
- return this.#engine.getStroke(block);
1474
- }
1475
- setStroke(block, stroke) {
1476
- this.#engine.setStroke(block, stroke);
1477
- }
1478
- getStrokeEnabled(block) {
1479
- return this.#engine.getStrokeEnabled(block);
1480
- }
1597
+ // Note: `getStroke`/`setStroke` removed — @cesdk/node has no such API
1598
+ // (strokes are block-level properties); the native stubs only threw.
1599
+ // `getStrokeEnabled` removed as a redundant alias of `isStrokeEnabled`.
1481
1600
  isStrokeEnabled(block) {
1482
1601
  return this.#engine.getStrokeEnabled(block);
1483
1602
  }
@@ -1565,9 +1684,10 @@ var BlockAPI = class {
1565
1684
  return this.#engine.isLineOrigin(block);
1566
1685
  }
1567
1686
  getStrokeColorRGBA(block) {
1568
- return this.#engine.getStrokeColorRGBA(block);
1687
+ const c = this.#engine.getStrokeColorRGBA(block);
1688
+ return [c.r, c.g, c.b, c.a];
1569
1689
  }
1570
- setStrokeColorRGBA(block, r, g, b, a) {
1690
+ setStrokeColorRGBA(block, r, g, b, a = 1) {
1571
1691
  this.#engine.setStrokeColorRGBA(block, r, g, b, a);
1572
1692
  }
1573
1693
  // Effects
@@ -1611,9 +1731,6 @@ var BlockAPI = class {
1611
1731
  setBlur(block, blur) {
1612
1732
  this.#engine.setBlur(block, blur);
1613
1733
  }
1614
- getBlurEnabled(block) {
1615
- return this.#engine.getBlurEnabled(block);
1616
- }
1617
1734
  isBlurEnabled(block) {
1618
1735
  return this.#engine.getBlurEnabled(block);
1619
1736
  }
@@ -1704,6 +1821,7 @@ var BlockAPI = class {
1704
1821
  // native stays honest with `: void`.
1705
1822
  adjustCropToFillFrame(block, minScaleRatio) {
1706
1823
  this.#engine.adjustCropToFillFrame(block, minScaleRatio);
1824
+ return void 0;
1707
1825
  }
1708
1826
  getCropRotation(block) {
1709
1827
  return this.#engine.getCropRotation(block);
@@ -1777,9 +1895,10 @@ var BlockAPI = class {
1777
1895
  this.#engine.setDropShadowColor(block, internalColor);
1778
1896
  }
1779
1897
  getDropShadowColorRGBA(block) {
1780
- return this.#engine.getDropShadowColorRGBA(block);
1898
+ const c = this.#engine.getDropShadowColorRGBA(block);
1899
+ return [c.r, c.g, c.b, c.a];
1781
1900
  }
1782
- setDropShadowColorRGBA(block, r, g, b, a) {
1901
+ setDropShadowColorRGBA(block, r, g, b, a = 1) {
1783
1902
  this.#engine.setDropShadowColorRGBA(block, r, g, b, a);
1784
1903
  }
1785
1904
  getDropShadowOffsetX(block) {
@@ -1839,18 +1958,12 @@ var BlockAPI = class {
1839
1958
  this.#engine.setOpacity(block, opacity);
1840
1959
  }
1841
1960
  // Visibility
1842
- getVisible(block) {
1843
- return this.#engine.getVisible(block);
1844
- }
1845
1961
  isVisible(block) {
1846
1962
  return this.#engine.getVisible(block);
1847
1963
  }
1848
1964
  setVisible(block, visible) {
1849
1965
  this.#engine.setVisible(block, visible);
1850
1966
  }
1851
- getClipped(block) {
1852
- return this.#engine.getClipped(block);
1853
- }
1854
1967
  isClipped(block) {
1855
1968
  return this.#engine.getClipped(block);
1856
1969
  }
@@ -2118,9 +2231,9 @@ var BlockAPI = class {
2118
2231
  if (!isRGBAColor2(color)) {
2119
2232
  throw new Error("Expected RGBA color for background color");
2120
2233
  }
2121
- return { r: color.r, g: color.g, b: color.b, a: color.a };
2234
+ return [color.r, color.g, color.b, color.a];
2122
2235
  }
2123
- setBackgroundColorRGBA(block, r, g, b, a) {
2236
+ setBackgroundColorRGBA(block, r, g, b, a = 1) {
2124
2237
  this.setColor(block, "backgroundColor", { r, g, b, a });
2125
2238
  }
2126
2239
  // Metadata
@@ -2221,7 +2334,11 @@ var BlockAPI = class {
2221
2334
  }
2222
2335
  getTextFontStyles(block, from = -1, to = -1) {
2223
2336
  const range = this.#toGraphemeRange(block, from, to);
2224
- return this.#engine.getTextFontStyles(block, range.from, range.to);
2337
+ return this.#engine.getTextFontStyles(
2338
+ block,
2339
+ range.from,
2340
+ range.to
2341
+ );
2225
2342
  }
2226
2343
  setTextFontStyle(block, style, from = -1, to = -1) {
2227
2344
  const range = this.#toGraphemeRange(block, from, to);
@@ -2229,7 +2346,11 @@ var BlockAPI = class {
2229
2346
  }
2230
2347
  getTextFontWeights(block, from = -1, to = -1) {
2231
2348
  const range = this.#toGraphemeRange(block, from, to);
2232
- return this.#engine.getTextFontWeights(block, range.from, range.to);
2349
+ return this.#engine.getTextFontWeights(
2350
+ block,
2351
+ range.from,
2352
+ range.to
2353
+ );
2233
2354
  }
2234
2355
  setTextFontWeight(block, weight, from = -1, to = -1) {
2235
2356
  const range = this.#toGraphemeRange(block, from, to);
@@ -2289,17 +2410,17 @@ var BlockAPI = class {
2289
2410
  setFont(block, fontUri, typeface) {
2290
2411
  this.#engine.setFont(block, fontUri, typeface);
2291
2412
  }
2292
- canToggleBoldFont(block) {
2293
- return this.#engine.canToggleBoldFont(block);
2413
+ canToggleBoldFont(block, from = -1, to = -1) {
2414
+ return this.#engine.canToggleBoldFont(block, from, to);
2294
2415
  }
2295
- toggleBoldFont(block) {
2296
- this.#engine.toggleBoldFont(block);
2416
+ toggleBoldFont(block, from = -1, to = -1) {
2417
+ this.#engine.toggleBoldFont(block, from, to);
2297
2418
  }
2298
- canToggleItalicFont(block) {
2299
- return this.#engine.canToggleItalicFont(block);
2419
+ canToggleItalicFont(block, from = -1, to = -1) {
2420
+ return this.#engine.canToggleItalicFont(block, from, to);
2300
2421
  }
2301
- toggleItalicFont(block) {
2302
- this.#engine.toggleItalicFont(block);
2422
+ toggleItalicFont(block, from = -1, to = -1) {
2423
+ this.#engine.toggleItalicFont(block, from, to);
2303
2424
  }
2304
2425
  /**
2305
2426
  * The text block currently being edited, or `undefined` when not in Text
@@ -2359,12 +2480,9 @@ var BlockAPI = class {
2359
2480
  }
2360
2481
  this.#engine.setTextCursorRange(from, to);
2361
2482
  }
2362
- getTextCursorPositionInScreenSpaceX(block) {
2363
- return this.#engine.getTextCursorPositionInScreenSpaceX(block);
2364
- }
2365
- getTextCursorPositionInScreenSpaceY(block) {
2366
- return this.#engine.getTextCursorPositionInScreenSpaceY(block);
2367
- }
2483
+ // getTextCursorPositionInScreenSpaceX/Y moved to the `editor` namespace
2484
+ // (no block argument) to match @cesdk/node, where the text cursor is
2485
+ // editor-level state.
2368
2486
  getTextVisibleLineCount(block) {
2369
2487
  return this.#engine.getTextVisibleLineCount(block);
2370
2488
  }
@@ -2517,9 +2635,8 @@ var BlockAPI = class {
2517
2635
  getTextOnPathFlipped(block) {
2518
2636
  return this.#engine.getTextOnPathFlipped(block);
2519
2637
  }
2520
- getFontMetrics(fontFileUri) {
2521
- return this.#engine.getFontMetrics(fontFileUri);
2522
- }
2638
+ // Note: getFontMetrics lives on the `editor` namespace (matching @cesdk/node);
2639
+ // the duplicate block-namespace copy was removed.
2523
2640
  // Source sets
2524
2641
  getSourceSet(block, property) {
2525
2642
  return this.#engine.getSourceSet(block, property);
@@ -2616,21 +2733,17 @@ var BlockAPI = class {
2616
2733
  findAllProperties(block) {
2617
2734
  return this.#engine.findAllProperties(block);
2618
2735
  }
2619
- getPropertyType(blockOrProperty, property) {
2620
- const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
2621
- return this.#engine.getPropertyType(propName);
2736
+ getPropertyType(property) {
2737
+ return this.#engine.getPropertyType(property);
2622
2738
  }
2623
- isPropertyReadable(blockOrProperty, property) {
2624
- const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
2625
- return this.#engine.isPropertyReadable(propName);
2739
+ isPropertyReadable(property) {
2740
+ return this.#engine.isPropertyReadable(property);
2626
2741
  }
2627
- isPropertyWritable(blockOrProperty, property) {
2628
- const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
2629
- return this.#engine.isPropertyWritable(propName);
2742
+ isPropertyWritable(property) {
2743
+ return this.#engine.isPropertyWritable(property);
2630
2744
  }
2631
- getEnumValues(blockOrProperty, property) {
2632
- const propName = typeof blockOrProperty === "string" ? blockOrProperty : property;
2633
- return this.#engine.getEnumValues(propName);
2745
+ getEnumValues(enumProperty) {
2746
+ return this.#engine.getEnumValues(enumProperty);
2634
2747
  }
2635
2748
  // State
2636
2749
  getState(block) {
@@ -2849,8 +2962,16 @@ var BlockAPI = class {
2849
2962
  }
2850
2963
  return this.#engine.loadBlocksFromArchiveURL(url);
2851
2964
  }
2852
- saveToString(blocks) {
2853
- return this.#engine.saveBlocksToString(blocks);
2965
+ saveToString(blocks, allowedResourceSchemes = ["buffer", "http", "https"], onDisallowedResourceScheme) {
2966
+ const persistenceCallback = onDisallowedResourceScheme ? async (url, dataHash, invoke) => {
2967
+ const persistedUrl = await onDisallowedResourceScheme(url, dataHash);
2968
+ invoke(url, persistedUrl);
2969
+ } : void 0;
2970
+ return this.#engine.saveBlocksToString(
2971
+ blocks,
2972
+ allowedResourceSchemes,
2973
+ persistenceCallback
2974
+ );
2854
2975
  }
2855
2976
  // BlockAPI.saveToArchive matches @cesdk/node and returns Promise<Blob>. The
2856
2977
  // raw Uint8Array form remains accessible via the engine binding for
@@ -2949,7 +3070,7 @@ var BlockAPI = class {
2949
3070
  *
2950
3071
  * @public
2951
3072
  */
2952
- addImage(url, options = {}) {
3073
+ async addImage(url, options = {}) {
2953
3074
  const {
2954
3075
  x,
2955
3076
  y,
@@ -3030,11 +3151,10 @@ var BlockAPI = class {
3030
3151
  *
3031
3152
  * @public
3032
3153
  */
3033
- addVideo(url, options = {}) {
3154
+ async addVideo(url, width, height, options = {}) {
3034
3155
  const {
3035
3156
  x,
3036
3157
  y,
3037
- size,
3038
3158
  timeline,
3039
3159
  animation,
3040
3160
  shadow,
@@ -3045,13 +3165,8 @@ var BlockAPI = class {
3045
3165
  loop,
3046
3166
  muted
3047
3167
  } = options;
3048
- if (size == null) {
3049
- throw new Error(
3050
- "[@cesdk/node-native] block.addVideo requires `options.size` in Node (no auto-probe). Pass `{ size: { width, height } }`."
3051
- );
3052
- }
3053
- const finalWidth = typeof size === "number" ? size : size.width;
3054
- const finalHeight = typeof size === "number" ? size : size.height;
3168
+ const finalWidth = width;
3169
+ const finalHeight = height;
3055
3170
  const pages = this.findByType("//ly.img.ubq/page");
3056
3171
  if (pages.length === 0) {
3057
3172
  throw new Error("No page found. Create a page first.");
@@ -3147,6 +3262,189 @@ var BlockAPI = class {
3147
3262
  const id = this.#engine.subscribeToBlockClicked(callback);
3148
3263
  return () => this.#engine.unsubscribe(id);
3149
3264
  }
3265
+ // --- Audio / video / captions / cutout (parity with @cesdk/node) ---
3266
+ getAudioInfoFromVideo(videoFillBlock) {
3267
+ return this.#engine.getAudioInfoFromVideo(videoFillBlock);
3268
+ }
3269
+ createAudioFromVideo(videoFillBlock, trackIndex, options) {
3270
+ return this.#engine.createAudioFromVideo(videoFillBlock, trackIndex, {
3271
+ keepTrimSettings: options?.keepTrimSettings ?? true,
3272
+ muteOriginalVideo: options?.muteOriginalVideo ?? true
3273
+ });
3274
+ }
3275
+ createAudiosFromVideo(videoFillBlock, options) {
3276
+ return this.#engine.createAudiosFromVideo(videoFillBlock, {
3277
+ keepTrimSettings: options?.keepTrimSettings ?? true,
3278
+ muteOriginalVideo: options?.muteOriginalVideo ?? true
3279
+ });
3280
+ }
3281
+ createCaptionsFromURI(uri) {
3282
+ return this.#engine.createCaptionsFromURI(uri);
3283
+ }
3284
+ createCutoutFromBlocks(ids, vectorizeDistanceThreshold, simplifyDistanceThreshold, useExistingShapeInformation) {
3285
+ return this.#engine.createCutoutFromBlocks(
3286
+ ids,
3287
+ vectorizeDistanceThreshold ?? 2,
3288
+ simplifyDistanceThreshold ?? 4,
3289
+ useExistingShapeInformation ?? true
3290
+ );
3291
+ }
3292
+ createCutoutFromOperation(ids, op) {
3293
+ return this.#engine.createCutoutFromOperation(ids, op);
3294
+ }
3295
+ createCutoutFromPath(pathData) {
3296
+ return this.#engine.createCutoutFromPath(pathData);
3297
+ }
3298
+ /** @deprecated Use `generateVideoThumbnailSequence` instead. */
3299
+ async getVideoFillThumbnail(id, thumbnailHeight) {
3300
+ const data = await this.#engine.getVideoFillThumbnail(id, thumbnailHeight);
3301
+ return new Blob([data], { type: "image/jpeg" });
3302
+ }
3303
+ /** @deprecated Use `generateVideoThumbnailSequence` instead. */
3304
+ async getVideoFillThumbnailAtlas(id, numberOfColumns, numberOfRows, thumbnailHeight) {
3305
+ const data = await this.#engine.getVideoFillThumbnailAtlas(
3306
+ id,
3307
+ numberOfColumns,
3308
+ numberOfRows,
3309
+ thumbnailHeight
3310
+ );
3311
+ return new Blob([data], { type: "image/jpeg" });
3312
+ }
3313
+ /** @deprecated */
3314
+ async getPageThumbnailAtlas(id, numberOfColumns, numberOfRows, thumbnailHeight) {
3315
+ const data = await this.#engine.getPageThumbnailAtlas(
3316
+ id,
3317
+ numberOfColumns,
3318
+ numberOfRows,
3319
+ thumbnailHeight
3320
+ );
3321
+ return new Blob([data], { type: "image/jpeg" });
3322
+ }
3323
+ unstable_isAVResourceLoaded(id) {
3324
+ return this.#engine.unstable_isAVResourceLoaded(id);
3325
+ }
3326
+ referencesAnyVariables(id) {
3327
+ return this.#engine.referencesAnyVariables(id);
3328
+ }
3329
+ /** @deprecated Use `getColor`. */
3330
+ getColorSpotName(id, property) {
3331
+ return this.#engine.getColorSpotName(id, property);
3332
+ }
3333
+ /** @deprecated Use `getColor`. */
3334
+ getColorSpotTint(id, property) {
3335
+ return this.#engine.getColorSpotTint(id, property);
3336
+ }
3337
+ /** @deprecated Use `setColor`. */
3338
+ setColorSpot(id, property, name, tint = 1) {
3339
+ this.#engine.setColorSpot(id, property, name, tint);
3340
+ }
3341
+ setState(id, state) {
3342
+ this.#engine.setState(id, state);
3343
+ }
3344
+ canRevertToOriginalRatio(id) {
3345
+ return this.#engine.canRevertToOriginalRatio(id);
3346
+ }
3347
+ getFillOverprint(id) {
3348
+ return this.#engine.getFillOverprint(id);
3349
+ }
3350
+ setFillOverprint(id, overprint) {
3351
+ this.#engine.setFillOverprint(id, overprint);
3352
+ }
3353
+ getStrokeOverprint(id) {
3354
+ return this.#engine.getStrokeOverprint(id);
3355
+ }
3356
+ setStrokeOverprint(id, overprint) {
3357
+ this.#engine.setStrokeOverprint(id, overprint);
3358
+ }
3359
+ getDominantColors(handle, options) {
3360
+ return this.#engine.getDominantColors(handle, options);
3361
+ }
3362
+ getTextRuns(id, from, to) {
3363
+ const runs = this.#engine.getTextRuns(
3364
+ id,
3365
+ from ?? -1,
3366
+ to ?? -1
3367
+ );
3368
+ return runs.map((run) => ({
3369
+ ...run,
3370
+ color: NativeColorInternal.toColor(run.color)
3371
+ }));
3372
+ }
3373
+ #currentPage() {
3374
+ const scene = this.#engine.findByType("scene")[0];
3375
+ if (scene == null) return null;
3376
+ return this.#engine.getCurrentPage(scene);
3377
+ }
3378
+ getBackgroundTrack() {
3379
+ const page = this.#currentPage();
3380
+ if (page == null) return null;
3381
+ const tracks = this.#engine.findByType("track");
3382
+ return tracks.find((track) => this.#engine.isPageDurationSource(track)) ?? null;
3383
+ }
3384
+ moveToBackgroundTrack(block) {
3385
+ let backgroundTrack = this.getBackgroundTrack();
3386
+ if (backgroundTrack == null) {
3387
+ const page = this.#currentPage();
3388
+ if (page == null) {
3389
+ throw new Error("No current page found");
3390
+ }
3391
+ backgroundTrack = this.#engine.create("//ly.img.ubq/track");
3392
+ this.#engine.appendChild(page, backgroundTrack);
3393
+ this.#engine.setAlwaysOnBottom(backgroundTrack, true);
3394
+ if (this.#engine.supportsPageDurationSource(page, backgroundTrack)) {
3395
+ this.#engine.setPageDurationSource(page, backgroundTrack);
3396
+ }
3397
+ }
3398
+ this.#engine.appendChild(backgroundTrack, block);
3399
+ }
3400
+ /**
3401
+ * Generates a sequence of video thumbnails; `onFrame` is called per frame.
3402
+ * Node has no `ImageData`, so each frame is a raw RGBA `{ data, width,
3403
+ * height }` (see `ThumbnailFrame`).
3404
+ */
3405
+ generateVideoThumbnailSequence(id, thumbnailHeight, timeBegin, timeEnd, numberOfFrames, onFrame) {
3406
+ const handle = this.#engine.generateVideoThumbnailSequence(
3407
+ id,
3408
+ thumbnailHeight,
3409
+ timeBegin,
3410
+ timeEnd,
3411
+ numberOfFrames,
3412
+ (err, frame) => {
3413
+ if (err) {
3414
+ onFrame(0, err);
3415
+ return;
3416
+ }
3417
+ onFrame(frame.frameIndex, {
3418
+ data: new Uint8ClampedArray(frame.data),
3419
+ width: frame.width,
3420
+ height: frame.height
3421
+ });
3422
+ }
3423
+ );
3424
+ return () => this.#engine.cancelVideoThumbnailSequenceGeneration(handle);
3425
+ }
3426
+ /**
3427
+ * Generates a sequence of audio waveform sample chunks. `onChunk` is called
3428
+ * per chunk with a `Float32Array` of samples (matching @cesdk/node).
3429
+ */
3430
+ generateAudioThumbnailSequence(id, samplesPerChunk, timeBegin, timeEnd, numberOfSamples, numberOfChannels, onChunk) {
3431
+ const handle = this.#engine.generateAudioThumbnailSequence(
3432
+ id,
3433
+ samplesPerChunk,
3434
+ timeBegin,
3435
+ timeEnd,
3436
+ numberOfSamples,
3437
+ numberOfChannels,
3438
+ (err, chunk) => {
3439
+ if (err) {
3440
+ onChunk(0, err);
3441
+ return;
3442
+ }
3443
+ onChunk(chunk.chunkIndex, Float32Array.from(chunk.samples));
3444
+ }
3445
+ );
3446
+ return () => this.#engine.cancelAudioThumbnailSequenceGeneration(handle);
3447
+ }
3150
3448
  };
3151
3449
  var SceneAPI = class {
3152
3450
  #engine;
@@ -3286,22 +3584,26 @@ var SceneAPI = class {
3286
3584
  waitForResources
3287
3585
  );
3288
3586
  }
3289
- /**
3290
- * Serializes the current scene into a string.
3291
- *
3292
- * Optionally accepts a `compression` option to apply Zstd compression to
3293
- * the output. When compression is enabled the returned string contains
3294
- * raw compressed bytes (not base64) — pass it back to `loadFromString`
3295
- * to round-trip.
3296
- *
3297
- * @returns A promise that resolves with the serialized scene.
3298
- */
3299
- async saveToString(options) {
3587
+ async saveToString(allowedResourceSchemesOrOptions, onDisallowedResourceSchemeParam) {
3300
3588
  const scene = this.get();
3301
3589
  if (scene === null) {
3302
3590
  throw new Error("No scene available.");
3303
3591
  }
3304
- return this.#engine.saveSceneToString(scene, options);
3592
+ const isOldStyle = Array.isArray(allowedResourceSchemesOrOptions);
3593
+ const options = isOldStyle ? {
3594
+ allowedResourceSchemes: allowedResourceSchemesOrOptions,
3595
+ onDisallowedResourceScheme: onDisallowedResourceSchemeParam
3596
+ } : allowedResourceSchemesOrOptions ?? {};
3597
+ const onDisallowedResourceScheme = options.onDisallowedResourceScheme;
3598
+ const persistenceCallback = onDisallowedResourceScheme ? async (url, dataHash, invoke) => {
3599
+ const persistedUrl = await onDisallowedResourceScheme(url, dataHash);
3600
+ invoke(url, persistedUrl);
3601
+ } : void 0;
3602
+ return this.#engine.saveSceneToString(scene, {
3603
+ resourceSchemesAllowed: options.allowedResourceSchemes,
3604
+ persistenceCallback,
3605
+ compression: options.compression
3606
+ });
3305
3607
  }
3306
3608
  /**
3307
3609
  * Saves the current scene and all of its referenced assets into an archive.
@@ -3499,8 +3801,8 @@ var SceneAPI = class {
3499
3801
  * @returns The current page in the scene or null when there is no scene
3500
3802
  * available or no current page is set.
3501
3803
  */
3502
- getCurrentPage(scene) {
3503
- const sceneId = scene ?? this.get();
3804
+ getCurrentPage() {
3805
+ const sceneId = this.get();
3504
3806
  if (sceneId === null) {
3505
3807
  return null;
3506
3808
  }
@@ -3619,15 +3921,6 @@ var SceneAPI = class {
3619
3921
  );
3620
3922
  }
3621
3923
  }
3622
- /**
3623
- * Continually adjust the zoom level to fit the block's bounding box on the
3624
- * chosen axis. For 'Horizontal'/'Vertical', the second/third arguments are
3625
- * `paddingBefore`/`paddingAfter` along that axis. For 'Both' the four
3626
- * arguments map to left/top/right/bottom.
3627
- *
3628
- * @param id - The block to follow.
3629
- * @param axis - 'Horizontal' | 'Vertical' | 'Both'.
3630
- */
3631
3924
  enableZoomAutoFit(id, axis, paddingBeforeOrLeft = 0, paddingAfterOrTop = 0, paddingRight = 0, paddingBottom = 0) {
3632
3925
  if (axis === "Horizontal") {
3633
3926
  this.#engine.enableZoomAutoFit(
@@ -3693,15 +3986,13 @@ var SceneAPI = class {
3693
3986
  scaledPaddingBottom
3694
3987
  );
3695
3988
  }
3696
- unstable_disableCameraPositionClamping(block) {
3697
- const target = block ?? this.get();
3698
- if (target == null) throw new Error("No scene available.");
3699
- this.#engine.unstable_disableCameraPositionClamping(target);
3989
+ unstable_disableCameraPositionClamping(blockOrScene = this.get()) {
3990
+ if (blockOrScene == null) throw new Error("No scene available.");
3991
+ this.#engine.unstable_disableCameraPositionClamping(blockOrScene);
3700
3992
  }
3701
- unstable_isCameraPositionClampingEnabled(block) {
3702
- const target = block ?? this.get();
3703
- if (target == null) throw new Error("No scene available.");
3704
- return this.#engine.unstable_isCameraPositionClampingEnabled(target);
3993
+ unstable_isCameraPositionClampingEnabled(blockOrScene = this.get()) {
3994
+ if (blockOrScene == null) throw new Error("No scene available.");
3995
+ return this.#engine.unstable_isCameraPositionClampingEnabled(blockOrScene);
3705
3996
  }
3706
3997
  /**
3707
3998
  * Continually clamp the camera zoom level to the range
@@ -3720,15 +4011,13 @@ var SceneAPI = class {
3720
4011
  paddingBottom
3721
4012
  );
3722
4013
  }
3723
- unstable_disableCameraZoomClamping(block) {
3724
- const target = block ?? this.get();
3725
- if (target == null) throw new Error("No scene available.");
3726
- this.#engine.unstable_disableCameraZoomClamping(target);
4014
+ unstable_disableCameraZoomClamping(blockOrScene = this.get()) {
4015
+ if (blockOrScene == null) throw new Error("No scene available.");
4016
+ this.#engine.unstable_disableCameraZoomClamping(blockOrScene);
3727
4017
  }
3728
- unstable_isCameraZoomClampingEnabled(block) {
3729
- const target = block ?? this.get();
3730
- if (target == null) throw new Error("No scene available.");
3731
- return this.#engine.unstable_isCameraZoomClampingEnabled(target);
4018
+ unstable_isCameraZoomClampingEnabled(blockOrScene = this.get()) {
4019
+ if (blockOrScene == null) throw new Error("No scene available.");
4020
+ return this.#engine.unstable_isCameraZoomClampingEnabled(blockOrScene);
3732
4021
  }
3733
4022
  /**
3734
4023
  * Subscribe to zoom-level changes.
@@ -3757,8 +4046,8 @@ var EditorAPI = class {
3757
4046
  getEditMode() {
3758
4047
  return this.#engine.getEditMode();
3759
4048
  }
3760
- setEditMode(mode) {
3761
- this.#engine.setEditMode(mode);
4049
+ setEditMode(mode, baseMode) {
4050
+ this.#engine.setEditMode(mode, baseMode ?? "");
3762
4051
  }
3763
4052
  /**
3764
4053
  * Returns the JWT string of the currently active license. An empty string
@@ -3784,7 +4073,6 @@ var EditorAPI = class {
3784
4073
  unlockWithLicense(license) {
3785
4074
  this.#engine.unlockWithLicense(license);
3786
4075
  }
3787
- // Settings
3788
4076
  getSettingBool(key) {
3789
4077
  const settingType = this.getSettingType(key);
3790
4078
  if (settingType !== "Bool") {
@@ -3840,12 +4128,12 @@ var EditorAPI = class {
3840
4128
  findAllSettings() {
3841
4129
  return this.#engine.findAllSettings();
3842
4130
  }
3843
- getSettingType(key) {
4131
+ getSettingType(keypath) {
3844
4132
  const allSettings = this.#engine.findAllSettings();
3845
- if (!allSettings.includes(key)) {
3846
- throw new Error(`Setting '${key}' does not exist`);
4133
+ if (!allSettings.includes(keypath)) {
4134
+ throw new Error(`Setting '${keypath}' does not exist`);
3847
4135
  }
3848
- return this.#engine.getSettingType(key);
4136
+ return this.#engine.getSettingType(keypath);
3849
4137
  }
3850
4138
  getSettingEnumOptions(key) {
3851
4139
  return this.#engine.getSettingEnumOptions(key);
@@ -3854,25 +4142,38 @@ var EditorAPI = class {
3854
4142
  * Generic setting getter that dispatches to the typed getter based on
3855
4143
  * `getSettingType`.
3856
4144
  */
3857
- getSetting(key) {
4145
+ getSetting(keypath) {
4146
+ const key = keypath;
3858
4147
  const settingType = this.getSettingType(key);
3859
4148
  switch (settingType) {
3860
4149
  case "Bool":
3861
- return this.#engine.getSettingBool(key);
4150
+ return this.#engine.getSettingBool(
4151
+ key
4152
+ );
3862
4153
  case "Int":
3863
- return this.#engine.getSettingInt(key);
4154
+ return this.#engine.getSettingInt(
4155
+ key
4156
+ );
3864
4157
  case "Float":
3865
- return this.#engine.getSettingFloat(key);
4158
+ return this.#engine.getSettingFloat(
4159
+ key
4160
+ );
3866
4161
  case "String":
3867
- return this.#engine.getSettingString(key);
4162
+ return this.#engine.getSettingString(
4163
+ key
4164
+ );
3868
4165
  case "Color": {
3869
4166
  const internalColor = this.#engine.getSettingColor(
3870
4167
  key
3871
4168
  );
3872
- return NativeColorInternal.toColor(internalColor);
4169
+ return NativeColorInternal.toColor(
4170
+ internalColor
4171
+ );
3873
4172
  }
3874
4173
  case "Enum":
3875
- return this.#engine.getSettingEnum(key);
4174
+ return this.#engine.getSettingEnum(
4175
+ key
4176
+ );
3876
4177
  default:
3877
4178
  throw new Error(
3878
4179
  `Unknown setting type for key '${key}': ${settingType}`
@@ -3883,7 +4184,8 @@ var EditorAPI = class {
3883
4184
  * Generic setting setter — dispatches to the typed setter via
3884
4185
  * `getSettingType`.
3885
4186
  */
3886
- setSetting(key, value) {
4187
+ setSetting(keypath, value) {
4188
+ const key = keypath;
3887
4189
  const settingType = this.getSettingType(key);
3888
4190
  switch (settingType) {
3889
4191
  case "Bool":
@@ -3899,7 +4201,9 @@ var EditorAPI = class {
3899
4201
  this.#engine.setSettingString(key, value);
3900
4202
  return;
3901
4203
  case "Color": {
3902
- const internalColor = NativeColorInternal.fromColor(value);
4204
+ const internalColor = NativeColorInternal.fromColor(
4205
+ value
4206
+ );
3903
4207
  this.#engine.setSettingColor(key, internalColor);
3904
4208
  return;
3905
4209
  }
@@ -3962,10 +4266,10 @@ var EditorAPI = class {
3962
4266
  // Safe area insets
3963
4267
  setSafeAreaInsets(insets) {
3964
4268
  this.#engine.setSafeAreaInsets(
3965
- insets.left,
3966
- insets.top,
3967
- insets.right,
3968
- insets.bottom
4269
+ insets.left ?? 0,
4270
+ insets.top ?? 0,
4271
+ insets.right ?? 0,
4272
+ insets.bottom ?? 0
3969
4273
  );
3970
4274
  }
3971
4275
  getSafeAreaInsets() {
@@ -3978,21 +4282,21 @@ var EditorAPI = class {
3978
4282
  getAvailableMemory() {
3979
4283
  return this.#engine.getAvailableMemory();
3980
4284
  }
3981
- // Color
3982
4285
  convertColorToColorSpace(color, colorSpace) {
3983
4286
  const internalColor = NativeColorInternal.fromColor(color);
3984
4287
  let colorSpaceNum;
3985
- if (colorSpace === "sRGB") {
3986
- colorSpaceNum = 0 /* sRGB */;
3987
- } else if (colorSpace === "CMYK") {
3988
- colorSpaceNum = 1 /* CMYK */;
3989
- } else if (colorSpace === "SpotColor") {
3990
- colorSpaceNum = 2 /* SpotColor */;
3991
- } else {
3992
- colorSpaceNum = parseInt(colorSpace, 10);
3993
- if (Number.isNaN(colorSpaceNum)) {
3994
- throw new Error(`Unknown color space: ${colorSpace}`);
3995
- }
4288
+ switch (colorSpace) {
4289
+ case "sRGB":
4290
+ colorSpaceNum = 0 /* sRGB */;
4291
+ break;
4292
+ case "CMYK":
4293
+ colorSpaceNum = 1 /* CMYK */;
4294
+ break;
4295
+ case "SpotColor":
4296
+ colorSpaceNum = 2 /* SpotColor */;
4297
+ break;
4298
+ default:
4299
+ throw new Error(`Unknown color space: ${String(colorSpace)}`);
3996
4300
  }
3997
4301
  const resultInternal = this.#engine.convertColorToColorSpace(
3998
4302
  internalColor,
@@ -4080,49 +4384,118 @@ var EditorAPI = class {
4080
4384
  /**
4081
4385
  * List all transient (in-engine) resources — typically `buffer://` URIs
4082
4386
  * created by importers (psd, pdf, idml) before they're uploaded to a
4083
- * permanent location. Each entry is `{ uri, size }`.
4387
+ * permanent location. Each entry is `{ URL, size }`, matching `@cesdk/node`.
4084
4388
  *
4085
- * Note: WASM uses `URL` as the key name; consumers that target both
4086
- * bindings should accept either (see e.g. psd-importer's
4087
- * `transient-resource-relocation.test.ts`).
4389
+ * @category Resource Management
4390
+ * @returns The URLs and sizes of transient resources.
4088
4391
  */
4089
4392
  findAllTransientResources() {
4090
4393
  return this.#engine.findAllTransientResources();
4091
4394
  }
4395
+ /**
4396
+ * Reads a resource's bytes in chunks. `onData` is called per chunk with a
4397
+ * `Uint8Array`; return `false` to stop early. Returns once fully streamed.
4398
+ *
4399
+ * @category Resource Management
4400
+ * @param uri - The URL of the resource.
4401
+ * @param chunkSize - Size in bytes of each chunk passed to `onData`.
4402
+ * @param onData - Called with each chunk; return `false` to stop.
4403
+ */
4404
+ getResourceData(uri, chunkSize, onData) {
4405
+ this.#engine.getResourceData(uri, chunkSize, onData);
4406
+ }
4407
+ // --- Parity additions on the editor namespace ---
4408
+ getMaxExportSize() {
4409
+ return this.#engine.getMaxExportSize();
4410
+ }
4411
+ unstable_isInteractionHappening() {
4412
+ return this.#engine.unstable_isInteractionHappening();
4413
+ }
4414
+ isHighlightingEnabled(id) {
4415
+ return this.#engine.isHighlightingEnabled(id);
4416
+ }
4417
+ setHighlightingEnabled(id, enabled) {
4418
+ this.#engine.setHighlightingEnabled(id, enabled);
4419
+ }
4420
+ isSelectionEnabled(id) {
4421
+ return this.#engine.isSelectionEnabled(id);
4422
+ }
4423
+ setSelectionEnabled(id, enabled) {
4424
+ this.#engine.setSelectionEnabled(id, enabled);
4425
+ }
4426
+ getTextCursorPositionInScreenSpaceX() {
4427
+ return this.#engine.getTextCursorPositionInScreenSpaceX();
4428
+ }
4429
+ getTextCursorPositionInScreenSpaceY() {
4430
+ return this.#engine.getTextCursorPositionInScreenSpaceY();
4431
+ }
4432
+ getSpotColorForCutoutType(type) {
4433
+ return this.#engine.getSpotColorForCutoutType(type);
4434
+ }
4435
+ setSpotColorForCutoutType(type, color) {
4436
+ this.#engine.setSpotColorForCutoutType(type, color);
4437
+ }
4438
+ /** @deprecated Use `getSettingColor` instead. */
4439
+ getSettingColorRGBA(keypath) {
4440
+ const c = this.#engine.getSettingColorRGBA(keypath);
4441
+ return [c.r, c.g, c.b, c.a];
4442
+ }
4443
+ /** @deprecated Use `setSettingColor` instead. */
4444
+ setSettingColorRGBA(keypath, r, g, b, a = 1) {
4445
+ this.#engine.setSettingColorRGBA(keypath, r, g, b, a);
4446
+ }
4447
+ // --- Vector edit mode (operates on the interactively selected node/path) ---
4448
+ addVectorNode() {
4449
+ this.#engine.addVectorNode();
4450
+ }
4451
+ deleteVectorNode() {
4452
+ this.#engine.deleteVectorNode();
4453
+ }
4454
+ deleteSelectedVectorControlPoints() {
4455
+ this.#engine.deleteSelectedVectorControlPoints();
4456
+ }
4457
+ getSelectedVectorNodeMirrorMode() {
4458
+ return this.#engine.getSelectedVectorNodeMirrorMode();
4459
+ }
4460
+ setSelectedVectorNodeMirrorMode(mode) {
4461
+ this.#engine.setSelectedVectorNodeMirrorMode(mode);
4462
+ }
4463
+ getVectorEditAddMode() {
4464
+ return this.#engine.getVectorEditAddMode();
4465
+ }
4466
+ setVectorEditAddMode(active) {
4467
+ this.#engine.setVectorEditAddMode(active);
4468
+ }
4469
+ getVectorEditBendMode() {
4470
+ return this.#engine.getVectorEditBendMode();
4471
+ }
4472
+ setVectorEditBendMode(active) {
4473
+ this.#engine.setVectorEditBendMode(active);
4474
+ }
4475
+ getVectorEditDeleteMode() {
4476
+ return this.#engine.getVectorEditDeleteMode();
4477
+ }
4478
+ setVectorEditDeleteMode(active) {
4479
+ this.#engine.setVectorEditDeleteMode(active);
4480
+ }
4481
+ hasSelectedVectorNode() {
4482
+ return this.#engine.hasSelectedVectorNode();
4483
+ }
4484
+ hasSelectedVectorControlPoint() {
4485
+ return this.#engine.hasSelectedVectorControlPoint();
4486
+ }
4487
+ toggleSelectedVectorNodeSmooth() {
4488
+ this.#engine.toggleSelectedVectorNodeSmooth();
4489
+ }
4092
4490
  // Spot colors
4093
4491
  findAllSpotColors() {
4094
4492
  return this.#engine.findAllSpotColors();
4095
4493
  }
4096
4494
  getSpotColorRGBA(name) {
4097
- const result = this.#engine.getSpotColorRGB(name);
4098
- const tuple = Array.isArray(result) ? result.slice(0, 4) : [
4099
- result.r,
4100
- result.g,
4101
- result.b,
4102
- result.a
4103
- ];
4104
- const rgba = tuple;
4105
- rgba.r = tuple[0];
4106
- rgba.g = tuple[1];
4107
- rgba.b = tuple[2];
4108
- rgba.a = tuple[3];
4109
- return rgba;
4495
+ return this.#engine.getSpotColorRGB(name);
4110
4496
  }
4111
4497
  getSpotColorCMYK(name) {
4112
- const result = this.#engine.getSpotColorCMYK(name);
4113
- const tuple = Array.isArray(result) ? result.slice(0, 4) : [
4114
- result.c,
4115
- result.m,
4116
- result.y,
4117
- result.k
4118
- ];
4119
- const cmyk = tuple;
4120
- cmyk.c = tuple[0];
4121
- cmyk.m = tuple[1];
4122
- cmyk.y = tuple[2];
4123
- cmyk.k = tuple[3];
4124
- cmyk.tint = !Array.isArray(result) && result.tint !== void 0 ? result.tint : 1;
4125
- return cmyk;
4498
+ return this.#engine.getSpotColorCMYK(name);
4126
4499
  }
4127
4500
  setSpotColorRGB(name, r, g, b) {
4128
4501
  this.#engine.setSpotColorRGB(name, r, g, b);
@@ -4258,7 +4631,9 @@ var EditorAPI = class {
4258
4631
  * @returns A function that unsubscribes when called.
4259
4632
  */
4260
4633
  onRoleChanged(callback) {
4261
- const id = this.#engine.subscribeToRoleChange(callback);
4634
+ const id = this.#engine.subscribeToRoleChange(
4635
+ (role) => callback(role)
4636
+ );
4262
4637
  return () => this.#engine.unsubscribe(id);
4263
4638
  }
4264
4639
  // Buffer management (matching WASM/Android EditorAPI)
@@ -4407,17 +4782,25 @@ var AssetAPI = class {
4407
4782
  }
4408
4783
  this.#engine.addLocalAssetSource(id, supportedMimeTypes ?? []);
4409
4784
  if (applyAsset != null) {
4410
- this.registerApplyMiddleware(id, async (asset, next) => {
4411
- const result = await applyAsset(asset);
4412
- if (result !== void 0) return result;
4413
- return next(asset);
4414
- });
4785
+ this.registerApplyMiddleware(
4786
+ async (sourceId, assetResult, apply, ctx) => {
4787
+ if (sourceId !== id) return apply(sourceId, assetResult, ctx);
4788
+ const result = await applyAsset(assetResult);
4789
+ if (result !== void 0) return result;
4790
+ return apply(sourceId, assetResult, ctx);
4791
+ }
4792
+ );
4415
4793
  }
4416
4794
  if (applyAssetToBlock != null) {
4417
- this.registerApplyToBlockMiddleware(id, async (asset, block, next) => {
4418
- await applyAssetToBlock(asset, block);
4419
- await next(asset, block);
4420
- });
4795
+ this.registerApplyToBlockMiddleware(
4796
+ async (sourceId, assetResult, block, applyToBlockNext) => {
4797
+ if (sourceId !== id) {
4798
+ return applyToBlockNext(sourceId, assetResult, block);
4799
+ }
4800
+ await applyAssetToBlock(assetResult, block);
4801
+ await applyToBlockNext(sourceId, assetResult, block);
4802
+ }
4803
+ );
4421
4804
  }
4422
4805
  }
4423
4806
  /**
@@ -4606,8 +4989,11 @@ var AssetAPI = class {
4606
4989
  // them through a TS-level middleware chain so registerApplyMiddleware /
4607
4990
  // registerApplyToBlockMiddleware work.
4608
4991
  // -------------------------------------------------------------------------
4609
- #applyMiddleware = /* @__PURE__ */ new Map();
4610
- #applyToBlockMiddleware = /* @__PURE__ */ new Map();
4992
+ // Global middleware sets, matching @cesdk/node's `AssetAPI`. Each middleware
4993
+ // gets the source id, the asset, and the `next` function so it can transform,
4994
+ // short-circuit, or defer to the rest of the chain.
4995
+ #applyAssetMiddlewares = /* @__PURE__ */ new Set();
4996
+ #applyAssetToBlockMiddlewares = /* @__PURE__ */ new Set();
4611
4997
  /**
4612
4998
  * Apply an asset to the current scene. Honors any middleware registered
4613
4999
  * via {@link registerApplyMiddleware} and falls back to
@@ -4615,16 +5001,17 @@ var AssetAPI = class {
4615
5001
  *
4616
5002
  * @public
4617
5003
  */
4618
- async apply(sourceId, asset) {
4619
- const tail = (a) => this.defaultApplyAsset(a);
4620
- const middlewares = this.#applyMiddleware.get(sourceId) ?? [];
4621
- let next = tail;
4622
- for (let i = middlewares.length - 1; i >= 0; i--) {
4623
- const mw = middlewares[i];
4624
- const prev = next;
4625
- next = (a) => mw(a, prev);
5004
+ async apply(sourceId, assetResult, options) {
5005
+ const context = { clipType: options?.clipType };
5006
+ const original = (id, asset) => this.defaultApplyAsset(asset);
5007
+ if (this.#applyAssetMiddlewares.size > 0) {
5008
+ const applyAsset = Array.from(this.#applyAssetMiddlewares).reduce(
5009
+ (next, middleware) => (id, asset) => middleware(id, asset, next, context),
5010
+ original
5011
+ );
5012
+ return applyAsset(sourceId, assetResult);
4626
5013
  }
4627
- return next(asset);
5014
+ return original(sourceId, assetResult);
4628
5015
  }
4629
5016
  /**
4630
5017
  * Apply an asset to a specific block. Honors any middleware registered
@@ -4633,16 +5020,18 @@ var AssetAPI = class {
4633
5020
  *
4634
5021
  * @public
4635
5022
  */
4636
- async applyToBlock(sourceId, asset, block) {
4637
- const tail = (a, b) => this.defaultApplyAssetToBlock(a, b);
4638
- const middlewares = this.#applyToBlockMiddleware.get(sourceId) ?? [];
4639
- let next = tail;
4640
- for (let i = middlewares.length - 1; i >= 0; i--) {
4641
- const mw = middlewares[i];
4642
- const prev = next;
4643
- next = (a, b) => mw(a, b, prev);
5023
+ async applyToBlock(sourceId, assetResult, block) {
5024
+ const original = (id, asset, blockId) => this.defaultApplyAssetToBlock(asset, blockId);
5025
+ if (this.#applyAssetToBlockMiddlewares.size > 0) {
5026
+ const applyToBlock = Array.from(
5027
+ this.#applyAssetToBlockMiddlewares
5028
+ ).reduce(
5029
+ (next, middleware) => (id, asset, blockId) => middleware(id, asset, blockId, next),
5030
+ original
5031
+ );
5032
+ return applyToBlock(sourceId, assetResult, block);
4644
5033
  }
4645
- return next(asset, block);
5034
+ return original(sourceId, assetResult, block);
4646
5035
  }
4647
5036
  /**
4648
5037
  * Apply a property change from an asset payload.
@@ -4650,7 +5039,11 @@ var AssetAPI = class {
4650
5039
  * @public
4651
5040
  */
4652
5041
  async applyProperty(sourceId, asset, property) {
4653
- return this.#engine.applyAssetSourceProperty(sourceId, asset, property);
5042
+ return this.#engine.applyAssetSourceProperty(
5043
+ sourceId,
5044
+ asset,
5045
+ property
5046
+ );
4654
5047
  }
4655
5048
  /**
4656
5049
  * Default apply-asset implementation (no middleware). Calls the engine's
@@ -4660,7 +5053,9 @@ var AssetAPI = class {
4660
5053
  * @public
4661
5054
  */
4662
5055
  async defaultApplyAsset(asset) {
4663
- const result = await this.#engine.defaultApplyAsset(asset);
5056
+ const result = await this.#engine.defaultApplyAsset(
5057
+ asset
5058
+ );
4664
5059
  return result === -1 || result == null ? void 0 : result;
4665
5060
  }
4666
5061
  /**
@@ -4670,31 +5065,36 @@ var AssetAPI = class {
4670
5065
  * @public
4671
5066
  */
4672
5067
  async defaultApplyAssetToBlock(asset, block) {
4673
- await this.#engine.defaultApplyAssetToBlock(asset, block);
5068
+ await this.#engine.defaultApplyAssetToBlock(
5069
+ asset,
5070
+ block
5071
+ );
4674
5072
  }
4675
5073
  /**
4676
- * Register a middleware in the apply-asset chain for a source.
5074
+ * Register a middleware in the global apply-asset chain, matching
5075
+ * `@cesdk/node`'s `registerApplyMiddleware`. Returns a function that
5076
+ * unregisters it.
4677
5077
  *
4678
- * @param sourceId - The source to install the middleware on.
4679
- * @param middleware - Callable that may consume the asset, defer to
4680
- * the next middleware, or short-circuit. Returns the created block id
4681
- * (or undefined to fall through).
4682
5078
  * @public
4683
5079
  */
4684
- registerApplyMiddleware(sourceId, middleware) {
4685
- const arr = this.#applyMiddleware.get(sourceId) ?? [];
4686
- arr.push(middleware);
4687
- this.#applyMiddleware.set(sourceId, arr);
5080
+ registerApplyMiddleware(middleware) {
5081
+ this.#applyAssetMiddlewares.add(middleware);
5082
+ return () => {
5083
+ this.#applyAssetMiddlewares.delete(middleware);
5084
+ };
4688
5085
  }
4689
5086
  /**
4690
- * Register a middleware in the apply-asset-to-block chain for a source.
5087
+ * Register a middleware in the global apply-asset-to-block chain. Mirrors
5088
+ * `@cesdk/node`'s `registerApplyToBlockMiddleware`. Returns a function that
5089
+ * unregisters it.
4691
5090
  *
4692
5091
  * @public
4693
5092
  */
4694
- registerApplyToBlockMiddleware(sourceId, middleware) {
4695
- const arr = this.#applyToBlockMiddleware.get(sourceId) ?? [];
4696
- arr.push(middleware);
4697
- this.#applyToBlockMiddleware.set(sourceId, arr);
5093
+ registerApplyToBlockMiddleware(middleware) {
5094
+ this.#applyAssetToBlockMiddlewares.add(middleware);
5095
+ return () => {
5096
+ this.#applyAssetToBlockMiddlewares.delete(middleware);
5097
+ };
4698
5098
  }
4699
5099
  /**
4700
5100
  * Whether the named source supports `addAssetToSource` /
@@ -4716,7 +5116,7 @@ var AssetAPI = class {
4716
5116
  }
4717
5117
  }
4718
5118
  };
4719
- var _version = true ? "1.77.0" : "0.0.0";
5119
+ var _version = true ? "1.77.1" : "0.0.0";
4720
5120
  var CreativeEngine = class _CreativeEngine {
4721
5121
  constructor(engine) {
4722
5122
  this.version = _CreativeEngine.version;
@@ -4729,6 +5129,9 @@ var CreativeEngine = class _CreativeEngine {
4729
5129
  this.event = new EventAPI(engine);
4730
5130
  this.scene = new SceneAPI(engine);
4731
5131
  this.variable = new VariableAPI(engine);
5132
+ this.actions = new EngineActions(
5133
+ engine
5134
+ );
4732
5135
  this.#startUpdateLoop();
4733
5136
  }
4734
5137
  static {
@@ -4767,6 +5170,7 @@ var CreativeEngine = class _CreativeEngine {
4767
5170
  */
4768
5171
  dispose() {
4769
5172
  this.#stopUpdateLoop();
5173
+ this.actions.dispose();
4770
5174
  this.#engine.dispose();
4771
5175
  this.#engine = null;
4772
5176
  this.asset = null;
@@ -4775,6 +5179,7 @@ var CreativeEngine = class _CreativeEngine {
4775
5179
  this.event = null;
4776
5180
  this.scene = null;
4777
5181
  this.variable = null;
5182
+ this.actions = null;
4778
5183
  }
4779
5184
  /**
4780
5185
  * Initialize a CreativeEngine.
@@ -4828,8 +5233,11 @@ var CreativeEngine = class _CreativeEngine {
4828
5233
  * `${baseURL}/<source-id>/content.json` for each id in the default set
4829
5234
  * and registers the contents as a local asset source. baseURL defaults
4830
5235
  * to the engine's configured baseURL (`file://<addon>/assets/` if none
4831
- * was passed to init).
5236
+ * was passed to init), which does not bundle these sources, so pass a
5237
+ * `baseURL` to load them.
4832
5238
  *
5239
+ * @deprecated This method uses legacy v4 asset source IDs and will be removed in a future version.
5240
+ * Please migrate to v5 asset sources using engine.asset.addLocalAssetSourceFromJSONURI().
4833
5241
  * @public
4834
5242
  */
4835
5243
  async addDefaultAssetSources({
@@ -4855,6 +5263,8 @@ var CreativeEngine = class _CreativeEngine {
4855
5263
  * — accepts `sceneMode`, `withUploadAssetSources`, and the full demo
4856
5264
  * source-ID union (templates + textComponents + uploads + media).
4857
5265
  *
5266
+ * @deprecated This method uses legacy v3 demo asset source IDs and will be removed in a future version.
5267
+ * Please migrate to v4 asset sources using engine.asset.addLocalAssetSourceFromJSONURI().
4858
5268
  * @public
4859
5269
  */
4860
5270
  async addDemoAssetSources({