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