@zaflun/lumio-agent-skill 0.5.3 → 0.6.5
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 +126 -0
- package/README.md +1 -1
- package/dist/bin/lumio-skills.js +1 -1
- package/dist/{chunk-TKNV5K6F.js → chunk-LKWF2Y7K.js} +108 -90
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@zaflun/lumio-agent-skill` are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## 0.6.5
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **`CHANGELOG.md` in the package** — the npm tarball ships this changelog.
|
|
13
|
+
- **Shopify events** — `SKILL.md` lists `shopify:order`,
|
|
14
|
+
`shopify:order_paid` and `shopify:product` (65 event types in total) and
|
|
15
|
+
describes their payloads: the store in `shop { domain, label }`, order
|
|
16
|
+
totals and line items only as the store's settings allow, and
|
|
17
|
+
`customer_display` only with the buyer's consent, to be rendered as text,
|
|
18
|
+
never as HTML.
|
|
19
|
+
- **Which URLs the host loads** — `components.md` explains that `<Image>`,
|
|
20
|
+
`<img src>` and `<a href>` load only from an `https` host in
|
|
21
|
+
`egress.allowHosts`, a `data:image/*` URL, the Lumio page, the extension's
|
|
22
|
+
runtime origin, or a platform avatar or emote URL served by Lumio's image
|
|
23
|
+
proxy. Any other URL renders an empty placeholder, and `style` values with
|
|
24
|
+
`url()` are dropped.
|
|
25
|
+
|
|
26
|
+
## 0.6.2
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **No `interactive` surface** — the skill files describe two surfaces,
|
|
31
|
+
editor and layer. Viewer input (votes, games) goes through chat commands
|
|
32
|
+
and channel point rewards handled by a bot module, which writes `ctx.db`
|
|
33
|
+
and calls `ctx.realtime.push`; the layer and editor receive it with
|
|
34
|
+
`useRealtime(topic, cb)`. The `interactive` template and target are gone
|
|
35
|
+
from the CLI and auth docs.
|
|
36
|
+
- **`useExtensionStorage(key, initialValue)`** — every example uses the
|
|
37
|
+
one-key-per-call signature instead of a whole-storage object with spread
|
|
38
|
+
updates.
|
|
39
|
+
- **Server functions** — they run in a V8 isolate on the Bot Module Worker
|
|
40
|
+
with a 5-second limit per call. `ctx.realtime.push` and `useRealtime` are
|
|
41
|
+
documented, `ctx.fetch` refuses every host in server functions, and
|
|
42
|
+
`secret()` works only in `action()` handlers. `lumio build` writes
|
|
43
|
+
`dist/functions.json` from `server/functions.ts`; declarative queries take
|
|
44
|
+
`orderBy`, `orderDir`, `limit` and `offset`.
|
|
45
|
+
- **`lumio env` replaces `lumio secrets`** — set, list and delete extension
|
|
46
|
+
secrets, with the key and value rules. Bot-module handlers read them with
|
|
47
|
+
`await ctx.secrets.get("KEY")`; server functions and automation nodes get
|
|
48
|
+
`null`.
|
|
49
|
+
- **Event list** — 62 event types: `twitch:gift_sub` is `twitch:gift`, and
|
|
50
|
+
`twitch:reward_status`, `twitch:reward_add`, `twitch:reward_update` and
|
|
51
|
+
`twitch:reward_remove` are added. `useLumioEvent()` examples show the typed
|
|
52
|
+
payload.
|
|
53
|
+
- **Developer limits link** — points to
|
|
54
|
+
`/dashboard/settings/developer/limits`.
|
|
55
|
+
|
|
56
|
+
## 0.5.3
|
|
57
|
+
|
|
58
|
+
### Added
|
|
59
|
+
|
|
60
|
+
- **Bundled sounds** — the `sounds` array in `lumio.config.json`, supported
|
|
61
|
+
formats and default limits.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **Per-extension runtime origin** — the skill files describe the Extension
|
|
66
|
+
Runtime on `<label>.runtime.ext.lumio.vision` (one origin per extension)
|
|
67
|
+
and the Supervisor on `supervisor.ext.lumio.vision`.
|
|
68
|
+
- **Extension actions** — the action list matches what the Lumio API
|
|
69
|
+
dispatches: chat send and delete, the OBS scene, source and stream
|
|
70
|
+
actions, `events:emit` and `overlay:update_layer`, each with its own
|
|
71
|
+
permission. Example parameters use the snake_case payloads
|
|
72
|
+
(`scene_name`, `event_type`, `layer_id`, …).
|
|
73
|
+
- **Event list** — 58 event types, including Kick resubs, KICKs, rewards and
|
|
74
|
+
stream updates, Twitch end and lock events, `streamelements:tip` and
|
|
75
|
+
`chat:message`.
|
|
76
|
+
- **`lumio build`** — documents the JS bundles, the bot-module server bundle,
|
|
77
|
+
Tailwind compilation and the pre-flight checks before upload.
|
|
78
|
+
|
|
79
|
+
## 0.5.0
|
|
80
|
+
|
|
81
|
+
### Added
|
|
82
|
+
|
|
83
|
+
- **Automation nodes** — `defineAutomationAction`, `defineAutomationTrigger`
|
|
84
|
+
and `defineAutomationLogic` handlers, the `lumio init` automation templates
|
|
85
|
+
and the `lumio dev` automation simulator.
|
|
86
|
+
- **Editor and picker components** — the 14 `Editor*` components with
|
|
87
|
+
`useEditorAction`, and `IconPicker`, `IconDisplay` and `useIconPicker`.
|
|
88
|
+
- **Config schema field types** — the extended field types, `visible_when`,
|
|
89
|
+
groups, and `designer_schema` for the full-page designer.
|
|
90
|
+
|
|
91
|
+
## 0.4.0
|
|
92
|
+
|
|
93
|
+
### Added
|
|
94
|
+
|
|
95
|
+
- **Bot modules** — the `command`, `keyword`, `pattern`, `event`, `timer`
|
|
96
|
+
and `moderate` handlers, their return actions and permissions, the handler
|
|
97
|
+
context (`ctx.user`, `ctx.cache`, `ctx.defer()`), and best practices for
|
|
98
|
+
rate limits, moderation escalation, overridable triggers and exempt roles.
|
|
99
|
+
|
|
100
|
+
### Changed
|
|
101
|
+
|
|
102
|
+
- **OBS wording** — the layer is described as running in a Browser Source,
|
|
103
|
+
not specifically OBS.
|
|
104
|
+
|
|
105
|
+
## 0.2.0
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- **`config_schema` is an array** of fields with `default_value` and
|
|
110
|
+
`required` in every example, and the config example uses the
|
|
111
|
+
`https://lumio.vision/schemas/lumio.config.schema.json` schema URL.
|
|
112
|
+
- **`useLumioAction(action)`** — examples drop the second argument; the
|
|
113
|
+
action list adds `chat:delete` and the OBS source and stream actions.
|
|
114
|
+
- **`instance` storage scope** — filtered by install as well as account and
|
|
115
|
+
overlay.
|
|
116
|
+
|
|
117
|
+
## 0.1.0
|
|
118
|
+
|
|
119
|
+
### Added
|
|
120
|
+
|
|
121
|
+
- **Initial release** — `npx lumio-skills add` writes eight skill files to
|
|
122
|
+
`.lumio/skills/` (`SKILL.md`, components, server functions, CLI workflows,
|
|
123
|
+
auth, runtime scopes, best practices, troubleshooting) and pointer files
|
|
124
|
+
for AI assistants (`AGENTS.md`, `GEMINI.md`, `.windsurfrules`,
|
|
125
|
+
`.github/copilot-instructions.md`). `installSkillFiles`, `SKILL_FILES` and
|
|
126
|
+
`ROOT_FILES` are exported for programmatic use.
|
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ This creates `.lumio/skills/` in your project with reference docs, plus agent co
|
|
|
21
21
|
| `server-functions.md` | Server function patterns, ctx API |
|
|
22
22
|
| `cli-workflows.md` | All 12 CLI commands |
|
|
23
23
|
| `auth.md` | Token types, permissions |
|
|
24
|
-
| `runtime-scopes.md` |
|
|
24
|
+
| `runtime-scopes.md` | Storage scopes (instance/overlay/account/global) |
|
|
25
25
|
| `best-practices.md` | Performance, security, UX |
|
|
26
26
|
| `troubleshooting.md` | Common errors and fixes |
|
|
27
27
|
|
package/dist/bin/lumio-skills.js
CHANGED
|
@@ -16,7 +16,7 @@ Lumio Extensions are sandboxed React apps that run inside a 3-layer iframe sandb
|
|
|
16
16
|
Host (lumio.vision / browser source)
|
|
17
17
|
\u2514\u2500\u2500 Supervisor iframe (supervisor.ext.lumio.vision)
|
|
18
18
|
\u2514\u2500\u2500 Extension Runtime iframe (<label>.runtime.ext.lumio.vision)
|
|
19
|
-
\u2514\u2500\u2500 Web Worker (
|
|
19
|
+
\u2514\u2500\u2500 Web Worker (the extension's UI code)
|
|
20
20
|
\`\`\`
|
|
21
21
|
|
|
22
22
|
\`\`\`
|
|
@@ -24,7 +24,6 @@ Extension Project:
|
|
|
24
24
|
lumio.config.json <- Extension manifest (ID, name, category, permissions, targets, config_schema)
|
|
25
25
|
src/editor.tsx <- Dashboard editor panel (sidebar in overlay editor)
|
|
26
26
|
src/layer.tsx <- Stream overlay surface (transparent, read-only inputs)
|
|
27
|
-
src/interactive.tsx <- Audience interaction page (optional)
|
|
28
27
|
server/schema.ts <- DB schema (defineTable + validators)
|
|
29
28
|
server/functions.ts <- Server functions (queries, mutations, actions)
|
|
30
29
|
\`\`\`
|
|
@@ -34,7 +33,7 @@ Extension Project:
|
|
|
34
33
|
2. \`Lumio.render(<Component />, { target: "layer" })\` must be called within 10 seconds
|
|
35
34
|
3. The custom React reconciler serializes the tree to \`LumioComponentNode[]\` via postMessage to the Supervisor
|
|
36
35
|
4. The Supervisor validates and forwards the node tree to the Host for rendering
|
|
37
|
-
5. Server functions
|
|
36
|
+
5. Server functions run on the Lumio backend (Bot Module Worker) in a V8 isolate (256 MB memory, 5 s per call); a handler's \`ctx.realtime.push(topic, payload)\` reaches every surface of the install through \`useRealtime(topic, cb)\`
|
|
38
37
|
6. Cross-frame messaging uses \`WorkerBridge\` (exported from \`@zaflun/lumio-sdk\`; replaces the legacy \`PostMessageBridge\`)
|
|
39
38
|
|
|
40
39
|
**Key constraints:**
|
|
@@ -47,15 +46,16 @@ Extension Project:
|
|
|
47
46
|
|
|
48
47
|
## Core Concepts
|
|
49
48
|
|
|
50
|
-
###
|
|
49
|
+
### Two Surfaces
|
|
51
50
|
|
|
52
51
|
| Target | Where | Purpose |
|
|
53
52
|
|--------|-------|---------|
|
|
54
53
|
| \`editor\` | Dashboard overlay editor sidebar | Config UI, settings, content management |
|
|
55
54
|
| \`layer\` | Browser Source (transparent) | Visual overlay in stream |
|
|
56
|
-
| \`interactive\` | Standalone page (\`/ext/{slug}\`) | Viewer interaction (votes, games) |
|
|
57
55
|
|
|
58
|
-
|
|
56
|
+
Both surfaces share storage via \`useExtensionStorage()\` \u2014 changes in editor propagate to layer in real-time.
|
|
57
|
+
|
|
58
|
+
**Viewer input** (votes, games) has no page of its own: viewers act through chat commands and channel point rewards. A bot-module handler \u2014 \`command("!vote", \u2026)\` or \`event("twitch:reward" | "kick:reward", \u2026)\` \u2014 writes \`ctx.db\` and calls \`ctx.realtime.push(topic, payload)\`; the layer and editor receive it with \`useRealtime(topic, cb)\`.
|
|
59
59
|
|
|
60
60
|
### lumio.config.json
|
|
61
61
|
|
|
@@ -99,7 +99,7 @@ All three surfaces share storage via \`useExtensionStorage()\` \u2014 changes in
|
|
|
99
99
|
- \`"visibility": "unlisted"\` \u2014 accessible by direct link only
|
|
100
100
|
- Private invite: grant \`free_access\` to specific accounts via dashboard
|
|
101
101
|
|
|
102
|
-
**Bundled sounds:** Place audio files in \`dist/sounds/\` and declare them in the \`sounds\` array. Supported: MP3, WAV, OGG, WebM, M4A, AAC, FLAC. Default limits: 50 sounds per extension, 10 MB per file, 200 MB total storage (all admin-configurable). Developers can view limits at \`/
|
|
102
|
+
**Bundled sounds:** Place audio files in \`dist/sounds/\` and declare them in the \`sounds\` array. Supported: MP3, WAV, OGG, WebM, M4A, AAC, FLAC. Default limits: 50 sounds per extension, 10 MB per file, 200 MB total storage (all admin-configurable). Developers can view limits at \`/dashboard/settings/developer/limits\` and request increases via a 4-step wizard. Requests are reviewed by admins in the admin app. Users cannot delete bundled sounds \u2014 uninstalling the extension removes them.
|
|
103
103
|
|
|
104
104
|
**Revenue split:** Configurable per developer (default 70/30 developer/Lumio).
|
|
105
105
|
|
|
@@ -161,9 +161,9 @@ See \`components.md\` for full props and examples.
|
|
|
161
161
|
|
|
162
162
|
| Hook | Returns | Purpose |
|
|
163
163
|
|------|---------|---------|
|
|
164
|
-
| \`useExtensionStorage()\` | \`[
|
|
165
|
-
| \`useVisionState(key, default)\` | \`[value, setValue]\` |
|
|
166
|
-
| \`useExtensionContext()\` | \`{ extensionId, target, overlayId
|
|
164
|
+
| \`useExtensionStorage(key, initialValue)\` | \`[value, setValue]\` | Persistent KV store, one key per call, synced across targets |
|
|
165
|
+
| \`useVisionState(key, default)\` | \`[value, setValue]\` | Same contract as \`useExtensionStorage\` |
|
|
166
|
+
| \`useExtensionContext()\` | \`{ extensionId, target, overlayId }\` | Extension metadata |
|
|
167
167
|
| \`useLumioEvent(eventType)\` | \`event\` | Live events (chat, alerts, spotify) \u2014 type-safe: \`eventType\` is \`LumioEventType\` |
|
|
168
168
|
| \`useLumioConfig()\` | \`[config, setConfig]\` | Extension config read/write (uses config_schema fields) |
|
|
169
169
|
| \`useLumioTheme()\` | \`theme\` | Current theme (dark/light/custom) |
|
|
@@ -171,10 +171,11 @@ See \`components.md\` for full props and examples.
|
|
|
171
171
|
| \`useLumioAction(action)\` | \`{ execute, data, isLoading, error }\` | Trigger Lumio actions \u2014 type-safe: \`action\` is \`LumioActionType\` |
|
|
172
172
|
| \`useQuery(fn, params?)\` | \`{ data, isLoading, error, refetch }\` | Call server query |
|
|
173
173
|
| \`useMutation(fn)\` | \`{ mutate, mutateAsync, data, isLoading, error }\` | Call server mutation/action |
|
|
174
|
+
| \`useRealtime(topic, cb)\` | \`void\` | Receive \`ctx.realtime.push(topic, payload)\` messages of this install |
|
|
174
175
|
| \`useAnimation(preset, options?)\` | \`animationProps\` | SDK animation presets for \`Animated\` component |
|
|
175
176
|
| \`useIconPicker(options?)\` | \`{ isOpen, selected, open, close, select, clear, sources }\` | Headless state for custom icon picker UIs |
|
|
176
177
|
|
|
177
|
-
**Important:** \`
|
|
178
|
+
**Important:** \`useExtensionStorage\` always takes a key and an initial value \u2014 call it once per key. A setter replaces only its own key; spread only when you store an object under one key: \`setScore({ ...score, home: 2 })\`
|
|
178
179
|
|
|
179
180
|
## Server Functions
|
|
180
181
|
|
|
@@ -189,7 +190,7 @@ export const updateItem = patchRow("items", arg("id"), { done: arg("done") });
|
|
|
189
190
|
export const removeItem = deleteRow("items", arg("id"), { editorOnly: true });
|
|
190
191
|
\`\`\`
|
|
191
192
|
|
|
192
|
-
**Handler-based** (V8 isolate
|
|
193
|
+
**Handler-based** (V8 isolate on the Bot Module Worker, full control):
|
|
193
194
|
\`\`\`typescript
|
|
194
195
|
import { action, arg, v } from "@zaflun/lumio-sdk/server";
|
|
195
196
|
export const fetchScores = action({
|
|
@@ -327,7 +328,7 @@ export const modCheck = moderate({
|
|
|
327
328
|
| \`lumio deploy\` | Upload to Lumio (status: draft). Flags: \`-v\`, \`-d\`, \`--breaking\`, \`--draft\` |
|
|
328
329
|
| \`lumio status\` | Check review status of latest version |
|
|
329
330
|
| \`lumio logs\` | Stream server function logs |
|
|
330
|
-
| \`lumio
|
|
331
|
+
| \`lumio env\` | Manage extension secrets (\`set\` / \`list\` / \`delete\`) |
|
|
331
332
|
| \`lumio team\` | Manage developer team members |
|
|
332
333
|
| \`lumio config\` | Show/set CLI configuration |
|
|
333
334
|
|
|
@@ -342,7 +343,7 @@ See \`cli-workflows.md\` for detailed usage and examples.
|
|
|
342
343
|
|
|
343
344
|
Extension tokens have no RBAC permissions (\`has_permission()\` always returns false) and can only access \`ext_{extension_id}.*\` DB tables via server functions.
|
|
344
345
|
|
|
345
|
-
**\`editorOnly: true\`** on server functions restricts mutations to editor surface only (layer
|
|
346
|
+
**\`editorOnly: true\`** on server functions restricts mutations to editor surface only (the layer cannot call them).
|
|
346
347
|
|
|
347
348
|
See \`auth.md\` for all 9 token types and the full token lifecycle.
|
|
348
349
|
|
|
@@ -360,26 +361,27 @@ lumio deploy -> draft -> [Submit via dashboard] -> pending_review
|
|
|
360
361
|
### Editor + Layer sync
|
|
361
362
|
\`\`\`tsx
|
|
362
363
|
// editor.tsx
|
|
363
|
-
const [
|
|
364
|
-
<Toggle label="Show" checked={
|
|
365
|
-
onChange={(v) => setStorage({ ...storage, visible: v })} />
|
|
364
|
+
const [visible, setVisible] = useExtensionStorage("visible", false);
|
|
365
|
+
<Toggle label="Show" checked={visible} onChange={setVisible} />
|
|
366
366
|
|
|
367
367
|
// layer.tsx
|
|
368
|
-
const [
|
|
369
|
-
|
|
370
|
-
|
|
368
|
+
const [visible] = useExtensionStorage("visible", false);
|
|
369
|
+
const [text] = useExtensionStorage("text", "");
|
|
370
|
+
if (!visible) return null;
|
|
371
|
+
return <Text content={text} />;
|
|
371
372
|
\`\`\`
|
|
372
373
|
|
|
373
374
|
### Live events
|
|
374
375
|
\`\`\`tsx
|
|
375
|
-
// eventType is LumioEventType \u2014 autocomplete shows all
|
|
376
|
-
const event = useLumioEvent("twitch:
|
|
377
|
-
// event updates automatically when a new
|
|
376
|
+
// eventType is LumioEventType \u2014 autocomplete shows all 65 valid event strings
|
|
377
|
+
const event = useLumioEvent("twitch:cheer");
|
|
378
|
+
// event updates automatically when a new cheer arrives; it is typed
|
|
379
|
+
// LumioEventPayloadMap["twitch:cheer"] | null, so event?.bits is a number
|
|
378
380
|
\`\`\`
|
|
379
381
|
|
|
380
|
-
**All
|
|
382
|
+
**All 65 event types** (\`LumioEventType\`):
|
|
381
383
|
|
|
382
|
-
Twitch (
|
|
384
|
+
Twitch (27): \`twitch:follower\`, \`twitch:subscribe\`, \`twitch:gift\`, \`twitch:resub\`, \`twitch:cheer\`, \`twitch:raid\`, \`twitch:reward\`, \`twitch:reward_status\`, \`twitch:reward_add\`, \`twitch:reward_update\`, \`twitch:reward_remove\`, \`twitch:hype_train\`, \`twitch:hype_train_end\`, \`twitch:poll\`, \`twitch:poll_end\`, \`twitch:prediction\`, \`twitch:prediction_lock\`, \`twitch:prediction_end\`, \`twitch:goal\`, \`twitch:goal_end\`, \`twitch:ad_break\`, \`twitch:ban\`, \`twitch:unban\`, \`twitch:stream_online\`, \`twitch:stream_offline\`, \`twitch:stream_update\`, \`twitch:chat\`
|
|
383
385
|
|
|
384
386
|
YouTube (10): \`youtube:subscribe\`, \`youtube:member\`, \`youtube:superchat\`, \`youtube:supersticker\`, \`youtube:gift_membership\`, \`youtube:gift_membership_received\`, \`youtube:poll\`, \`youtube:stream_online\`, \`youtube:stream_offline\`, \`youtube:chat\`
|
|
385
387
|
|
|
@@ -389,9 +391,11 @@ Spotify (12): \`spotify:track\`, \`spotify:play\`, \`spotify:pause\`, \`spotify:
|
|
|
389
391
|
|
|
390
392
|
StreamElements (1): \`streamelements:tip\`
|
|
391
393
|
|
|
394
|
+
Shopify (3): \`shopify:order\`, \`shopify:order_paid\`, \`shopify:product\`
|
|
395
|
+
|
|
392
396
|
Cross-platform chat (1, fires for every platform): \`chat:message\`
|
|
393
397
|
|
|
394
|
-
Kick events carry canonical top-level fields (\`user_id\`, \`user_login\`, \`user_name\`, \`avatarUrl\`, \`is_anonymous\`) plus the original Kick payload. \`kick:kicks\` has \`kicks\` (amount, like Twitch \`bits\`) and \`message\`; \`kick:reward\` / \`kick:reward_status\` have \`status\`, \`user_input\` and \`reward { id, title, cost, prompt }\`; \`kick:resub\` has \`cumulative_months\`.
|
|
398
|
+
Kick events carry canonical top-level fields (\`user_id\`, \`user_login\`, \`user_name\`, \`avatarUrl\`, \`is_anonymous\`) plus the original Kick payload. \`kick:kicks\` has \`kicks\` (amount, like Twitch \`bits\`) and \`message\`; \`kick:reward\` / \`kick:reward_status\` have \`status\`, \`user_input\` and \`reward { id, title, cost, prompt }\`; \`kick:resub\` has \`cumulative_months\`. \`twitch:reward_status\` has the \`twitch:reward\` shape with \`status\` \`fulfilled\` / \`canceled\`. \`twitch:reward_add\` / \`_update\` / \`_remove\` carry the Twitch reward (\`id\`, \`title\`, \`cost\`, \`prompt\`, \`is_enabled\`, \`is_paused\`, \u2026); these three arrive live only (\`broadcast_only\`), never from the event history. Every \`shopify:*\` event names its store in \`shop { domain, label }\` (absent on events stored before stores carried it). \`shopify:order\` / \`shopify:order_paid\` carry \`order_number\`, \`name\`, \`financial_status\`, \`line_items\` and \`total_price\` / \`currency\` only as the store's settings allow, and \`customer_display\` only with the buyer's consent \u2014 untrusted buyer text, render it with \`<Text>\`, never as HTML. \`shopify:product\` has \`title\`, \`vendor\`, \`product_type\`, \`handle\`, \`image_url\`.
|
|
395
399
|
|
|
396
400
|
### Server queries
|
|
397
401
|
\`\`\`tsx
|
|
@@ -421,7 +425,7 @@ const anim = useAnimation("slide-in", { duration: 300 });
|
|
|
421
425
|
| \`EXTENSION_NOT_FOUND\` | Invalid extensionId in config | Run \`lumio init\` or create via dashboard |
|
|
422
426
|
| \`EGRESS_BLOCKED\` | Fetch to undeclared host | Add host to \`egress.allowHosts\` in config |
|
|
423
427
|
| \`STORAGE_QUOTA\` | Exceeded storage limit | Reduce data or request limit increase |
|
|
424
|
-
| \`EDITOR_ONLY\` | Mutation called from layer
|
|
428
|
+
| \`EDITOR_ONLY\` | Mutation called from the layer | Remove \`editorOnly\` or restrict to editor |
|
|
425
429
|
| \`SUPERVISOR_BLOCKED\` | Supervisor rejected a postMessage | Check message origin matches the extension's runtime origin (\`<label>.runtime.ext.lumio.vision\`) |
|
|
426
430
|
| \`WORKER_CREATION_FAILED\` | Web Worker could not be created | Verify server functions bundle is valid JS |
|
|
427
431
|
| \`STORAGE_DOM_EXCEPTION\` | localStorage/sessionStorage access | Use \`useExtensionStorage()\` instead (storage blocked) |
|
|
@@ -620,6 +624,8 @@ import { Image } from "@zaflun/lumio-sdk";
|
|
|
620
624
|
- \`height?: number | string\`
|
|
621
625
|
- \`style?: VisionStyle\`
|
|
622
626
|
|
|
627
|
+
The host loads \`src\` only from an \`https\` host listed in \`egress.allowHosts\` (default port), a \`data:image/*\` URL, the Lumio page itself, the extension's runtime origin, or a Twitch/7TV/BTTV/FFZ/YouTube/Discord/Kick avatar or emote URL that Lumio's image proxy serves. Any other URL renders an empty placeholder. The same applies to \`<img src>\` and \`<a href>\`; \`style\` values with \`url()\` are dropped.
|
|
628
|
+
|
|
623
629
|
## Input Components
|
|
624
630
|
|
|
625
631
|
**Important:** On the layer surface, all input components become read-only. Buttons are hidden, toggles show "On"/"Off" text, dropdowns show the selected value.
|
|
@@ -816,18 +822,18 @@ import { IconPicker, IconDisplay } from "@zaflun/lumio-sdk";
|
|
|
816
822
|
import type { IconValue } from "@zaflun/lumio-sdk";
|
|
817
823
|
|
|
818
824
|
// In editor.tsx \u2014 let the user pick an icon
|
|
819
|
-
const [
|
|
825
|
+
const [icon, setIcon] = useExtensionStorage<IconValue | null>("icon", null);
|
|
820
826
|
|
|
821
827
|
<IconPicker
|
|
822
|
-
value={
|
|
823
|
-
onChange={
|
|
828
|
+
value={icon}
|
|
829
|
+
onChange={setIcon}
|
|
824
830
|
sources={["lucide", "emoji", "emote", "upload"]}
|
|
825
831
|
size="md"
|
|
826
832
|
placeholder="Choose an icon..."
|
|
827
833
|
/>
|
|
828
834
|
|
|
829
835
|
// In layer.tsx \u2014 render the selected icon
|
|
830
|
-
<IconDisplay icon={
|
|
836
|
+
<IconDisplay icon={icon} size={32} />
|
|
831
837
|
\`\`\`
|
|
832
838
|
|
|
833
839
|
**IconPickerProps:**
|
|
@@ -950,9 +956,12 @@ import { queryRows, insertRow, patchRow, deleteRow, arg, filter } from "@zaflun/
|
|
|
950
956
|
// Read all rows
|
|
951
957
|
export const getItems = queryRows("items");
|
|
952
958
|
|
|
953
|
-
// Read with filter
|
|
959
|
+
// Read with filter, order and paging
|
|
954
960
|
export const getDoneItems = queryRows("items", {
|
|
955
961
|
filter: filter("done", "=", true),
|
|
962
|
+
orderBy: "created_at",
|
|
963
|
+
orderDir: "desc",
|
|
964
|
+
limit: arg("limit"),
|
|
956
965
|
});
|
|
957
966
|
|
|
958
967
|
// Insert a row (editorOnly: only callable from editor surface)
|
|
@@ -975,8 +984,10 @@ export const removeItem = deleteRow("items", arg("id"), { editorOnly: true });
|
|
|
975
984
|
|
|
976
985
|
- \`arg("name")\` \u2014 reads from the client-provided arguments
|
|
977
986
|
- \`identity()\` \u2014 returns \`{ userId, accountId }\` of the caller
|
|
978
|
-
- \`secret("KEY")\` \u2014 reads a server-side secret (
|
|
979
|
-
- \`filter(field, op, value)\` \u2014 query filter
|
|
987
|
+
- \`secret("KEY")\` \u2014 reads a server-side secret in \`action()\` handlers only; \`lumio build\` rejects it in declarative functions
|
|
988
|
+
- \`filter(field, op, value)\` \u2014 query filter, \`op\` one of \`=\`, \`!=\`, \`>\`, \`>=\`, \`<\`, \`<=\`, \`like\`, \`in\`; pass a list for AND
|
|
989
|
+
- \`queryRows\` options: \`filter\`, \`orderBy\`, \`orderDir\` (\`asc\`/\`desc\`), \`limit\` / \`offset\` (integer or \`arg()\`)
|
|
990
|
+
- Definitions must be plain JSON: \`lumio build\` serialises every export of \`server/functions.ts\` to \`dist/functions.json\` and fails on anything else (keep helpers in another module)
|
|
980
991
|
|
|
981
992
|
## Handler-Based Functions
|
|
982
993
|
|
|
@@ -1006,45 +1017,48 @@ export const submitScore = mutation({
|
|
|
1006
1017
|
editorOnly: false,
|
|
1007
1018
|
});
|
|
1008
1019
|
|
|
1009
|
-
//
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
args: { sport: v.string(), league: v.string() },
|
|
1020
|
+
// Push a live update to every surface of the install (overlay, widget, editor)
|
|
1021
|
+
export const castVote = mutation({
|
|
1022
|
+
args: { choice: v.string() },
|
|
1013
1023
|
handler: async (ctx, args) => {
|
|
1014
|
-
|
|
1015
|
-
const
|
|
1016
|
-
|
|
1017
|
-
{ headers: { "Authorization": \`Bearer \${apiKey}\` } }
|
|
1018
|
-
);
|
|
1019
|
-
return res.json();
|
|
1024
|
+
await ctx.db.insert("votes", { choice: args.choice });
|
|
1025
|
+
const votes = await ctx.db.list("votes");
|
|
1026
|
+
ctx.realtime.push("poll:votes", { total: votes.length });
|
|
1020
1027
|
},
|
|
1021
1028
|
});
|
|
1022
1029
|
\`\`\`
|
|
1023
1030
|
|
|
1031
|
+
Receive the push in any surface with \`useRealtime\`:
|
|
1032
|
+
|
|
1033
|
+
\`\`\`tsx
|
|
1034
|
+
import { useRealtime } from "@zaflun/lumio-sdk";
|
|
1035
|
+
|
|
1036
|
+
useRealtime<{ total: number }>("poll:votes", (payload) => setTotal(payload.total));
|
|
1037
|
+
\`\`\`
|
|
1038
|
+
|
|
1024
1039
|
### Handler Context (\`ctx\`)
|
|
1025
1040
|
|
|
1026
|
-
Handler-based functions run
|
|
1041
|
+
Handler-based functions run in a V8 isolate on the Bot Module Worker (never in the API process or the browser). The \`ctx\` object:
|
|
1027
1042
|
|
|
1028
1043
|
| Property | Description |
|
|
1029
1044
|
|----------|-------------|
|
|
1030
|
-
| \`ctx.db.get(table, id)\` | Read
|
|
1031
|
-
| \`ctx.db.insert(table, data)\` |
|
|
1032
|
-
| \`ctx.
|
|
1033
|
-
| \`ctx.
|
|
1034
|
-
| \`ctx.
|
|
1035
|
-
| \`ctx.
|
|
1036
|
-
| \`ctx.auth\` | \`{ userId, accountId,
|
|
1045
|
+
| \`ctx.db.get(table, id)\` / \`list(table, filters?)\` | Read rows of the extension's tables (install's account only) |
|
|
1046
|
+
| \`ctx.db.insert(table, data)\` / \`patch\` / \`delete\` | Write rows |
|
|
1047
|
+
| \`ctx.realtime.push(topic, payload?)\` | Push \`{ topic, payload }\` to every rendered surface of the install (\`useRealtime\`). Topic: 1-64 chars of \`A-Z a-z 0-9 _ . : -\`; payload \u2264 16 KiB; \u2264 32 per call, 300 per install and minute. Sent after the handler returns, only if it did not throw |
|
|
1048
|
+
| \`ctx.cache\` / \`ctx.defer\` | Install-scoped cache and background jobs, as in bot modules |
|
|
1049
|
+
| \`ctx.secrets.get(key)\` | The extension's owner secret (\`lumio env set\`), or \`null\` |
|
|
1050
|
+
| \`ctx.fetch(url, options?)\` | Refuses every host in server functions (no egress allow-list yet); call external APIs from a bot module |
|
|
1051
|
+
| \`ctx.auth\` | \`{ userId, accountId, role }\` \u2014 \`userId\` is \`null\` for overlay, widget and extension tokens |
|
|
1037
1052
|
|
|
1038
1053
|
### Sandbox Limits
|
|
1039
1054
|
|
|
1040
1055
|
| Limit | Value |
|
|
1041
1056
|
|-------|-------|
|
|
1042
1057
|
| Memory | 256 MB per invocation |
|
|
1043
|
-
|
|
|
1058
|
+
| Wall-clock timeout | 5 seconds per call |
|
|
1044
1059
|
| Filesystem | No access |
|
|
1045
|
-
| Network |
|
|
1060
|
+
| Network | None for server functions (\`ctx.fetch\` refuses every host) |
|
|
1046
1061
|
| Dynamic code | Blocked (\`eval\`, \`Function\`, \`import()\`) |
|
|
1047
|
-
| Storage APIs | localStorage/sessionStorage blocked (separate origin) |
|
|
1048
1062
|
|
|
1049
1063
|
### Rate Limits
|
|
1050
1064
|
|
|
@@ -1145,7 +1159,8 @@ export default defineAutomationTrigger({
|
|
|
1145
1159
|
const lastCheck = await ctx.cache.get("last_check") ?? "1970-01-01T00:00:00Z";
|
|
1146
1160
|
const res = await ctx.fetch(
|
|
1147
1161
|
\`https://api.example.com/events?since=\${lastCheck}\`,
|
|
1148
|
-
|
|
1162
|
+
// Automation nodes get no secrets yet: the token comes from the node config.
|
|
1163
|
+
{ headers: { "Authorization": \`Bearer \${ctx.nodeConfig.apiToken}\` } }
|
|
1149
1164
|
);
|
|
1150
1165
|
const events = await res.json();
|
|
1151
1166
|
await ctx.cache.set("last_check", new Date().toISOString());
|
|
@@ -1179,7 +1194,7 @@ export default defineAutomationLogic({
|
|
|
1179
1194
|
| \`ctx.inputData\` | Action, Logic | Data from the upstream node |
|
|
1180
1195
|
| \`ctx.fetch(url, options?)\` | All | HTTP request (egress allowlist enforced) |
|
|
1181
1196
|
| \`ctx.cache.get(key)\` / \`ctx.cache.set(key, value, ttl?)\` | All | Per-installation KV cache (Redis, 1h default TTL) |
|
|
1182
|
-
| \`ctx.secrets.get(key)\` | All |
|
|
1197
|
+
| \`ctx.secrets.get(key)\` | All | Not wired for automation nodes yet: always \`null\` |
|
|
1183
1198
|
| \`ctx.db\` | All | Extension DB schema access |
|
|
1184
1199
|
| \`ctx.auth\` | All | \`{ accountId }\` \u2014 account identity |
|
|
1185
1200
|
| \`ctx.defer()\` | Action | Mark execution as async (returns 202, completes in background) |
|
|
@@ -1444,7 +1459,6 @@ Automation nodes always generate \`server/handler.ts\` (not \`server/functions.t
|
|
|
1444
1459
|
| Blank | editor + layer | No | Minimal starting point |
|
|
1445
1460
|
| Widget | editor + layer | Yes | Widget with storage |
|
|
1446
1461
|
| Full-Stack | editor + layer | Yes | Complete extension with server functions |
|
|
1447
|
-
| Interactive Game | editor + layer + interactive | Yes | Viewer interaction game |
|
|
1448
1462
|
| Bot Module | server-only | Yes | Chat command module |
|
|
1449
1463
|
| Automation Action | server + editor | Yes | Automation workflow action node |
|
|
1450
1464
|
| Automation Trigger | server + editor | Yes | Automation workflow trigger node |
|
|
@@ -1461,9 +1475,8 @@ lumio dev
|
|
|
1461
1475
|
|
|
1462
1476
|
# Output:
|
|
1463
1477
|
# Lumio Dev Server running at http://localhost:5173
|
|
1464
|
-
# Editor:
|
|
1465
|
-
# Layer:
|
|
1466
|
-
# Interactive: http://localhost:5173/interactive
|
|
1478
|
+
# Editor: http://localhost:5173/editor
|
|
1479
|
+
# Layer: http://localhost:5173/layer
|
|
1467
1480
|
#
|
|
1468
1481
|
# Mock events available. Press 'e' to emit a test event.
|
|
1469
1482
|
# Press 'q' to quit.
|
|
@@ -1507,6 +1520,7 @@ lumio build
|
|
|
1507
1520
|
# Output for widgets:
|
|
1508
1521
|
# Built: dist/editor.js
|
|
1509
1522
|
# Built: dist/layer.js
|
|
1523
|
+
# Built: dist/server.js + dist/functions.json (if server: true)
|
|
1510
1524
|
# Compiled: dist/styles.css (if Tailwind detected)
|
|
1511
1525
|
# Archive: dist/source.tar.gz
|
|
1512
1526
|
#
|
|
@@ -1517,10 +1531,11 @@ lumio build
|
|
|
1517
1531
|
\`\`\`
|
|
1518
1532
|
|
|
1519
1533
|
Build steps:
|
|
1520
|
-
1. UI targets (\`editor\`, \`layer\`, \`
|
|
1521
|
-
2. Server handler (\`server: true\`) \u2014 compiles \`server/handler.ts\` to \`dist/server.js\` (ESM)
|
|
1522
|
-
3.
|
|
1523
|
-
4.
|
|
1534
|
+
1. UI targets (\`editor\`, \`layer\`, \`designer\`) \u2014 esbuild IIFE bundles
|
|
1535
|
+
2. Server handler (\`server: true\`) \u2014 compiles \`server/handler.ts\` (or \`server/index.ts\`, else \`server/functions.ts\`) to \`dist/server.js\` (ESM)
|
|
1536
|
+
3. Functions manifest (\`server: true\`, not bot modules / automation nodes) \u2014 evaluates \`server/functions.ts\` and writes every export to \`dist/functions.json\` (\`{ version: 1, functions: { name: { kind, category, editorOnly, table?, \u2026 } } }\`; handlers become \`{ kind: "handler", category }\` stubs). Fails on a non-definition export, a non-JSON value, \`secret()\` in a declarative function, a table missing from \`server/schema.ts\`, or names that differ only in case. \`lumio deploy\` uploads it with the version.
|
|
1537
|
+
4. CSS \u2014 Tailwind v4 auto-detected and compiled, or plain CSS copied
|
|
1538
|
+
5. Source archive \u2014 \`dist/source.tar.gz\`
|
|
1524
1539
|
|
|
1525
1540
|
Warns if \`CHANGELOG.md\` is missing.
|
|
1526
1541
|
|
|
@@ -1617,25 +1632,27 @@ lumio logs --filter fetchScores
|
|
|
1617
1632
|
lumio logs --level error
|
|
1618
1633
|
\`\`\`
|
|
1619
1634
|
|
|
1620
|
-
## lumio
|
|
1635
|
+
## lumio env
|
|
1621
1636
|
|
|
1622
|
-
Manage
|
|
1637
|
+
Manage the extension's secrets. Bot-module handlers read them via \`await ctx.secrets.get("KEY")\` (\`null\` when unset). Server functions and automation nodes do not get secrets yet (\`ctx.secrets.get\` returns \`null\` there).
|
|
1623
1638
|
|
|
1624
1639
|
\`\`\`bash
|
|
1625
|
-
# Set a secret
|
|
1626
|
-
lumio
|
|
1640
|
+
# Set a secret (prompts with hidden input when VALUE is omitted)
|
|
1641
|
+
lumio env set ESPN_API_KEY
|
|
1642
|
+
|
|
1643
|
+
# Non-interactive (CI): value from LUMIO_SECRET, keeps it out of shell history
|
|
1644
|
+
LUMIO_SECRET="$ESPN_API_KEY" lumio env set ESPN_API_KEY
|
|
1627
1645
|
|
|
1628
1646
|
# List secret keys (values are never shown)
|
|
1629
|
-
lumio
|
|
1647
|
+
lumio env list
|
|
1630
1648
|
# Output:
|
|
1631
|
-
#
|
|
1632
|
-
# WEATHER_TOKEN (set 2026-04-01)
|
|
1649
|
+
# ESPN_API_KEY (created 2026-05-19T00:00:00Z)
|
|
1633
1650
|
|
|
1634
1651
|
# Delete a secret
|
|
1635
|
-
lumio
|
|
1652
|
+
lumio env delete ESPN_API_KEY
|
|
1636
1653
|
\`\`\`
|
|
1637
1654
|
|
|
1638
|
-
|
|
1655
|
+
Keys match \`^[A-Z0-9_]{1,64}$\`; values are 1 to 4096 bytes. A developer API key (\`lm_dev_\`) may manage secrets, so this works in CI. Secrets are stored encrypted (AES-256-GCM), one set per extension shared by every install, and are never returned by the API or exposed to the frontend or other extensions.
|
|
1639
1656
|
|
|
1640
1657
|
## lumio team
|
|
1641
1658
|
|
|
@@ -1711,7 +1728,7 @@ AuthContext::ExtensionToken {
|
|
|
1711
1728
|
extension_id: Uuid,
|
|
1712
1729
|
install_id: Uuid,
|
|
1713
1730
|
account_id: Uuid,
|
|
1714
|
-
target: "editor" | "layer"
|
|
1731
|
+
target: "editor" | "layer",
|
|
1715
1732
|
}
|
|
1716
1733
|
\`\`\`
|
|
1717
1734
|
|
|
@@ -1752,7 +1769,7 @@ Widget tokens are suitable for persistent, public-facing embeds where session re
|
|
|
1752
1769
|
Server functions marked with \`editorOnly: true\` can only be called from the \`editor\` surface.
|
|
1753
1770
|
|
|
1754
1771
|
\`\`\`typescript
|
|
1755
|
-
// Only callable from editor.tsx \u2014 layer.tsx
|
|
1772
|
+
// Only callable from editor.tsx \u2014 layer.tsx gets 403
|
|
1756
1773
|
export const addItem = insertRow("items", { text: arg("text") }, { editorOnly: true });
|
|
1757
1774
|
|
|
1758
1775
|
// Callable from any surface
|
|
@@ -1912,8 +1929,8 @@ var bestPracticesContent = `# Best Practices
|
|
|
1912
1929
|
## Performance
|
|
1913
1930
|
|
|
1914
1931
|
### Minimize renders
|
|
1915
|
-
-
|
|
1916
|
-
-
|
|
1932
|
+
- Call \`useExtensionStorage(key, initialValue)\` once per value \u2014 each key loads, syncs and re-renders on its own
|
|
1933
|
+
- Debounce text inputs \u2014 every setter call is one storage write
|
|
1917
1934
|
- Use \`useMemo\` and \`useCallback\` to avoid unnecessary re-renders
|
|
1918
1935
|
|
|
1919
1936
|
### Optimize server function calls
|
|
@@ -1938,22 +1955,21 @@ Always use \`useExtensionStorage()\` for state that should be visible on both ed
|
|
|
1938
1955
|
|
|
1939
1956
|
\`\`\`tsx
|
|
1940
1957
|
// editor.tsx \u2014 user configures
|
|
1941
|
-
const [
|
|
1942
|
-
<TextField label="Title" value={
|
|
1943
|
-
onChange={(v) => setStorage({ ...storage, title: v })} />
|
|
1958
|
+
const [title, setTitle] = useExtensionStorage("title", "Default Title");
|
|
1959
|
+
<TextField label="Title" value={title} onChange={setTitle} />
|
|
1944
1960
|
|
|
1945
1961
|
// layer.tsx \u2014 displays result
|
|
1946
|
-
const [
|
|
1947
|
-
<Text content={
|
|
1962
|
+
const [title] = useExtensionStorage("title", "Default Title");
|
|
1963
|
+
<Text content={title} variant="heading" />
|
|
1948
1964
|
\`\`\`
|
|
1949
1965
|
|
|
1950
1966
|
### Graceful defaults
|
|
1951
|
-
|
|
1967
|
+
Pass a sensible \`initialValue\` for every key. The hook returns it until the stored value has loaded, and for a key that was never stored.
|
|
1952
1968
|
|
|
1953
1969
|
\`\`\`tsx
|
|
1954
|
-
const visible =
|
|
1955
|
-
const maxItems =
|
|
1956
|
-
const theme =
|
|
1970
|
+
const [visible] = useExtensionStorage("visible", true);
|
|
1971
|
+
const [maxItems] = useExtensionStorage("maxItems", 10);
|
|
1972
|
+
const [theme] = useExtensionStorage("theme", "dark");
|
|
1957
1973
|
\`\`\`
|
|
1958
1974
|
|
|
1959
1975
|
### Loading states
|
|
@@ -2081,7 +2097,8 @@ For beta testing before public launch:
|
|
|
2081
2097
|
| Mistake | Fix |
|
|
2082
2098
|
|---------|-----|
|
|
2083
2099
|
| Direct DOM manipulation | Use SDK components only \u2014 reconciler serializes to \`LumioComponentNode[]\` |
|
|
2084
|
-
| \`
|
|
2100
|
+
| \`useExtensionStorage()\` without a key | \`useExtensionStorage(key, initialValue)\` \u2014 one call per key |
|
|
2101
|
+
| Object under one key set without spread | \`setScore({ ...score, home: 2 })\` \u2014 the setter replaces that key's value |
|
|
2085
2102
|
| Polling with setInterval | Use \`useLumioEvent()\` for live data |
|
|
2086
2103
|
| Large inline images | Use URL-based images via \`Image\` component |
|
|
2087
2104
|
| Missing \`Lumio.render()\` | Must be called within 10s of page load |
|
|
@@ -2217,7 +2234,7 @@ var troubleshootingContent = `# Troubleshooting
|
|
|
2217
2234
|
| \`EGRESS_BLOCKED\` | Host not in allowlist | \`ctx.fetch()\` called with undeclared host | Add host to \`egress.allowHosts\` in \`lumio.config.json\` |
|
|
2218
2235
|
| \`EGRESS_PRIVATE_IP\` | Private IP range blocked | Fetch targeting localhost or private network | Use public HTTPS endpoints only |
|
|
2219
2236
|
| \`STORAGE_QUOTA\` | Storage quota exceeded | Extension data exceeds allocated storage | Reduce stored data or request limit increase |
|
|
2220
|
-
| \`EDITOR_ONLY\` | Function restricted to editor | Mutation with \`editorOnly: true\` called from layer
|
|
2237
|
+
| \`EDITOR_ONLY\` | Function restricted to editor | Mutation with \`editorOnly: true\` called from the layer | Remove \`editorOnly\` flag or call only from editor |
|
|
2221
2238
|
| \`MEMORY_LIMIT\` | V8 isolate memory exceeded (128 MB) | Handler-based function using too much memory | Reduce data processing, stream large datasets |
|
|
2222
2239
|
| \`CPU_TIMEOUT\` | V8 isolate CPU timeout (5s) | Handler-based function running too long | Optimize logic, break into smaller operations |
|
|
2223
2240
|
| \`RATE_LIMITED\` | Too many requests (429) | Exceeded per-installation rate limit | Reduce call frequency, batch operations |
|
|
@@ -2225,7 +2242,8 @@ var troubleshootingContent = `# Troubleshooting
|
|
|
2225
2242
|
| \`SCHEMA_VALIDATION\` | Invalid function arguments | Args do not match \`v.string()\`/\`v.number()\` validators | Check argument types match schema definition |
|
|
2226
2243
|
| \`TABLE_NOT_FOUND\` | Table does not exist | Referenced table not defined in \`server/schema.ts\` | Add table to \`defineSchema()\` and redeploy |
|
|
2227
2244
|
| \`PERMISSION_DENIED\` | Missing declared permission | Action requires undeclared permission | Add permission to \`lumio.config.json -> permissions\` |
|
|
2228
|
-
| \`
|
|
2245
|
+
| \`ctx.secrets.get\` returns \`null\` | Secret key not set | Bot-module handler reads a key nobody set | \`lumio env set KEY\` or Dashboard \u2192 Extensions \u2192 your extension \u2192 Secrets |
|
|
2246
|
+
| \`ctx.secrets is unavailable\` | Secret store unreadable right now | Transient platform issue | Retry; handle the error instead of crashing the handler |
|
|
2229
2247
|
| \`CHANGELOG_MISSING\` | No changelog entry for version | \`lumio deploy\` without matching CHANGELOG.md entry | Add entry for the version in CHANGELOG.md, or use \`-d\` flag |
|
|
2230
2248
|
| \`BUNDLE_TOO_LARGE\` | Bundle exceeds size limit | Built bundle exceeds \`max_bundle_size_mb\` | Reduce bundle size or request limit increase |
|
|
2231
2249
|
| \`SUPERVISOR_BLOCKED\` | Supervisor rejected postMessage | Message origin or schema invalid | Ensure you are in the correct iframe layer; do not post to Host directly |
|
package/dist/index.d.ts
CHANGED
|
@@ -13,4 +13,5 @@ declare const ROOT_FILES: SkillFile[];
|
|
|
13
13
|
*/
|
|
14
14
|
declare function installSkillFiles(targetDir: string): void;
|
|
15
15
|
|
|
16
|
-
export { ROOT_FILES, SKILL_FILES,
|
|
16
|
+
export { ROOT_FILES, SKILL_FILES, installSkillFiles };
|
|
17
|
+
export type { SkillFile };
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zaflun/lumio-agent-skill",
|
|
3
|
-
"version": "0.5
|
|
3
|
+
"version": "0.6.5",
|
|
4
4
|
"description": "AI agent skill files for building Lumio Extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"lumio-skills": "dist/bin/lumio-skills.js"
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
|
-
"dist"
|
|
12
|
+
"dist",
|
|
13
|
+
"CHANGELOG.md"
|
|
13
14
|
],
|
|
14
15
|
"keywords": [
|
|
15
16
|
"lumio",
|
|
@@ -28,9 +29,9 @@
|
|
|
28
29
|
"license": "MIT",
|
|
29
30
|
"devDependencies": {
|
|
30
31
|
"@types/node": "^26.1.2",
|
|
31
|
-
"tsup": "^
|
|
32
|
+
"tsup": "^9.0.0",
|
|
32
33
|
"typescript": "^6.0.3",
|
|
33
|
-
"vitest": "^
|
|
34
|
+
"vitest": "^5.0.5"
|
|
34
35
|
},
|
|
35
36
|
"repository": {
|
|
36
37
|
"type": "git",
|