@zaflun/lumio-sdk 0.6.3 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -31,9 +31,9 @@
31
31
  mod
32
32
  ));
33
33
 
34
- // ../../node_modules/.pnpm/react@19.2.5/node_modules/react/cjs/react.production.js
34
+ // ../../node_modules/.pnpm/react@19.2.8/node_modules/react/cjs/react.production.js
35
35
  var require_react_production = __commonJS({
36
- "../../node_modules/.pnpm/react@19.2.5/node_modules/react/cjs/react.production.js"(exports$1) {
36
+ "../../node_modules/.pnpm/react@19.2.8/node_modules/react/cjs/react.production.js"(exports$1) {
37
37
  var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element");
38
38
  var REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal");
39
39
  var REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment");
@@ -467,22 +467,22 @@
467
467
  exports$1.useTransition = function() {
468
468
  return ReactSharedInternals.H.useTransition();
469
469
  };
470
- exports$1.version = "19.2.5";
470
+ exports$1.version = "19.2.8";
471
471
  }
472
472
  });
473
473
 
474
- // ../../node_modules/.pnpm/react@19.2.5/node_modules/react/index.js
474
+ // ../../node_modules/.pnpm/react@19.2.8/node_modules/react/index.js
475
475
  var require_react = __commonJS({
476
- "../../node_modules/.pnpm/react@19.2.5/node_modules/react/index.js"(exports$1, module) {
476
+ "../../node_modules/.pnpm/react@19.2.8/node_modules/react/index.js"(exports$1, module) {
477
477
  {
478
478
  module.exports = require_react_production();
479
479
  }
480
480
  }
481
481
  });
482
482
 
483
- // ../../node_modules/.pnpm/react@19.2.5/node_modules/react/cjs/react-jsx-runtime.production.js
483
+ // ../../node_modules/.pnpm/react@19.2.8/node_modules/react/cjs/react-jsx-runtime.production.js
484
484
  var require_react_jsx_runtime_production = __commonJS({
485
- "../../node_modules/.pnpm/react@19.2.5/node_modules/react/cjs/react-jsx-runtime.production.js"(exports$1) {
485
+ "../../node_modules/.pnpm/react@19.2.8/node_modules/react/cjs/react-jsx-runtime.production.js"(exports$1) {
486
486
  var REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element");
487
487
  var REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment");
488
488
  function jsxProd(type, config2, maybeKey) {
@@ -509,9 +509,9 @@
509
509
  }
510
510
  });
511
511
 
512
- // ../../node_modules/.pnpm/react@19.2.5/node_modules/react/jsx-runtime.js
512
+ // ../../node_modules/.pnpm/react@19.2.8/node_modules/react/jsx-runtime.js
513
513
  var require_jsx_runtime = __commonJS({
514
- "../../node_modules/.pnpm/react@19.2.5/node_modules/react/jsx-runtime.js"(exports$1, module) {
514
+ "../../node_modules/.pnpm/react@19.2.8/node_modules/react/jsx-runtime.js"(exports$1, module) {
515
515
  {
516
516
  module.exports = require_react_jsx_runtime_production();
517
517
  }
@@ -799,9 +799,9 @@
799
799
  }
800
800
  });
801
801
 
802
- // ../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/cjs/react-dom.production.js
802
+ // ../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/cjs/react-dom.production.js
803
803
  var require_react_dom_production = __commonJS({
804
- "../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/cjs/react-dom.production.js"(exports$1) {
804
+ "../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/cjs/react-dom.production.js"(exports$1) {
805
805
  var React33 = require_react();
806
806
  function formatProdErrorMessage(code) {
807
807
  var url2 = "https://react.dev/errors/" + code;
@@ -943,13 +943,13 @@
943
943
  exports$1.useFormStatus = function() {
944
944
  return ReactSharedInternals.H.useHostTransitionStatus();
945
945
  };
946
- exports$1.version = "19.2.5";
946
+ exports$1.version = "19.2.8";
947
947
  }
948
948
  });
949
949
 
950
- // ../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/index.js
950
+ // ../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/index.js
951
951
  var require_react_dom = __commonJS({
952
- "../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/index.js"(exports$1, module) {
952
+ "../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/index.js"(exports$1, module) {
953
953
  function checkDCE() {
954
954
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined" || typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== "function") {
955
955
  return;
@@ -967,9 +967,9 @@
967
967
  }
968
968
  });
969
969
 
970
- // ../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/cjs/react-dom-client.production.js
970
+ // ../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/cjs/react-dom-client.production.js
971
971
  var require_react_dom_client_production = __commonJS({
972
- "../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/cjs/react-dom-client.production.js"(exports$1) {
972
+ "../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/cjs/react-dom-client.production.js"(exports$1) {
973
973
  var Scheduler = require_scheduler();
974
974
  var React33 = require_react();
975
975
  var ReactDOM = require_react_dom();
@@ -12608,12 +12608,12 @@
12608
12608
  }
12609
12609
  };
12610
12610
  var isomorphicReactPackageVersion$jscomp$inline_1840 = React33.version;
12611
- if ("19.2.5" !== isomorphicReactPackageVersion$jscomp$inline_1840)
12611
+ if ("19.2.8" !== isomorphicReactPackageVersion$jscomp$inline_1840)
12612
12612
  throw Error(
12613
12613
  formatProdErrorMessage(
12614
12614
  527,
12615
12615
  isomorphicReactPackageVersion$jscomp$inline_1840,
12616
- "19.2.5"
12616
+ "19.2.8"
12617
12617
  )
12618
12618
  );
12619
12619
  ReactDOMSharedInternals.findDOMNode = function(componentOrElement) {
@@ -12631,10 +12631,10 @@
12631
12631
  };
12632
12632
  var internals$jscomp$inline_2347 = {
12633
12633
  bundleType: 0,
12634
- version: "19.2.5",
12634
+ version: "19.2.8",
12635
12635
  rendererPackageName: "react-dom",
12636
12636
  currentDispatcherRef: ReactSharedInternals,
12637
- reconcilerVersion: "19.2.5"
12637
+ reconcilerVersion: "19.2.8"
12638
12638
  };
12639
12639
  if ("undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__) {
12640
12640
  hook$jscomp$inline_2348 = __REACT_DEVTOOLS_GLOBAL_HOOK__;
@@ -12702,13 +12702,13 @@
12702
12702
  listenToAllSupportedEvents(container);
12703
12703
  return new ReactDOMHydrationRoot(initialChildren);
12704
12704
  };
12705
- exports$1.version = "19.2.5";
12705
+ exports$1.version = "19.2.8";
12706
12706
  }
12707
12707
  });
12708
12708
 
12709
- // ../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/client.js
12709
+ // ../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/client.js
12710
12710
  var require_client = __commonJS({
12711
- "../../node_modules/.pnpm/react-dom@19.2.5_react@19.2.5/node_modules/react-dom/client.js"(exports$1, module) {
12711
+ "../../node_modules/.pnpm/react-dom@19.2.8_react@19.2.8/node_modules/react-dom/client.js"(exports$1, module) {
12712
12712
  function checkDCE() {
12713
12713
  if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === "undefined" || typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE !== "function") {
12714
12714
  return;
@@ -13007,9 +13007,9 @@
13007
13007
  }
13008
13008
  });
13009
13009
 
13010
- // ../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.5/node_modules/react-reconciler/cjs/react-reconciler.production.js
13010
+ // ../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.8/node_modules/react-reconciler/cjs/react-reconciler.production.js
13011
13011
  var require_react_reconciler_production = __commonJS({
13012
- "../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.5/node_modules/react-reconciler/cjs/react-reconciler.production.js"(exports$1, module) {
13012
+ "../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.8/node_modules/react-reconciler/cjs/react-reconciler.production.js"(exports$1, module) {
13013
13013
  module.exports = function($$$config) {
13014
13014
  function createFiber(tag, pendingProps, key, mode) {
13015
13015
  return new FiberNode(tag, pendingProps, key, mode);
@@ -20834,9 +20834,9 @@
20834
20834
  }
20835
20835
  });
20836
20836
 
20837
- // ../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.5/node_modules/react-reconciler/index.js
20837
+ // ../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.8/node_modules/react-reconciler/index.js
20838
20838
  var require_react_reconciler = __commonJS({
20839
- "../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.5/node_modules/react-reconciler/index.js"(exports$1, module) {
20839
+ "../../node_modules/.pnpm/react-reconciler@0.32.0_react@19.2.8/node_modules/react-reconciler/index.js"(exports$1, module) {
20840
20840
  {
20841
20841
  module.exports = require_react_reconciler_production();
20842
20842
  }
@@ -20901,6 +20901,7 @@
20901
20901
  useLumioTheme: () => useLumioTheme,
20902
20902
  useMutation: () => useMutation,
20903
20903
  useQuery: () => useQuery,
20904
+ useRealtime: () => useRealtime,
20904
20905
  useVisionState: () => useVisionState
20905
20906
  });
20906
20907
 
@@ -20909,6 +20910,15 @@
20909
20910
  var RENDER_TIMEOUT_MS = 1e4;
20910
20911
  var hasRendered = false;
20911
20912
  var renderTimeout = null;
20913
+ function hostOrigin() {
20914
+ try {
20915
+ if (typeof document !== "undefined" && document.referrer) {
20916
+ return new URL(document.referrer).origin;
20917
+ }
20918
+ } catch {
20919
+ }
20920
+ return "*";
20921
+ }
20912
20922
  function startRenderTimeout() {
20913
20923
  if (renderTimeout) return;
20914
20924
  renderTimeout = setTimeout(() => {
@@ -20922,7 +20932,7 @@
20922
20932
  code: "RENDER_TIMEOUT",
20923
20933
  message: "Extension did not render within 10 seconds"
20924
20934
  },
20925
- "*"
20935
+ hostOrigin()
20926
20936
  );
20927
20937
  }
20928
20938
  }, RENDER_TIMEOUT_MS);
@@ -20945,7 +20955,7 @@
20945
20955
  }
20946
20956
  const root = (0, import_client.createRoot)(rootElement);
20947
20957
  root.render(element);
20948
- window.parent.postMessage({ type: "READY" }, "*");
20958
+ window.parent.postMessage({ type: "READY" }, hostOrigin());
20949
20959
  }
20950
20960
  };
20951
20961
 
@@ -21297,6 +21307,7 @@
21297
21307
  // src/renderer/bridge-context.ts
21298
21308
  var bridgeInstance = null;
21299
21309
  var registryInstance = null;
21310
+ var initParams = null;
21300
21311
  function getBridge() {
21301
21312
  if (!bridgeInstance) {
21302
21313
  bridgeInstance = new WorkerBridge();
@@ -21309,6 +21320,15 @@
21309
21320
  }
21310
21321
  return registryInstance;
21311
21322
  }
21323
+ function setInitParams(params) {
21324
+ const rest = { ...params };
21325
+ delete rest.bundleCode;
21326
+ delete rest.bundleUrl;
21327
+ initParams = rest;
21328
+ }
21329
+ function getInitParams() {
21330
+ return initParams;
21331
+ }
21312
21332
  function destroyBridgeContext() {
21313
21333
  if (bridgeInstance) {
21314
21334
  bridgeInstance.destroy();
@@ -21318,6 +21338,7 @@
21318
21338
  registryInstance.clear();
21319
21339
  registryInstance = null;
21320
21340
  }
21341
+ initParams = null;
21321
21342
  }
21322
21343
 
21323
21344
  // src/hooks/useEditorAction.ts
@@ -21359,24 +21380,36 @@
21359
21380
  // ../protocol/dist/index.js
21360
21381
  var dist_exports = {};
21361
21382
  __export(dist_exports, {
21383
+ ACTION_EXECUTE_ERRORS: () => ACTION_EXECUTE_ERRORS,
21362
21384
  ACTION_TYPES: () => ACTION_TYPES,
21385
+ EXTENSION_RUNTIME_LABEL_PLACEHOLDER: () => EXTENSION_RUNTIME_LABEL_PLACEHOLDER,
21363
21386
  HOST_METHODS: () => HOST_METHODS,
21364
21387
  LUMIO_COMPONENT_TYPES: () => LUMIO_COMPONENT_TYPES,
21388
+ LUMIO_EVENT_PAYLOAD_SCHEMAS: () => LUMIO_EVENT_PAYLOAD_SCHEMAS,
21365
21389
  LUMIO_EVENT_TYPES: () => LUMIO_EVENT_TYPES,
21366
21390
  MESSAGE_TYPES: () => MESSAGE_TYPES,
21391
+ REALTIME_LIMITS: () => REALTIME_LIMITS,
21392
+ SERVER_FUNCTION_ERRORS: () => SERVER_FUNCTION_ERRORS,
21367
21393
  STORAGE_SCOPES: () => STORAGE_SCOPES,
21368
21394
  WORKER_METHODS: () => WORKER_METHODS,
21369
21395
  actionMessageSchema: () => actionMessageSchema,
21396
+ chatMessagePayloadSchema: () => chatMessagePayloadSchema,
21370
21397
  configUpdateMessageSchema: () => configUpdateMessageSchema,
21371
21398
  errorMessageSchema: () => errorMessageSchema,
21372
21399
  eventMessageSchema: () => eventMessageSchema,
21373
21400
  extensionConfigSchema: () => extensionConfigSchema,
21401
+ extensionRuntimeLabel: () => extensionRuntimeLabel,
21402
+ extensionRuntimeOrigin: () => extensionRuntimeOrigin,
21403
+ extensionRuntimeOriginLabel: () => extensionRuntimeOriginLabel,
21374
21404
  initMessageSchema: () => initMessageSchema,
21405
+ isValidExtensionRuntimeOriginTemplate: () => isValidExtensionRuntimeOriginTemplate,
21375
21406
  lumioActionTypeSchema: () => lumioActionTypeSchema,
21407
+ lumioEventPayloadSchema: () => lumioEventPayloadSchema,
21376
21408
  lumioEventTypeSchema: () => lumioEventTypeSchema,
21377
21409
  lumioMessageSchema: () => lumioMessageSchema,
21378
21410
  nodeConfigRequestMessageSchema: () => nodeConfigRequestMessageSchema,
21379
21411
  nodeConfigUpdateMessageSchema: () => nodeConfigUpdateMessageSchema,
21412
+ parseLumioEventPayload: () => parseLumioEventPayload,
21380
21413
  readyMessageSchema: () => readyMessageSchema,
21381
21414
  storageScopeSchema: () => storageScopeSchema,
21382
21415
  storageUpdateMessageSchema: () => storageUpdateMessageSchema,
@@ -21387,6 +21420,50 @@
21387
21420
  themeSchema: () => themeSchema
21388
21421
  });
21389
21422
 
21423
+ // ../protocol/dist/chunk-746VSR4E.js
21424
+ var EXTENSION_RUNTIME_LABEL_PLACEHOLDER = "{label}";
21425
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
21426
+ var LABEL_PATTERN = /^[0-9a-f]{32}$/;
21427
+ var DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
21428
+ var TEMPLATE_PATTERN = /^(https:\/\/|http:\/\/)\{label\}(\.[a-z0-9.-]+(?::[0-9]{1,5})?)$/;
21429
+ function parseTemplate(template) {
21430
+ const match = TEMPLATE_PATTERN.exec(template);
21431
+ if (!match) return null;
21432
+ const prefix = match[1];
21433
+ const suffix = match[2];
21434
+ const host = suffix.slice(1).replace(/:[0-9]+$/, "");
21435
+ if (prefix === "http://" && host !== "localhost") return null;
21436
+ if (!host.split(".").every((label) => DNS_LABEL_PATTERN.test(label))) return null;
21437
+ const sample = `${prefix}${"0".repeat(32)}${suffix}`;
21438
+ try {
21439
+ if (new URL(sample).origin !== sample) return null;
21440
+ } catch {
21441
+ return null;
21442
+ }
21443
+ return { prefix, suffix };
21444
+ }
21445
+ function extensionRuntimeLabel(extensionId) {
21446
+ if (typeof extensionId !== "string" || !UUID_PATTERN.test(extensionId)) return null;
21447
+ return extensionId.replaceAll("-", "");
21448
+ }
21449
+ function extensionRuntimeOrigin(extensionId, template) {
21450
+ const label = extensionRuntimeLabel(extensionId);
21451
+ if (!label) return null;
21452
+ const parsed = parseTemplate(template);
21453
+ if (!parsed) return null;
21454
+ return `${parsed.prefix}${label}${parsed.suffix}`;
21455
+ }
21456
+ function extensionRuntimeOriginLabel(origin, template) {
21457
+ const parsed = parseTemplate(template);
21458
+ if (!parsed) return null;
21459
+ if (!origin.startsWith(parsed.prefix) || !origin.endsWith(parsed.suffix)) return null;
21460
+ const label = origin.slice(parsed.prefix.length, origin.length - parsed.suffix.length);
21461
+ return LABEL_PATTERN.test(label) ? label : null;
21462
+ }
21463
+ function isValidExtensionRuntimeOriginTemplate(template) {
21464
+ return parseTemplate(template) !== null;
21465
+ }
21466
+
21390
21467
  // ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
21391
21468
  var external_exports = {};
21392
21469
  __export(external_exports, {
@@ -22170,14 +22247,14 @@
22170
22247
  }
22171
22248
  function randomString(length = 10) {
22172
22249
  const chars = "abcdefghijklmnopqrstuvwxyz";
22173
- let str = "";
22250
+ let str2 = "";
22174
22251
  for (let i = 0; i < length; i++) {
22175
- str += chars[Math.floor(Math.random() * chars.length)];
22252
+ str2 += chars[Math.floor(Math.random() * chars.length)];
22176
22253
  }
22177
- return str;
22254
+ return str2;
22178
22255
  }
22179
- function esc(str) {
22180
- return JSON.stringify(str);
22256
+ function esc(str2) {
22257
+ return JSON.stringify(str2);
22181
22258
  }
22182
22259
  function slugify(input) {
22183
22260
  return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -22277,8 +22354,8 @@
22277
22354
  };
22278
22355
  var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
22279
22356
  var primitiveTypes = /* @__PURE__ */ new Set(["string", "number", "bigint", "boolean", "symbol", "undefined"]);
22280
- function escapeRegex(str) {
22281
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22357
+ function escapeRegex(str2) {
22358
+ return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22282
22359
  }
22283
22360
  function clone(inst, def, params) {
22284
22361
  const cl = new inst._zod.constr(def ?? inst._zod.def);
@@ -35178,7 +35255,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35178
35255
  extension_id: external_exports.string(),
35179
35256
  install_id: external_exports.string(),
35180
35257
  account_id: external_exports.string(),
35181
- target: external_exports.enum(["editor", "layer", "interactive"]),
35258
+ target: external_exports.enum(["editor", "layer"]),
35182
35259
  permissions: external_exports.array(external_exports.string()),
35183
35260
  settings: external_exports.record(external_exports.string(), external_exports.unknown())
35184
35261
  });
@@ -35258,11 +35335,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35258
35335
  // Twitch
35259
35336
  "twitch:follower",
35260
35337
  "twitch:subscribe",
35261
- "twitch:gift_sub",
35338
+ "twitch:gift",
35262
35339
  "twitch:resub",
35263
35340
  "twitch:cheer",
35264
35341
  "twitch:raid",
35265
35342
  "twitch:reward",
35343
+ // Redemption status change (fulfilled / canceled) and reward lifecycle
35344
+ // (created / updated / deleted on Twitch) — ZAF-2393. The lifecycle types are
35345
+ // live-only (`broadcast_only`), never in the event history.
35346
+ "twitch:reward_status",
35347
+ "twitch:reward_add",
35348
+ "twitch:reward_update",
35349
+ "twitch:reward_remove",
35266
35350
  "twitch:hype_train",
35267
35351
  "twitch:hype_train_end",
35268
35352
  "twitch:poll",
@@ -35286,15 +35370,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35286
35370
  "youtube:gift_membership",
35287
35371
  "youtube:gift_membership_received",
35288
35372
  "youtube:poll",
35289
- // Kick
35373
+ // YouTube stream lifecycle (ZAF-1444 / ZAF-622 §75) — emitted by the poll-driven
35374
+ // YouTube worker on the channel-status online/offline edge, mirroring Twitch/Kick.
35375
+ "youtube:stream_online",
35376
+ "youtube:stream_offline",
35377
+ // Kick — the webhook receiver normalizes every Kick payload into these types
35378
+ // (ZAF-1624): canonical fields on top, the original payload kept in `raw`.
35290
35379
  "kick:follower",
35291
35380
  "kick:subscribe",
35381
+ "kick:resub",
35292
35382
  "kick:gift",
35383
+ "kick:kicks",
35384
+ "kick:reward",
35385
+ "kick:reward_status",
35293
35386
  "kick:stream_online",
35294
35387
  "kick:stream_offline",
35295
- // Trovo
35296
- "trovo:subscribe",
35297
- "trovo:spell",
35388
+ "kick:stream_update",
35298
35389
  // Spotify
35299
35390
  "spotify:track",
35300
35391
  "spotify:play",
@@ -35314,7 +35405,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35314
35405
  "twitch:chat",
35315
35406
  "youtube:chat",
35316
35407
  "kick:chat",
35317
- "trovo:chat",
35318
35408
  // Chat (cross-platform catch-all — fires for ALL platforms)
35319
35409
  "chat:message"
35320
35410
  ];
@@ -35355,6 +35445,645 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35355
35445
  "global"
35356
35446
  ];
35357
35447
  var storageScopeSchema = external_exports.enum(STORAGE_SCOPES);
35448
+ var str = external_exports.string();
35449
+ var num = external_exports.number();
35450
+ var bool = external_exports.boolean();
35451
+ var nullableStr = external_exports.string().nullable();
35452
+ var twitchBroadcaster = {
35453
+ broadcaster_user_id: str,
35454
+ broadcaster_user_login: str,
35455
+ broadcaster_user_name: str
35456
+ };
35457
+ var twitchUser = {
35458
+ user_id: str,
35459
+ user_login: str,
35460
+ user_name: str
35461
+ };
35462
+ var avatarUrl = { avatarUrl: str.optional() };
35463
+ var twitchBadge = external_exports.looseObject({ set_id: str, id: str, info: str });
35464
+ var twitchChatNotice = {
35465
+ ...twitchBroadcaster,
35466
+ ...twitchUser,
35467
+ ...avatarUrl,
35468
+ chatter_user_id: str,
35469
+ chatter_user_login: str,
35470
+ chatter_user_name: str,
35471
+ chatter_is_anonymous: bool,
35472
+ color: str,
35473
+ badges: external_exports.array(twitchBadge),
35474
+ message: external_exports.looseObject({ text: str, fragments: external_exports.array(external_exports.unknown()) }),
35475
+ message_id: str,
35476
+ notice_type: str,
35477
+ system_message: str,
35478
+ /** Emotes of `message`, normalised like chat-message emotes (ZAF-1306). */
35479
+ emotes: external_exports.array(external_exports.unknown()).optional()
35480
+ };
35481
+ var twitchImage = external_exports.looseObject({ url_1x: str, url_2x: str, url_4x: str });
35482
+ var twitchEnabledValue = external_exports.looseObject({ is_enabled: bool, value: num });
35483
+ var twitchRewardDefinition = external_exports.looseObject({
35484
+ ...twitchBroadcaster,
35485
+ id: str,
35486
+ title: str,
35487
+ cost: num,
35488
+ prompt: str,
35489
+ background_color: str,
35490
+ is_enabled: bool,
35491
+ is_paused: bool,
35492
+ is_in_stock: bool,
35493
+ is_user_input_required: bool,
35494
+ should_redemptions_skip_request_queue: bool,
35495
+ max_per_stream: twitchEnabledValue,
35496
+ max_per_user_per_stream: twitchEnabledValue,
35497
+ global_cooldown: external_exports.looseObject({ is_enabled: bool, seconds: num }),
35498
+ image: twitchImage.nullable(),
35499
+ default_image: twitchImage,
35500
+ cooldown_expires_at: nullableStr,
35501
+ redemptions_redeemed_current_stream: num.nullable()
35502
+ });
35503
+ var twitchRedemption = external_exports.looseObject({
35504
+ ...twitchBroadcaster,
35505
+ ...twitchUser,
35506
+ ...avatarUrl,
35507
+ id: str,
35508
+ user_input: str,
35509
+ status: str,
35510
+ redeemed_at: str,
35511
+ reward: external_exports.looseObject({ id: str, title: str, cost: num, prompt: str })
35512
+ });
35513
+ var twitchPollVoting = external_exports.looseObject({ is_enabled: bool, amount_per_vote: num });
35514
+ var twitchPollBase = {
35515
+ ...twitchBroadcaster,
35516
+ id: str,
35517
+ title: str,
35518
+ choices: external_exports.array(
35519
+ external_exports.looseObject({
35520
+ id: str,
35521
+ title: str,
35522
+ votes: num.optional(),
35523
+ bits_votes: num.optional(),
35524
+ channel_points_votes: num.optional()
35525
+ })
35526
+ ),
35527
+ bits_voting: twitchPollVoting,
35528
+ channel_points_voting: twitchPollVoting,
35529
+ started_at: str
35530
+ };
35531
+ var twitchPredictionOutcome = external_exports.looseObject({
35532
+ id: str,
35533
+ title: str,
35534
+ color: str,
35535
+ users: num.optional(),
35536
+ channel_points: num.optional(),
35537
+ top_predictors: external_exports.array(
35538
+ external_exports.looseObject({
35539
+ ...twitchUser,
35540
+ channel_points_used: num,
35541
+ channel_points_won: num.nullable()
35542
+ })
35543
+ ).nullable().optional()
35544
+ });
35545
+ var twitchPredictionBase = {
35546
+ ...twitchBroadcaster,
35547
+ id: str,
35548
+ title: str,
35549
+ outcomes: external_exports.array(twitchPredictionOutcome),
35550
+ started_at: str
35551
+ };
35552
+ var twitchGoalBase = {
35553
+ ...twitchBroadcaster,
35554
+ id: str,
35555
+ type: str,
35556
+ description: str,
35557
+ current_amount: num,
35558
+ target_amount: num,
35559
+ started_at: str
35560
+ };
35561
+ var twitchHypeTrainBase = {
35562
+ ...twitchBroadcaster,
35563
+ id: str,
35564
+ type: str,
35565
+ level: num,
35566
+ total: num,
35567
+ top_contributions: external_exports.array(
35568
+ external_exports.looseObject({ ...twitchUser, type: str, total: num })
35569
+ ),
35570
+ started_at: str,
35571
+ is_shared_train: bool,
35572
+ shared_train_participants: external_exports.array(external_exports.unknown()).nullable()
35573
+ };
35574
+ var moderationLogEntry = external_exports.looseObject({
35575
+ action: str,
35576
+ platform: str,
35577
+ target_user_id: nullableStr,
35578
+ target_username: nullableStr,
35579
+ target_display_name: nullableStr,
35580
+ moderator_name: str,
35581
+ moderator_login: nullableStr,
35582
+ reason: nullableStr,
35583
+ duration_secs: num.nullable(),
35584
+ ends_at: nullableStr,
35585
+ target_message_id: nullableStr,
35586
+ created_at: str
35587
+ });
35588
+ var chatMessagePayloadSchema = external_exports.looseObject({
35589
+ account_id: str,
35590
+ platform: str,
35591
+ channel_name: nullableStr,
35592
+ user_id: nullableStr,
35593
+ username: str,
35594
+ display_name: nullableStr,
35595
+ avatar_url: nullableStr,
35596
+ message: str,
35597
+ /** Platform-specific emote entries. */
35598
+ emotes: external_exports.array(external_exports.unknown()).nullable(),
35599
+ /** Twitch GIF fragments `{ id, url, provider, alt }`; absent without a GIF. */
35600
+ gifs: external_exports.array(external_exports.unknown()).optional(),
35601
+ /** Platform-specific badge entries. */
35602
+ badges: external_exports.array(external_exports.unknown()).nullable(),
35603
+ color: nullableStr,
35604
+ is_mod: bool,
35605
+ is_sub: bool,
35606
+ is_vip: bool,
35607
+ sub_tier: nullableStr,
35608
+ platform_message_id: nullableStr,
35609
+ lumio_user_id: nullableStr,
35610
+ reply_parent_msg_id: nullableStr,
35611
+ reply_parent_username: nullableStr,
35612
+ reply_parent_login: nullableStr,
35613
+ reply_parent_message: nullableStr,
35614
+ created_at: nullableStr,
35615
+ message_type: nullableStr,
35616
+ user_treatment: nullableStr,
35617
+ live_chat_id: str.optional(),
35618
+ is_shared_chat: bool.optional(),
35619
+ source_channel: external_exports.unknown().optional(),
35620
+ announcement_color: external_exports.unknown().optional()
35621
+ });
35622
+ var kickUser = external_exports.looseObject({
35623
+ user_id: num,
35624
+ username: str,
35625
+ channel_slug: str,
35626
+ is_verified: bool,
35627
+ profile_picture: str,
35628
+ is_anonymous: bool.optional(),
35629
+ identity: external_exports.unknown().optional()
35630
+ });
35631
+ var kickCanonicalUser = {
35632
+ user_id: str,
35633
+ user_login: str,
35634
+ user_name: str,
35635
+ is_anonymous: bool
35636
+ };
35637
+ var kickSubscription = external_exports.looseObject({
35638
+ ...kickCanonicalUser,
35639
+ ...avatarUrl,
35640
+ broadcaster: kickUser,
35641
+ subscriber: kickUser,
35642
+ duration: num,
35643
+ cumulative_months: num,
35644
+ created_at: str,
35645
+ expires_at: str
35646
+ });
35647
+ var kickRedemption = external_exports.looseObject({
35648
+ ...kickCanonicalUser,
35649
+ broadcaster: kickUser,
35650
+ redeemer: kickUser,
35651
+ id: str,
35652
+ user_input: str,
35653
+ status: str,
35654
+ redeemed_at: str,
35655
+ reward: external_exports.looseObject({ id: str, title: str, cost: num })
35656
+ });
35657
+ var spotifySource = {
35658
+ source: str.optional(),
35659
+ extension_id: str.optional(),
35660
+ install_id: str.optional()
35661
+ };
35662
+ var spotifyTrackInfo = {
35663
+ action: str,
35664
+ track_id: str,
35665
+ track_name: str,
35666
+ artist: str,
35667
+ album: str,
35668
+ album_art: str,
35669
+ song_url: str
35670
+ };
35671
+ var youtubeAuthor = {
35672
+ user_id: str,
35673
+ user_login: str,
35674
+ displayName: str,
35675
+ avatarUrl: str
35676
+ };
35677
+ var LUMIO_EVENT_PAYLOAD_SCHEMAS = {
35678
+ // Twitch
35679
+ "twitch:follower": external_exports.looseObject({
35680
+ ...twitchBroadcaster,
35681
+ ...twitchUser,
35682
+ ...avatarUrl,
35683
+ followed_at: str
35684
+ }),
35685
+ "twitch:subscribe": external_exports.looseObject({
35686
+ ...twitchChatNotice,
35687
+ tier: str,
35688
+ duration_months: num,
35689
+ is_prime: bool.optional(),
35690
+ sub: external_exports.looseObject({ sub_tier: str, is_prime: bool, duration_months: num })
35691
+ }),
35692
+ "twitch:gift": external_exports.looseObject({
35693
+ ...twitchChatNotice,
35694
+ /** Sub tier (`1000`, `2000`, `3000`). */
35695
+ tier: str.optional(),
35696
+ duration_months: num.optional(),
35697
+ /** Gifts in a community gift (`community_sub_gift`). */
35698
+ total: num.optional(),
35699
+ /** The gifter's all-time gift count; `null` when anonymous. */
35700
+ cumulative_total: num.nullable().optional(),
35701
+ community_gift_id: nullableStr.optional(),
35702
+ /** Set for a single gift (`sub_gift`), absent for a community gift. */
35703
+ recipient_user_id: str.optional(),
35704
+ recipient_user_login: str.optional(),
35705
+ recipient_user_name: str.optional()
35706
+ }),
35707
+ "twitch:resub": external_exports.looseObject({
35708
+ ...twitchChatNotice,
35709
+ cumulative_months: num,
35710
+ duration_months: num,
35711
+ streak_months: num.nullable(),
35712
+ is_gift: bool,
35713
+ tier: str.optional(),
35714
+ is_prime: bool.optional(),
35715
+ gifter_is_anonymous: bool.nullable(),
35716
+ gifter_user_login: nullableStr,
35717
+ gifter_user_name: nullableStr,
35718
+ resub: external_exports.looseObject({
35719
+ cumulative_months: num,
35720
+ duration_months: num,
35721
+ streak_months: num.nullable(),
35722
+ sub_plan: str,
35723
+ is_gift: bool
35724
+ })
35725
+ }),
35726
+ "twitch:cheer": external_exports.looseObject({
35727
+ ...twitchBroadcaster,
35728
+ ...avatarUrl,
35729
+ user_id: nullableStr,
35730
+ user_login: nullableStr,
35731
+ user_name: nullableStr,
35732
+ is_anonymous: bool,
35733
+ bits: num,
35734
+ message: str,
35735
+ /** Cheermote entries for the cheer words in `message` (`kind: "cheermote"`). */
35736
+ emotes: external_exports.array(external_exports.unknown()).optional(),
35737
+ /** The cheermote for the total, when the channel's cheermotes loaded. */
35738
+ cheermote: external_exports.unknown().optional()
35739
+ }),
35740
+ "twitch:raid": external_exports.looseObject({
35741
+ from_broadcaster_user_id: str,
35742
+ from_broadcaster_user_login: str,
35743
+ from_broadcaster_user_name: str,
35744
+ to_broadcaster_user_id: str,
35745
+ to_broadcaster_user_login: str,
35746
+ to_broadcaster_user_name: str,
35747
+ viewers: num,
35748
+ ...avatarUrl,
35749
+ displayName: str.optional(),
35750
+ /** The raider's channel info from Helix, when it loaded. */
35751
+ title: str.optional(),
35752
+ category: str.optional()
35753
+ }),
35754
+ "twitch:reward": twitchRedemption,
35755
+ "twitch:reward_status": twitchRedemption,
35756
+ "twitch:reward_add": twitchRewardDefinition,
35757
+ "twitch:reward_update": twitchRewardDefinition,
35758
+ "twitch:reward_remove": twitchRewardDefinition,
35759
+ "twitch:hype_train": external_exports.looseObject({
35760
+ ...twitchHypeTrainBase,
35761
+ progress: num,
35762
+ goal: num,
35763
+ expires_at: str,
35764
+ all_time_high_level: num.optional(),
35765
+ all_time_high_total: num.optional()
35766
+ }),
35767
+ "twitch:hype_train_end": external_exports.looseObject({
35768
+ ...twitchHypeTrainBase,
35769
+ ended_at: str,
35770
+ cooldown_ends_at: str
35771
+ }),
35772
+ "twitch:poll": external_exports.looseObject({ ...twitchPollBase, ends_at: str }),
35773
+ "twitch:poll_end": external_exports.looseObject({
35774
+ ...twitchPollBase,
35775
+ status: str,
35776
+ ended_at: str
35777
+ }),
35778
+ "twitch:prediction": external_exports.looseObject({ ...twitchPredictionBase, locks_at: str }),
35779
+ "twitch:prediction_lock": external_exports.looseObject({
35780
+ ...twitchPredictionBase,
35781
+ locked_at: str
35782
+ }),
35783
+ "twitch:prediction_end": external_exports.looseObject({
35784
+ ...twitchPredictionBase,
35785
+ status: str,
35786
+ ended_at: str,
35787
+ winning_outcome_id: nullableStr
35788
+ }),
35789
+ "twitch:goal": external_exports.looseObject(twitchGoalBase),
35790
+ "twitch:goal_end": external_exports.looseObject({
35791
+ ...twitchGoalBase,
35792
+ ended_at: str,
35793
+ is_achieved: bool
35794
+ }),
35795
+ "twitch:ad_break": external_exports.looseObject({
35796
+ ...twitchBroadcaster,
35797
+ requester_user_id: str,
35798
+ requester_user_login: str,
35799
+ requester_user_name: str,
35800
+ /** Seconds; Twitch's own sample payload sends it as a string. */
35801
+ duration_seconds: external_exports.union([num, str]),
35802
+ /** Twitch's own sample payload sends it as a string. */
35803
+ is_automatic: external_exports.union([bool, str]),
35804
+ started_at: str
35805
+ }),
35806
+ "twitch:ban": moderationLogEntry,
35807
+ "twitch:unban": moderationLogEntry,
35808
+ "twitch:stream_online": external_exports.looseObject({
35809
+ ...twitchBroadcaster,
35810
+ id: str,
35811
+ type: str,
35812
+ started_at: str,
35813
+ /** Channel info from Helix, when it loaded. */
35814
+ title: str.optional(),
35815
+ category: str.optional()
35816
+ }),
35817
+ "twitch:stream_offline": external_exports.looseObject({
35818
+ ...twitchBroadcaster,
35819
+ /** Set when the stream's start is known. */
35820
+ started_at: str.optional(),
35821
+ duration_seconds: num.optional()
35822
+ }),
35823
+ "twitch:stream_update": external_exports.looseObject({
35824
+ ...twitchBroadcaster,
35825
+ title: str,
35826
+ language: str,
35827
+ category_id: str,
35828
+ category_name: str,
35829
+ content_classification_labels: external_exports.array(str),
35830
+ tags: external_exports.array(str).optional(),
35831
+ /** Diff against the previous channel info, when it was known. */
35832
+ title_changed: bool.optional(),
35833
+ category_changed: bool.optional(),
35834
+ language_changed: bool.optional(),
35835
+ tags_changed: bool.optional(),
35836
+ old_title: str.optional(),
35837
+ old_category_name: str.optional(),
35838
+ old_tags: external_exports.array(str).optional()
35839
+ }),
35840
+ // YouTube
35841
+ "youtube:subscribe": external_exports.looseObject({
35842
+ channel_id: str,
35843
+ video_id: str,
35844
+ title: str,
35845
+ published: str,
35846
+ updated: str
35847
+ }),
35848
+ "youtube:member": external_exports.looseObject({
35849
+ ...youtubeAuthor,
35850
+ membership_event_type: str,
35851
+ memberLevelName: nullableStr,
35852
+ memberMonth: num.nullable(),
35853
+ isUpgrade: bool,
35854
+ display_message: str,
35855
+ userComment: str
35856
+ }),
35857
+ "youtube:superchat": external_exports.looseObject({
35858
+ ...youtubeAuthor,
35859
+ amountMicros: num,
35860
+ amountDisplayString: str,
35861
+ currency: str,
35862
+ tier: num,
35863
+ userComment: str,
35864
+ headerBackgroundColor: num,
35865
+ bodyBackgroundColor: num
35866
+ }),
35867
+ "youtube:supersticker": external_exports.looseObject({
35868
+ ...youtubeAuthor,
35869
+ amountMicros: num,
35870
+ amountDisplayString: str,
35871
+ currency: str,
35872
+ stickerName: str,
35873
+ stickerUrl: str
35874
+ }),
35875
+ "youtube:gift_membership": external_exports.looseObject({
35876
+ ...youtubeAuthor,
35877
+ giftCount: num,
35878
+ isGift: bool,
35879
+ gift_memberships_level_name: nullableStr
35880
+ }),
35881
+ /** Stored in the event history only; never broadcast live (no fixture). */
35882
+ "youtube:gift_membership_received": external_exports.looseObject({
35883
+ user_id: nullableStr,
35884
+ user_login: nullableStr,
35885
+ displayName: str,
35886
+ avatarUrl: nullableStr,
35887
+ gifter_channel_id: nullableStr,
35888
+ gifter_display_name: nullableStr,
35889
+ gift_memberships_level_name: nullableStr
35890
+ }),
35891
+ "youtube:poll": external_exports.looseObject({
35892
+ poll_id: str,
35893
+ question: str,
35894
+ status: str,
35895
+ options: external_exports.array(
35896
+ external_exports.looseObject({
35897
+ option_text: str,
35898
+ tally: nullableStr,
35899
+ vote_ratio: num.nullable()
35900
+ })
35901
+ )
35902
+ }),
35903
+ "youtube:stream_online": external_exports.looseObject({
35904
+ broadcast_id: str,
35905
+ started_at: str,
35906
+ title: str.optional(),
35907
+ category: str.optional()
35908
+ }),
35909
+ "youtube:stream_offline": external_exports.looseObject({
35910
+ broadcast_id: str,
35911
+ started_at: str.optional(),
35912
+ duration_seconds: num.optional()
35913
+ }),
35914
+ // Kick
35915
+ "kick:follower": external_exports.looseObject({
35916
+ ...kickCanonicalUser,
35917
+ ...avatarUrl,
35918
+ broadcaster: kickUser,
35919
+ follower: kickUser
35920
+ }),
35921
+ "kick:subscribe": kickSubscription,
35922
+ "kick:resub": kickSubscription,
35923
+ "kick:gift": external_exports.looseObject({
35924
+ ...kickCanonicalUser,
35925
+ ...avatarUrl,
35926
+ broadcaster: kickUser,
35927
+ gifter: kickUser,
35928
+ giftees: external_exports.array(kickUser),
35929
+ /** Usernames of `giftees`. */
35930
+ giftRecipients: external_exports.array(str),
35931
+ giftCount: num,
35932
+ total: num,
35933
+ isGift: bool,
35934
+ is_gift: bool,
35935
+ /** The first giftee. */
35936
+ recipient_user_id: str.optional(),
35937
+ recipient_user_login: str.optional(),
35938
+ recipient_user_name: str.optional(),
35939
+ created_at: str,
35940
+ expires_at: str
35941
+ }),
35942
+ "kick:kicks": external_exports.looseObject({
35943
+ ...kickCanonicalUser,
35944
+ ...avatarUrl,
35945
+ broadcaster: kickUser,
35946
+ sender: kickUser,
35947
+ gift: external_exports.looseObject({
35948
+ amount: num,
35949
+ name: str,
35950
+ type: str,
35951
+ tier: str,
35952
+ message: str,
35953
+ pinned_time_seconds: num
35954
+ }),
35955
+ kicks: num,
35956
+ message: str,
35957
+ kick_gift_id: str,
35958
+ kick_gift_name: str,
35959
+ kick_gift_type: str,
35960
+ kick_gift_tier: str,
35961
+ kick_gift_color: str,
35962
+ kick_gift_image: external_exports.looseObject({ static: str, animated: str }),
35963
+ kick_pinned_time_seconds: num,
35964
+ created_at: str
35965
+ }),
35966
+ "kick:reward": kickRedemption,
35967
+ "kick:reward_status": kickRedemption,
35968
+ "kick:stream_online": external_exports.looseObject({
35969
+ broadcaster: kickUser,
35970
+ is_live: bool,
35971
+ title: str,
35972
+ started_at: str,
35973
+ ended_at: nullableStr
35974
+ }),
35975
+ "kick:stream_offline": external_exports.looseObject({
35976
+ broadcaster: kickUser,
35977
+ is_live: bool,
35978
+ title: str,
35979
+ started_at: str,
35980
+ ended_at: str,
35981
+ duration_seconds: num.optional()
35982
+ }),
35983
+ "kick:stream_update": external_exports.looseObject({
35984
+ broadcaster: kickUser,
35985
+ metadata: external_exports.looseObject({
35986
+ title: str,
35987
+ language: str,
35988
+ has_mature_content: bool,
35989
+ category: external_exports.looseObject({ id: num, name: str, thumbnail: str })
35990
+ }),
35991
+ title: str,
35992
+ language: str,
35993
+ has_mature_content: bool,
35994
+ category_id: str,
35995
+ category_name: str,
35996
+ /** Diff against the previous stream info, when it was known. */
35997
+ title_changed: bool.optional(),
35998
+ category_changed: bool.optional(),
35999
+ language_changed: bool.optional(),
36000
+ old_title: str.optional()
36001
+ }),
36002
+ // Spotify
36003
+ "spotify:track": external_exports.looseObject({
36004
+ is_playing: bool,
36005
+ progress_ms: num,
36006
+ timestamp: num,
36007
+ shuffle: str,
36008
+ repeat: str,
36009
+ track: external_exports.looseObject({
36010
+ id: str,
36011
+ uri: str,
36012
+ name: str,
36013
+ artist: str,
36014
+ album: str,
36015
+ album_art: str,
36016
+ duration_ms: num
36017
+ }),
36018
+ device: external_exports.looseObject({
36019
+ id: str,
36020
+ name: str,
36021
+ device_type: str,
36022
+ is_active: bool,
36023
+ volume_percent: num.nullable()
36024
+ }).nullable(),
36025
+ context: external_exports.looseObject({ context_type: str, id: str, name: nullableStr, uri: str }).nullable(),
36026
+ /** The Lumio user whose action caused the change; `null` when it came from Spotify. */
36027
+ triggered_by: nullableStr.optional()
36028
+ }),
36029
+ "spotify:play": external_exports.looseObject({
36030
+ ...spotifyTrackInfo,
36031
+ ...spotifySource,
36032
+ track_uri: str
36033
+ }),
36034
+ "spotify:pause": external_exports.looseObject({ ...spotifyTrackInfo, ...spotifySource }),
36035
+ "spotify:skip": external_exports.looseObject({ action: str, ...spotifySource }),
36036
+ "spotify:volume": external_exports.looseObject({
36037
+ ...spotifyTrackInfo,
36038
+ ...spotifySource,
36039
+ oldVolume: num,
36040
+ newVolume: num,
36041
+ volume_percent: num
36042
+ }),
36043
+ "spotify:queue_add": external_exports.looseObject({ uri: str, ...spotifySource }),
36044
+ "spotify:device": external_exports.looseObject({
36045
+ fromDevice: str,
36046
+ fromDeviceType: str,
36047
+ toDevice: str,
36048
+ toDeviceType: str
36049
+ }),
36050
+ "spotify:playlist_add": external_exports.looseObject({ playlistId: str }),
36051
+ "spotify:playlist_remove": external_exports.looseObject({ playlistId: str, trackUri: str }),
36052
+ "spotify:playlist_create": external_exports.looseObject({ playlistName: str }),
36053
+ "spotify:playlist_edit": external_exports.looseObject({ playlistName: str }),
36054
+ "spotify:playlist_delete": external_exports.looseObject({ playlistId: str }),
36055
+ // StreamElements
36056
+ "streamelements:tip": external_exports.looseObject({
36057
+ _id: str,
36058
+ channel: str,
36059
+ provider: str,
36060
+ type: str,
36061
+ flagged: bool,
36062
+ createdAt: str,
36063
+ updatedAt: str,
36064
+ data: external_exports.looseObject({
36065
+ tipId: str,
36066
+ username: str,
36067
+ displayName: str,
36068
+ providerId: str.optional(),
36069
+ amount: num,
36070
+ currency: str,
36071
+ message: str,
36072
+ avatar: str.optional()
36073
+ })
36074
+ }),
36075
+ // Chat
36076
+ "twitch:chat": chatMessagePayloadSchema,
36077
+ "youtube:chat": chatMessagePayloadSchema,
36078
+ "kick:chat": chatMessagePayloadSchema,
36079
+ "chat:message": chatMessagePayloadSchema
36080
+ };
36081
+ function lumioEventPayloadSchema(type) {
36082
+ return LUMIO_EVENT_PAYLOAD_SCHEMAS[type];
36083
+ }
36084
+ function parseLumioEventPayload(type, data) {
36085
+ return LUMIO_EVENT_PAYLOAD_SCHEMAS[type].safeParse(data);
36086
+ }
35358
36087
  var LUMIO_COMPONENT_TYPES = [
35359
36088
  "Box",
35360
36089
  "VStack",
@@ -35387,6 +36116,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35387
36116
  "EditorFontPicker",
35388
36117
  "EditorChannelRow"
35389
36118
  ];
36119
+ var ACTION_EXECUTE_ERRORS = {
36120
+ /** Malformed request: `action` is not a string or `params` is not an object. */
36121
+ INVALID_REQUEST: -32602,
36122
+ /** This host cannot run actions (no install, or a credential that may not run them). */
36123
+ UNAVAILABLE: -32001,
36124
+ /** The extension does not declare the action's permission, or the caller may not use it. */
36125
+ DENIED: -32002,
36126
+ /** The API does not dispatch this action. */
36127
+ UNKNOWN_ACTION: -32003,
36128
+ /** The API rejected the action's params. */
36129
+ INVALID_PARAMS: -32004,
36130
+ /** The action ran and failed (e.g. its target service is not connected). */
36131
+ FAILED: -32005
36132
+ };
36133
+ var SERVER_FUNCTION_ERRORS = {
36134
+ /** Malformed request: `fn` is not a function name or `params` is not an object. */
36135
+ INVALID_REQUEST: -32602,
36136
+ /** This host cannot call server functions (no install, or a credential that may not call them). */
36137
+ UNAVAILABLE: -32001,
36138
+ /** The caller may not run the function (an `editorOnly` function outside the editor, or missing permission). */
36139
+ DENIED: -32002,
36140
+ /** The install's published version has no server function with this name, or not of this kind. */
36141
+ UNKNOWN_FUNCTION: -32003,
36142
+ /** The API rejected the params (missing or mistyped `arg()` value, invalid row id or column value). */
36143
+ INVALID_PARAMS: -32004,
36144
+ /** The function ran and failed (rate limit, no data schema, storage quota, timeout). */
36145
+ FAILED: -32005
36146
+ };
35390
36147
  var WORKER_METHODS = {
35391
36148
  UI_RENDER: "ui.render",
35392
36149
  UI_READY: "ui.ready",
@@ -35399,7 +36156,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35399
36156
  UI_ACTION: "ui.action",
35400
36157
  SOUND_PLAY: "sound.play",
35401
36158
  SOUND_STOP: "sound.stop",
35402
- SOUND_LIST: "sound.list"
36159
+ SOUND_LIST: "sound.list",
36160
+ ACTION_EXECUTE: "action.execute"
35403
36161
  };
35404
36162
  var HOST_METHODS = {
35405
36163
  LIFECYCLE_INIT: "lifecycle.init",
@@ -35408,7 +36166,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35408
36166
  EVENT_PLATFORM: "event.platform",
35409
36167
  STORAGE_UPDATE: "storage.update",
35410
36168
  THEME_CHANGE: "theme.change",
35411
- CONFIG_UPDATE: "config.update"
36169
+ CONFIG_UPDATE: "config.update",
36170
+ SERVER_REALTIME: "server.realtime"
36171
+ };
36172
+ var REALTIME_LIMITS = {
36173
+ /** 1–64 characters of `A-Z a-z 0-9 _ . : -`, starting with a letter or digit. */
36174
+ TOPIC_PATTERN: /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$/,
36175
+ /** Largest serialized payload of one push, in bytes. */
36176
+ MAX_PAYLOAD_BYTES: 16 * 1024,
36177
+ /** Most pushes one handler run may make. */
36178
+ MAX_PUSHES_PER_INVOCATION: 32,
36179
+ /** Pushes per install and minute; pushes over the cap are dropped. */
36180
+ MAX_PUSHES_PER_MINUTE: 300,
36181
+ /**
36182
+ * Published bytes (serialized `{ topic, payload }`) per install and minute;
36183
+ * pushes over the cap are dropped.
36184
+ */
36185
+ MAX_BYTES_PER_MINUTE: 1024 * 1024
35412
36186
  };
35413
36187
 
35414
36188
  // src/hooks/useExtensionStorage.ts
@@ -35485,24 +36259,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35485
36259
  var defaultContext = {
35486
36260
  extensionId: null,
35487
36261
  target: null,
35488
- overlayId: null,
35489
- interactiveUrl: null
36262
+ overlayId: null
35490
36263
  };
36264
+ function fromInit(p) {
36265
+ return {
36266
+ extensionId: p.extensionId ?? null,
36267
+ target: p.target ?? null,
36268
+ overlayId: p.installId ?? null
36269
+ };
36270
+ }
35491
36271
  function useExtensionContext() {
35492
- const [context, setContext] = (0, import_react35.useState)(defaultContext);
36272
+ const [context, setContext] = (0, import_react35.useState)(() => {
36273
+ const init = getInitParams();
36274
+ return init ? fromInit(init) : defaultContext;
36275
+ });
35493
36276
  (0, import_react35.useEffect)(() => {
35494
36277
  const bridge2 = getBridge();
35495
36278
  const unsub = bridge2.onNotification(
35496
36279
  HOST_METHODS.LIFECYCLE_INIT,
35497
- (params) => {
35498
- const p = params;
35499
- setContext({
35500
- extensionId: p.extensionId ?? null,
35501
- target: p.target ?? null,
35502
- overlayId: p.installId ?? null,
35503
- interactiveUrl: p.interactiveUrl ?? null
35504
- });
35505
- }
36280
+ (params) => setContext(fromInit(params))
35506
36281
  );
35507
36282
  return unsub;
35508
36283
  }, []);
@@ -35512,7 +36287,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35512
36287
  // src/hooks/useLumioEvent.ts
35513
36288
  var import_react36 = __toESM(require_react());
35514
36289
  function useLumioEvent(eventType) {
35515
- const [eventData, setEventData] = (0, import_react36.useState)(null);
36290
+ const [eventData, setEventData] = (0, import_react36.useState)(
36291
+ null
36292
+ );
35516
36293
  (0, import_react36.useEffect)(() => {
35517
36294
  const bridge2 = getBridge();
35518
36295
  const unsub = bridge2.onNotification(
@@ -35529,17 +36306,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35529
36306
  return eventData;
35530
36307
  }
35531
36308
 
35532
- // src/hooks/useLumioConfig.ts
36309
+ // src/hooks/useRealtime.ts
35533
36310
  var import_react37 = __toESM(require_react());
36311
+ function useRealtime(topic, cb) {
36312
+ const cbRef = (0, import_react37.useRef)(cb);
36313
+ cbRef.current = cb;
36314
+ (0, import_react37.useEffect)(() => {
36315
+ const bridge2 = getBridge();
36316
+ return bridge2.onNotification(HOST_METHODS.SERVER_REALTIME, (params) => {
36317
+ const p = params;
36318
+ if (p && p.topic === topic) {
36319
+ cbRef.current(p.payload);
36320
+ }
36321
+ });
36322
+ }, [topic]);
36323
+ }
36324
+
36325
+ // src/hooks/useLumioConfig.ts
36326
+ var import_react38 = __toESM(require_react());
35534
36327
  function hasShim() {
35535
36328
  return typeof window !== "undefined" && typeof window.__lumio_config === "function";
35536
36329
  }
36330
+ function fromInit2(p) {
36331
+ return {
36332
+ extension_id: p.extensionId,
36333
+ install_id: p.installId,
36334
+ account_id: p.accountId,
36335
+ target: p.target,
36336
+ permissions: p.permissions,
36337
+ settings: p.settings
36338
+ };
36339
+ }
35537
36340
  function useLumioConfig() {
35538
- const [config2, setConfigState] = (0, import_react37.useState)(() => {
36341
+ const [config2, setConfigState] = (0, import_react38.useState)(() => {
35539
36342
  if (hasShim()) return window.__lumio_config();
35540
- return {};
36343
+ const init = getInitParams();
36344
+ return init ? fromInit2(init) : {};
35541
36345
  });
35542
- (0, import_react37.useEffect)(() => {
36346
+ (0, import_react38.useEffect)(() => {
35543
36347
  if (hasShim()) {
35544
36348
  const unsub2 = window.__lumio_on_config((newConfig) => {
35545
36349
  setConfigState(newConfig);
@@ -35550,23 +36354,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35550
36354
  const bridge2 = getBridge();
35551
36355
  const unsub = bridge2.onNotification(
35552
36356
  HOST_METHODS.LIFECYCLE_INIT,
35553
- (params) => {
35554
- const p = params;
35555
- setConfigState({
35556
- extension_id: p.extensionId,
35557
- install_id: p.installId,
35558
- account_id: p.accountId,
35559
- target: p.target,
35560
- permissions: p.permissions,
35561
- settings: p.settings
35562
- });
35563
- }
36357
+ (params) => setConfigState(fromInit2(params))
35564
36358
  );
35565
36359
  const unsubConfig = bridge2.onNotification(
35566
36360
  HOST_METHODS.CONFIG_UPDATE,
35567
36361
  (params) => {
35568
36362
  const p = params;
35569
- setConfigState(p);
36363
+ setConfigState((prev) => ({ ...prev, ...p }));
35570
36364
  }
35571
36365
  );
35572
36366
  return () => {
@@ -35574,7 +36368,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35574
36368
  unsubConfig();
35575
36369
  };
35576
36370
  }, []);
35577
- const setConfig = (0, import_react37.useCallback)(
36371
+ const setConfig = (0, import_react38.useCallback)(
35578
36372
  (newConfigOrUpdater) => {
35579
36373
  setConfigState((prev) => {
35580
36374
  const next = typeof newConfigOrUpdater === "function" ? newConfigOrUpdater(prev) : newConfigOrUpdater;
@@ -35593,7 +36387,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35593
36387
  }
35594
36388
 
35595
36389
  // src/hooks/useLumioTheme.ts
35596
- var import_react38 = __toESM(require_react());
36390
+ var import_react39 = __toESM(require_react());
35597
36391
  var DEFAULT_THEME = {
35598
36392
  colors: {
35599
36393
  primary: "#6366f1",
@@ -35617,8 +36411,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35617
36411
  spacing: 8
35618
36412
  };
35619
36413
  function useLumioTheme() {
35620
- const [theme, setTheme] = (0, import_react38.useState)(DEFAULT_THEME);
35621
- (0, import_react38.useEffect)(() => {
36414
+ const [theme, setTheme] = (0, import_react39.useState)(() => {
36415
+ const initTheme = getInitParams()?.theme;
36416
+ return initTheme ? { ...DEFAULT_THEME, ...initTheme } : DEFAULT_THEME;
36417
+ });
36418
+ (0, import_react39.useEffect)(() => {
35622
36419
  const bridge2 = getBridge();
35623
36420
  const unsubInit = bridge2.onNotification(
35624
36421
  HOST_METHODS.LIFECYCLE_INIT,
@@ -35647,26 +36444,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35647
36444
  }
35648
36445
 
35649
36446
  // src/hooks/useLumioIdentity.ts
35650
- var import_react39 = __toESM(require_react());
36447
+ var import_react40 = __toESM(require_react());
35651
36448
  var defaultIdentity = {
35652
36449
  userId: null,
35653
36450
  accountId: null,
35654
36451
  role: null
35655
36452
  };
36453
+ function fromInit3(p) {
36454
+ return {
36455
+ userId: p.userId ?? null,
36456
+ accountId: p.accountId ?? null,
36457
+ role: p.role ?? null
36458
+ };
36459
+ }
35656
36460
  function useLumioIdentity() {
35657
- const [identity2, setIdentity] = (0, import_react39.useState)(defaultIdentity);
35658
- (0, import_react39.useEffect)(() => {
36461
+ const [identity2, setIdentity] = (0, import_react40.useState)(() => {
36462
+ const init = getInitParams();
36463
+ return init ? fromInit3(init) : defaultIdentity;
36464
+ });
36465
+ (0, import_react40.useEffect)(() => {
35659
36466
  const bridge2 = getBridge();
35660
36467
  const unsub = bridge2.onNotification(
35661
36468
  HOST_METHODS.LIFECYCLE_INIT,
35662
- (params) => {
35663
- const p = params;
35664
- setIdentity({
35665
- userId: p.userId ?? null,
35666
- accountId: p.accountId ?? null,
35667
- role: p.role ?? null
35668
- });
35669
- }
36469
+ (params) => setIdentity(fromInit3(params))
35670
36470
  );
35671
36471
  return unsub;
35672
36472
  }, []);
@@ -35674,27 +36474,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35674
36474
  }
35675
36475
 
35676
36476
  // src/hooks/useLumioAction.ts
35677
- var import_react40 = __toESM(require_react());
36477
+ var import_react41 = __toESM(require_react());
35678
36478
  function useLumioAction(action2) {
35679
- const [data, setData] = (0, import_react40.useState)(null);
35680
- const [isLoading, setIsLoading] = (0, import_react40.useState)(false);
35681
- const [error48, setError] = (0, import_react40.useState)(null);
35682
- const actionRef = (0, import_react40.useRef)(action2);
35683
- actionRef.current = action2;
35684
- const execute = (0, import_react40.useCallback)(
35685
- (params = {}) => {
36479
+ const [data, setData] = (0, import_react41.useState)(null);
36480
+ const [isLoading, setIsLoading] = (0, import_react41.useState)(false);
36481
+ const [error48, setError] = (0, import_react41.useState)(null);
36482
+ const execute = (0, import_react41.useCallback)(
36483
+ async (params = {}) => {
35686
36484
  setIsLoading(true);
35687
36485
  setError(null);
35688
- const bridge2 = getBridge();
35689
- bridge2.request("action.execute", { action: action2, params }).then((result) => {
35690
- setIsLoading(false);
35691
- setData(result ?? null);
36486
+ const request = { action: action2, params };
36487
+ try {
36488
+ const result = await getBridge().request(WORKER_METHODS.ACTION_EXECUTE, request);
36489
+ setData(result?.data ?? null);
35692
36490
  setError(null);
35693
- }).catch((err) => {
35694
- setIsLoading(false);
36491
+ } catch (err) {
35695
36492
  setError(err instanceof Error ? err.message : "Unknown error");
35696
36493
  setData(null);
35697
- });
36494
+ } finally {
36495
+ setIsLoading(false);
36496
+ }
35698
36497
  },
35699
36498
  [action2]
35700
36499
  );
@@ -35702,17 +36501,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35702
36501
  }
35703
36502
 
35704
36503
  // src/hooks/useLumioSound.ts
35705
- var import_react41 = __toESM(require_react());
36504
+ var import_react42 = __toESM(require_react());
35706
36505
  function useLumioSound() {
35707
- const playSound = (0, import_react41.useCallback)(async (soundId, volume) => {
36506
+ const playSound = (0, import_react42.useCallback)(async (soundId, volume) => {
35708
36507
  const bridge2 = getBridge();
35709
36508
  await bridge2.request(WORKER_METHODS.SOUND_PLAY, { sound_id: soundId, volume });
35710
36509
  }, []);
35711
- const stopSound = (0, import_react41.useCallback)(async (soundId) => {
36510
+ const stopSound = (0, import_react42.useCallback)(async (soundId) => {
35712
36511
  const bridge2 = getBridge();
35713
36512
  await bridge2.request(WORKER_METHODS.SOUND_STOP, { sound_id: soundId });
35714
36513
  }, []);
35715
- const getSounds = (0, import_react41.useCallback)(async () => {
36514
+ const getSounds = (0, import_react42.useCallback)(async () => {
35716
36515
  const bridge2 = getBridge();
35717
36516
  const result = await bridge2.request(WORKER_METHODS.SOUND_LIST, {});
35718
36517
  return result ?? [];
@@ -35721,14 +36520,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35721
36520
  }
35722
36521
 
35723
36522
  // src/hooks/useQuery.ts
35724
- var import_react42 = __toESM(require_react());
36523
+ var import_react43 = __toESM(require_react());
35725
36524
  function useQuery(functionName, params) {
35726
- const [data, setData] = (0, import_react42.useState)(null);
35727
- const [isLoading, setIsLoading] = (0, import_react42.useState)(false);
35728
- const [error48, setError] = (0, import_react42.useState)(null);
35729
- const fnRef = (0, import_react42.useRef)(functionName);
36525
+ const [data, setData] = (0, import_react43.useState)(null);
36526
+ const [isLoading, setIsLoading] = (0, import_react43.useState)(false);
36527
+ const [error48, setError] = (0, import_react43.useState)(null);
36528
+ const fnRef = (0, import_react43.useRef)(functionName);
35730
36529
  fnRef.current = functionName;
35731
- const sendQuery = (0, import_react42.useCallback)(() => {
36530
+ const sendQuery = (0, import_react43.useCallback)(() => {
35732
36531
  setIsLoading(true);
35733
36532
  setError(null);
35734
36533
  const bridge2 = getBridge();
@@ -35742,19 +36541,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35742
36541
  setData(null);
35743
36542
  });
35744
36543
  }, [functionName, params]);
35745
- (0, import_react42.useEffect)(() => {
36544
+ (0, import_react43.useEffect)(() => {
35746
36545
  sendQuery();
35747
36546
  }, [sendQuery]);
35748
36547
  return { data, isLoading, error: error48, refetch: sendQuery };
35749
36548
  }
35750
36549
 
35751
36550
  // src/hooks/useMutation.ts
35752
- var import_react43 = __toESM(require_react());
36551
+ var import_react44 = __toESM(require_react());
35753
36552
  function useMutation(functionName) {
35754
- const [data, setData] = (0, import_react43.useState)(null);
35755
- const [isLoading, setIsLoading] = (0, import_react43.useState)(false);
35756
- const [error48, setError] = (0, import_react43.useState)(null);
35757
- const sendMutation = (0, import_react43.useCallback)(
36553
+ const [data, setData] = (0, import_react44.useState)(null);
36554
+ const [isLoading, setIsLoading] = (0, import_react44.useState)(false);
36555
+ const [error48, setError] = (0, import_react44.useState)(null);
36556
+ const sendMutation = (0, import_react44.useCallback)(
35758
36557
  (params = {}) => {
35759
36558
  setIsLoading(true);
35760
36559
  setError(null);
@@ -35774,11 +36573,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35774
36573
  },
35775
36574
  [functionName]
35776
36575
  );
35777
- const mutateAsync = (0, import_react43.useCallback)(
36576
+ const mutateAsync = (0, import_react44.useCallback)(
35778
36577
  (params) => sendMutation(params),
35779
36578
  [sendMutation]
35780
36579
  );
35781
- const mutate = (0, import_react43.useCallback)(
36580
+ const mutate = (0, import_react44.useCallback)(
35782
36581
  (params) => {
35783
36582
  sendMutation(params).catch(() => {
35784
36583
  });
@@ -35791,8 +36590,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35791
36590
  // src/animation/keyframes.ts
35792
36591
  var registry2 = /* @__PURE__ */ new Map();
35793
36592
  var counter = 0;
35794
- function camelToKebab(str) {
35795
- return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
36593
+ function camelToKebab(str2) {
36594
+ return str2.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
35796
36595
  }
35797
36596
  function keyframesToCSS(name, def) {
35798
36597
  const stops = Object.entries(def).map(([stop, block]) => {
@@ -35874,7 +36673,7 @@ ${stops}
35874
36673
  }
35875
36674
 
35876
36675
  // src/animation/Animated.tsx
35877
- var import_react44 = __toESM(require_react());
36676
+ var import_react45 = __toESM(require_react());
35878
36677
  function resolveAnimation(name) {
35879
36678
  if (name === void 0) return void 0;
35880
36679
  try {
@@ -35895,16 +36694,16 @@ ${stops}
35895
36694
  visible = true,
35896
36695
  onAnimationEnd
35897
36696
  }) {
35898
- const [phase, setPhase] = (0, import_react44.useState)(() => visible ? "in" : "idle");
35899
- const prevVisibleRef = (0, import_react44.useRef)(visible);
35900
- const timerRef = (0, import_react44.useRef)(null);
36697
+ const [phase, setPhase] = (0, import_react45.useState)(() => visible ? "in" : "idle");
36698
+ const prevVisibleRef = (0, import_react45.useRef)(visible);
36699
+ const timerRef = (0, import_react45.useRef)(null);
35901
36700
  function clearTimer() {
35902
36701
  if (timerRef.current !== null) {
35903
36702
  clearTimeout(timerRef.current);
35904
36703
  timerRef.current = null;
35905
36704
  }
35906
36705
  }
35907
- (0, import_react44.useEffect)(() => {
36706
+ (0, import_react45.useEffect)(() => {
35908
36707
  const prevVisible = prevVisibleRef.current;
35909
36708
  prevVisibleRef.current = visible;
35910
36709
  if (visible && !prevVisible) {
@@ -35915,7 +36714,7 @@ ${stops}
35915
36714
  setPhase("out");
35916
36715
  }
35917
36716
  }, [visible]);
35918
- (0, import_react44.useEffect)(() => {
36717
+ (0, import_react45.useEffect)(() => {
35919
36718
  if (phase === "in") {
35920
36719
  const totalDuration = duration3 + delay;
35921
36720
  if (loopProp !== void 0) {
@@ -35969,11 +36768,11 @@ ${stops}
35969
36768
  animationStyles.animationIterationCount = 1;
35970
36769
  }
35971
36770
  }
35972
- return import_react44.default.createElement("Box", { style: animationStyles }, children);
36771
+ return import_react45.default.createElement("Box", { style: animationStyles }, children);
35973
36772
  }
35974
36773
 
35975
36774
  // src/animation/useAnimation.ts
35976
- var import_react45 = __toESM(require_react());
36775
+ var import_react46 = __toESM(require_react());
35977
36776
  function resolvePreset(name) {
35978
36777
  try {
35979
36778
  return getPreset(name);
@@ -35982,10 +36781,10 @@ ${stops}
35982
36781
  }
35983
36782
  }
35984
36783
  function useAnimation() {
35985
- const [isAnimating, setIsAnimating] = (0, import_react45.useState)(false);
35986
- const [currentAnimation, setCurrentAnimation] = (0, import_react45.useState)(null);
35987
- const [style, setStyle] = (0, import_react45.useState)({});
35988
- const trigger = (0, import_react45.useCallback)((preset, duration3 = 300) => {
36784
+ const [isAnimating, setIsAnimating] = (0, import_react46.useState)(false);
36785
+ const [currentAnimation, setCurrentAnimation] = (0, import_react46.useState)(null);
36786
+ const [style, setStyle] = (0, import_react46.useState)({});
36787
+ const trigger = (0, import_react46.useCallback)((preset, duration3 = 300) => {
35989
36788
  const animationName = resolvePreset(preset);
35990
36789
  setIsAnimating(true);
35991
36790
  setCurrentAnimation(preset);
@@ -35996,7 +36795,7 @@ ${stops}
35996
36795
  });
35997
36796
  return animationName;
35998
36797
  }, []);
35999
- const reset = (0, import_react45.useCallback)(() => {
36798
+ const reset = (0, import_react46.useCallback)(() => {
36000
36799
  setIsAnimating(false);
36001
36800
  setCurrentAnimation(null);
36002
36801
  setStyle({});
@@ -36009,12 +36808,21 @@ ${stops}
36009
36808
  if (lower.endsWith(".woff")) return "woff";
36010
36809
  return "truetype";
36011
36810
  }
36811
+ var FAMILY_RE = /^[\w -]+$/;
36812
+ function escapeCssUrl(src) {
36813
+ return src.replace(/[\\"\n\r\f]/g, (c) => `\\${c}`);
36814
+ }
36012
36815
  function buildFontFace(family, src, display, weight, style) {
36816
+ if (!FAMILY_RE.test(family)) {
36817
+ throw new Error(
36818
+ `Invalid font family "${family}": only letters, digits, spaces, "-" and "_" are allowed.`
36819
+ );
36820
+ }
36013
36821
  const format = formatFromPath(src);
36014
36822
  const lines = [
36015
36823
  "@font-face {",
36016
36824
  ` font-family: "${family}";`,
36017
- ` src: url("${src}") format("${format}");`,
36825
+ ` src: url("${escapeCssUrl(src)}") format("${format}");`,
36018
36826
  ` font-display: ${display};`
36019
36827
  ];
36020
36828
  if (weight !== void 0) {
@@ -36130,8 +36938,14 @@ ${stops}
36130
36938
  };
36131
36939
 
36132
36940
  // src/server/queryRows.ts
36133
- function queryRows(table) {
36134
- return { __type: "queryRows", table };
36941
+ function queryRows(table, opts) {
36942
+ const def = { __type: "queryRows", table };
36943
+ if (opts?.filter !== void 0) def.filter = opts.filter;
36944
+ if (opts?.orderBy !== void 0) def.orderBy = opts.orderBy;
36945
+ if (opts?.orderDir !== void 0) def.orderDir = opts.orderDir;
36946
+ if (opts?.limit !== void 0) def.limit = opts.limit;
36947
+ if (opts?.offset !== void 0) def.offset = opts.offset;
36948
+ return def;
36135
36949
  }
36136
36950
 
36137
36951
  // src/server/insertRow.ts
@@ -36167,13 +36981,13 @@ ${stops}
36167
36981
 
36168
36982
  // src/server/handlers.ts
36169
36983
  function query(config2) {
36170
- return { __type: "query", args: config2.args, handler: config2.handler };
36984
+ return { __type: "query", args: config2.args, editorOnly: config2.editorOnly, handler: config2.handler };
36171
36985
  }
36172
36986
  function mutation(config2) {
36173
- return { __type: "mutation", args: config2.args, handler: config2.handler };
36987
+ return { __type: "mutation", args: config2.args, editorOnly: config2.editorOnly, handler: config2.handler };
36174
36988
  }
36175
36989
  function action(config2) {
36176
- return { __type: "action", args: config2.args, handler: config2.handler };
36990
+ return { __type: "action", args: config2.args, editorOnly: config2.editorOnly, handler: config2.handler };
36177
36991
  }
36178
36992
 
36179
36993
  // src/server/fetchAction.ts
@@ -36260,7 +37074,7 @@ ${stops}
36260
37074
  }
36261
37075
 
36262
37076
  // src/renderer/render.ts
36263
- var import_react46 = __toESM(require_react());
37077
+ var import_react47 = __toESM(require_react());
36264
37078
  var import_react_reconciler = __toESM(require_react_reconciler());
36265
37079
 
36266
37080
  // src/renderer/reconciler.ts
@@ -36321,7 +37135,12 @@ ${stops}
36321
37135
  }
36322
37136
 
36323
37137
  // src/renderer/host-config.ts
36324
- function createHostConfig(registry3) {
37138
+ var NO_EVENT_PRIORITY = 0;
37139
+ var DISCRETE_EVENT_PRIORITY = 2;
37140
+ var LEGACY_UPDATE_PRIORITY = 16;
37141
+ function createHostConfig(registry3, options = {}) {
37142
+ const syncUpdates = options.syncUpdates === true;
37143
+ let currentUpdatePriority = NO_EVENT_PRIORITY;
36325
37144
  return {
36326
37145
  supportsMutation: true,
36327
37146
  supportsPersistence: false,
@@ -36443,13 +37262,15 @@ ${stops}
36443
37262
  return null;
36444
37263
  },
36445
37264
  // Priority methods required by react-reconciler 0.32
36446
- setCurrentUpdatePriority() {
37265
+ setCurrentUpdatePriority(priority) {
37266
+ if (syncUpdates) currentUpdatePriority = priority;
36447
37267
  },
36448
37268
  getCurrentUpdatePriority() {
36449
- return 16;
37269
+ return syncUpdates ? currentUpdatePriority : LEGACY_UPDATE_PRIORITY;
36450
37270
  },
36451
37271
  resolveUpdatePriority() {
36452
- return 16;
37272
+ if (!syncUpdates) return LEGACY_UPDATE_PRIORITY;
37273
+ return currentUpdatePriority !== NO_EVENT_PRIORITY ? currentUpdatePriority : DISCRETE_EVENT_PRIORITY;
36453
37274
  },
36454
37275
  // Transition support (not used — Lumio SDK does not support transitions)
36455
37276
  NotPendingTransition: null,
@@ -36502,11 +37323,12 @@ ${stops}
36502
37323
 
36503
37324
  // src/renderer/render.ts
36504
37325
  var hasRendered2 = false;
36505
- function createReconcilerAndRender(element) {
37326
+ function mountRoot(element, options = {}) {
36506
37327
  const registry3 = getRegistry();
36507
37328
  const bridge2 = getBridge();
36508
- const hostConfig = createHostConfig(registry3);
37329
+ const hostConfig = createHostConfig(registry3, { syncUpdates: options.syncUpdates });
36509
37330
  const reconciler = (0, import_react_reconciler.default)(hostConfig);
37331
+ const { flushSyncFromReconciler } = reconciler;
36510
37332
  let lastFingerprint = "";
36511
37333
  const container = {
36512
37334
  children: [],
@@ -36545,16 +37367,35 @@ ${stops}
36545
37367
  null
36546
37368
  // transitionCallbacks
36547
37369
  );
36548
- bridge2.onNotification(HOST_METHODS.EVENT_CALLBACK, (params) => {
37370
+ const stopCallbacks = bridge2.onNotification(HOST_METHODS.EVENT_CALLBACK, (params) => {
36549
37371
  const { handlerId, args } = params;
36550
37372
  try {
36551
37373
  registry3.invoke(handlerId, args);
36552
37374
  } catch {
36553
37375
  }
36554
37376
  });
36555
- reconciler.updateContainer(element, root, null, () => {
36556
- bridge2.notify("ui.ready", {});
37377
+ const flushSync = (fn) => {
37378
+ if (options.syncUpdates) {
37379
+ flushSyncFromReconciler(fn);
37380
+ reconciler.flushPassiveEffects();
37381
+ } else {
37382
+ fn();
37383
+ }
37384
+ };
37385
+ flushSync(() => {
37386
+ reconciler.updateContainer(element, root, null, () => {
37387
+ bridge2.notify("ui.ready", {});
37388
+ });
36557
37389
  });
37390
+ return {
37391
+ flushSync,
37392
+ unmount() {
37393
+ stopCallbacks();
37394
+ flushSync(() => {
37395
+ reconciler.updateContainer(null, root, null, null);
37396
+ });
37397
+ }
37398
+ };
36558
37399
  }
36559
37400
  var Lumio2 = {
36560
37401
  render(input, _options) {
@@ -36562,12 +37403,82 @@ ${stops}
36562
37403
  throw new Error("Lumio.render() can only be called once");
36563
37404
  }
36564
37405
  hasRendered2 = true;
36565
- const element = typeof input === "function" ? (0, import_react46.createElement)(input) : input;
36566
- createReconcilerAndRender(element);
37406
+ const element = typeof input === "function" ? (0, import_react47.createElement)(input) : input;
37407
+ mountRoot(element);
36567
37408
  }
36568
37409
  };
36569
37410
 
37411
+ // src/runtime/lockdown.ts
37412
+ var BLOCKED_GLOBAL_PROPS = [
37413
+ // Origin-scoped storage
37414
+ "indexedDB",
37415
+ "caches",
37416
+ // Cross-context channels on the shared origin
37417
+ "BroadcastChannel",
37418
+ // Nested workers would start with a fresh, un-locked global
37419
+ "Worker",
37420
+ "SharedWorker",
37421
+ // Legacy origin-scoped file systems (Chromium)
37422
+ "webkitRequestFileSystem",
37423
+ "webkitRequestFileSystemSync",
37424
+ "webkitResolveLocalFileSystemURL",
37425
+ "webkitResolveLocalFileSystemSyncURL"
37426
+ ];
37427
+ var BLOCKED_NAVIGATOR_PROPS = [
37428
+ // StorageManager — quota, persistence and the origin-private file system
37429
+ "storage",
37430
+ // Web Locks are shared by every context on the origin
37431
+ "locks",
37432
+ // Service workers are registered per origin
37433
+ "serviceWorker",
37434
+ // Storage Buckets (Chromium 122+) — each bucket opens its own indexedDB,
37435
+ // caches and getDirectory(), all shared across the origin
37436
+ "storageBuckets"
37437
+ ];
37438
+ function blockedError(prop) {
37439
+ const message = `${prop} is not available in the Lumio extension sandbox`;
37440
+ return typeof DOMException === "function" ? new DOMException(message, "SecurityError") : new Error(message);
37441
+ }
37442
+ function blockProperty(target, prop) {
37443
+ const descriptor = {
37444
+ get() {
37445
+ throw blockedError(prop);
37446
+ },
37447
+ set() {
37448
+ throw blockedError(prop);
37449
+ },
37450
+ enumerable: false,
37451
+ configurable: false
37452
+ };
37453
+ let obj = Object.getPrototypeOf(target);
37454
+ while (obj && obj !== Object.prototype) {
37455
+ if (Object.prototype.hasOwnProperty.call(obj, prop)) {
37456
+ try {
37457
+ Object.defineProperty(obj, prop, descriptor);
37458
+ } catch {
37459
+ }
37460
+ }
37461
+ obj = Object.getPrototypeOf(obj);
37462
+ }
37463
+ try {
37464
+ Object.defineProperty(target, prop, descriptor);
37465
+ } catch {
37466
+ }
37467
+ }
37468
+ function lockDownWorkerGlobal(scope = globalThis) {
37469
+ const nav = scope.navigator;
37470
+ for (const prop of BLOCKED_GLOBAL_PROPS) {
37471
+ blockProperty(scope, prop);
37472
+ }
37473
+ if (nav && typeof nav === "object") {
37474
+ for (const prop of BLOCKED_NAVIGATOR_PROPS) {
37475
+ blockProperty(nav, prop);
37476
+ }
37477
+ }
37478
+ }
37479
+
36570
37480
  // src/runtime/worker-entry.ts
37481
+ lockDownWorkerGlobal();
36571
37482
  var LumioSDK = {
36572
37483
  ...src_exports,
36573
37484
  Lumio: Lumio2
@@ -36590,11 +37501,12 @@ ${stops}
36590
37501
  var bridge = getBridge();
36591
37502
  var extensionLoaded = false;
36592
37503
  bridge.onNotification(HOST_METHODS.LIFECYCLE_INIT, (params) => {
36593
- const initParams = params;
37504
+ const initParams2 = params;
37505
+ setInitParams(initParams2);
36594
37506
  if (extensionLoaded) return;
36595
- if (initParams.bundleCode) {
37507
+ if (initParams2.bundleCode) {
36596
37508
  try {
36597
- (0, eval)(initParams.bundleCode);
37509
+ (0, eval)(initParams2.bundleCode);
36598
37510
  extensionLoaded = true;
36599
37511
  } catch (err) {
36600
37512
  bridge.notify("ui.error", {
@@ -36604,12 +37516,12 @@ ${stops}
36604
37516
  }
36605
37517
  return;
36606
37518
  }
36607
- if (!initParams.bundleUrl) {
37519
+ if (!initParams2.bundleUrl) {
36608
37520
  bridge.notify("ui.error", { code: "MISSING_BUNDLE", message: "No bundle URL or code provided" });
36609
37521
  return;
36610
37522
  }
36611
37523
  try {
36612
- importScripts(initParams.bundleUrl);
37524
+ importScripts(initParams2.bundleUrl);
36613
37525
  extensionLoaded = true;
36614
37526
  } catch (err) {
36615
37527
  bridge.notify("ui.error", {