lumia-plugin 0.1.4 → 0.1.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/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # Lumia Stream Plugin CLI
2
2
 
3
- The `@lumiastream/plugin-cli` package bundles the command-line tools for creating, building, and validating Lumia Stream plugins without pulling the full SDK into your runtime dependencies.
3
+ The `lumia-plugin` package bundles the command-line tools for creating, building, and validating Lumia Stream plugins without pulling the full SDK into your runtime dependencies.
4
4
 
5
5
  ## Commands
6
6
 
7
7
  ```
8
- npx @lumiastream/plugin-cli create <directory>
9
- npx @lumiastream/plugin-cli build [--dir <path>] [--out <file>]
10
- npx @lumiastream/plugin-cli validate <plugin-directory>
8
+ npx lumia-plugin create <directory>
9
+ npx lumia-plugin build [--dir <path>] [--out <file>]
10
+ npx lumia-plugin validate <plugin-directory>
11
11
  ```
12
12
 
13
13
  Run any command with `--help` to see detailed options.
@@ -11,7 +11,7 @@ This template demonstrates a handful of common Lumia Stream plugin capabilities:
11
11
  Use the CLI to copy and customise the template:
12
12
 
13
13
  ```
14
- npx @lumiastream/plugin-cli create my-plugin
14
+ npx lumia-plugin create my-plugin
15
15
  ```
16
16
 
17
17
  After scaffolding you can tailor the manifest, code, and README to match your idea.
@@ -1,143 +1,150 @@
1
- const { Plugin } = require('@lumiastream/plugin-sdk');
1
+ const { Plugin } = require("@lumiastream/plugin");
2
2
 
3
3
  const VARIABLE_NAMES = {
4
- lastMessage: 'last_message',
5
- lastAlertColor: 'last_alert_color',
4
+ lastMessage: "last_message",
5
+ lastAlertColor: "last_alert_color",
6
6
  };
7
7
 
8
8
  const DEFAULTS = {
9
- welcomeMessage: 'Hello from Showcase Plugin!',
10
- color: '#00c2ff',
11
- alertDuration: 5,
9
+ welcomeMessage: "Hello from Showcase Plugin!",
10
+ color: "#00c2ff",
11
+ alertDuration: 5,
12
12
  };
13
13
 
14
14
  class ShowcasePluginTemplate extends Plugin {
15
- async onload() {
16
- const message = this._currentMessage();
17
- await this._log('Plugin loaded');
18
- await this._rememberMessage(message);
19
-
20
- if (this.settings.autoAlert === 'load') {
21
- await this._triggerSampleAlert({
22
- color: this.settings.favoriteColor,
23
- duration: DEFAULTS.alertDuration,
24
- });
25
- }
26
- }
27
-
28
- async onunload() {
29
- await this._log('Plugin unloaded');
30
- }
31
-
32
- async onsettingsupdate(settings, previous = {}) {
33
- await this._log('Settings updated');
34
-
35
- if (settings?.welcomeMessage && settings.welcomeMessage !== previous?.welcomeMessage) {
36
- await this._rememberMessage(settings.welcomeMessage);
37
- }
38
-
39
- if (settings?.autoAlert === 'load' && previous?.autoAlert !== 'load') {
40
- await this._log('Auto alert configured to fire on load');
41
- }
42
- }
43
-
44
- async actions(config = {}) {
45
- const actions = Array.isArray(config.actions) ? config.actions : [];
46
- for (const action of actions) {
47
- switch (action?.type) {
48
- case 'log_message':
49
- await this._handleLogMessage(action.data);
50
- break;
51
- case 'update_variable':
52
- await this._handleUpdateVariable(action.data);
53
- break;
54
- case 'trigger_alert':
55
- await this._triggerSampleAlert(action.data);
56
- break;
57
- default:
58
- await this._log(`Unknown action type: ${action?.type ?? 'undefined'}`);
59
- }
60
- }
61
- }
62
-
63
- _tag() {
64
- return `[${this.manifest?.id ?? 'showcase-plugin'}]`;
65
- }
66
-
67
- _currentMessage() {
68
- return (
69
- this.settings?.welcomeMessage ||
70
- `Hello from ${this.manifest?.name ?? 'Showcase Plugin'}!`
71
- );
72
- }
73
-
74
- async _log(message, severity = 'info') {
75
- const prefix = this._tag();
76
- const decorated =
77
- severity === 'warn'
78
- ? `${prefix} ⚠️ ${message}`
79
- : severity === 'error'
80
- ? `${prefix} ${message}`
81
- : `${prefix} ${message}`;
82
-
83
- await this.lumia.addLog(decorated);
84
- }
85
-
86
- async _rememberMessage(value) {
87
- await this.lumia.setVariable(VARIABLE_NAMES.lastMessage, value);
88
- }
89
-
90
- async _handleLogMessage(data = {}) {
91
- const message = data?.message || this._currentMessage();
92
- const severity = data?.severity || 'info';
93
-
94
- await this._log(message, severity);
95
-
96
- if (typeof this.lumia.showToast === 'function') {
97
- await this.lumia.showToast({
98
- message: `${this.manifest?.name ?? 'Plugin'}: ${message}`,
99
- time: 4,
100
- });
101
- }
102
-
103
- if (this.settings.autoAlert === 'after-log') {
104
- await this._triggerSampleAlert({
105
- color: this.settings.favoriteColor,
106
- duration: DEFAULTS.alertDuration,
107
- });
108
- }
109
- }
110
-
111
- async _handleUpdateVariable(data = {}) {
112
- const value = data?.value ?? new Date().toISOString();
113
- await this._rememberMessage(value);
114
- await this._log(`Stored variable value: ${value}`);
115
- }
116
-
117
- async _triggerSampleAlert(data = {}) {
118
- const color =
119
- data?.color ||
120
- this.settings?.favoriteColor ||
121
- DEFAULTS.color;
122
- const duration = Number(data?.duration) || DEFAULTS.alertDuration;
123
-
124
- try {
125
- const success = await this.lumia.triggerAlert({
126
- alert: 'sample_light',
127
- extraSettings: { color, duration },
128
- });
129
-
130
- if (!success) {
131
- await this._log('Sample alert reported failure', 'warn');
132
- return;
133
- }
134
-
135
- await this.lumia.setVariable(VARIABLE_NAMES.lastAlertColor, color);
136
- await this._log(`Triggered sample alert with color ${color} for ${duration}s`);
137
- } catch (error) {
138
- await this._log(`Failed to trigger sample alert: ${error.message ?? error}`, 'error');
139
- }
140
- }
15
+ async onload() {
16
+ const message = this._currentMessage();
17
+ await this._log("Plugin loaded");
18
+ await this._rememberMessage(message);
19
+
20
+ if (this.settings.autoAlert === "load") {
21
+ await this._triggerSampleAlert({
22
+ color: this.settings.favoriteColor,
23
+ duration: DEFAULTS.alertDuration,
24
+ });
25
+ }
26
+ }
27
+
28
+ async onunload() {
29
+ await this._log("Plugin unloaded");
30
+ }
31
+
32
+ async onsettingsupdate(settings, previous = {}) {
33
+ await this._log("Settings updated");
34
+
35
+ if (
36
+ settings?.welcomeMessage &&
37
+ settings.welcomeMessage !== previous?.welcomeMessage
38
+ ) {
39
+ await this._rememberMessage(settings.welcomeMessage);
40
+ }
41
+
42
+ if (settings?.autoAlert === "load" && previous?.autoAlert !== "load") {
43
+ await this._log("Auto alert configured to fire on load");
44
+ }
45
+ }
46
+
47
+ async actions(config = {}) {
48
+ const actions = Array.isArray(config.actions) ? config.actions : [];
49
+ for (const action of actions) {
50
+ switch (action?.type) {
51
+ case "log_message":
52
+ await this._handleLogMessage(action.data);
53
+ break;
54
+ case "update_variable":
55
+ await this._handleUpdateVariable(action.data);
56
+ break;
57
+ case "trigger_alert":
58
+ await this._triggerSampleAlert(action.data);
59
+ break;
60
+ default:
61
+ await this._log(
62
+ `Unknown action type: ${action?.type ?? "undefined"}`
63
+ );
64
+ }
65
+ }
66
+ }
67
+
68
+ _tag() {
69
+ return `[${this.manifest?.id ?? "showcase-plugin"}]`;
70
+ }
71
+
72
+ _currentMessage() {
73
+ return (
74
+ this.settings?.welcomeMessage ||
75
+ `Hello from ${this.manifest?.name ?? "Showcase Plugin"}!`
76
+ );
77
+ }
78
+
79
+ async _log(message, severity = "info") {
80
+ const prefix = this._tag();
81
+ const decorated =
82
+ severity === "warn"
83
+ ? `${prefix} ⚠️ ${message}`
84
+ : severity === "error"
85
+ ? `${prefix} ❌ ${message}`
86
+ : `${prefix} ${message}`;
87
+
88
+ await this.lumia.addLog(decorated);
89
+ }
90
+
91
+ async _rememberMessage(value) {
92
+ await this.lumia.setVariable(VARIABLE_NAMES.lastMessage, value);
93
+ }
94
+
95
+ async _handleLogMessage(data = {}) {
96
+ const message = data?.message || this._currentMessage();
97
+ const severity = data?.severity || "info";
98
+
99
+ await this._log(message, severity);
100
+
101
+ if (typeof this.lumia.showToast === "function") {
102
+ await this.lumia.showToast({
103
+ message: `${this.manifest?.name ?? "Plugin"}: ${message}`,
104
+ time: 4,
105
+ });
106
+ }
107
+
108
+ if (this.settings.autoAlert === "after-log") {
109
+ await this._triggerSampleAlert({
110
+ color: this.settings.favoriteColor,
111
+ duration: DEFAULTS.alertDuration,
112
+ });
113
+ }
114
+ }
115
+
116
+ async _handleUpdateVariable(data = {}) {
117
+ const value = data?.value ?? new Date().toISOString();
118
+ await this._rememberMessage(value);
119
+ await this._log(`Stored variable value: ${value}`);
120
+ }
121
+
122
+ async _triggerSampleAlert(data = {}) {
123
+ const color = data?.color || this.settings?.favoriteColor || DEFAULTS.color;
124
+ const duration = Number(data?.duration) || DEFAULTS.alertDuration;
125
+
126
+ try {
127
+ const success = await this.lumia.triggerAlert({
128
+ alert: "sample_light",
129
+ extraSettings: { color, duration },
130
+ });
131
+
132
+ if (!success) {
133
+ await this._log("Sample alert reported failure", "warn");
134
+ return;
135
+ }
136
+
137
+ await this.lumia.setVariable(VARIABLE_NAMES.lastAlertColor, color);
138
+ await this._log(
139
+ `Triggered sample alert with color ${color} for ${duration}s`
140
+ );
141
+ } catch (error) {
142
+ await this._log(
143
+ `Failed to trigger sample alert: ${error.message ?? error}`,
144
+ "error"
145
+ );
146
+ }
147
+ }
141
148
  }
142
149
 
143
150
  module.exports = ShowcasePluginTemplate;
@@ -1,10 +1,10 @@
1
1
  {
2
- "name": "lumia-showcase-plugin-template",
3
- "version": "1.0.0",
4
- "private": true,
5
- "description": "Internal template illustrating logging, variables, actions, and alerts for Lumia Stream plugins.",
6
- "main": "main.js",
7
- "dependencies": {
8
- "@lumiastream/plugin-sdk": "^0.1.0"
9
- }
2
+ "name": "lumia-showcase-plugin-template",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "description": "Internal template illustrating logging, variables, actions, and alerts for Lumia Stream plugins.",
6
+ "main": "main.js",
7
+ "dependencies": {
8
+ "@lumiastream/plugin": "^0.1.0"
9
+ }
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lumia-plugin",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Command-line tools for creating, building, and validating Lumia Stream plugins.",
5
5
  "bin": {
6
6
  "lumia-plugin": "scripts/cli.js"
@@ -43,7 +43,7 @@ function parseArgs() {
43
43
  function printHelp() {
44
44
  console.log(`Build a .lumiaplugin archive for distribution.
45
45
 
46
- Usage: npx @lumiastream/plugin-cli build [options]
46
+ Usage: npx lumia-plugin build [options]
47
47
 
48
48
  Options:
49
49
  --dir, -d Plugin directory (defaults to cwd)
@@ -23,7 +23,7 @@ function toDisplayName(id) {
23
23
  }
24
24
 
25
25
  function printHelp() {
26
- console.log(`Scaffold a new Lumia Stream plugin directory using the showcase template.\n\nUsage: npx @lumiastream/plugin-cli create [target-directory]\n\nExamples:\n npx @lumiastream/plugin-cli create ./plugins/my-plugin\n npx @lumiastream/plugin-cli create my-awesome-plugin\n`);
26
+ console.log(`Scaffold a new Lumia Stream plugin directory using the showcase template.\n\nUsage: npx lumia-plugin create [target-directory]\n\nExamples:\n npx lumia-plugin create ./plugins/my-plugin\n npx lumia-plugin create my-awesome-plugin\n`);
27
27
  }
28
28
 
29
29
  async function ensureEmptyDir(targetDir) {
package/scripts/utils.js CHANGED
@@ -1,109 +1,129 @@
1
- const fs = require('fs');
2
- const path = require('path');
3
- const JSZip = require('jszip');
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+ const JSZip = require("jszip");
4
4
 
5
5
  const DEFAULT_IGNORE = new Set([
6
- '.git',
7
- '.DS_Store',
8
- 'Thumbs.db',
9
- 'package-lock.json',
10
- 'yarn.lock',
11
- '.npmrc',
12
- '.gitignore',
6
+ ".git",
7
+ ".DS_Store",
8
+ "Thumbs.db",
9
+ "package-lock.json",
10
+ "yarn.lock",
11
+ ".npmrc",
12
+ ".gitignore",
13
13
  ]);
14
14
 
15
15
  function toPosix(p) {
16
- return p.split(path.sep).join('/');
16
+ return p.split(path.sep).join("/");
17
17
  }
18
18
 
19
19
  async function readManifest(pluginDir) {
20
- const manifestPath = path.join(pluginDir, 'manifest.json');
21
- const raw = await fs.promises.readFile(manifestPath, 'utf8');
22
- return { manifest: JSON.parse(raw), manifestPath };
20
+ const manifestPath = path.join(pluginDir, "manifest.json");
21
+ const raw = await fs.promises.readFile(manifestPath, "utf8");
22
+ return { manifest: JSON.parse(raw), manifestPath };
23
23
  }
24
24
 
25
25
  function validateManifest(manifest) {
26
- const errors = [];
27
- const requiredStringFields = ['id', 'name', 'version', 'author', 'description', 'license', 'lumiaVersion'];
28
- for (const field of requiredStringFields) {
29
- const value = manifest[field];
30
- if (typeof value !== 'string' || value.trim().length === 0) {
31
- errors.push(`Missing or invalid manifest field: ${field}`);
32
- }
33
- }
26
+ const errors = [];
27
+ const requiredStringFields = [
28
+ "id",
29
+ "name",
30
+ "version",
31
+ "author",
32
+ "description",
33
+ "license",
34
+ "lumiaVersion",
35
+ ];
36
+ for (const field of requiredStringFields) {
37
+ const value = manifest[field];
38
+ if (typeof value !== "string" || value.trim().length === 0) {
39
+ errors.push(`Missing or invalid manifest field: ${field}`);
40
+ }
41
+ }
34
42
 
35
- if (!manifest.category || (typeof manifest.category !== 'string' && !Array.isArray(manifest.category))) {
36
- errors.push('Manifest must declare a category string');
37
- }
43
+ if (
44
+ !manifest.category ||
45
+ (typeof manifest.category !== "string" && !Array.isArray(manifest.category))
46
+ ) {
47
+ errors.push("Manifest must declare a category string");
48
+ }
38
49
 
39
- if (!manifest.config || typeof manifest.config !== 'object') {
40
- errors.push('Manifest config must be an object');
41
- }
50
+ if (!manifest.config || typeof manifest.config !== "object") {
51
+ errors.push("Manifest config must be an object");
52
+ }
42
53
 
43
- if (manifest.config) {
44
- if (manifest.config.settings && !Array.isArray(manifest.config.settings)) {
45
- errors.push('config.settings must be an array when provided');
46
- }
47
- if (manifest.config.actions && !Array.isArray(manifest.config.actions)) {
48
- errors.push('config.actions must be an array when provided');
49
- }
50
- if (manifest.config.variables && !Array.isArray(manifest.config.variables)) {
51
- errors.push('config.variables must be an array when provided');
52
- }
53
- if (manifest.config.alerts && !Array.isArray(manifest.config.alerts)) {
54
- errors.push('config.alerts must be an array when provided');
55
- }
56
- }
54
+ if (manifest.config) {
55
+ if (manifest.config.settings && !Array.isArray(manifest.config.settings)) {
56
+ errors.push("config.settings must be an array when provided");
57
+ }
58
+ if (manifest.config.actions && !Array.isArray(manifest.config.actions)) {
59
+ errors.push("config.actions must be an array when provided");
60
+ }
61
+ if (
62
+ manifest.config.variables &&
63
+ !Array.isArray(manifest.config.variables)
64
+ ) {
65
+ errors.push("config.variables must be an array when provided");
66
+ }
67
+ if (manifest.config.alerts && !Array.isArray(manifest.config.alerts)) {
68
+ errors.push("config.alerts must be an array when provided");
69
+ }
70
+ }
57
71
 
58
- return errors;
72
+ return errors;
59
73
  }
60
74
 
61
75
  async function collectFiles(pluginDir, ignore = DEFAULT_IGNORE) {
62
- const entries = [];
76
+ const entries = [];
63
77
 
64
- async function walk(currentDir) {
65
- const list = await fs.promises.readdir(currentDir, { withFileTypes: true });
66
- for (const entry of list) {
67
- if (ignore.has(entry.name)) continue;
68
- const absolute = path.join(currentDir, entry.name);
69
- const relative = path.relative(pluginDir, absolute);
70
- if (!relative || relative.startsWith('..')) continue;
78
+ async function walk(currentDir) {
79
+ const list = await fs.promises.readdir(currentDir, { withFileTypes: true });
80
+ for (const entry of list) {
81
+ if (ignore.has(entry.name)) continue;
82
+ const absolute = path.join(currentDir, entry.name);
83
+ const relative = path.relative(pluginDir, absolute);
84
+ if (!relative || relative.startsWith("..")) continue;
71
85
 
72
- // Skip bundled Lumia packages in node_modules
73
- if (relative === 'node_modules/@lumiastream'
74
- || relative.startsWith('node_modules/@lumiastream/plugin-sdk')
75
- || relative.startsWith('node_modules/@lumiastream/plugin-cli')) {
76
- continue;
77
- }
86
+ // Skip bundled Lumia packages in node_modules
87
+ if (
88
+ relative === "node_modules/@lumiastream" ||
89
+ relative.startsWith("node_modules/@lumiastream/plugin") ||
90
+ relative.startsWith("node_modules/lumia-plugin")
91
+ ) {
92
+ continue;
93
+ }
78
94
 
79
- if (entry.isDirectory()) {
80
- await walk(absolute);
81
- } else if (entry.isFile()) {
82
- entries.push({ absolute, relative: toPosix(relative) });
83
- }
84
- }
85
- }
95
+ if (entry.isDirectory()) {
96
+ await walk(absolute);
97
+ } else if (entry.isFile()) {
98
+ entries.push({ absolute, relative: toPosix(relative) });
99
+ }
100
+ }
101
+ }
86
102
 
87
- await walk(pluginDir);
88
- return entries;
103
+ await walk(pluginDir);
104
+ return entries;
89
105
  }
90
106
 
91
107
  async function createPluginArchive(pluginDir, outputFile, files) {
92
- const zip = new JSZip();
93
- for (const file of files) {
94
- const data = await fs.promises.readFile(file.absolute);
95
- zip.file(file.relative, data);
96
- }
97
- const content = await zip.generateAsync({ type: 'nodebuffer', compression: 'DEFLATE', compressionOptions: { level: 9 } });
98
- await fs.promises.mkdir(path.dirname(outputFile), { recursive: true });
99
- await fs.promises.writeFile(outputFile, content);
100
- return outputFile;
108
+ const zip = new JSZip();
109
+ for (const file of files) {
110
+ const data = await fs.promises.readFile(file.absolute);
111
+ zip.file(file.relative, data);
112
+ }
113
+ const content = await zip.generateAsync({
114
+ type: "nodebuffer",
115
+ compression: "DEFLATE",
116
+ compressionOptions: { level: 9 },
117
+ });
118
+ await fs.promises.mkdir(path.dirname(outputFile), { recursive: true });
119
+ await fs.promises.writeFile(outputFile, content);
120
+ return outputFile;
101
121
  }
102
122
 
103
123
  module.exports = {
104
- readManifest,
105
- validateManifest,
106
- collectFiles,
107
- createPluginArchive,
108
- DEFAULT_IGNORE,
124
+ readManifest,
125
+ validateManifest,
126
+ collectFiles,
127
+ createPluginArchive,
128
+ DEFAULT_IGNORE,
109
129
  };