@zaflun/lumio-protocol 0.2.4 → 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/CHANGELOG.md +129 -1
- package/README.md +1 -1
- package/dist/chunk-746VSR4E.js +51 -0
- package/dist/index.d.ts +1409 -12
- package/dist/index.js +729 -9
- package/dist/origin.d.ts +24 -0
- package/dist/origin.js +14 -0
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EXTENSION_RUNTIME_LABEL_PLACEHOLDER,
|
|
3
|
+
extensionRuntimeLabel,
|
|
4
|
+
extensionRuntimeOrigin,
|
|
5
|
+
extensionRuntimeOriginLabel,
|
|
6
|
+
isValidExtensionRuntimeOriginTemplate
|
|
7
|
+
} from "./chunk-746VSR4E.js";
|
|
8
|
+
|
|
1
9
|
// src/messages.ts
|
|
2
10
|
import { z } from "zod/v4";
|
|
3
11
|
var themeColorsSchema = z.object({
|
|
@@ -29,7 +37,7 @@ var extensionConfigSchema = z.object({
|
|
|
29
37
|
extension_id: z.string(),
|
|
30
38
|
install_id: z.string(),
|
|
31
39
|
account_id: z.string(),
|
|
32
|
-
target: z.enum(["editor", "layer"
|
|
40
|
+
target: z.enum(["editor", "layer"]),
|
|
33
41
|
permissions: z.array(z.string()),
|
|
34
42
|
settings: z.record(z.string(), z.unknown())
|
|
35
43
|
});
|
|
@@ -112,11 +120,18 @@ var LUMIO_EVENT_TYPES = [
|
|
|
112
120
|
// Twitch
|
|
113
121
|
"twitch:follower",
|
|
114
122
|
"twitch:subscribe",
|
|
115
|
-
"twitch:
|
|
123
|
+
"twitch:gift",
|
|
116
124
|
"twitch:resub",
|
|
117
125
|
"twitch:cheer",
|
|
118
126
|
"twitch:raid",
|
|
119
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",
|
|
120
135
|
"twitch:hype_train",
|
|
121
136
|
"twitch:hype_train_end",
|
|
122
137
|
"twitch:poll",
|
|
@@ -140,15 +155,22 @@ var LUMIO_EVENT_TYPES = [
|
|
|
140
155
|
"youtube:gift_membership",
|
|
141
156
|
"youtube:gift_membership_received",
|
|
142
157
|
"youtube:poll",
|
|
143
|
-
//
|
|
158
|
+
// YouTube stream lifecycle (ZAF-1444 / ZAF-622 §75) — emitted by the poll-driven
|
|
159
|
+
// YouTube worker on the channel-status online/offline edge, mirroring Twitch/Kick.
|
|
160
|
+
"youtube:stream_online",
|
|
161
|
+
"youtube:stream_offline",
|
|
162
|
+
// Kick — the webhook receiver normalizes every Kick payload into these types
|
|
163
|
+
// (ZAF-1624): canonical fields on top, the original payload kept in `raw`.
|
|
144
164
|
"kick:follower",
|
|
145
165
|
"kick:subscribe",
|
|
166
|
+
"kick:resub",
|
|
146
167
|
"kick:gift",
|
|
168
|
+
"kick:kicks",
|
|
169
|
+
"kick:reward",
|
|
170
|
+
"kick:reward_status",
|
|
147
171
|
"kick:stream_online",
|
|
148
172
|
"kick:stream_offline",
|
|
149
|
-
|
|
150
|
-
"trovo:subscribe",
|
|
151
|
-
"trovo:spell",
|
|
173
|
+
"kick:stream_update",
|
|
152
174
|
// Spotify
|
|
153
175
|
"spotify:track",
|
|
154
176
|
"spotify:play",
|
|
@@ -168,7 +190,6 @@ var LUMIO_EVENT_TYPES = [
|
|
|
168
190
|
"twitch:chat",
|
|
169
191
|
"youtube:chat",
|
|
170
192
|
"kick:chat",
|
|
171
|
-
"trovo:chat",
|
|
172
193
|
// Chat (cross-platform catch-all — fires for ALL platforms)
|
|
173
194
|
"chat:message"
|
|
174
195
|
];
|
|
@@ -210,6 +231,648 @@ var STORAGE_SCOPES = [
|
|
|
210
231
|
];
|
|
211
232
|
var storageScopeSchema = z2.enum(STORAGE_SCOPES);
|
|
212
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
|
+
|
|
213
876
|
// src/components.ts
|
|
214
877
|
var LUMIO_COMPONENT_TYPES = [
|
|
215
878
|
"Box",
|
|
@@ -243,6 +906,34 @@ var LUMIO_COMPONENT_TYPES = [
|
|
|
243
906
|
"EditorFontPicker",
|
|
244
907
|
"EditorChannelRow"
|
|
245
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
|
+
};
|
|
246
937
|
var WORKER_METHODS = {
|
|
247
938
|
UI_RENDER: "ui.render",
|
|
248
939
|
UI_READY: "ui.ready",
|
|
@@ -255,7 +946,8 @@ var WORKER_METHODS = {
|
|
|
255
946
|
UI_ACTION: "ui.action",
|
|
256
947
|
SOUND_PLAY: "sound.play",
|
|
257
948
|
SOUND_STOP: "sound.stop",
|
|
258
|
-
SOUND_LIST: "sound.list"
|
|
949
|
+
SOUND_LIST: "sound.list",
|
|
950
|
+
ACTION_EXECUTE: "action.execute"
|
|
259
951
|
};
|
|
260
952
|
var HOST_METHODS = {
|
|
261
953
|
LIFECYCLE_INIT: "lifecycle.init",
|
|
@@ -264,27 +956,55 @@ var HOST_METHODS = {
|
|
|
264
956
|
EVENT_PLATFORM: "event.platform",
|
|
265
957
|
STORAGE_UPDATE: "storage.update",
|
|
266
958
|
THEME_CHANGE: "theme.change",
|
|
267
|
-
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
|
|
268
976
|
};
|
|
269
977
|
export {
|
|
978
|
+
ACTION_EXECUTE_ERRORS,
|
|
270
979
|
ACTION_TYPES,
|
|
980
|
+
EXTENSION_RUNTIME_LABEL_PLACEHOLDER,
|
|
271
981
|
HOST_METHODS,
|
|
272
982
|
LUMIO_COMPONENT_TYPES,
|
|
983
|
+
LUMIO_EVENT_PAYLOAD_SCHEMAS,
|
|
273
984
|
LUMIO_EVENT_TYPES,
|
|
274
985
|
MESSAGE_TYPES,
|
|
986
|
+
REALTIME_LIMITS,
|
|
987
|
+
SERVER_FUNCTION_ERRORS,
|
|
275
988
|
STORAGE_SCOPES,
|
|
276
989
|
WORKER_METHODS,
|
|
277
990
|
actionMessageSchema,
|
|
991
|
+
chatMessagePayloadSchema,
|
|
278
992
|
configUpdateMessageSchema,
|
|
279
993
|
errorMessageSchema,
|
|
280
994
|
eventMessageSchema,
|
|
281
995
|
extensionConfigSchema,
|
|
996
|
+
extensionRuntimeLabel,
|
|
997
|
+
extensionRuntimeOrigin,
|
|
998
|
+
extensionRuntimeOriginLabel,
|
|
282
999
|
initMessageSchema,
|
|
1000
|
+
isValidExtensionRuntimeOriginTemplate,
|
|
283
1001
|
lumioActionTypeSchema,
|
|
1002
|
+
lumioEventPayloadSchema,
|
|
284
1003
|
lumioEventTypeSchema,
|
|
285
1004
|
lumioMessageSchema,
|
|
286
1005
|
nodeConfigRequestMessageSchema,
|
|
287
1006
|
nodeConfigUpdateMessageSchema,
|
|
1007
|
+
parseLumioEventPayload,
|
|
288
1008
|
readyMessageSchema,
|
|
289
1009
|
storageScopeSchema,
|
|
290
1010
|
storageUpdateMessageSchema,
|