@zaflun/lumio-protocol 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -37,7 +37,7 @@ var extensionConfigSchema = z.object({
37
37
  extension_id: z.string(),
38
38
  install_id: z.string(),
39
39
  account_id: z.string(),
40
- target: z.enum(["editor", "layer", "interactive"]),
40
+ target: z.enum(["editor", "layer"]),
41
41
  permissions: z.array(z.string()),
42
42
  settings: z.record(z.string(), z.unknown())
43
43
  });
@@ -120,11 +120,18 @@ var LUMIO_EVENT_TYPES = [
120
120
  // Twitch
121
121
  "twitch:follower",
122
122
  "twitch:subscribe",
123
- "twitch:gift_sub",
123
+ "twitch:gift",
124
124
  "twitch:resub",
125
125
  "twitch:cheer",
126
126
  "twitch:raid",
127
127
  "twitch:reward",
128
+ // Redemption status change (fulfilled / canceled) and reward lifecycle
129
+ // (created / updated / deleted on Twitch) — ZAF-2393. The lifecycle types are
130
+ // live-only (`broadcast_only`), never in the event history.
131
+ "twitch:reward_status",
132
+ "twitch:reward_add",
133
+ "twitch:reward_update",
134
+ "twitch:reward_remove",
128
135
  "twitch:hype_train",
129
136
  "twitch:hype_train_end",
130
137
  "twitch:poll",
@@ -224,6 +231,648 @@ var STORAGE_SCOPES = [
224
231
  ];
225
232
  var storageScopeSchema = z2.enum(STORAGE_SCOPES);
226
233
 
234
+ // src/event-payloads.ts
235
+ import { z as z3 } from "zod/v4";
236
+ var str = z3.string();
237
+ var num = z3.number();
238
+ var bool = z3.boolean();
239
+ var nullableStr = z3.string().nullable();
240
+ var twitchBroadcaster = {
241
+ broadcaster_user_id: str,
242
+ broadcaster_user_login: str,
243
+ broadcaster_user_name: str
244
+ };
245
+ var twitchUser = {
246
+ user_id: str,
247
+ user_login: str,
248
+ user_name: str
249
+ };
250
+ var avatarUrl = { avatarUrl: str.optional() };
251
+ var twitchBadge = z3.looseObject({ set_id: str, id: str, info: str });
252
+ var twitchChatNotice = {
253
+ ...twitchBroadcaster,
254
+ ...twitchUser,
255
+ ...avatarUrl,
256
+ chatter_user_id: str,
257
+ chatter_user_login: str,
258
+ chatter_user_name: str,
259
+ chatter_is_anonymous: bool,
260
+ color: str,
261
+ badges: z3.array(twitchBadge),
262
+ message: z3.looseObject({ text: str, fragments: z3.array(z3.unknown()) }),
263
+ message_id: str,
264
+ notice_type: str,
265
+ system_message: str,
266
+ /** Emotes of `message`, normalised like chat-message emotes (ZAF-1306). */
267
+ emotes: z3.array(z3.unknown()).optional()
268
+ };
269
+ var twitchImage = z3.looseObject({ url_1x: str, url_2x: str, url_4x: str });
270
+ var twitchEnabledValue = z3.looseObject({ is_enabled: bool, value: num });
271
+ var twitchRewardDefinition = z3.looseObject({
272
+ ...twitchBroadcaster,
273
+ id: str,
274
+ title: str,
275
+ cost: num,
276
+ prompt: str,
277
+ background_color: str,
278
+ is_enabled: bool,
279
+ is_paused: bool,
280
+ is_in_stock: bool,
281
+ is_user_input_required: bool,
282
+ should_redemptions_skip_request_queue: bool,
283
+ max_per_stream: twitchEnabledValue,
284
+ max_per_user_per_stream: twitchEnabledValue,
285
+ global_cooldown: z3.looseObject({ is_enabled: bool, seconds: num }),
286
+ image: twitchImage.nullable(),
287
+ default_image: twitchImage,
288
+ cooldown_expires_at: nullableStr,
289
+ redemptions_redeemed_current_stream: num.nullable()
290
+ });
291
+ var twitchRedemption = z3.looseObject({
292
+ ...twitchBroadcaster,
293
+ ...twitchUser,
294
+ ...avatarUrl,
295
+ id: str,
296
+ user_input: str,
297
+ status: str,
298
+ redeemed_at: str,
299
+ reward: z3.looseObject({ id: str, title: str, cost: num, prompt: str })
300
+ });
301
+ var twitchPollVoting = z3.looseObject({ is_enabled: bool, amount_per_vote: num });
302
+ var twitchPollBase = {
303
+ ...twitchBroadcaster,
304
+ id: str,
305
+ title: str,
306
+ choices: z3.array(
307
+ z3.looseObject({
308
+ id: str,
309
+ title: str,
310
+ votes: num.optional(),
311
+ bits_votes: num.optional(),
312
+ channel_points_votes: num.optional()
313
+ })
314
+ ),
315
+ bits_voting: twitchPollVoting,
316
+ channel_points_voting: twitchPollVoting,
317
+ started_at: str
318
+ };
319
+ var twitchPredictionOutcome = z3.looseObject({
320
+ id: str,
321
+ title: str,
322
+ color: str,
323
+ users: num.optional(),
324
+ channel_points: num.optional(),
325
+ top_predictors: z3.array(
326
+ z3.looseObject({
327
+ ...twitchUser,
328
+ channel_points_used: num,
329
+ channel_points_won: num.nullable()
330
+ })
331
+ ).nullable().optional()
332
+ });
333
+ var twitchPredictionBase = {
334
+ ...twitchBroadcaster,
335
+ id: str,
336
+ title: str,
337
+ outcomes: z3.array(twitchPredictionOutcome),
338
+ started_at: str
339
+ };
340
+ var twitchGoalBase = {
341
+ ...twitchBroadcaster,
342
+ id: str,
343
+ type: str,
344
+ description: str,
345
+ current_amount: num,
346
+ target_amount: num,
347
+ started_at: str
348
+ };
349
+ var twitchHypeTrainBase = {
350
+ ...twitchBroadcaster,
351
+ id: str,
352
+ type: str,
353
+ level: num,
354
+ total: num,
355
+ top_contributions: z3.array(
356
+ z3.looseObject({ ...twitchUser, type: str, total: num })
357
+ ),
358
+ started_at: str,
359
+ is_shared_train: bool,
360
+ shared_train_participants: z3.array(z3.unknown()).nullable()
361
+ };
362
+ var moderationLogEntry = z3.looseObject({
363
+ action: str,
364
+ platform: str,
365
+ target_user_id: nullableStr,
366
+ target_username: nullableStr,
367
+ target_display_name: nullableStr,
368
+ moderator_name: str,
369
+ moderator_login: nullableStr,
370
+ reason: nullableStr,
371
+ duration_secs: num.nullable(),
372
+ ends_at: nullableStr,
373
+ target_message_id: nullableStr,
374
+ created_at: str
375
+ });
376
+ var chatMessagePayloadSchema = z3.looseObject({
377
+ account_id: str,
378
+ platform: str,
379
+ channel_name: nullableStr,
380
+ user_id: nullableStr,
381
+ username: str,
382
+ display_name: nullableStr,
383
+ avatar_url: nullableStr,
384
+ message: str,
385
+ /** Platform-specific emote entries. */
386
+ emotes: z3.array(z3.unknown()).nullable(),
387
+ /** Twitch GIF fragments `{ id, url, provider, alt }`; absent without a GIF. */
388
+ gifs: z3.array(z3.unknown()).optional(),
389
+ /** Platform-specific badge entries. */
390
+ badges: z3.array(z3.unknown()).nullable(),
391
+ color: nullableStr,
392
+ is_mod: bool,
393
+ is_sub: bool,
394
+ is_vip: bool,
395
+ sub_tier: nullableStr,
396
+ platform_message_id: nullableStr,
397
+ lumio_user_id: nullableStr,
398
+ reply_parent_msg_id: nullableStr,
399
+ reply_parent_username: nullableStr,
400
+ reply_parent_login: nullableStr,
401
+ reply_parent_message: nullableStr,
402
+ created_at: nullableStr,
403
+ message_type: nullableStr,
404
+ user_treatment: nullableStr,
405
+ live_chat_id: str.optional(),
406
+ is_shared_chat: bool.optional(),
407
+ source_channel: z3.unknown().optional(),
408
+ announcement_color: z3.unknown().optional()
409
+ });
410
+ var kickUser = z3.looseObject({
411
+ user_id: num,
412
+ username: str,
413
+ channel_slug: str,
414
+ is_verified: bool,
415
+ profile_picture: str,
416
+ is_anonymous: bool.optional(),
417
+ identity: z3.unknown().optional()
418
+ });
419
+ var kickCanonicalUser = {
420
+ user_id: str,
421
+ user_login: str,
422
+ user_name: str,
423
+ is_anonymous: bool
424
+ };
425
+ var kickSubscription = z3.looseObject({
426
+ ...kickCanonicalUser,
427
+ ...avatarUrl,
428
+ broadcaster: kickUser,
429
+ subscriber: kickUser,
430
+ duration: num,
431
+ cumulative_months: num,
432
+ created_at: str,
433
+ expires_at: str
434
+ });
435
+ var kickRedemption = z3.looseObject({
436
+ ...kickCanonicalUser,
437
+ broadcaster: kickUser,
438
+ redeemer: kickUser,
439
+ id: str,
440
+ user_input: str,
441
+ status: str,
442
+ redeemed_at: str,
443
+ reward: z3.looseObject({ id: str, title: str, cost: num })
444
+ });
445
+ var spotifySource = {
446
+ source: str.optional(),
447
+ extension_id: str.optional(),
448
+ install_id: str.optional()
449
+ };
450
+ var spotifyTrackInfo = {
451
+ action: str,
452
+ track_id: str,
453
+ track_name: str,
454
+ artist: str,
455
+ album: str,
456
+ album_art: str,
457
+ song_url: str
458
+ };
459
+ var youtubeAuthor = {
460
+ user_id: str,
461
+ user_login: str,
462
+ displayName: str,
463
+ avatarUrl: str
464
+ };
465
+ var LUMIO_EVENT_PAYLOAD_SCHEMAS = {
466
+ // Twitch
467
+ "twitch:follower": z3.looseObject({
468
+ ...twitchBroadcaster,
469
+ ...twitchUser,
470
+ ...avatarUrl,
471
+ followed_at: str
472
+ }),
473
+ "twitch:subscribe": z3.looseObject({
474
+ ...twitchChatNotice,
475
+ tier: str,
476
+ duration_months: num,
477
+ is_prime: bool.optional(),
478
+ sub: z3.looseObject({ sub_tier: str, is_prime: bool, duration_months: num })
479
+ }),
480
+ "twitch:gift": z3.looseObject({
481
+ ...twitchChatNotice,
482
+ /** Sub tier (`1000`, `2000`, `3000`). */
483
+ tier: str.optional(),
484
+ duration_months: num.optional(),
485
+ /** Gifts in a community gift (`community_sub_gift`). */
486
+ total: num.optional(),
487
+ /** The gifter's all-time gift count; `null` when anonymous. */
488
+ cumulative_total: num.nullable().optional(),
489
+ community_gift_id: nullableStr.optional(),
490
+ /** Set for a single gift (`sub_gift`), absent for a community gift. */
491
+ recipient_user_id: str.optional(),
492
+ recipient_user_login: str.optional(),
493
+ recipient_user_name: str.optional()
494
+ }),
495
+ "twitch:resub": z3.looseObject({
496
+ ...twitchChatNotice,
497
+ cumulative_months: num,
498
+ duration_months: num,
499
+ streak_months: num.nullable(),
500
+ is_gift: bool,
501
+ tier: str.optional(),
502
+ is_prime: bool.optional(),
503
+ gifter_is_anonymous: bool.nullable(),
504
+ gifter_user_login: nullableStr,
505
+ gifter_user_name: nullableStr,
506
+ resub: z3.looseObject({
507
+ cumulative_months: num,
508
+ duration_months: num,
509
+ streak_months: num.nullable(),
510
+ sub_plan: str,
511
+ is_gift: bool
512
+ })
513
+ }),
514
+ "twitch:cheer": z3.looseObject({
515
+ ...twitchBroadcaster,
516
+ ...avatarUrl,
517
+ user_id: nullableStr,
518
+ user_login: nullableStr,
519
+ user_name: nullableStr,
520
+ is_anonymous: bool,
521
+ bits: num,
522
+ message: str,
523
+ /** Cheermote entries for the cheer words in `message` (`kind: "cheermote"`). */
524
+ emotes: z3.array(z3.unknown()).optional(),
525
+ /** The cheermote for the total, when the channel's cheermotes loaded. */
526
+ cheermote: z3.unknown().optional()
527
+ }),
528
+ "twitch:raid": z3.looseObject({
529
+ from_broadcaster_user_id: str,
530
+ from_broadcaster_user_login: str,
531
+ from_broadcaster_user_name: str,
532
+ to_broadcaster_user_id: str,
533
+ to_broadcaster_user_login: str,
534
+ to_broadcaster_user_name: str,
535
+ viewers: num,
536
+ ...avatarUrl,
537
+ displayName: str.optional(),
538
+ /** The raider's channel info from Helix, when it loaded. */
539
+ title: str.optional(),
540
+ category: str.optional()
541
+ }),
542
+ "twitch:reward": twitchRedemption,
543
+ "twitch:reward_status": twitchRedemption,
544
+ "twitch:reward_add": twitchRewardDefinition,
545
+ "twitch:reward_update": twitchRewardDefinition,
546
+ "twitch:reward_remove": twitchRewardDefinition,
547
+ "twitch:hype_train": z3.looseObject({
548
+ ...twitchHypeTrainBase,
549
+ progress: num,
550
+ goal: num,
551
+ expires_at: str,
552
+ all_time_high_level: num.optional(),
553
+ all_time_high_total: num.optional()
554
+ }),
555
+ "twitch:hype_train_end": z3.looseObject({
556
+ ...twitchHypeTrainBase,
557
+ ended_at: str,
558
+ cooldown_ends_at: str
559
+ }),
560
+ "twitch:poll": z3.looseObject({ ...twitchPollBase, ends_at: str }),
561
+ "twitch:poll_end": z3.looseObject({
562
+ ...twitchPollBase,
563
+ status: str,
564
+ ended_at: str
565
+ }),
566
+ "twitch:prediction": z3.looseObject({ ...twitchPredictionBase, locks_at: str }),
567
+ "twitch:prediction_lock": z3.looseObject({
568
+ ...twitchPredictionBase,
569
+ locked_at: str
570
+ }),
571
+ "twitch:prediction_end": z3.looseObject({
572
+ ...twitchPredictionBase,
573
+ status: str,
574
+ ended_at: str,
575
+ winning_outcome_id: nullableStr
576
+ }),
577
+ "twitch:goal": z3.looseObject(twitchGoalBase),
578
+ "twitch:goal_end": z3.looseObject({
579
+ ...twitchGoalBase,
580
+ ended_at: str,
581
+ is_achieved: bool
582
+ }),
583
+ "twitch:ad_break": z3.looseObject({
584
+ ...twitchBroadcaster,
585
+ requester_user_id: str,
586
+ requester_user_login: str,
587
+ requester_user_name: str,
588
+ /** Seconds; Twitch's own sample payload sends it as a string. */
589
+ duration_seconds: z3.union([num, str]),
590
+ /** Twitch's own sample payload sends it as a string. */
591
+ is_automatic: z3.union([bool, str]),
592
+ started_at: str
593
+ }),
594
+ "twitch:ban": moderationLogEntry,
595
+ "twitch:unban": moderationLogEntry,
596
+ "twitch:stream_online": z3.looseObject({
597
+ ...twitchBroadcaster,
598
+ id: str,
599
+ type: str,
600
+ started_at: str,
601
+ /** Channel info from Helix, when it loaded. */
602
+ title: str.optional(),
603
+ category: str.optional()
604
+ }),
605
+ "twitch:stream_offline": z3.looseObject({
606
+ ...twitchBroadcaster,
607
+ /** Set when the stream's start is known. */
608
+ started_at: str.optional(),
609
+ duration_seconds: num.optional()
610
+ }),
611
+ "twitch:stream_update": z3.looseObject({
612
+ ...twitchBroadcaster,
613
+ title: str,
614
+ language: str,
615
+ category_id: str,
616
+ category_name: str,
617
+ content_classification_labels: z3.array(str),
618
+ tags: z3.array(str).optional(),
619
+ /** Diff against the previous channel info, when it was known. */
620
+ title_changed: bool.optional(),
621
+ category_changed: bool.optional(),
622
+ language_changed: bool.optional(),
623
+ tags_changed: bool.optional(),
624
+ old_title: str.optional(),
625
+ old_category_name: str.optional(),
626
+ old_tags: z3.array(str).optional()
627
+ }),
628
+ // YouTube
629
+ "youtube:subscribe": z3.looseObject({
630
+ channel_id: str,
631
+ video_id: str,
632
+ title: str,
633
+ published: str,
634
+ updated: str
635
+ }),
636
+ "youtube:member": z3.looseObject({
637
+ ...youtubeAuthor,
638
+ membership_event_type: str,
639
+ memberLevelName: nullableStr,
640
+ memberMonth: num.nullable(),
641
+ isUpgrade: bool,
642
+ display_message: str,
643
+ userComment: str
644
+ }),
645
+ "youtube:superchat": z3.looseObject({
646
+ ...youtubeAuthor,
647
+ amountMicros: num,
648
+ amountDisplayString: str,
649
+ currency: str,
650
+ tier: num,
651
+ userComment: str,
652
+ headerBackgroundColor: num,
653
+ bodyBackgroundColor: num
654
+ }),
655
+ "youtube:supersticker": z3.looseObject({
656
+ ...youtubeAuthor,
657
+ amountMicros: num,
658
+ amountDisplayString: str,
659
+ currency: str,
660
+ stickerName: str,
661
+ stickerUrl: str
662
+ }),
663
+ "youtube:gift_membership": z3.looseObject({
664
+ ...youtubeAuthor,
665
+ giftCount: num,
666
+ isGift: bool,
667
+ gift_memberships_level_name: nullableStr
668
+ }),
669
+ /** Stored in the event history only; never broadcast live (no fixture). */
670
+ "youtube:gift_membership_received": z3.looseObject({
671
+ user_id: nullableStr,
672
+ user_login: nullableStr,
673
+ displayName: str,
674
+ avatarUrl: nullableStr,
675
+ gifter_channel_id: nullableStr,
676
+ gifter_display_name: nullableStr,
677
+ gift_memberships_level_name: nullableStr
678
+ }),
679
+ "youtube:poll": z3.looseObject({
680
+ poll_id: str,
681
+ question: str,
682
+ status: str,
683
+ options: z3.array(
684
+ z3.looseObject({
685
+ option_text: str,
686
+ tally: nullableStr,
687
+ vote_ratio: num.nullable()
688
+ })
689
+ )
690
+ }),
691
+ "youtube:stream_online": z3.looseObject({
692
+ broadcast_id: str,
693
+ started_at: str,
694
+ title: str.optional(),
695
+ category: str.optional()
696
+ }),
697
+ "youtube:stream_offline": z3.looseObject({
698
+ broadcast_id: str,
699
+ started_at: str.optional(),
700
+ duration_seconds: num.optional()
701
+ }),
702
+ // Kick
703
+ "kick:follower": z3.looseObject({
704
+ ...kickCanonicalUser,
705
+ ...avatarUrl,
706
+ broadcaster: kickUser,
707
+ follower: kickUser
708
+ }),
709
+ "kick:subscribe": kickSubscription,
710
+ "kick:resub": kickSubscription,
711
+ "kick:gift": z3.looseObject({
712
+ ...kickCanonicalUser,
713
+ ...avatarUrl,
714
+ broadcaster: kickUser,
715
+ gifter: kickUser,
716
+ giftees: z3.array(kickUser),
717
+ /** Usernames of `giftees`. */
718
+ giftRecipients: z3.array(str),
719
+ giftCount: num,
720
+ total: num,
721
+ isGift: bool,
722
+ is_gift: bool,
723
+ /** The first giftee. */
724
+ recipient_user_id: str.optional(),
725
+ recipient_user_login: str.optional(),
726
+ recipient_user_name: str.optional(),
727
+ created_at: str,
728
+ expires_at: str
729
+ }),
730
+ "kick:kicks": z3.looseObject({
731
+ ...kickCanonicalUser,
732
+ ...avatarUrl,
733
+ broadcaster: kickUser,
734
+ sender: kickUser,
735
+ gift: z3.looseObject({
736
+ amount: num,
737
+ name: str,
738
+ type: str,
739
+ tier: str,
740
+ message: str,
741
+ pinned_time_seconds: num
742
+ }),
743
+ kicks: num,
744
+ message: str,
745
+ kick_gift_id: str,
746
+ kick_gift_name: str,
747
+ kick_gift_type: str,
748
+ kick_gift_tier: str,
749
+ kick_gift_color: str,
750
+ kick_gift_image: z3.looseObject({ static: str, animated: str }),
751
+ kick_pinned_time_seconds: num,
752
+ created_at: str
753
+ }),
754
+ "kick:reward": kickRedemption,
755
+ "kick:reward_status": kickRedemption,
756
+ "kick:stream_online": z3.looseObject({
757
+ broadcaster: kickUser,
758
+ is_live: bool,
759
+ title: str,
760
+ started_at: str,
761
+ ended_at: nullableStr
762
+ }),
763
+ "kick:stream_offline": z3.looseObject({
764
+ broadcaster: kickUser,
765
+ is_live: bool,
766
+ title: str,
767
+ started_at: str,
768
+ ended_at: str,
769
+ duration_seconds: num.optional()
770
+ }),
771
+ "kick:stream_update": z3.looseObject({
772
+ broadcaster: kickUser,
773
+ metadata: z3.looseObject({
774
+ title: str,
775
+ language: str,
776
+ has_mature_content: bool,
777
+ category: z3.looseObject({ id: num, name: str, thumbnail: str })
778
+ }),
779
+ title: str,
780
+ language: str,
781
+ has_mature_content: bool,
782
+ category_id: str,
783
+ category_name: str,
784
+ /** Diff against the previous stream info, when it was known. */
785
+ title_changed: bool.optional(),
786
+ category_changed: bool.optional(),
787
+ language_changed: bool.optional(),
788
+ old_title: str.optional()
789
+ }),
790
+ // Spotify
791
+ "spotify:track": z3.looseObject({
792
+ is_playing: bool,
793
+ progress_ms: num,
794
+ timestamp: num,
795
+ shuffle: str,
796
+ repeat: str,
797
+ track: z3.looseObject({
798
+ id: str,
799
+ uri: str,
800
+ name: str,
801
+ artist: str,
802
+ album: str,
803
+ album_art: str,
804
+ duration_ms: num
805
+ }),
806
+ device: z3.looseObject({
807
+ id: str,
808
+ name: str,
809
+ device_type: str,
810
+ is_active: bool,
811
+ volume_percent: num.nullable()
812
+ }).nullable(),
813
+ context: z3.looseObject({ context_type: str, id: str, name: nullableStr, uri: str }).nullable(),
814
+ /** The Lumio user whose action caused the change; `null` when it came from Spotify. */
815
+ triggered_by: nullableStr.optional()
816
+ }),
817
+ "spotify:play": z3.looseObject({
818
+ ...spotifyTrackInfo,
819
+ ...spotifySource,
820
+ track_uri: str
821
+ }),
822
+ "spotify:pause": z3.looseObject({ ...spotifyTrackInfo, ...spotifySource }),
823
+ "spotify:skip": z3.looseObject({ action: str, ...spotifySource }),
824
+ "spotify:volume": z3.looseObject({
825
+ ...spotifyTrackInfo,
826
+ ...spotifySource,
827
+ oldVolume: num,
828
+ newVolume: num,
829
+ volume_percent: num
830
+ }),
831
+ "spotify:queue_add": z3.looseObject({ uri: str, ...spotifySource }),
832
+ "spotify:device": z3.looseObject({
833
+ fromDevice: str,
834
+ fromDeviceType: str,
835
+ toDevice: str,
836
+ toDeviceType: str
837
+ }),
838
+ "spotify:playlist_add": z3.looseObject({ playlistId: str }),
839
+ "spotify:playlist_remove": z3.looseObject({ playlistId: str, trackUri: str }),
840
+ "spotify:playlist_create": z3.looseObject({ playlistName: str }),
841
+ "spotify:playlist_edit": z3.looseObject({ playlistName: str }),
842
+ "spotify:playlist_delete": z3.looseObject({ playlistId: str }),
843
+ // StreamElements
844
+ "streamelements:tip": z3.looseObject({
845
+ _id: str,
846
+ channel: str,
847
+ provider: str,
848
+ type: str,
849
+ flagged: bool,
850
+ createdAt: str,
851
+ updatedAt: str,
852
+ data: z3.looseObject({
853
+ tipId: str,
854
+ username: str,
855
+ displayName: str,
856
+ providerId: str.optional(),
857
+ amount: num,
858
+ currency: str,
859
+ message: str,
860
+ avatar: str.optional()
861
+ })
862
+ }),
863
+ // Chat
864
+ "twitch:chat": chatMessagePayloadSchema,
865
+ "youtube:chat": chatMessagePayloadSchema,
866
+ "kick:chat": chatMessagePayloadSchema,
867
+ "chat:message": chatMessagePayloadSchema
868
+ };
869
+ function lumioEventPayloadSchema(type) {
870
+ return LUMIO_EVENT_PAYLOAD_SCHEMAS[type];
871
+ }
872
+ function parseLumioEventPayload(type, data) {
873
+ return LUMIO_EVENT_PAYLOAD_SCHEMAS[type].safeParse(data);
874
+ }
875
+
227
876
  // src/components.ts
228
877
  var LUMIO_COMPONENT_TYPES = [
229
878
  "Box",
@@ -257,6 +906,34 @@ var LUMIO_COMPONENT_TYPES = [
257
906
  "EditorFontPicker",
258
907
  "EditorChannelRow"
259
908
  ];
909
+ var ACTION_EXECUTE_ERRORS = {
910
+ /** Malformed request: `action` is not a string or `params` is not an object. */
911
+ INVALID_REQUEST: -32602,
912
+ /** This host cannot run actions (no install, or a credential that may not run them). */
913
+ UNAVAILABLE: -32001,
914
+ /** The extension does not declare the action's permission, or the caller may not use it. */
915
+ DENIED: -32002,
916
+ /** The API does not dispatch this action. */
917
+ UNKNOWN_ACTION: -32003,
918
+ /** The API rejected the action's params. */
919
+ INVALID_PARAMS: -32004,
920
+ /** The action ran and failed (e.g. its target service is not connected). */
921
+ FAILED: -32005
922
+ };
923
+ var SERVER_FUNCTION_ERRORS = {
924
+ /** Malformed request: `fn` is not a function name or `params` is not an object. */
925
+ INVALID_REQUEST: -32602,
926
+ /** This host cannot call server functions (no install, or a credential that may not call them). */
927
+ UNAVAILABLE: -32001,
928
+ /** The caller may not run the function (an `editorOnly` function outside the editor, or missing permission). */
929
+ DENIED: -32002,
930
+ /** The install's published version has no server function with this name, or not of this kind. */
931
+ UNKNOWN_FUNCTION: -32003,
932
+ /** The API rejected the params (missing or mistyped `arg()` value, invalid row id or column value). */
933
+ INVALID_PARAMS: -32004,
934
+ /** The function ran and failed (rate limit, no data schema, storage quota, timeout). */
935
+ FAILED: -32005
936
+ };
260
937
  var WORKER_METHODS = {
261
938
  UI_RENDER: "ui.render",
262
939
  UI_READY: "ui.ready",
@@ -269,7 +946,8 @@ var WORKER_METHODS = {
269
946
  UI_ACTION: "ui.action",
270
947
  SOUND_PLAY: "sound.play",
271
948
  SOUND_STOP: "sound.stop",
272
- SOUND_LIST: "sound.list"
949
+ SOUND_LIST: "sound.list",
950
+ ACTION_EXECUTE: "action.execute"
273
951
  };
274
952
  var HOST_METHODS = {
275
953
  LIFECYCLE_INIT: "lifecycle.init",
@@ -278,18 +956,39 @@ var HOST_METHODS = {
278
956
  EVENT_PLATFORM: "event.platform",
279
957
  STORAGE_UPDATE: "storage.update",
280
958
  THEME_CHANGE: "theme.change",
281
- CONFIG_UPDATE: "config.update"
959
+ CONFIG_UPDATE: "config.update",
960
+ SERVER_REALTIME: "server.realtime"
961
+ };
962
+ var REALTIME_LIMITS = {
963
+ /** 1–64 characters of `A-Z a-z 0-9 _ . : -`, starting with a letter or digit. */
964
+ TOPIC_PATTERN: /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,63}$/,
965
+ /** Largest serialized payload of one push, in bytes. */
966
+ MAX_PAYLOAD_BYTES: 16 * 1024,
967
+ /** Most pushes one handler run may make. */
968
+ MAX_PUSHES_PER_INVOCATION: 32,
969
+ /** Pushes per install and minute; pushes over the cap are dropped. */
970
+ MAX_PUSHES_PER_MINUTE: 300,
971
+ /**
972
+ * Published bytes (serialized `{ topic, payload }`) per install and minute;
973
+ * pushes over the cap are dropped.
974
+ */
975
+ MAX_BYTES_PER_MINUTE: 1024 * 1024
282
976
  };
283
977
  export {
978
+ ACTION_EXECUTE_ERRORS,
284
979
  ACTION_TYPES,
285
980
  EXTENSION_RUNTIME_LABEL_PLACEHOLDER,
286
981
  HOST_METHODS,
287
982
  LUMIO_COMPONENT_TYPES,
983
+ LUMIO_EVENT_PAYLOAD_SCHEMAS,
288
984
  LUMIO_EVENT_TYPES,
289
985
  MESSAGE_TYPES,
986
+ REALTIME_LIMITS,
987
+ SERVER_FUNCTION_ERRORS,
290
988
  STORAGE_SCOPES,
291
989
  WORKER_METHODS,
292
990
  actionMessageSchema,
991
+ chatMessagePayloadSchema,
293
992
  configUpdateMessageSchema,
294
993
  errorMessageSchema,
295
994
  eventMessageSchema,
@@ -300,10 +999,12 @@ export {
300
999
  initMessageSchema,
301
1000
  isValidExtensionRuntimeOriginTemplate,
302
1001
  lumioActionTypeSchema,
1002
+ lumioEventPayloadSchema,
303
1003
  lumioEventTypeSchema,
304
1004
  lumioMessageSchema,
305
1005
  nodeConfigRequestMessageSchema,
306
1006
  nodeConfigUpdateMessageSchema,
1007
+ parseLumioEventPayload,
307
1008
  readyMessageSchema,
308
1009
  storageScopeSchema,
309
1010
  storageUpdateMessageSchema,