@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 CHANGED
@@ -5,6 +5,134 @@ All notable changes to `@zaflun/lumio-protocol` are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## 0.9.0
9
+
10
+ ### Added
11
+
12
+ - **Typed event payloads** — `LUMIO_EVENT_PAYLOAD_SCHEMAS` holds one zod
13
+ schema per `LUMIO_EVENT_TYPES` entry for the `data` of an `event.platform`
14
+ notification (the backend's event `raw`; a `ChatMessageInput` for the chat
15
+ types). `LumioEventPayloadMap` / `LumioEventPayload<K>` are the inferred
16
+ types, `ChatMessagePayload` and `ModerationLogPayload` the shared ones.
17
+ `lumioEventPayloadSchema(type)` and `parseLumioEventPayload(type, data)`
18
+ validate a payload. The map is checked with `satisfies` against
19
+ `LumioEventType`, so a new event type without a schema fails typecheck. The
20
+ shapes follow the golden fixtures the backend exports to `fixtures/events/`.
21
+ Object schemas are loose: fields the backend adds later are kept, typed
22
+ `unknown`. The wire format is unchanged.
23
+
24
+ ### Changed
25
+
26
+ - **`twitch:gift_sub` is now `twitch:gift`** in `LUMIO_EVENT_TYPES`. The
27
+ backend has always emitted gifted subs as `twitch:gift`, so no event ever
28
+ matched `twitch:gift_sub`. Replace the type in `useLumioEvent()` calls and
29
+ `event()` triggers. Breaking.
30
+
31
+ ## 0.8.0
32
+
33
+ ### Added
34
+
35
+ - **`SERVER_FUNCTION_ERRORS`** — the JSON-RPC error codes a host answers a
36
+ failed `server.query` / `server.mutation` with (`INVALID_REQUEST`,
37
+ `UNAVAILABLE`, `DENIED`, `UNKNOWN_FUNCTION`, `INVALID_PARAMS`, `FAILED`),
38
+ and the `ServerFunctionErrorCode` type. `ServerQueryParams` /
39
+ `ServerMutationParams` document their results: `server.query` resolves with
40
+ the rows, `server.mutation` with the written row or `null`. Additive.
41
+ - **`server.realtime`** — `HOST_METHODS.SERVER_REALTIME` (`"server.realtime"`)
42
+ is the host → worker notification that carries a message a handler of the
43
+ install pushed with `ctx.realtime.push(topic, payload)`, with
44
+ `ServerRealtimeParams` (`{ topic; payload }`). `REALTIME_LIMITS` holds the
45
+ push rules (`TOPIC_PATTERN`, `MAX_PAYLOAD_BYTES` 16 KiB,
46
+ `MAX_PUSHES_PER_INVOCATION` 32, `MAX_PUSHES_PER_MINUTE` 300 and
47
+ `MAX_BYTES_PER_MINUTE` 1 MiB per install). Additive.
48
+
49
+ ### Removed
50
+
51
+ - **`interactive` target** — `LifecycleInitParams["target"]` and the
52
+ `extensionConfigSchema` `target` enum accept only `editor` and `layer`. No
53
+ host ever rendered an `interactive` surface; viewers interact through chat
54
+ commands and channel point rewards (`twitch:reward`, `kick:reward`) that a
55
+ bot-module handler turns into `ctx.realtime.push`, received with
56
+ `server.realtime`.
57
+
58
+ **Breaking for consumers** that pass or `switch` over `"interactive"`. Drop
59
+ that arm; an init message carrying `target: "interactive"` now fails
60
+ validation.
61
+
62
+ ## 0.7.0
63
+
64
+ ### Added
65
+
66
+ - **`action.execute`** — `WORKER_METHODS.ACTION_EXECUTE` (`"action.execute"`)
67
+ is the worker → host request `useLumioAction()` sends, with
68
+ `ActionExecuteParams` (`{ action: LumioActionType; params }`) and
69
+ `ActionExecuteResult` (`{ data }`). `ACTION_EXECUTE_ERRORS` lists the
70
+ JSON-RPC error codes a host answers a failed action with (`INVALID_REQUEST`,
71
+ `UNAVAILABLE`, `DENIED`, `UNKNOWN_ACTION`, `INVALID_PARAMS`, `FAILED`).
72
+ Additive.
73
+ - **Twitch reward lifecycle event types** — `twitch:reward_status`,
74
+ `twitch:reward_add`, `twitch:reward_update` and `twitch:reward_remove` are in
75
+ `LUMIO_EVENT_TYPES`, `LumioEventType` and the `lumioEventTypeSchema` Zod enum.
76
+ `twitch:reward_status` is a redemption's status change (`fulfilled` /
77
+ `canceled`) with the same shape as `twitch:reward`. `twitch:reward_add` /
78
+ `_update` / `_remove` fire when the streamer creates, changes or deletes a
79
+ channel-point reward on Twitch and carry the Twitch custom-reward object; they
80
+ are delivered live only (`broadcast_only`) and never appear in the event
81
+ history. Additive.
82
+
83
+ ## 0.6.0
84
+
85
+ ### Added
86
+
87
+ - **Per-extension runtime origins** — new entry point
88
+ `@zaflun/lumio-protocol/origin` (also re-exported from the package root) with
89
+ `extensionRuntimeLabel(extensionId)` (canonical lowercase UUID → 32 lowercase
90
+ hex, otherwise `null`), `extensionRuntimeOrigin(extensionId, template)`
91
+ (`https://{label}.runtime.ext.lumio.vision` → the extension's origin, `null` for an
92
+ invalid id or template), `extensionRuntimeOriginLabel(origin, template)` and
93
+ `isValidExtensionRuntimeOriginTemplate(template)`. The `/origin` entry has no
94
+ runtime dependencies. Additive.
95
+
96
+ ## 0.5.0
97
+
98
+ ### Added
99
+
100
+ - **Kick event types** — `kick:resub`, `kick:kicks`, `kick:reward`,
101
+ `kick:reward_status` and `kick:stream_update` are in `LUMIO_EVENT_TYPES`,
102
+ `LumioEventType` and the `lumioEventTypeSchema` Zod enum. The Lumio webhook
103
+ receiver emits them for Kick subscription renewals, KICKs gifts, channel-point
104
+ redemptions (first delivery of a redemption `id` → `kick:reward`, every later
105
+ status change → `kick:reward_status`) and livestream metadata changes. Every
106
+ Kick event carries canonical top-level fields (`user_id`, `user_login`,
107
+ `user_name`, `avatarUrl`, `is_anonymous`) next to the original Kick payload.
108
+ `LUMIO_EVENT_TYPES` now holds 58 event types.
109
+
110
+ Additive: existing event strings are unchanged. Consumers that exhaustively
111
+ `switch` over `LumioEventType` need arms for the five new Kick types.
112
+
113
+ ## 0.4.0
114
+
115
+ ### Added
116
+
117
+ - **YouTube stream lifecycle** — `youtube:stream_online` and
118
+ `youtube:stream_offline`, emitted by the poll-driven YouTube worker on the
119
+ channel-status online/offline edge (once per real transition).
120
+
121
+ ## 0.3.0
122
+
123
+ ### Removed
124
+
125
+ - **Trovo event types** — `trovo:subscribe`, `trovo:spell` and `trovo:chat` are
126
+ gone from `LUMIO_EVENT_TYPES`, `LumioEventType` and the `lumioEventTypeSchema`
127
+ Zod enum. The Trovo platform has been shut down by its operator, so these
128
+ events can no longer be emitted. `LUMIO_EVENT_TYPES` now holds 72 event types
129
+ across Twitch, YouTube, Kick, Spotify, StreamElements, and per-platform +
130
+ cross-platform chat.
131
+
132
+ **Breaking for consumers** that reference a Trovo event type by name or
133
+ exhaustively `switch` over `LumioEventType`. Drop the Trovo arms; validation of
134
+ a Trovo event string now fails closed via `lumioEventTypeSchema`.
135
+
8
136
  ## 0.2.4
9
137
 
10
138
  Wire-format types for the Lumio Extension Platform — the contract for
@@ -15,7 +143,7 @@ the validated schemas.
15
143
  ### Exports
16
144
 
17
145
  - **Events** (`src/events.ts`)
18
- - `LUMIO_EVENT_TYPES` — 54 platform event types across Twitch, YouTube, Kick,
146
+ - `LUMIO_EVENT_TYPES` — 75 platform event types across Twitch, YouTube, Kick,
19
147
  Trovo, Spotify, StreamElements, and per-platform + cross-platform chat, with
20
148
  `LumioEventType` and the `lumioEventTypeSchema` Zod enum.
21
149
  - `ACTION_TYPES` — 21 action types (Chat, OBS, Spotify, Events, Overlay), with
package/README.md CHANGED
@@ -10,7 +10,7 @@ npm install @zaflun/lumio-protocol
10
10
 
11
11
  ## What's included
12
12
 
13
- - **54 Event Types** — Twitch, YouTube, Kick, Trovo, Spotify, StreamElements, Chat
13
+ - **54 Event Types** — Twitch, YouTube, Kick, Spotify, StreamElements, Chat
14
14
  - **21 Action Types** — Chat, OBS, Spotify, Events, Overlay
15
15
  - **Message Schemas** — JSON-RPC 2.0 wire format (Zod validated)
16
16
  - **30 Component Types** — `LumioComponentNode` for serialized UI trees
@@ -0,0 +1,51 @@
1
+ // src/origin.ts
2
+ var EXTENSION_RUNTIME_LABEL_PLACEHOLDER = "{label}";
3
+ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
4
+ var LABEL_PATTERN = /^[0-9a-f]{32}$/;
5
+ var DNS_LABEL_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
6
+ var TEMPLATE_PATTERN = /^(https:\/\/|http:\/\/)\{label\}(\.[a-z0-9.-]+(?::[0-9]{1,5})?)$/;
7
+ function parseTemplate(template) {
8
+ const match = TEMPLATE_PATTERN.exec(template);
9
+ if (!match) return null;
10
+ const prefix = match[1];
11
+ const suffix = match[2];
12
+ const host = suffix.slice(1).replace(/:[0-9]+$/, "");
13
+ if (prefix === "http://" && host !== "localhost") return null;
14
+ if (!host.split(".").every((label) => DNS_LABEL_PATTERN.test(label))) return null;
15
+ const sample = `${prefix}${"0".repeat(32)}${suffix}`;
16
+ try {
17
+ if (new URL(sample).origin !== sample) return null;
18
+ } catch {
19
+ return null;
20
+ }
21
+ return { prefix, suffix };
22
+ }
23
+ function extensionRuntimeLabel(extensionId) {
24
+ if (typeof extensionId !== "string" || !UUID_PATTERN.test(extensionId)) return null;
25
+ return extensionId.replaceAll("-", "");
26
+ }
27
+ function extensionRuntimeOrigin(extensionId, template) {
28
+ const label = extensionRuntimeLabel(extensionId);
29
+ if (!label) return null;
30
+ const parsed = parseTemplate(template);
31
+ if (!parsed) return null;
32
+ return `${parsed.prefix}${label}${parsed.suffix}`;
33
+ }
34
+ function extensionRuntimeOriginLabel(origin, template) {
35
+ const parsed = parseTemplate(template);
36
+ if (!parsed) return null;
37
+ if (!origin.startsWith(parsed.prefix) || !origin.endsWith(parsed.suffix)) return null;
38
+ const label = origin.slice(parsed.prefix.length, origin.length - parsed.suffix.length);
39
+ return LABEL_PATTERN.test(label) ? label : null;
40
+ }
41
+ function isValidExtensionRuntimeOriginTemplate(template) {
42
+ return parseTemplate(template) !== null;
43
+ }
44
+
45
+ export {
46
+ EXTENSION_RUNTIME_LABEL_PLACEHOLDER,
47
+ extensionRuntimeLabel,
48
+ extensionRuntimeOrigin,
49
+ extensionRuntimeOriginLabel,
50
+ isValidExtensionRuntimeOriginTemplate
51
+ };