@zaflun/lumio-sdk 0.6.6 → 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.
@@ -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
 
@@ -21306,6 +21307,7 @@
21306
21307
  // src/renderer/bridge-context.ts
21307
21308
  var bridgeInstance = null;
21308
21309
  var registryInstance = null;
21310
+ var initParams = null;
21309
21311
  function getBridge() {
21310
21312
  if (!bridgeInstance) {
21311
21313
  bridgeInstance = new WorkerBridge();
@@ -21318,6 +21320,15 @@
21318
21320
  }
21319
21321
  return registryInstance;
21320
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
+ }
21321
21332
  function destroyBridgeContext() {
21322
21333
  if (bridgeInstance) {
21323
21334
  bridgeInstance.destroy();
@@ -21327,6 +21338,7 @@
21327
21338
  registryInstance.clear();
21328
21339
  registryInstance = null;
21329
21340
  }
21341
+ initParams = null;
21330
21342
  }
21331
21343
 
21332
21344
  // src/hooks/useEditorAction.ts
@@ -21368,15 +21380,20 @@
21368
21380
  // ../protocol/dist/index.js
21369
21381
  var dist_exports = {};
21370
21382
  __export(dist_exports, {
21383
+ ACTION_EXECUTE_ERRORS: () => ACTION_EXECUTE_ERRORS,
21371
21384
  ACTION_TYPES: () => ACTION_TYPES,
21372
21385
  EXTENSION_RUNTIME_LABEL_PLACEHOLDER: () => EXTENSION_RUNTIME_LABEL_PLACEHOLDER,
21373
21386
  HOST_METHODS: () => HOST_METHODS,
21374
21387
  LUMIO_COMPONENT_TYPES: () => LUMIO_COMPONENT_TYPES,
21388
+ LUMIO_EVENT_PAYLOAD_SCHEMAS: () => LUMIO_EVENT_PAYLOAD_SCHEMAS,
21375
21389
  LUMIO_EVENT_TYPES: () => LUMIO_EVENT_TYPES,
21376
21390
  MESSAGE_TYPES: () => MESSAGE_TYPES,
21391
+ REALTIME_LIMITS: () => REALTIME_LIMITS,
21392
+ SERVER_FUNCTION_ERRORS: () => SERVER_FUNCTION_ERRORS,
21377
21393
  STORAGE_SCOPES: () => STORAGE_SCOPES,
21378
21394
  WORKER_METHODS: () => WORKER_METHODS,
21379
21395
  actionMessageSchema: () => actionMessageSchema,
21396
+ chatMessagePayloadSchema: () => chatMessagePayloadSchema,
21380
21397
  configUpdateMessageSchema: () => configUpdateMessageSchema,
21381
21398
  errorMessageSchema: () => errorMessageSchema,
21382
21399
  eventMessageSchema: () => eventMessageSchema,
@@ -21387,10 +21404,12 @@
21387
21404
  initMessageSchema: () => initMessageSchema,
21388
21405
  isValidExtensionRuntimeOriginTemplate: () => isValidExtensionRuntimeOriginTemplate,
21389
21406
  lumioActionTypeSchema: () => lumioActionTypeSchema,
21407
+ lumioEventPayloadSchema: () => lumioEventPayloadSchema,
21390
21408
  lumioEventTypeSchema: () => lumioEventTypeSchema,
21391
21409
  lumioMessageSchema: () => lumioMessageSchema,
21392
21410
  nodeConfigRequestMessageSchema: () => nodeConfigRequestMessageSchema,
21393
21411
  nodeConfigUpdateMessageSchema: () => nodeConfigUpdateMessageSchema,
21412
+ parseLumioEventPayload: () => parseLumioEventPayload,
21394
21413
  readyMessageSchema: () => readyMessageSchema,
21395
21414
  storageScopeSchema: () => storageScopeSchema,
21396
21415
  storageUpdateMessageSchema: () => storageUpdateMessageSchema,
@@ -22228,14 +22247,14 @@
22228
22247
  }
22229
22248
  function randomString(length = 10) {
22230
22249
  const chars = "abcdefghijklmnopqrstuvwxyz";
22231
- let str = "";
22250
+ let str2 = "";
22232
22251
  for (let i = 0; i < length; i++) {
22233
- str += chars[Math.floor(Math.random() * chars.length)];
22252
+ str2 += chars[Math.floor(Math.random() * chars.length)];
22234
22253
  }
22235
- return str;
22254
+ return str2;
22236
22255
  }
22237
- function esc(str) {
22238
- return JSON.stringify(str);
22256
+ function esc(str2) {
22257
+ return JSON.stringify(str2);
22239
22258
  }
22240
22259
  function slugify(input) {
22241
22260
  return input.toLowerCase().trim().replace(/[^\w\s-]/g, "").replace(/[\s_-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -22335,8 +22354,8 @@
22335
22354
  };
22336
22355
  var propertyKeyTypes = /* @__PURE__ */ new Set(["string", "number", "symbol"]);
22337
22356
  var primitiveTypes = /* @__PURE__ */ new Set(["string", "number", "bigint", "boolean", "symbol", "undefined"]);
22338
- function escapeRegex(str) {
22339
- return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22357
+ function escapeRegex(str2) {
22358
+ return str2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22340
22359
  }
22341
22360
  function clone(inst, def, params) {
22342
22361
  const cl = new inst._zod.constr(def ?? inst._zod.def);
@@ -35236,7 +35255,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35236
35255
  extension_id: external_exports.string(),
35237
35256
  install_id: external_exports.string(),
35238
35257
  account_id: external_exports.string(),
35239
- target: external_exports.enum(["editor", "layer", "interactive"]),
35258
+ target: external_exports.enum(["editor", "layer"]),
35240
35259
  permissions: external_exports.array(external_exports.string()),
35241
35260
  settings: external_exports.record(external_exports.string(), external_exports.unknown())
35242
35261
  });
@@ -35316,11 +35335,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35316
35335
  // Twitch
35317
35336
  "twitch:follower",
35318
35337
  "twitch:subscribe",
35319
- "twitch:gift_sub",
35338
+ "twitch:gift",
35320
35339
  "twitch:resub",
35321
35340
  "twitch:cheer",
35322
35341
  "twitch:raid",
35323
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",
35324
35350
  "twitch:hype_train",
35325
35351
  "twitch:hype_train_end",
35326
35352
  "twitch:poll",
@@ -35419,6 +35445,645 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35419
35445
  "global"
35420
35446
  ];
35421
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
+ }
35422
36087
  var LUMIO_COMPONENT_TYPES = [
35423
36088
  "Box",
35424
36089
  "VStack",
@@ -35451,6 +36116,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35451
36116
  "EditorFontPicker",
35452
36117
  "EditorChannelRow"
35453
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
+ };
35454
36147
  var WORKER_METHODS = {
35455
36148
  UI_RENDER: "ui.render",
35456
36149
  UI_READY: "ui.ready",
@@ -35463,7 +36156,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35463
36156
  UI_ACTION: "ui.action",
35464
36157
  SOUND_PLAY: "sound.play",
35465
36158
  SOUND_STOP: "sound.stop",
35466
- SOUND_LIST: "sound.list"
36159
+ SOUND_LIST: "sound.list",
36160
+ ACTION_EXECUTE: "action.execute"
35467
36161
  };
35468
36162
  var HOST_METHODS = {
35469
36163
  LIFECYCLE_INIT: "lifecycle.init",
@@ -35472,7 +36166,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35472
36166
  EVENT_PLATFORM: "event.platform",
35473
36167
  STORAGE_UPDATE: "storage.update",
35474
36168
  THEME_CHANGE: "theme.change",
35475
- 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
35476
36186
  };
35477
36187
 
35478
36188
  // src/hooks/useExtensionStorage.ts
@@ -35549,24 +36259,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35549
36259
  var defaultContext = {
35550
36260
  extensionId: null,
35551
36261
  target: null,
35552
- overlayId: null,
35553
- interactiveUrl: null
36262
+ overlayId: null
35554
36263
  };
36264
+ function fromInit(p) {
36265
+ return {
36266
+ extensionId: p.extensionId ?? null,
36267
+ target: p.target ?? null,
36268
+ overlayId: p.installId ?? null
36269
+ };
36270
+ }
35555
36271
  function useExtensionContext() {
35556
- 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
+ });
35557
36276
  (0, import_react35.useEffect)(() => {
35558
36277
  const bridge2 = getBridge();
35559
36278
  const unsub = bridge2.onNotification(
35560
36279
  HOST_METHODS.LIFECYCLE_INIT,
35561
- (params) => {
35562
- const p = params;
35563
- setContext({
35564
- extensionId: p.extensionId ?? null,
35565
- target: p.target ?? null,
35566
- overlayId: p.installId ?? null,
35567
- interactiveUrl: p.interactiveUrl ?? null
35568
- });
35569
- }
36280
+ (params) => setContext(fromInit(params))
35570
36281
  );
35571
36282
  return unsub;
35572
36283
  }, []);
@@ -35576,7 +36287,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35576
36287
  // src/hooks/useLumioEvent.ts
35577
36288
  var import_react36 = __toESM(require_react());
35578
36289
  function useLumioEvent(eventType) {
35579
- const [eventData, setEventData] = (0, import_react36.useState)(null);
36290
+ const [eventData, setEventData] = (0, import_react36.useState)(
36291
+ null
36292
+ );
35580
36293
  (0, import_react36.useEffect)(() => {
35581
36294
  const bridge2 = getBridge();
35582
36295
  const unsub = bridge2.onNotification(
@@ -35593,17 +36306,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35593
36306
  return eventData;
35594
36307
  }
35595
36308
 
35596
- // src/hooks/useLumioConfig.ts
36309
+ // src/hooks/useRealtime.ts
35597
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());
35598
36327
  function hasShim() {
35599
36328
  return typeof window !== "undefined" && typeof window.__lumio_config === "function";
35600
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
+ }
35601
36340
  function useLumioConfig() {
35602
- const [config2, setConfigState] = (0, import_react37.useState)(() => {
36341
+ const [config2, setConfigState] = (0, import_react38.useState)(() => {
35603
36342
  if (hasShim()) return window.__lumio_config();
35604
- return {};
36343
+ const init = getInitParams();
36344
+ return init ? fromInit2(init) : {};
35605
36345
  });
35606
- (0, import_react37.useEffect)(() => {
36346
+ (0, import_react38.useEffect)(() => {
35607
36347
  if (hasShim()) {
35608
36348
  const unsub2 = window.__lumio_on_config((newConfig) => {
35609
36349
  setConfigState(newConfig);
@@ -35614,23 +36354,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35614
36354
  const bridge2 = getBridge();
35615
36355
  const unsub = bridge2.onNotification(
35616
36356
  HOST_METHODS.LIFECYCLE_INIT,
35617
- (params) => {
35618
- const p = params;
35619
- setConfigState({
35620
- extension_id: p.extensionId,
35621
- install_id: p.installId,
35622
- account_id: p.accountId,
35623
- target: p.target,
35624
- permissions: p.permissions,
35625
- settings: p.settings
35626
- });
35627
- }
36357
+ (params) => setConfigState(fromInit2(params))
35628
36358
  );
35629
36359
  const unsubConfig = bridge2.onNotification(
35630
36360
  HOST_METHODS.CONFIG_UPDATE,
35631
36361
  (params) => {
35632
36362
  const p = params;
35633
- setConfigState(p);
36363
+ setConfigState((prev) => ({ ...prev, ...p }));
35634
36364
  }
35635
36365
  );
35636
36366
  return () => {
@@ -35638,7 +36368,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35638
36368
  unsubConfig();
35639
36369
  };
35640
36370
  }, []);
35641
- const setConfig = (0, import_react37.useCallback)(
36371
+ const setConfig = (0, import_react38.useCallback)(
35642
36372
  (newConfigOrUpdater) => {
35643
36373
  setConfigState((prev) => {
35644
36374
  const next = typeof newConfigOrUpdater === "function" ? newConfigOrUpdater(prev) : newConfigOrUpdater;
@@ -35657,7 +36387,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35657
36387
  }
35658
36388
 
35659
36389
  // src/hooks/useLumioTheme.ts
35660
- var import_react38 = __toESM(require_react());
36390
+ var import_react39 = __toESM(require_react());
35661
36391
  var DEFAULT_THEME = {
35662
36392
  colors: {
35663
36393
  primary: "#6366f1",
@@ -35681,8 +36411,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35681
36411
  spacing: 8
35682
36412
  };
35683
36413
  function useLumioTheme() {
35684
- const [theme, setTheme] = (0, import_react38.useState)(DEFAULT_THEME);
35685
- (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)(() => {
35686
36419
  const bridge2 = getBridge();
35687
36420
  const unsubInit = bridge2.onNotification(
35688
36421
  HOST_METHODS.LIFECYCLE_INIT,
@@ -35711,26 +36444,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35711
36444
  }
35712
36445
 
35713
36446
  // src/hooks/useLumioIdentity.ts
35714
- var import_react39 = __toESM(require_react());
36447
+ var import_react40 = __toESM(require_react());
35715
36448
  var defaultIdentity = {
35716
36449
  userId: null,
35717
36450
  accountId: null,
35718
36451
  role: null
35719
36452
  };
36453
+ function fromInit3(p) {
36454
+ return {
36455
+ userId: p.userId ?? null,
36456
+ accountId: p.accountId ?? null,
36457
+ role: p.role ?? null
36458
+ };
36459
+ }
35720
36460
  function useLumioIdentity() {
35721
- const [identity2, setIdentity] = (0, import_react39.useState)(defaultIdentity);
35722
- (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)(() => {
35723
36466
  const bridge2 = getBridge();
35724
36467
  const unsub = bridge2.onNotification(
35725
36468
  HOST_METHODS.LIFECYCLE_INIT,
35726
- (params) => {
35727
- const p = params;
35728
- setIdentity({
35729
- userId: p.userId ?? null,
35730
- accountId: p.accountId ?? null,
35731
- role: p.role ?? null
35732
- });
35733
- }
36469
+ (params) => setIdentity(fromInit3(params))
35734
36470
  );
35735
36471
  return unsub;
35736
36472
  }, []);
@@ -35738,27 +36474,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35738
36474
  }
35739
36475
 
35740
36476
  // src/hooks/useLumioAction.ts
35741
- var import_react40 = __toESM(require_react());
36477
+ var import_react41 = __toESM(require_react());
35742
36478
  function useLumioAction(action2) {
35743
- const [data, setData] = (0, import_react40.useState)(null);
35744
- const [isLoading, setIsLoading] = (0, import_react40.useState)(false);
35745
- const [error48, setError] = (0, import_react40.useState)(null);
35746
- const actionRef = (0, import_react40.useRef)(action2);
35747
- actionRef.current = action2;
35748
- const execute = (0, import_react40.useCallback)(
35749
- (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 = {}) => {
35750
36484
  setIsLoading(true);
35751
36485
  setError(null);
35752
- const bridge2 = getBridge();
35753
- bridge2.request("action.execute", { action: action2, params }).then((result) => {
35754
- setIsLoading(false);
35755
- 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);
35756
36490
  setError(null);
35757
- }).catch((err) => {
35758
- setIsLoading(false);
36491
+ } catch (err) {
35759
36492
  setError(err instanceof Error ? err.message : "Unknown error");
35760
36493
  setData(null);
35761
- });
36494
+ } finally {
36495
+ setIsLoading(false);
36496
+ }
35762
36497
  },
35763
36498
  [action2]
35764
36499
  );
@@ -35766,17 +36501,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35766
36501
  }
35767
36502
 
35768
36503
  // src/hooks/useLumioSound.ts
35769
- var import_react41 = __toESM(require_react());
36504
+ var import_react42 = __toESM(require_react());
35770
36505
  function useLumioSound() {
35771
- const playSound = (0, import_react41.useCallback)(async (soundId, volume) => {
36506
+ const playSound = (0, import_react42.useCallback)(async (soundId, volume) => {
35772
36507
  const bridge2 = getBridge();
35773
36508
  await bridge2.request(WORKER_METHODS.SOUND_PLAY, { sound_id: soundId, volume });
35774
36509
  }, []);
35775
- const stopSound = (0, import_react41.useCallback)(async (soundId) => {
36510
+ const stopSound = (0, import_react42.useCallback)(async (soundId) => {
35776
36511
  const bridge2 = getBridge();
35777
36512
  await bridge2.request(WORKER_METHODS.SOUND_STOP, { sound_id: soundId });
35778
36513
  }, []);
35779
- const getSounds = (0, import_react41.useCallback)(async () => {
36514
+ const getSounds = (0, import_react42.useCallback)(async () => {
35780
36515
  const bridge2 = getBridge();
35781
36516
  const result = await bridge2.request(WORKER_METHODS.SOUND_LIST, {});
35782
36517
  return result ?? [];
@@ -35785,14 +36520,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35785
36520
  }
35786
36521
 
35787
36522
  // src/hooks/useQuery.ts
35788
- var import_react42 = __toESM(require_react());
36523
+ var import_react43 = __toESM(require_react());
35789
36524
  function useQuery(functionName, params) {
35790
- const [data, setData] = (0, import_react42.useState)(null);
35791
- const [isLoading, setIsLoading] = (0, import_react42.useState)(false);
35792
- const [error48, setError] = (0, import_react42.useState)(null);
35793
- 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);
35794
36529
  fnRef.current = functionName;
35795
- const sendQuery = (0, import_react42.useCallback)(() => {
36530
+ const sendQuery = (0, import_react43.useCallback)(() => {
35796
36531
  setIsLoading(true);
35797
36532
  setError(null);
35798
36533
  const bridge2 = getBridge();
@@ -35806,19 +36541,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35806
36541
  setData(null);
35807
36542
  });
35808
36543
  }, [functionName, params]);
35809
- (0, import_react42.useEffect)(() => {
36544
+ (0, import_react43.useEffect)(() => {
35810
36545
  sendQuery();
35811
36546
  }, [sendQuery]);
35812
36547
  return { data, isLoading, error: error48, refetch: sendQuery };
35813
36548
  }
35814
36549
 
35815
36550
  // src/hooks/useMutation.ts
35816
- var import_react43 = __toESM(require_react());
36551
+ var import_react44 = __toESM(require_react());
35817
36552
  function useMutation(functionName) {
35818
- const [data, setData] = (0, import_react43.useState)(null);
35819
- const [isLoading, setIsLoading] = (0, import_react43.useState)(false);
35820
- const [error48, setError] = (0, import_react43.useState)(null);
35821
- 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)(
35822
36557
  (params = {}) => {
35823
36558
  setIsLoading(true);
35824
36559
  setError(null);
@@ -35838,11 +36573,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35838
36573
  },
35839
36574
  [functionName]
35840
36575
  );
35841
- const mutateAsync = (0, import_react43.useCallback)(
36576
+ const mutateAsync = (0, import_react44.useCallback)(
35842
36577
  (params) => sendMutation(params),
35843
36578
  [sendMutation]
35844
36579
  );
35845
- const mutate = (0, import_react43.useCallback)(
36580
+ const mutate = (0, import_react44.useCallback)(
35846
36581
  (params) => {
35847
36582
  sendMutation(params).catch(() => {
35848
36583
  });
@@ -35855,8 +36590,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
35855
36590
  // src/animation/keyframes.ts
35856
36591
  var registry2 = /* @__PURE__ */ new Map();
35857
36592
  var counter = 0;
35858
- function camelToKebab(str) {
35859
- return str.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
36593
+ function camelToKebab(str2) {
36594
+ return str2.replace(/([A-Z])/g, (match) => `-${match.toLowerCase()}`);
35860
36595
  }
35861
36596
  function keyframesToCSS(name, def) {
35862
36597
  const stops = Object.entries(def).map(([stop, block]) => {
@@ -35938,7 +36673,7 @@ ${stops}
35938
36673
  }
35939
36674
 
35940
36675
  // src/animation/Animated.tsx
35941
- var import_react44 = __toESM(require_react());
36676
+ var import_react45 = __toESM(require_react());
35942
36677
  function resolveAnimation(name) {
35943
36678
  if (name === void 0) return void 0;
35944
36679
  try {
@@ -35959,16 +36694,16 @@ ${stops}
35959
36694
  visible = true,
35960
36695
  onAnimationEnd
35961
36696
  }) {
35962
- const [phase, setPhase] = (0, import_react44.useState)(() => visible ? "in" : "idle");
35963
- const prevVisibleRef = (0, import_react44.useRef)(visible);
35964
- 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);
35965
36700
  function clearTimer() {
35966
36701
  if (timerRef.current !== null) {
35967
36702
  clearTimeout(timerRef.current);
35968
36703
  timerRef.current = null;
35969
36704
  }
35970
36705
  }
35971
- (0, import_react44.useEffect)(() => {
36706
+ (0, import_react45.useEffect)(() => {
35972
36707
  const prevVisible = prevVisibleRef.current;
35973
36708
  prevVisibleRef.current = visible;
35974
36709
  if (visible && !prevVisible) {
@@ -35979,7 +36714,7 @@ ${stops}
35979
36714
  setPhase("out");
35980
36715
  }
35981
36716
  }, [visible]);
35982
- (0, import_react44.useEffect)(() => {
36717
+ (0, import_react45.useEffect)(() => {
35983
36718
  if (phase === "in") {
35984
36719
  const totalDuration = duration3 + delay;
35985
36720
  if (loopProp !== void 0) {
@@ -36033,11 +36768,11 @@ ${stops}
36033
36768
  animationStyles.animationIterationCount = 1;
36034
36769
  }
36035
36770
  }
36036
- return import_react44.default.createElement("Box", { style: animationStyles }, children);
36771
+ return import_react45.default.createElement("Box", { style: animationStyles }, children);
36037
36772
  }
36038
36773
 
36039
36774
  // src/animation/useAnimation.ts
36040
- var import_react45 = __toESM(require_react());
36775
+ var import_react46 = __toESM(require_react());
36041
36776
  function resolvePreset(name) {
36042
36777
  try {
36043
36778
  return getPreset(name);
@@ -36046,10 +36781,10 @@ ${stops}
36046
36781
  }
36047
36782
  }
36048
36783
  function useAnimation() {
36049
- const [isAnimating, setIsAnimating] = (0, import_react45.useState)(false);
36050
- const [currentAnimation, setCurrentAnimation] = (0, import_react45.useState)(null);
36051
- const [style, setStyle] = (0, import_react45.useState)({});
36052
- 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) => {
36053
36788
  const animationName = resolvePreset(preset);
36054
36789
  setIsAnimating(true);
36055
36790
  setCurrentAnimation(preset);
@@ -36060,7 +36795,7 @@ ${stops}
36060
36795
  });
36061
36796
  return animationName;
36062
36797
  }, []);
36063
- const reset = (0, import_react45.useCallback)(() => {
36798
+ const reset = (0, import_react46.useCallback)(() => {
36064
36799
  setIsAnimating(false);
36065
36800
  setCurrentAnimation(null);
36066
36801
  setStyle({});
@@ -36203,8 +36938,14 @@ ${stops}
36203
36938
  };
36204
36939
 
36205
36940
  // src/server/queryRows.ts
36206
- function queryRows(table) {
36207
- 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;
36208
36949
  }
36209
36950
 
36210
36951
  // src/server/insertRow.ts
@@ -36240,13 +36981,13 @@ ${stops}
36240
36981
 
36241
36982
  // src/server/handlers.ts
36242
36983
  function query(config2) {
36243
- return { __type: "query", args: config2.args, handler: config2.handler };
36984
+ return { __type: "query", args: config2.args, editorOnly: config2.editorOnly, handler: config2.handler };
36244
36985
  }
36245
36986
  function mutation(config2) {
36246
- return { __type: "mutation", args: config2.args, handler: config2.handler };
36987
+ return { __type: "mutation", args: config2.args, editorOnly: config2.editorOnly, handler: config2.handler };
36247
36988
  }
36248
36989
  function action(config2) {
36249
- return { __type: "action", args: config2.args, handler: config2.handler };
36990
+ return { __type: "action", args: config2.args, editorOnly: config2.editorOnly, handler: config2.handler };
36250
36991
  }
36251
36992
 
36252
36993
  // src/server/fetchAction.ts
@@ -36333,7 +37074,7 @@ ${stops}
36333
37074
  }
36334
37075
 
36335
37076
  // src/renderer/render.ts
36336
- var import_react46 = __toESM(require_react());
37077
+ var import_react47 = __toESM(require_react());
36337
37078
  var import_react_reconciler = __toESM(require_react_reconciler());
36338
37079
 
36339
37080
  // src/renderer/reconciler.ts
@@ -36394,7 +37135,12 @@ ${stops}
36394
37135
  }
36395
37136
 
36396
37137
  // src/renderer/host-config.ts
36397
- 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;
36398
37144
  return {
36399
37145
  supportsMutation: true,
36400
37146
  supportsPersistence: false,
@@ -36516,13 +37262,15 @@ ${stops}
36516
37262
  return null;
36517
37263
  },
36518
37264
  // Priority methods required by react-reconciler 0.32
36519
- setCurrentUpdatePriority() {
37265
+ setCurrentUpdatePriority(priority) {
37266
+ if (syncUpdates) currentUpdatePriority = priority;
36520
37267
  },
36521
37268
  getCurrentUpdatePriority() {
36522
- return 16;
37269
+ return syncUpdates ? currentUpdatePriority : LEGACY_UPDATE_PRIORITY;
36523
37270
  },
36524
37271
  resolveUpdatePriority() {
36525
- return 16;
37272
+ if (!syncUpdates) return LEGACY_UPDATE_PRIORITY;
37273
+ return currentUpdatePriority !== NO_EVENT_PRIORITY ? currentUpdatePriority : DISCRETE_EVENT_PRIORITY;
36526
37274
  },
36527
37275
  // Transition support (not used — Lumio SDK does not support transitions)
36528
37276
  NotPendingTransition: null,
@@ -36575,11 +37323,12 @@ ${stops}
36575
37323
 
36576
37324
  // src/renderer/render.ts
36577
37325
  var hasRendered2 = false;
36578
- function createReconcilerAndRender(element) {
37326
+ function mountRoot(element, options = {}) {
36579
37327
  const registry3 = getRegistry();
36580
37328
  const bridge2 = getBridge();
36581
- const hostConfig = createHostConfig(registry3);
37329
+ const hostConfig = createHostConfig(registry3, { syncUpdates: options.syncUpdates });
36582
37330
  const reconciler = (0, import_react_reconciler.default)(hostConfig);
37331
+ const { flushSyncFromReconciler } = reconciler;
36583
37332
  let lastFingerprint = "";
36584
37333
  const container = {
36585
37334
  children: [],
@@ -36618,16 +37367,35 @@ ${stops}
36618
37367
  null
36619
37368
  // transitionCallbacks
36620
37369
  );
36621
- bridge2.onNotification(HOST_METHODS.EVENT_CALLBACK, (params) => {
37370
+ const stopCallbacks = bridge2.onNotification(HOST_METHODS.EVENT_CALLBACK, (params) => {
36622
37371
  const { handlerId, args } = params;
36623
37372
  try {
36624
37373
  registry3.invoke(handlerId, args);
36625
37374
  } catch {
36626
37375
  }
36627
37376
  });
36628
- reconciler.updateContainer(element, root, null, () => {
36629
- 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
+ });
36630
37389
  });
37390
+ return {
37391
+ flushSync,
37392
+ unmount() {
37393
+ stopCallbacks();
37394
+ flushSync(() => {
37395
+ reconciler.updateContainer(null, root, null, null);
37396
+ });
37397
+ }
37398
+ };
36631
37399
  }
36632
37400
  var Lumio2 = {
36633
37401
  render(input, _options) {
@@ -36635,8 +37403,8 @@ ${stops}
36635
37403
  throw new Error("Lumio.render() can only be called once");
36636
37404
  }
36637
37405
  hasRendered2 = true;
36638
- const element = typeof input === "function" ? (0, import_react46.createElement)(input) : input;
36639
- createReconcilerAndRender(element);
37406
+ const element = typeof input === "function" ? (0, import_react47.createElement)(input) : input;
37407
+ mountRoot(element);
36640
37408
  }
36641
37409
  };
36642
37410
 
@@ -36733,11 +37501,12 @@ ${stops}
36733
37501
  var bridge = getBridge();
36734
37502
  var extensionLoaded = false;
36735
37503
  bridge.onNotification(HOST_METHODS.LIFECYCLE_INIT, (params) => {
36736
- const initParams = params;
37504
+ const initParams2 = params;
37505
+ setInitParams(initParams2);
36737
37506
  if (extensionLoaded) return;
36738
- if (initParams.bundleCode) {
37507
+ if (initParams2.bundleCode) {
36739
37508
  try {
36740
- (0, eval)(initParams.bundleCode);
37509
+ (0, eval)(initParams2.bundleCode);
36741
37510
  extensionLoaded = true;
36742
37511
  } catch (err) {
36743
37512
  bridge.notify("ui.error", {
@@ -36747,12 +37516,12 @@ ${stops}
36747
37516
  }
36748
37517
  return;
36749
37518
  }
36750
- if (!initParams.bundleUrl) {
37519
+ if (!initParams2.bundleUrl) {
36751
37520
  bridge.notify("ui.error", { code: "MISSING_BUNDLE", message: "No bundle URL or code provided" });
36752
37521
  return;
36753
37522
  }
36754
37523
  try {
36755
- importScripts(initParams.bundleUrl);
37524
+ importScripts(initParams2.bundleUrl);
36756
37525
  extensionLoaded = true;
36757
37526
  } catch (err) {
36758
37527
  bridge.notify("ui.error", {