@skyvexsoftware/stratos-sdk 0.1.13 → 0.1.15
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/dist/bin/deploy.js +14 -6
- package/dist/types/manifest.d.ts +2 -0
- package/dist/vite/css-inject.d.ts +11 -0
- package/dist/vite/css-inject.js +47 -0
- package/dist/vite/plugin-config.js +77 -38
- package/package.json +2 -1
package/dist/bin/deploy.js
CHANGED
|
@@ -15,6 +15,12 @@ import { execSync } from "child_process";
|
|
|
15
15
|
import * as https from "https";
|
|
16
16
|
import * as http from "http";
|
|
17
17
|
const API_BASE = "https://skyvexsoftware.com/api/stratos";
|
|
18
|
+
// ── CLI flags ───────────────────────────────────────────────────────
|
|
19
|
+
const releaseModeArg = process.argv.find((a) => a.startsWith("--release-mode="));
|
|
20
|
+
const releaseMode = releaseModeArg?.split("=")[1] ?? "automatic";
|
|
21
|
+
if (releaseMode !== "automatic" && releaseMode !== "manual") {
|
|
22
|
+
fatal("--release-mode must be 'automatic' or 'manual'");
|
|
23
|
+
}
|
|
18
24
|
// ── Helpers ──────────────────────────────────────────────────────────
|
|
19
25
|
function fatal(message) {
|
|
20
26
|
console.error(`\n Error: ${message}\n`);
|
|
@@ -67,17 +73,18 @@ function createBundle(cwd) {
|
|
|
67
73
|
return bundlePath;
|
|
68
74
|
}
|
|
69
75
|
// ── Upload ───────────────────────────────────────────────────────────
|
|
70
|
-
function upload(pluginId,
|
|
76
|
+
function upload(pluginId, bundlePath, token) {
|
|
71
77
|
return new Promise((resolve) => {
|
|
72
78
|
const boundary = `----StratosDeploy${Date.now()}`;
|
|
73
79
|
const fileContent = fs.readFileSync(bundlePath);
|
|
74
80
|
const parts = [];
|
|
75
|
-
//
|
|
76
|
-
parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="version"\r\n\r\n${version}\r\n`));
|
|
77
|
-
// File field
|
|
81
|
+
// File field (version is extracted from plugin.json inside the zip server-side)
|
|
78
82
|
parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="file"; filename="bundle.zip"\r\nContent-Type: application/zip\r\n\r\n`));
|
|
79
83
|
parts.push(fileContent);
|
|
80
|
-
parts.push(Buffer.from(
|
|
84
|
+
parts.push(Buffer.from("\r\n"));
|
|
85
|
+
// Release mode field
|
|
86
|
+
parts.push(Buffer.from(`--${boundary}\r\nContent-Disposition: form-data; name="release_mode"\r\n\r\n${releaseMode}\r\n`));
|
|
87
|
+
parts.push(Buffer.from(`--${boundary}--\r\n`));
|
|
81
88
|
const body = Buffer.concat(parts);
|
|
82
89
|
const url = new URL(`${API_BASE}/plugins/${pluginId}/versions`);
|
|
83
90
|
const options = {
|
|
@@ -114,10 +121,11 @@ async function main() {
|
|
|
114
121
|
const bundlePath = createBundle(cwd);
|
|
115
122
|
const bundleSize = fs.statSync(bundlePath).size;
|
|
116
123
|
console.log(`\n ${name} v${version} — bundle.zip (${formatSize(bundleSize)})`);
|
|
124
|
+
console.log(` Release mode: ${releaseMode}`);
|
|
117
125
|
const token = process.env.SKYVEX_API_TOKEN;
|
|
118
126
|
if (token) {
|
|
119
127
|
console.log(" Uploading to Skyvex...");
|
|
120
|
-
const result = await upload(id,
|
|
128
|
+
const result = await upload(id, bundlePath, token);
|
|
121
129
|
if (result.ok) {
|
|
122
130
|
console.log(" Published! Server is signing and publishing to CDN.\n");
|
|
123
131
|
fs.unlinkSync(bundlePath);
|
package/dist/types/manifest.d.ts
CHANGED
|
@@ -38,5 +38,7 @@ export type PluginManifest = {
|
|
|
38
38
|
icon_dark: string;
|
|
39
39
|
/** Typed settings this plugin declares. User-scoped settings render in the Settings page; airline-scoped settings are managed by the VA platform. */
|
|
40
40
|
availableSettings?: PluginSettingDefinition[];
|
|
41
|
+
/** Whether to include source maps in the published CDN bundle. Defaults to false — source maps are stripped on approval. Set to true if you want end users to have access to source maps for debugging. */
|
|
42
|
+
includeSourceMaps?: boolean;
|
|
41
43
|
};
|
|
42
44
|
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin that injects extracted CSS into the JS bundle for library mode.
|
|
3
|
+
*
|
|
4
|
+
* In Vite library mode, CSS imports are extracted to a separate .css file.
|
|
5
|
+
* Since plugins are loaded via dynamic import(), the CSS file is never loaded.
|
|
6
|
+
* This plugin moves the CSS content into the JS entry chunk so it's injected
|
|
7
|
+
* into the DOM automatically when the plugin module is imported.
|
|
8
|
+
*/
|
|
9
|
+
import type { Plugin } from "vite";
|
|
10
|
+
export declare function cssInject(): Plugin;
|
|
11
|
+
//# sourceMappingURL=css-inject.d.ts.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vite plugin that injects extracted CSS into the JS bundle for library mode.
|
|
3
|
+
*
|
|
4
|
+
* In Vite library mode, CSS imports are extracted to a separate .css file.
|
|
5
|
+
* Since plugins are loaded via dynamic import(), the CSS file is never loaded.
|
|
6
|
+
* This plugin moves the CSS content into the JS entry chunk so it's injected
|
|
7
|
+
* into the DOM automatically when the plugin module is imported.
|
|
8
|
+
*/
|
|
9
|
+
export function cssInject() {
|
|
10
|
+
return {
|
|
11
|
+
name: "stratos-css-inject",
|
|
12
|
+
apply: "build",
|
|
13
|
+
enforce: "post",
|
|
14
|
+
generateBundle(_, bundle) {
|
|
15
|
+
// Find emitted CSS assets
|
|
16
|
+
const cssAssets = [];
|
|
17
|
+
let cssContent = "";
|
|
18
|
+
for (const [fileName, chunk] of Object.entries(bundle)) {
|
|
19
|
+
if (fileName.endsWith(".css") && chunk.type === "asset") {
|
|
20
|
+
cssContent +=
|
|
21
|
+
typeof chunk.source === "string"
|
|
22
|
+
? chunk.source
|
|
23
|
+
: new TextDecoder().decode(chunk.source);
|
|
24
|
+
cssAssets.push(fileName);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (!cssContent)
|
|
28
|
+
return;
|
|
29
|
+
// Find the JS entry chunk
|
|
30
|
+
const jsEntry = Object.values(bundle).find((chunk) => chunk.type === "chunk" && chunk.isEntry);
|
|
31
|
+
if (!jsEntry || jsEntry.type !== "chunk")
|
|
32
|
+
return;
|
|
33
|
+
// Prepend CSS injection code to the JS entry
|
|
34
|
+
const escaped = cssContent
|
|
35
|
+
.replace(/\\/g, "\\\\")
|
|
36
|
+
.replace(/`/g, "\\`")
|
|
37
|
+
.replace(/\$/g, "\\$");
|
|
38
|
+
const injection = `(function(){try{var s=document.createElement("style");s.textContent=\`${escaped}\`;document.head.appendChild(s)}catch(e){}})();\n`;
|
|
39
|
+
jsEntry.code = injection + jsEntry.code;
|
|
40
|
+
// Remove the separate CSS files
|
|
41
|
+
for (const name of cssAssets) {
|
|
42
|
+
delete bundle[name];
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=css-inject.js.map
|
|
@@ -17,9 +17,11 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import * as fs from "fs";
|
|
19
19
|
import * as path from "path";
|
|
20
|
+
import MagicString from "magic-string";
|
|
20
21
|
import { UI_EXTERNALS } from "./externals.js";
|
|
21
22
|
import { serveExternals } from "./serve-externals.js";
|
|
22
23
|
import { stratosDevServer } from "./stratos-dev-server.js";
|
|
24
|
+
import { cssInject } from "./css-inject.js";
|
|
23
25
|
/** Modules external in background builds (available in Electron main process) */
|
|
24
26
|
const BG_EXTERNALS = ["electron", "socket.io-client"];
|
|
25
27
|
/** Node.js built-in modules to externalize in background builds */
|
|
@@ -63,49 +65,84 @@ function stratosExternals() {
|
|
|
63
65
|
return {
|
|
64
66
|
name: "stratos-externals",
|
|
65
67
|
renderChunk(code) {
|
|
66
|
-
|
|
68
|
+
const s = new MagicString(code);
|
|
67
69
|
for (const modId of UI_EXTERNALS) {
|
|
68
70
|
const escaped = modId.replace(/[-/\\^$*+?.()|[\]{}@]/g, "\\$&");
|
|
69
71
|
const global = `window.__stratos_modules__[${JSON.stringify(modId)}]`;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
72
|
+
const patterns = [
|
|
73
|
+
// 1. import Default, { named } from 'mod';
|
|
74
|
+
[
|
|
75
|
+
new RegExp(`import\\s+([\\w$]+)\\s*,\\s*\\{([^}]+)\\}\\s+from\\s+['"]${escaped}['"]\\s*;?`, "g"),
|
|
76
|
+
(_, def, names) => {
|
|
77
|
+
const destructured = names.replace(/([\w$]+)\s+as\s+([\w$]+)/g, "$1: $2");
|
|
78
|
+
return `const ${def} = ${global}.default || ${global};\nconst {${destructured}} = ${global};`;
|
|
79
|
+
},
|
|
80
|
+
],
|
|
81
|
+
// 2. import { named } from 'mod';
|
|
82
|
+
[
|
|
83
|
+
new RegExp(`import\\s*\\{([^}]+)\\}\\s+from\\s+['"]${escaped}['"]\\s*;?`, "g"),
|
|
84
|
+
(_, names) => {
|
|
85
|
+
const destructured = names.replace(/([\w$]+)\s+as\s+([\w$]+)/g, "$1: $2");
|
|
86
|
+
return `const {${destructured}} = ${global};`;
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
// 3. import * as ns from 'mod';
|
|
90
|
+
[
|
|
91
|
+
new RegExp(`import\\s+\\*\\s+as\\s+([\\w$]+)\\s+from\\s+['"]${escaped}['"]\\s*;?`, "g"),
|
|
92
|
+
(_, name) => `const ${name} = ${global};`,
|
|
93
|
+
],
|
|
94
|
+
// 4. import Default from 'mod';
|
|
95
|
+
[
|
|
96
|
+
new RegExp(`import\\s+([\\w$]+)\\s+from\\s+['"]${escaped}['"]\\s*;?`, "g"),
|
|
97
|
+
(_, def) => `const ${def} = ${global}.default || ${global};`,
|
|
98
|
+
],
|
|
99
|
+
// 5. import 'mod';
|
|
100
|
+
[new RegExp(`import\\s+['"]${escaped}['"]\\s*;?`, "g"), () => ""],
|
|
101
|
+
// 6. export { name } from 'mod';
|
|
102
|
+
[
|
|
103
|
+
new RegExp(`export\\s*\\{([^}]+)\\}\\s+from\\s+['"]${escaped}['"]\\s*;?`, "g"),
|
|
104
|
+
(_, names) => {
|
|
105
|
+
const parts = names.split(",").map((n) => n.trim());
|
|
106
|
+
const decls = [];
|
|
107
|
+
const exportNames = [];
|
|
108
|
+
for (const part of parts) {
|
|
109
|
+
const asMatch = part.match(/^([\w$]+)\s+as\s+([\w$]+)$/);
|
|
110
|
+
if (asMatch) {
|
|
111
|
+
decls.push(`const ${asMatch[2]} = ${global}[${JSON.stringify(asMatch[1])}];`);
|
|
112
|
+
exportNames.push(asMatch[2]);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
exportNames.push(part);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (decls.length > 0) {
|
|
119
|
+
return `${decls.join("\n")}\nconst {${exportNames.join(", ")}} = ${global};\nexport {${exportNames.join(", ")}};`;
|
|
120
|
+
}
|
|
121
|
+
return `const {${exportNames.join(", ")}} = ${global};\nexport {${exportNames.join(", ")}};`;
|
|
122
|
+
},
|
|
123
|
+
],
|
|
124
|
+
];
|
|
125
|
+
// Collect all matches first, then apply in reverse order to preserve offsets
|
|
126
|
+
const matches = [];
|
|
127
|
+
for (const [re, replacer] of patterns) {
|
|
128
|
+
re.lastIndex = 0;
|
|
129
|
+
let match;
|
|
130
|
+
while ((match = re.exec(code)) !== null) {
|
|
131
|
+
matches.push({
|
|
132
|
+
start: match.index,
|
|
133
|
+
end: match.index + match[0].length,
|
|
134
|
+
replacement: replacer(match[0], ...match.slice(1)),
|
|
135
|
+
});
|
|
101
136
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
137
|
+
}
|
|
138
|
+
// Apply in reverse so earlier offsets stay valid
|
|
139
|
+
matches
|
|
140
|
+
.sort((a, b) => b.start - a.start)
|
|
141
|
+
.forEach((m) => s.overwrite(m.start, m.end, m.replacement));
|
|
107
142
|
}
|
|
108
|
-
|
|
143
|
+
if (!s.hasChanged())
|
|
144
|
+
return null;
|
|
145
|
+
return { code: s.toString(), map: s.generateMap({ hires: true }) };
|
|
109
146
|
},
|
|
110
147
|
};
|
|
111
148
|
}
|
|
@@ -205,6 +242,7 @@ function createUIConfig(pluginDir, entry, extraConfig) {
|
|
|
205
242
|
},
|
|
206
243
|
sourcemap: true,
|
|
207
244
|
minify: isProduction ? "esbuild" : false,
|
|
245
|
+
assetsInlineLimit: 10 * 1024 * 1024,
|
|
208
246
|
},
|
|
209
247
|
esbuild: {
|
|
210
248
|
jsx: "automatic",
|
|
@@ -216,6 +254,7 @@ function createUIConfig(pluginDir, entry, extraConfig) {
|
|
|
216
254
|
serveExternals(),
|
|
217
255
|
stratosDevServer({ pluginDir }),
|
|
218
256
|
stratosExternals(),
|
|
257
|
+
cssInject(),
|
|
219
258
|
copyPluginAssets(pluginDir),
|
|
220
259
|
...(extraConfig?.plugins ?? []),
|
|
221
260
|
],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyvexsoftware/stratos-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "Plugin SDK for Stratos — types, hooks, and UI components",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Skyvex Software",
|
|
@@ -84,6 +84,7 @@
|
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"clsx": "^2.1.1",
|
|
87
|
+
"magic-string": "^0.30.21",
|
|
87
88
|
"tailwind-merge": "^3.2.0"
|
|
88
89
|
},
|
|
89
90
|
"devDependencies": {
|