sammi-next 1.2.2 → 1.4.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.
@@ -0,0 +1,170 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import colors from "picocolors";
4
+ import chokidar from "chokidar";
5
+ import { build } from "tsdown";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ //#region package.json
9
+ var version = "1.4.0";
10
+
11
+ //#endregion
12
+ //#region src/node/constants.ts
13
+ const DEFAULT_CONFIG_EXTENSIONS = [
14
+ ".mjs",
15
+ ".js",
16
+ ".mts",
17
+ ".ts"
18
+ ];
19
+ const GLOBAL_NAME = "SAMMIExtensions";
20
+ const BUILD_PREFIX = colors.blue("[sammi-next]");
21
+ const GREEN_CHECK = colors.green("✔");
22
+ const RED_X = colors.red("✗");
23
+ function findPackageDir() {
24
+ let initPath = fileURLToPath(import.meta.url);
25
+ while (!initPath.endsWith("sammi-next")) initPath = path.resolve(initPath, "..");
26
+ return path.resolve(initPath, "..");
27
+ }
28
+ const SAMMI_NEXT_PACKAGE_DIR = findPackageDir();
29
+
30
+ //#endregion
31
+ //#region src/node/utils.ts
32
+ function displayTime(time) {
33
+ if (time < 1e3) return `${time}ms`;
34
+ time = time / 1e3;
35
+ if (time < 60) return `${time.toFixed(2)}s`;
36
+ const mins = Math.floor(time / 60);
37
+ const seconds = Math.round(time % 60);
38
+ if (seconds === 60) return `${mins + 1}m`;
39
+ return `${mins}m${seconds < 1 ? "" : ` ${seconds}s`}`;
40
+ }
41
+
42
+ //#endregion
43
+ //#region src/node/build.ts
44
+ let BuildMode = /* @__PURE__ */ function(BuildMode) {
45
+ BuildMode[BuildMode["DEV"] = 0] = "DEV";
46
+ BuildMode[BuildMode["PRODUCTION"] = 1] = "PRODUCTION";
47
+ return BuildMode;
48
+ }({});
49
+ const BuildModes = Object.keys(BuildMode).filter((key) => isNaN(Number(key)));
50
+ function readOptionalFile(path$1) {
51
+ if (!fs.existsSync(path$1)) return;
52
+ return fs.readFileSync(path$1, "utf-8");
53
+ }
54
+ const CommandRE = /\w+\(\w+,\s*{\s*default:/gm;
55
+ function generateSEF(options) {
56
+ const { config, rootDir, mode } = options;
57
+ const content = [];
58
+ const required_files = [
59
+ {
60
+ header: "extension_name",
61
+ content: config.name
62
+ },
63
+ {
64
+ header: "extension_info",
65
+ content: config.info
66
+ },
67
+ {
68
+ header: "extension_version",
69
+ content: config.version
70
+ }
71
+ ];
72
+ for (const field of required_files) content.push(`[${field.header}]`, field.content, "");
73
+ const external = readOptionalFile(config.external);
74
+ content.push("[insert_external]", external ? `<div id="${config.id}-external">${external}</div>` : "", "");
75
+ const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), "utf-8");
76
+ content.push("[insert_command]", CommandRE.test(js_script) ? `${GLOBAL_NAME}.${config.id}.default()` : "", "");
77
+ content.push("[insert_hook]", "", "");
78
+ content.push("[insert_script]", js_script, "");
79
+ let over = readOptionalFile(config.over);
80
+ if (over && mode === BuildMode.PRODUCTION) over = JSON.stringify(JSON.parse(over));
81
+ content.push("[insert_over]", over && over != "{}" ? over : "", "");
82
+ return content.join("\n");
83
+ }
84
+ function generatePreview(options) {
85
+ const { config } = options;
86
+ const external = readOptionalFile(config.external);
87
+ const script = fs.readFileSync(config.entry, "utf-8");
88
+ return fs.readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, ".sammi", "preview.blueprint.html"), "utf-8").replace(/{{EXTERNAL}}/g, external ? `<div id="${config.id}-external">${external}</div>` : "").replace(/{{SCRIPT}}/g, script);
89
+ }
90
+ async function buildOnce(options) {
91
+ const { config, rootDir, mode } = options;
92
+ const startTime = Date.now();
93
+ const bundle = await build({
94
+ entry: [config.entry],
95
+ outDir: path.join(rootDir, config.out.dir),
96
+ platform: "browser",
97
+ format: "iife",
98
+ target: ["es2022"],
99
+ sourcemap: false,
100
+ minify: mode === BuildMode.PRODUCTION,
101
+ banner: { js: `/* ${config.name} v${config.version} - Built with SAMMI Next v${version} */` },
102
+ noExternal: ["**"],
103
+ outputOptions: {
104
+ entryFileNames: config.out.js,
105
+ extend: true,
106
+ name: `${GLOBAL_NAME}.${config.id}`,
107
+ exports: "named"
108
+ }
109
+ });
110
+ const tsdownTime = Date.now();
111
+ console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);
112
+ fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), "utf-8");
113
+ const sefTime = Date.now();
114
+ console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.sef} in ${displayTime(sefTime - tsdownTime)}`);
115
+ fs.writeFileSync(path.join(rootDir, config.out.dir, "preview.html"), generatePreview(options), "utf-8");
116
+ const previewTime = Date.now();
117
+ console.info(GREEN_CHECK, BUILD_PREFIX, `built preview.html in ${displayTime(previewTime - sefTime)}`);
118
+ return {
119
+ bundle,
120
+ startTime
121
+ };
122
+ }
123
+ async function buildExtension(options) {
124
+ const { config, mode } = options;
125
+ console.info(colors.cyan(`SAMMI Next v${version} ${colors.green(`building "${config.name}" extension in ${BuildMode[mode].toLowerCase()} mode...`)}`));
126
+ let bundle;
127
+ let startTime;
128
+ try {
129
+ const res = await buildOnce(options);
130
+ bundle = res.bundle;
131
+ startTime = res.startTime;
132
+ if (options.mode !== BuildMode.DEV) return bundle;
133
+ console.info(BUILD_PREFIX, colors.cyan("watching for file changes..."));
134
+ const watchPaths = [
135
+ path.dirname(config.entry),
136
+ config.external,
137
+ config.over
138
+ ].filter(Boolean);
139
+ const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });
140
+ let timer = null;
141
+ watcher.on("all", (event, p) => {
142
+ console.info(colors.cyan(`${event}: ${p}`));
143
+ if (timer) clearTimeout(timer);
144
+ timer = setTimeout(() => {
145
+ buildOnce(options).then((res$1) => {
146
+ bundle = res$1.bundle;
147
+ startTime = res$1.startTime;
148
+ }).catch((e) => console.error(e));
149
+ }, 100);
150
+ });
151
+ process.on("SIGINT", () => {
152
+ console.info("\nStopping watch mode...");
153
+ watcher.close().then(() => process.exit(0)).catch((e) => {
154
+ console.error(e);
155
+ process.exit(1);
156
+ });
157
+ });
158
+ return watcher;
159
+ } catch (error) {
160
+ if (startTime) {
161
+ console.error(RED_X, BUILD_PREFIX, `Build failed in ${displayTime(Date.now() - startTime)}`);
162
+ startTime = void 0;
163
+ }
164
+ throw error;
165
+ }
166
+ }
167
+
168
+ //#endregion
169
+ export { version as a, DEFAULT_CONFIG_EXTENSIONS as i, BuildModes as n, buildExtension as r, BuildMode as t };
170
+ //# sourceMappingURL=build-DotYlefN.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"build-DotYlefN.mjs","names":["path","VERSION","res"],"sources":["../package.json","../src/node/constants.ts","../src/node/utils.ts","../src/node/build.ts"],"sourcesContent":["","import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport colors from 'picocolors'\n\nexport { version as VERSION } from '../../package.json';\n\nexport const DEFAULT_CONFIG_EXTENSIONS: string[] = [\n '.mjs',\n '.js',\n '.mts',\n '.ts',\n]\n\nexport const GLOBAL_NAME = \"SAMMIExtensions\";\n\nexport const BUILD_PREFIX = colors.blue(\"[sammi-next]\");\nexport const GREEN_CHECK = colors.green('✔');\nexport const RED_X = colors.red('✗');\n\nfunction findPackageDir() {\n let initPath = fileURLToPath(import.meta.url);\n while (!initPath.endsWith('sammi-next')) {\n initPath = path.resolve(initPath, '..');\n }\n return path.resolve(initPath, '..');\n}\nexport const SAMMI_NEXT_PACKAGE_DIR = findPackageDir();\n","export function displayTime(time: number): string {\n if (time < 1_000)\n return `${time}ms`;\n\n time = time / 1_000;\n\n if (time < 60)\n return `${time.toFixed(2)}s`\n\n const mins = Math.floor(time / 60);\n const seconds = Math.round(time % 60);\n\n if (seconds === 60)\n return `${mins + 1}m`\n\n return `${mins}m${seconds < 1 ? '' : ` ${seconds}s`}`;\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport colors from 'picocolors';\nimport chokidar from 'chokidar';\nimport { ResolvedExtensionConfig } from \"@shared/config-types\";\nimport { build, TsdownBundle } from \"tsdown\";\nimport { BUILD_PREFIX, GLOBAL_NAME, GREEN_CHECK, RED_X, SAMMI_NEXT_PACKAGE_DIR, VERSION } from \"./constants\";\nimport { displayTime } from './utils';\n\nexport enum BuildMode {\n DEV,\n PRODUCTION,\n}\n\nexport const BuildModes = Object.keys(BuildMode).filter(key => isNaN(Number(key)));\n\nexport interface BuildOptions {\n config: ResolvedExtensionConfig;\n rootDir: string;\n mode?: BuildMode;\n}\n\nexport type ResolvedBuildOptions = Required<BuildOptions>;\n\nfunction readOptionalFile(path: string): string | undefined {\n if (!fs.existsSync(path)) return;\n\n return fs.readFileSync(path, 'utf-8');\n}\n\nconst CommandRE = /\\w+\\(\\w+,\\s*{\\s*default:/gm;\n\nfunction generateSEF(options: ResolvedBuildOptions): string {\n const { config, rootDir, mode } = options;\n const content = [];\n\n const required_files: {\n header: string,\n content: string,\n }[] = [\n {\n header: \"extension_name\",\n content: config.name,\n },\n {\n header: \"extension_info\",\n content: config.info,\n },\n {\n header: \"extension_version\",\n content: config.version,\n },\n ]\n\n for (const field of required_files) {\n content.push(`[${field.header}]`, field.content, \"\");\n }\n\n const external = readOptionalFile(config.external);\n content.push(\"[insert_external]\", external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\", \"\");\n\n const js_script = fs.readFileSync(path.join(rootDir, config.out.dir, config.out.js), \"utf-8\");\n content.push(\"[insert_command]\", CommandRE.test(js_script) ? `${GLOBAL_NAME}.${config.id}.default()` : \"\", \"\");\n content.push(\"[insert_hook]\", \"\", \"\") // TODO: maybe add hook retro-compatibility\n content.push(\"[insert_script]\", js_script, \"\");\n\n let over = readOptionalFile(config.over);\n if (over && mode === BuildMode.PRODUCTION) {\n over = JSON.stringify(JSON.parse(over));\n }\n content.push(\"[insert_over]\", over && over != \"{}\" ? over : \"\", \"\");\n return content.join(\"\\n\");\n}\n\nfunction generatePreview(options: ResolvedBuildOptions): string {\n const { config } = options;\n\n const external = readOptionalFile(config.external);\n const script = fs.readFileSync(config.entry, \"utf-8\");\n return fs\n .readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, \".sammi\", \"preview.blueprint.html\"), \"utf-8\")\n .replace(/{{EXTERNAL}}/g, external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\")\n .replace(/{{SCRIPT}}/g, script);\n}\n\nasync function buildOnce(options: ResolvedBuildOptions) {\n const { config, rootDir, mode } = options;\n\n const startTime = Date.now();\n const bundle = await build({\n entry: [config.entry],\n outDir: path.join(rootDir, config.out.dir),\n platform: 'browser',\n format: 'iife',\n target: ['es2022'],\n sourcemap: false,\n minify: mode === BuildMode.PRODUCTION,\n banner: {\n js: `/* ${config.name} v${config.version} - Built with SAMMI Next v${VERSION} */`,\n },\n noExternal: ['**'],\n outputOptions: {\n entryFileNames: config.out.js,\n extend: true,\n name: `${GLOBAL_NAME}.${config.id}`,\n exports: 'named',\n },\n });\n const tsdownTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);\n\n fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), 'utf-8');\n const sefTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.sef} in ${displayTime(sefTime - tsdownTime)}`);\n\n fs.writeFileSync(path.join(rootDir, config.out.dir, \"preview.html\"), generatePreview(options), 'utf-8');\n const previewTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built preview.html in ${displayTime(previewTime - sefTime)}`);\n return { bundle, startTime };\n}\n\nexport async function buildExtension(options: ResolvedBuildOptions) {\n const { config, mode } = options;\n\n console.info(\n colors.cyan(\n `SAMMI Next v${VERSION} ${colors.green(\n `building \"${config.name}\" extension in ${BuildMode[mode].toLowerCase()} mode...`\n )}`\n ),\n );\n\n let bundle: TsdownBundle[] | undefined;\n let startTime: number | undefined;\n\n try {\n const res = await buildOnce(options);\n bundle = res.bundle;\n startTime = res.startTime;\n\n if (options.mode !== BuildMode.DEV) return bundle;\n\n console.info(BUILD_PREFIX, colors.cyan(\"watching for file changes...\"));\n\n const watchPaths = [\n path.dirname(config.entry),\n config.external,\n config.over,\n ].filter(Boolean);\n\n const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });\n let timer: NodeJS.Timeout | null = null;\n\n watcher.on('all', (event, p) => {\n console.info(colors.cyan(`${event}: ${p}`));\n if (timer)\n clearTimeout(timer);\n\n timer = setTimeout(() => {\n buildOnce(options).then(res => {\n bundle = res.bundle;\n startTime = res.startTime;\n }).catch(e => console.error(e));\n }, 100);\n });\n\n process.on('SIGINT', () => {\n console.info(\"\\nStopping watch mode...\");\n watcher\n .close()\n .then(() => process.exit(0))\n .catch(e => {\n console.error(e);\n process.exit(1);\n });\n });\n return watcher;\n } catch (error) {\n if (startTime) {\n console.error(RED_X, BUILD_PREFIX, `Build failed in ${displayTime(Date.now() - startTime)}`);\n startTime = undefined;\n }\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,349 @@
1
+ import EventEmitter from "node:events";
2
+
3
+ //#region ../sammi-websocket-types/dist/Socket.d.ts
4
+ declare class Socket extends EventEmitter<any> {
5
+ constructor();
6
+ _connected: boolean;
7
+ _socket: any;
8
+ connect(args: any): Promise<any>;
9
+ /**
10
+ * Opens a WebSocket connection to an sammi-websocket server, but does not attempt any authentication.
11
+ *
12
+ * @param {String} address url without ws:// or wss:// prefix.
13
+ * @param {Boolean} secure whether to us ws:// or wss://
14
+ * @returns {Promise}
15
+ * @private
16
+ * @return {Promise} on attempted creation of WebSocket connection.
17
+ */
18
+ private _connect;
19
+ /**
20
+ * Authenticates to an sammi-websocket server. Must already have an active connection before calling this method.
21
+ *
22
+ * @param {String} [name=''] name of the client.
23
+ * @param {String} [password=''] authentication string.
24
+ * @private
25
+ * @return {Promise} on resolution of authentication call.
26
+ */
27
+ private _authenticate;
28
+ /**
29
+ * Close and disconnect the WebSocket connection.
30
+ *
31
+ * @function
32
+ * @category request
33
+ */
34
+ disconnect(): void;
35
+ }
36
+ //#endregion
37
+ //#region ../sammi-websocket-types/dist/SAMMIWebSocket.d.ts
38
+ declare class SAMMIWebSocket extends Socket {
39
+ /**
40
+ * Generic Socket request method. Returns a promise.
41
+ * Generates a messageId internally and will override any passed in the args.
42
+ * Note that the requestType here is pre-marshaling and currently must match exactly what the websocket plugin is expecting.
43
+ *
44
+ * @param {String} requestType sammi-websocket plugin expected request type.
45
+ * @param {Object} [arg={}] request arguments.
46
+ * @return {Promise} Promise, passes the plugin response object.
47
+ */
48
+ send(requestType: string, args?: {}): Promise<any>;
49
+ }
50
+ //#endregion
51
+ //#region ../sammi-bridge-types/src/SAMMICommands.d.ts
52
+ /** SAMMI Core Helper Functions
53
+ * You can call them with SAMMI.{helperfunction}
54
+ * Use promises if you want to get a reply back from SAMMI
55
+ * No promise example: SAMMI.setVariable(myVariable, 'some value', 'someButtonID')
56
+ * Promise example: SAMMI.getVariable(myVariable, 'someButtonID').then(reply=>console.log(reply))
57
+ */
58
+ declare class SAMMICommands$1 {
59
+ /**
60
+ * Get a variable from SAMMI
61
+ * @param {string} name - name of the variable
62
+ * @param {string} buttonId - button ID for local variable, default = global variable
63
+ */
64
+ getVariable(name?: string, buttonId?: string): Promise<any>;
65
+ /**
66
+ * Set a variable in SAMMI
67
+ * @param {string} name - name of the variable
68
+ * @param {(string|number|object|array|null)} value - new value of the variable
69
+ * @param {string} buttonId - button ID for local variable, default = global variable
70
+ */
71
+ setVariable(name?: string, value?: (string | number | object | any[] | null), buttonId?: string, instanceId?: number): Promise<any>;
72
+ /**
73
+ * Send a popup message to SAMMI
74
+ * @param {string} msg - message to send
75
+ */
76
+ popUp(msg?: string): Promise<any>;
77
+ /**
78
+ * Send a yellow notification message to SAMMI
79
+ * @param {string} msg - message to send
80
+ */
81
+ alert(msg?: string): Promise<any>;
82
+ /**
83
+ * send extension command to SAMMI
84
+ * @param {string} name - name of the extension command
85
+ * @param {string} color - box color, accepts hex/dec colors (include # for hex), default 3355443
86
+ * @param {string} height - height of the box in pixels, 52 for regular or 80 for resizable box, default 52
87
+ * @param {Object} boxes
88
+ * - one object per box, key = boxVariable, value = array of box params
89
+ * - boxVariable = variable to save the box value under
90
+ * - boxName = name of the box shown in the user interface
91
+ * - boxType = type of the box, 0 = resizable, 2 = checkbox (true/false), 14 = regular box, 15 = variable box, 18 = select box, see extension guide for more
92
+ * - defaultValue = default value of the variable
93
+ * - (optional) sizeModifier = horizontal box size, 1 is normal
94
+ * - (optional) [] selectOptions = array of options for the user to select (when using Select box type)
95
+ * @param {[boxName: string, boxType: number, defaultValue: (string | number), sizeModifier: (number|undefined), selectOptions: Array|undefined]} boxes.boxVariable
96
+ * */
97
+ extCommand(name?: string, color?: string, height?: string, boxes?: {
98
+ boxVariable: [boxName: string, boxType: number, defaultValue: (string | number), sizeModifier: (number | undefined), selectOptions: any[] | undefined];
99
+ }, triggerButton?: boolean, hidden?: boolean): Promise<any>;
100
+ /**
101
+ * Close SAMMI Bridge connection to SAMMI Core.
102
+ */
103
+ close(): Promise<any>;
104
+ /**
105
+ * Get deck and button updates
106
+ * @param {boolean} enabled - enable or disable updates
107
+ */
108
+ stayInformed(enabled: boolean): Promise<any>;
109
+ /**
110
+ * Request an array of all decks
111
+ * - Replies with an array ["Deck1 Name","Unique ID",crc32,"Deck2 Name","Unique ID",crc32,...]
112
+ * - Use crc32 value to verify deck you saved localy is the same
113
+ */
114
+ getDeckList(): Promise<any>;
115
+ /**
116
+ * Request a deck params
117
+ * @param {string} id - Unique deck ID retrieved from getDeckList
118
+ * - Replies with an object containing a full deck
119
+ */
120
+ getDeck(id?: string): Promise<any>;
121
+ /**
122
+ * Get deck status
123
+ * - Replies with either 0 (deck is disabled) or 1 (deck is enabled)
124
+ * @param {string} id - Unique deck ID retrieved from getDeckList
125
+ */
126
+ getDeckStatus(deckID?: number): Promise<any>;
127
+ /**
128
+ * Change deck status
129
+ * @param {string} id - Unique deck ID retrieved from getDeckList
130
+ * @param {int} status - New deck status, 0 = disable, 1 = enable, 2 = toggle
131
+ */
132
+ changeDeckStatus(deckID?: number, status?: int): Promise<any>;
133
+ /**
134
+ * Retrieve an image in base64
135
+ * @param {string} fileName - image file name without the path (image.png)
136
+ * - Replies with an object containing the Base64 string of the image
137
+ */
138
+ getImage(fileName?: string): Promise<any>;
139
+ /**
140
+ * Retrieves CRC32 of a file
141
+ * @param {string} fileName - file name without the path (image.png)
142
+ */
143
+ getSum(fileName?: string): Promise<any>;
144
+ /**
145
+ * Retrieves all currently active buttons
146
+ * - Replies with an array of button param objects
147
+ */
148
+ getActiveButtons(): Promise<any>;
149
+ /**
150
+ * Retrieves params of all linked Twitch accounts
151
+ */
152
+ getTwitchList(): Promise<any>;
153
+ /**
154
+ * Sends a trigger
155
+ * @param {number} type - type of trigger
156
+ * - trigger types: 0 Twitch chat, 1 Twitch Sub, 2 Twitch Gift, 3 Twitch redeem
157
+ * 4 Twitch Raid, 5 Twitch Bits, 6 Twitch Follower, 7 Hotkey
158
+ * 8 Timer, 9 OBS Trigger, 10 SAMMI Bridge, 11 twitch moderation, 12 extension trigger
159
+ * @param {object} data - whatever data is required for the trigger, see manual
160
+ */
161
+ trigger(type?: number, data?: object): Promise<any>;
162
+ /**
163
+ * Sends a test trigger that will automatically include channel ID for from_channel_id pull value
164
+ * @param {number} type - type of trigger
165
+ * - trigger types: 0 Twitch chat, 1 Twitch Sub, 2 Twitch Gift, 3 Twitch redeem
166
+ * 4 Twitch Raid, 5 Twitch Bits, 6 Twitch Follower, 7 Hotkey
167
+ * 8 Timer, 9 OBS Trigger, 10 SAMMI Bridge, 11 twitch moderation, 12 extension trigger
168
+ * @param {object} data - whatever data is required for the trigger, see manual
169
+ */
170
+ testTrigger(type: number, data: object): Promise<any>;
171
+ /**
172
+ * Triggers a button
173
+ * @param {string} id - button ID to trigger
174
+ */
175
+ triggerButton(id?: string): Promise<any>;
176
+ /**
177
+ * Releases a button
178
+ * @param {string} id - button ID to release
179
+ */
180
+ releaseButton(id?: string): Promise<any>;
181
+ /**
182
+ * Modifies a button
183
+ * @param {string} id - button ID to modify
184
+ * @param {number|undefined} color - decimal button color (BGR)
185
+ * @param {string|undefined} text - button text
186
+ * @param {string|undefined} image - button image file name
187
+ * @param {number|undefined} border - border size, 0-7
188
+ * - leave parameters empty to reset button back to default values
189
+ */
190
+ modifyButton(id: string, color: number | undefined, text: string | undefined, image: string | undefined, border: number | undefined): Promise<any>;
191
+ /**
192
+ * Opens edit command screen in SAMMI for the selected button
193
+ * @param {string} deckId - deckId ID to edit
194
+ * @param {string} buttonId - button ID to edit
195
+ */
196
+ editButton(deckId?: string, buttonId?: string): Promise<any>;
197
+ /**
198
+ * Retrieves all currently modified buttons
199
+ * - object of button objects that are currently modified
200
+ */
201
+ getModifiedButtons(): Promise<any>;
202
+ /**
203
+ * Sends an extension trigger
204
+ * @param {string} trigger - name of the trigger
205
+ * @param {object} dats - object containing all trigger pull data
206
+ */
207
+ triggerExt(trigger?: string, data?: {}): Promise<any>;
208
+ /**
209
+ * Deletes a variable
210
+ * @param {string} name - name of the variable
211
+ * @param {string} buttonId - button ID for local variable, default = global variable
212
+ */
213
+ deleteVariable(name?: string, buttonId?: string): Promise<any>;
214
+ /**
215
+ * Inserts an array value
216
+ * @param {string} arrayName - name of the array
217
+ * @param {number} index - index to insert the new item at
218
+ * @param {string|number|object|array} value - item value
219
+ * @param {string} buttonId - button id, default is global
220
+ */
221
+ insertArray(arrayName?: string, index?: number, value?: string | number | object | any[], buttonId?: string): Promise<any>;
222
+ /**
223
+ * Deletes an array value at specified index
224
+ * @param {string} arrayName - name of the array
225
+ * @param {number} index - index of the item to delete
226
+ * @param {string} buttonId - button id, default is global
227
+ */
228
+ deleteArray(arrayName?: string, slot?: number, buttonId?: string): Promise<any>;
229
+ /**
230
+ * Saves a number/string into an ini file
231
+ * @param {string} fileName - name of the ini file
232
+ * @param {number} section - section name
233
+ * @param {string} key - key name
234
+ * @param {string|number} value - value to save
235
+ * @param {string} type - type of the value, text or number
236
+ */
237
+ saveIni(fileName?: string, section?: number, key?: string, value?: string | number, type?: string): Promise<any>;
238
+ /**
239
+ * Loads a number/string from an ini file
240
+ * @param {string} fileName - name of the ini file
241
+ * @param {number} section - section name
242
+ * @param {string} key - key name
243
+ * @param {string} type - type of the value, text or number
244
+ */
245
+ loadIni(fileName?: string, section?: number, key?: string, type?: string): Promise<any>;
246
+ /**
247
+ * Sends an HTTP request
248
+ * @param {string} url - url to send the request to
249
+ * @param {string} method - request method, GET, POST, PUT, DELETE
250
+ * @param {json} headers - stringified JSON object of headers (optional)
251
+ * @param {json} body - stringified request body (optional)
252
+ */
253
+ httpRequest(url?: string, method?: string, headers?: json, body?: json): Promise<any>;
254
+ /**
255
+ * Sends a notification (tray icon bubble) message to SAMMI
256
+ * @param {string} msg - message to show
257
+ */
258
+ notification(msg?: string): Promise<any>;
259
+ /**
260
+ * Opens a URL in the default browser from SAMMI
261
+ * @param {string} url - url to open
262
+ */
263
+ openURL(url?: string): Promise<any>;
264
+ generateMessage(): string;
265
+ }
266
+ //#endregion
267
+ //#region ../sammi-bridge-types/src/index.d.ts
268
+ declare class SAMMICommands extends SAMMICommands$1 {
269
+ /**
270
+ * send extension command to SAMMI
271
+ * @param name - name of the extension command
272
+ * @param color - box color, accepts hex/dec colors (include # for hex), default 3355443
273
+ * @param height - height of the box in pixels, 52 for regular or 80 for resizable box, default 52
274
+ * @param boxes
275
+ * - one object per box, key = boxVariable, value = array of box params
276
+ * - boxVariable = variable to save the box value under
277
+ * - boxName = name of the box shown in the user interface
278
+ * - boxType = type of the box, 0 = resizable, 2 = checkbox (true/false), 14 = regular box, 15 = variable box, 18 = select box, see extension guide for more
279
+ * - defaultValue = default value of the variable
280
+ * - (optional) sizeModifier = horizontal box size, 1 is normal
281
+ * - (optional) [] selectOptions = array of options for the user to select (when using Select box type)
282
+ * @param boxes.boxVariable
283
+ * */
284
+ extCommand(name?: string, color?: string | number, height?: string | number, boxes?: {
285
+ [boxVariable: string]: [boxName: string, boxType: number, defaultValue: (string | number), sizeModifier: (number | undefined), selectOptions: any[] | undefined];
286
+ }, triggerButton?: boolean, hidden?: boolean): Promise<any>;
287
+ }
288
+ declare global {
289
+ /**
290
+ * Bridge provides native helper functions to make your life easier, without the need to use SAMMI Websocket library directly.
291
+ *
292
+ * You can call all helper functions with SAMMI.method(arguments).
293
+ *
294
+ * To use promises, you can call them with SAMMI.method(arguments).then(response=>console.log(response)).
295
+ */
296
+ const SAMMI: SAMMICommands;
297
+ /**
298
+ * When a user triggers an extension command, SAMMI will send the data to Bridge (unless the `sendAsExtensionTrigger` parameter is set to `true`).
299
+ *
300
+ * You can listen to this data by using `sammiclient.on('extension name', (payload) => {})`.
301
+ *
302
+ * You can also use `sammiclient.addListener('extension name', functionToExecute)`.
303
+ *
304
+ * For example, let's say your extension command is called Lucky Wheel:
305
+ * @example
306
+ * sammiclient.on('Lucky Wheel', (payload) => {
307
+ * console.log(payload)
308
+ * // DO SOMETHING WITH THE EXTENSION PAYLOAD
309
+ * // FromButton - button ID the extension command was triggered in
310
+ * // instanceId - instance ID of a button the extension command was triggered in
311
+ * const { FromButton, instanceId } = payload.Data
312
+ * });
313
+ */
314
+ const sammiclient: SAMMIWebSocket;
315
+ }
316
+ //#endregion
317
+ //#region src/runtime/types.d.ts
318
+ /**
319
+ * Represents useful data from the sammi.config.json. Friendly to export.
320
+ */
321
+ interface ExtensionConfig {
322
+ /** This section names your extension, and is visible in SAMMI Bridge and SAMMI Core. Please use alphanumeric characters and spaces only. */
323
+ name: string;
324
+ /** Specify a unique id for your extension here. Please use alphanumeric characters, dashes, and underscores only. */
325
+ id: string;
326
+ /** This section is for descriptive text about the extension, e.g. what the extension does. This information is displayed to the users in SAMMI Bridge-Extensions tab when they hover over the extension name inside the list of installed extensions. */
327
+ info?: string;
328
+ /** Specify your extension version here, using numbers and dots (e.g., 2.01). This is crucial for the automatic version checker in Bridge, which can notify users of updates. */
329
+ version: string;
330
+ }
331
+ /**
332
+ * Interface that represents most of the structures built with SAMMI Next.
333
+ */
334
+ interface SAMMINextExtension {
335
+ readonly default?: () => void;
336
+ readonly _config?: ExtensionConfig;
337
+ readonly [key: string]: unknown;
338
+ }
339
+ //#endregion
340
+ //#region src/runtime/global.d.ts
341
+ declare global {
342
+ /**
343
+ * Global namespace where SAMMI Next stores all the extensions.
344
+ */
345
+ var SAMMIExtensions: Record<string, SAMMINextExtension | undefined>;
346
+ }
347
+ //#endregion
348
+ export { SAMMINextExtension as n, ExtensionConfig as t };
349
+ //# sourceMappingURL=global-BaL6-Y6j.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-BaL6-Y6j.d.mts","names":["Socket","default","Promise","EventEmitter","constructor","_connected","_socket","connect","args","_connect","_authenticate","disconnect","SAMMIWebSocket","default","Promise","Socket","send","requestType","args","SAMMICommands","Promise","int","json","getVariable","name","buttonId","setVariable","value","instanceId","popUp","msg","alert","extCommand","color","height","boxVariable","boxName","boxType","defaultValue","sizeModifier","selectOptions","boxes","triggerButton","hidden","close","stayInformed","enabled","getDeckList","getDeck","id","getDeckStatus","deckID","changeDeckStatus","status","getImage","fileName","getSum","getActiveButtons","getTwitchList","trigger","type","data","testTrigger","releaseButton","modifyButton","text","image","border","editButton","deckId","getModifiedButtons","triggerExt","deleteVariable","insertArray","arrayName","index","deleteArray","slot","saveIni","section","key","loadIni","httpRequest","url","method","headers","body","notification","openURL","generateMessage","SAMMIWebSocket","SAMMICommands","Commands","Promise","extCommand","name","color","height","boxVariable","boxName","boxType","defaultValue","sizeModifier","selectOptions","boxes","triggerButton","hidden","_0","global","SAMMI","sammiclient","sideEffect","SAMMINextExtension","_0","Record","global","SAMMIExtensions","sideEffect"],"sources":["../../sammi-websocket-types/dist/Socket.d.ts","../../sammi-websocket-types/dist/SAMMIWebSocket.d.ts","../../sammi-bridge-types/src/SAMMICommands.d.ts","../../sammi-bridge-types/src/index.d.ts","../src/runtime/types.ts","../src/runtime/global.d.ts"],"mappings":"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"}
@@ -1,137 +1,3 @@
1
- import { version } from "../package.mjs";
2
- import { BUILD_PREFIX, GLOBAL_NAME, GREEN_CHECK, RED_X, SAMMI_NEXT_PACKAGE_DIR } from "./constants.mjs";
3
- import { displayTime } from "./utils.mjs";
4
- import fs from "node:fs";
5
- import path from "node:path";
6
- import colors from "picocolors";
7
- import chokidar from "chokidar";
8
- import { build } from "tsdown";
1
+ import { n as BuildModes, r as buildExtension, t as BuildMode } from "../build-DotYlefN.mjs";
9
2
 
10
- //#region src/node/build.ts
11
- let BuildMode = /* @__PURE__ */ function(BuildMode) {
12
- BuildMode[BuildMode["DEV"] = 0] = "DEV";
13
- BuildMode[BuildMode["PRODUCTION"] = 1] = "PRODUCTION";
14
- return BuildMode;
15
- }({});
16
- const BuildModes = Object.keys(BuildMode).filter((key) => isNaN(Number(key)));
17
- function readOptionalFile(path$1) {
18
- if (!fs.existsSync(path$1)) return;
19
- return fs.readFileSync(path$1, "utf-8");
20
- }
21
- const CommandRE = /\w+\(\w+,\s*{\s*default:/gm;
22
- function generateSEF(options) {
23
- const { config, mode } = options;
24
- const content = [];
25
- const required_files = [
26
- {
27
- header: "extension_name",
28
- content: config.name
29
- },
30
- {
31
- header: "extension_info",
32
- content: config.info
33
- },
34
- {
35
- header: "extension_version",
36
- content: config.version
37
- }
38
- ];
39
- for (const field of required_files) content.push(`[${field.header}]`, field.content, "");
40
- const external = readOptionalFile(config.external);
41
- content.push("[insert_external]", external ? `<div id="${config.id}-external">${external}</div>` : "", "");
42
- const script = fs.readFileSync(config.entry, "utf-8");
43
- content.push("[insert_command]", CommandRE.test(script) ? `${GLOBAL_NAME}.${config.id}.default()` : "", "");
44
- content.push("[insert_hook]", "", "");
45
- content.push("[insert_script]", script, "");
46
- let over = readOptionalFile(config.over);
47
- if (over && mode === BuildMode.PRODUCTION) over = JSON.stringify(JSON.parse(over));
48
- content.push("[insert_over]", over && over != "{}" ? over : "", "");
49
- return content.join("\n");
50
- }
51
- function generatePreview(options) {
52
- const { config } = options;
53
- const external = readOptionalFile(config.external);
54
- const script = fs.readFileSync(config.entry, "utf-8");
55
- return fs.readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, ".sammi", "preview.blueprint.html"), "utf-8").replace(/{{EXTERNAL}}/g, external ? `<div id="${config.id}-external">${external}</div>` : "").replace(/{{SCRIPT}}/g, script);
56
- }
57
- async function buildOnce(options) {
58
- const { config, rootDir, mode } = options;
59
- const startTime = Date.now();
60
- const bundle = await build({
61
- entry: [config.entry],
62
- outDir: path.join(rootDir, config.out.dir),
63
- platform: "browser",
64
- format: "iife",
65
- target: ["es2022"],
66
- sourcemap: false,
67
- minify: mode === BuildMode.PRODUCTION,
68
- banner: { js: `/* ${config.name} v${config.version} - Built with SAMMI Next v${version} */` },
69
- noExternal: ["**"],
70
- outputOptions: {
71
- entryFileNames: config.out.js,
72
- extend: true,
73
- name: `${GLOBAL_NAME}.${config.id}`,
74
- exports: "named"
75
- }
76
- });
77
- const tsdownTime = Date.now();
78
- console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);
79
- fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), "utf-8");
80
- const sefTime = Date.now();
81
- console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.sef} in ${displayTime(sefTime - tsdownTime)}`);
82
- fs.writeFileSync(path.join(rootDir, config.out.dir, "preview.html"), generatePreview(options), "utf-8");
83
- const previewTime = Date.now();
84
- console.info(GREEN_CHECK, BUILD_PREFIX, `built preview.html in ${displayTime(previewTime - sefTime)}`);
85
- return {
86
- bundle,
87
- startTime
88
- };
89
- }
90
- async function buildExtension(options) {
91
- const { config, mode } = options;
92
- console.info(colors.cyan(`SAMMI Next v${version} ${colors.green(`building "${config.name}" extension in ${BuildMode[mode].toLowerCase()} mode...`)}`));
93
- let bundle;
94
- let startTime;
95
- try {
96
- const res = await buildOnce(options);
97
- bundle = res.bundle;
98
- startTime = res.startTime;
99
- if (options.mode !== BuildMode.DEV) return bundle;
100
- console.info(BUILD_PREFIX, colors.cyan("watching for file changes..."));
101
- const watchPaths = [
102
- path.dirname(config.entry),
103
- config.external,
104
- config.over
105
- ].filter(Boolean);
106
- const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });
107
- let timer = null;
108
- watcher.on("all", (event, p) => {
109
- console.info(colors.cyan(`${event}: ${p}`));
110
- if (timer) clearTimeout(timer);
111
- timer = setTimeout(() => {
112
- buildOnce(options).then((res$1) => {
113
- bundle = res$1.bundle;
114
- startTime = res$1.startTime;
115
- }).catch((e) => console.error(e));
116
- }, 100);
117
- });
118
- process.on("SIGINT", () => {
119
- console.info("\nStopping watch mode...");
120
- watcher.close().then(() => process.exit(0)).catch((e) => {
121
- console.error(e);
122
- process.exit(1);
123
- });
124
- });
125
- return watcher;
126
- } catch (error) {
127
- if (startTime) {
128
- console.error(RED_X, BUILD_PREFIX, `Build failed in ${displayTime(Date.now() - startTime)}`);
129
- startTime = void 0;
130
- }
131
- throw error;
132
- }
133
- }
134
-
135
- //#endregion
136
- export { BuildMode, BuildModes, buildExtension };
137
- //# sourceMappingURL=build.mjs.map
3
+ export { BuildMode, BuildModes, buildExtension };
package/dist/node/cli.mjs CHANGED
@@ -1,6 +1,4 @@
1
- import { version } from "../package.mjs";
2
- import "./constants.mjs";
3
- import { BuildMode, buildExtension } from "./build.mjs";
1
+ import { a as version, r as buildExtension, t as BuildMode } from "../build-DotYlefN.mjs";
4
2
  import { resolveBuildConfig } from "./config.mjs";
5
3
  import cac from "cac";
6
4
  import colors from "picocolors";
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["VERSION"],"sources":["../../src/node/cli.ts"],"sourcesContent":["import cac from \"cac\";\nimport { buildExtension, BuildMode } from \"./build\";\nimport colors from 'picocolors';\nimport { resolveBuildConfig } from \"./config\";\nimport { VERSION } from \"./constants\";\n\nconst cli = cac('sammi-next');\n\nexport interface GlobalCLIOptions {\n m?: string\n mode?: string\n}\n\nconst filterDuplicateOptions = <T extends object>(options: T) => {\n for (const [key, value] of Object.entries(options)) {\n if (!Array.isArray(value)) continue;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n options[key as keyof T] = value[value.length - 1];\n }\n};\n\nfunction cleanGlobalCLIOptions<Options extends GlobalCLIOptions>(options: Options): Omit<Options, keyof GlobalCLIOptions> {\n const ret = { ...options };\n delete ret.m\n delete ret.mode\n\n return ret;\n}\n\ncli.option('-m, --mode <mode>', '[string] set build mode');\n\nexport interface BuildCLIOptions {\n outDir?: string\n outJs?: string\n outSef?: string\n}\n\ncli\n .command('[root]', 'build extension')\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\n .action(\n async (\n root: string | undefined,\n options: GlobalCLIOptions,\n ) => {\n filterDuplicateOptions(options);\n\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\n\n try {\n const buildConfig = await resolveBuildConfig(\n root,\n options.mode || BuildMode[BuildMode.PRODUCTION],\n buildOptions,\n );\n\n await buildExtension(buildConfig);\n } catch (e) {\n const error = e as Error;\n console.error(colors.red(`error during build:\\n${error.stack}`));\n process.exit(1);\n }\n }\n )\n\ncli\n .command('dev [root]', 'build extension in dev mode')\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\n .action(\n async (\n root: string | undefined,\n options: GlobalCLIOptions,\n ) => {\n filterDuplicateOptions(options);\n\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\n\n try {\n const buildConfig = await resolveBuildConfig(\n root,\n options.mode || BuildMode[BuildMode.DEV],\n buildOptions,\n );\n\n await buildExtension(buildConfig);\n } catch (e) {\n const error = e as Error;\n console.error(colors.red(`error during build:\\n${error.stack}`));\n process.exit(1);\n }\n }\n )\n\ncli.help();\ncli.version(VERSION);\n\ncli.parse();\n"],"mappings":";;;;;;;;AAMA,MAAM,MAAM,IAAI,aAAa;AAO7B,MAAM,0BAA4C,YAAe;AAC7D,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAChD,MAAI,CAAC,MAAM,QAAQ,MAAM,CAAE;AAG3B,UAAQ,OAAkB,MAAM,MAAM,SAAS;;;AAIvD,SAAS,sBAAwD,SAAyD;CACtH,MAAM,MAAM,EAAE,GAAG,SAAS;AAC1B,QAAO,IAAI;AACX,QAAO,IAAI;AAEX,QAAO;;AAGX,IAAI,OAAO,qBAAqB,0BAA0B;AAQ1D,IACK,QAAQ,UAAU,kBAAkB,CACpC,OAAO,kBAAkB,gDAA8C,CACvE,OAAO,kBAAkB,+DAA+D,CACxF,OAAO,mBAAmB,iEAAiE,CAC3F,OACG,OACI,MACA,YACC;AACD,wBAAuB,QAAQ;CAE/B,MAAM,eAAgC,sBAAsB,QAAQ;AAEpE,KAAI;AAOA,QAAM,eANc,MAAM,mBACtB,MACA,QAAQ,QAAQ,UAAU,UAAU,aACpC,aACH,CAEgC;UAC5B,GAAG;EACR,MAAM,QAAQ;AACd,UAAQ,MAAM,OAAO,IAAI,wBAAwB,MAAM,QAAQ,CAAC;AAChE,UAAQ,KAAK,EAAE;;EAG1B;AAEL,IACK,QAAQ,cAAc,8BAA8B,CACpD,OAAO,kBAAkB,gDAA8C,CACvE,OAAO,kBAAkB,+DAA+D,CACxF,OAAO,mBAAmB,iEAAiE,CAC3F,OACG,OACI,MACA,YACC;AACD,wBAAuB,QAAQ;CAE/B,MAAM,eAAgC,sBAAsB,QAAQ;AAEpE,KAAI;AAOA,QAAM,eANc,MAAM,mBACtB,MACA,QAAQ,QAAQ,UAAU,UAAU,MACpC,aACH,CAEgC;UAC5B,GAAG;EACR,MAAM,QAAQ;AACd,UAAQ,MAAM,OAAO,IAAI,wBAAwB,MAAM,QAAQ,CAAC;AAChE,UAAQ,KAAK,EAAE;;EAG1B;AAEL,IAAI,MAAM;AACV,IAAI,QAAQA,QAAQ;AAEpB,IAAI,OAAO"}
1
+ {"version":3,"file":"cli.mjs","names":["VERSION"],"sources":["../../src/node/cli.ts"],"sourcesContent":["import cac from \"cac\";\nimport { buildExtension, BuildMode } from \"./build\";\nimport colors from 'picocolors';\nimport { resolveBuildConfig } from \"./config\";\nimport { VERSION } from \"./constants\";\n\nconst cli = cac('sammi-next');\n\nexport interface GlobalCLIOptions {\n m?: string\n mode?: string\n}\n\nconst filterDuplicateOptions = <T extends object>(options: T) => {\n for (const [key, value] of Object.entries(options)) {\n if (!Array.isArray(value)) continue;\n\n // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n options[key as keyof T] = value[value.length - 1];\n }\n};\n\nfunction cleanGlobalCLIOptions<Options extends GlobalCLIOptions>(options: Options): Omit<Options, keyof GlobalCLIOptions> {\n const ret = { ...options };\n delete ret.m\n delete ret.mode\n\n return ret;\n}\n\ncli.option('-m, --mode <mode>', '[string] set build mode');\n\nexport interface BuildCLIOptions {\n outDir?: string\n outJs?: string\n outSef?: string\n}\n\ncli\n .command('[root]', 'build extension')\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\n .action(\n async (\n root: string | undefined,\n options: GlobalCLIOptions,\n ) => {\n filterDuplicateOptions(options);\n\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\n\n try {\n const buildConfig = await resolveBuildConfig(\n root,\n options.mode || BuildMode[BuildMode.PRODUCTION],\n buildOptions,\n );\n\n await buildExtension(buildConfig);\n } catch (e) {\n const error = e as Error;\n console.error(colors.red(`error during build:\\n${error.stack}`));\n process.exit(1);\n }\n }\n )\n\ncli\n .command('dev [root]', 'build extension in dev mode')\n .option('--outDir <dir>', '[string] output directory (default: \"dist\")')\n .option('--outJs <name>', '[string] output file name for the JS (default: extension.js)')\n .option('--outSef <name>', '[string] output file name for the SEF (default: extension.sef)')\n .action(\n async (\n root: string | undefined,\n options: GlobalCLIOptions,\n ) => {\n filterDuplicateOptions(options);\n\n const buildOptions: BuildCLIOptions = cleanGlobalCLIOptions(options);\n\n try {\n const buildConfig = await resolveBuildConfig(\n root,\n options.mode || BuildMode[BuildMode.DEV],\n buildOptions,\n );\n\n await buildExtension(buildConfig);\n } catch (e) {\n const error = e as Error;\n console.error(colors.red(`error during build:\\n${error.stack}`));\n process.exit(1);\n }\n }\n )\n\ncli.help();\ncli.version(VERSION);\n\ncli.parse();\n"],"mappings":";;;;;;AAMA,MAAM,MAAM,IAAI,aAAa;AAO7B,MAAM,0BAA4C,YAAe;AAC7D,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AAChD,MAAI,CAAC,MAAM,QAAQ,MAAM,CAAE;AAG3B,UAAQ,OAAkB,MAAM,MAAM,SAAS;;;AAIvD,SAAS,sBAAwD,SAAyD;CACtH,MAAM,MAAM,EAAE,GAAG,SAAS;AAC1B,QAAO,IAAI;AACX,QAAO,IAAI;AAEX,QAAO;;AAGX,IAAI,OAAO,qBAAqB,0BAA0B;AAQ1D,IACK,QAAQ,UAAU,kBAAkB,CACpC,OAAO,kBAAkB,gDAA8C,CACvE,OAAO,kBAAkB,+DAA+D,CACxF,OAAO,mBAAmB,iEAAiE,CAC3F,OACG,OACI,MACA,YACC;AACD,wBAAuB,QAAQ;CAE/B,MAAM,eAAgC,sBAAsB,QAAQ;AAEpE,KAAI;AAOA,QAAM,eANc,MAAM,mBACtB,MACA,QAAQ,QAAQ,UAAU,UAAU,aACpC,aACH,CAEgC;UAC5B,GAAG;EACR,MAAM,QAAQ;AACd,UAAQ,MAAM,OAAO,IAAI,wBAAwB,MAAM,QAAQ,CAAC;AAChE,UAAQ,KAAK,EAAE;;EAG1B;AAEL,IACK,QAAQ,cAAc,8BAA8B,CACpD,OAAO,kBAAkB,gDAA8C,CACvE,OAAO,kBAAkB,+DAA+D,CACxF,OAAO,mBAAmB,iEAAiE,CAC3F,OACG,OACI,MACA,YACC;AACD,wBAAuB,QAAQ;CAE/B,MAAM,eAAgC,sBAAsB,QAAQ;AAEpE,KAAI;AAOA,QAAM,eANc,MAAM,mBACtB,MACA,QAAQ,QAAQ,UAAU,UAAU,MACpC,aACH,CAEgC;UAC5B,GAAG;EACR,MAAM,QAAQ;AACd,UAAQ,MAAM,OAAO,IAAI,wBAAwB,MAAM,QAAQ,CAAC;AAChE,UAAQ,KAAK,EAAE;;EAG1B;AAEL,IAAI,MAAM;AACV,IAAI,QAAQA,QAAQ;AAEpB,IAAI,OAAO"}
@@ -1,5 +1,4 @@
1
- import { DEFAULT_CONFIG_EXTENSIONS } from "./constants.mjs";
2
- import { BuildModes } from "./build.mjs";
1
+ import { i as DEFAULT_CONFIG_EXTENSIONS, n as BuildModes } from "../build-DotYlefN.mjs";
3
2
  import fs from "node:fs";
4
3
  import path from "node:path";
5
4
  import Ajv from "ajv";
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":[],"sources":["../../src/node/config.ts"],"sourcesContent":["\n\nimport { ExtensionConfig, ResolvedExtensionConfig } from \"@shared/config-types\";\nimport Ajv, { JSONSchemaType } from \"ajv\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { DEFAULT_CONFIG_EXTENSIONS } from \"./constants\";\nimport { BuildCLIOptions } from \"./cli\";\nimport { BuildModes, ResolvedBuildOptions } from \"./build\";\n\nconst ajv = new Ajv();\n\najv.addKeyword({\n keyword: \"fileExists\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n validate: (_schema: any, data: any) => {\n if (!data) return true;\n\n return fs.existsSync(data as string);\n },\n errors: false\n});\n\nconst schema: JSONSchemaType<ExtensionConfig> = {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[a-zA-Z0-9-_]+$\",\n },\n name: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[a-zA-Z0-9 -_]+$\",\n },\n info: {\n type: \"string\",\n default: \"\",\n nullable: true,\n },\n version: {\n type: \"string\",\n minLength: 1,\n pattern: \"^\\\\d+(?:\\\\.\\\\d+)*(?:-.*)?$\",\n },\n entry: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n },\n external: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n nullable: true,\n },\n over: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n nullable: true,\n },\n out: {\n type: \"object\",\n properties: {\n dir: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[^<>:\\\"|?*]+$\",\n default: \"dist\",\n nullable: true,\n },\n js: {\n type: \"string\",\n minLength: 4,\n pattern: \"^[\\\\w\\\\-. ]+\\\\.js$\",\n default: \"extension.js\",\n nullable: true,\n },\n sef: {\n type: \"string\",\n minLength: 5,\n pattern: \"^[\\\\w\\\\-. ]+\\\\.sef$\",\n default: \"extension.sef\",\n nullable: true,\n }\n },\n required: [],\n nullable: true,\n additionalProperties: false,\n }\n },\n required: [\"name\", \"id\", \"version\", \"entry\"],\n additionalProperties: false,\n};\n\nconst configValidator = ajv.compile(schema);\n\nexport async function loadConfig(rootDir: string) {\n for (const ext of DEFAULT_CONFIG_EXTENSIONS) {\n const configPath = path.join(rootDir, `sammi.config${ext}`);\n\n if (!fs.existsSync(configPath)) continue;\n\n try {\n const { createJiti } = await import('jiti');\n const jiti = createJiti(rootDir, {\n interopDefault: true,\n moduleCache: true,\n });\n\n const config = await jiti.import(configPath, { default: true });\n\n return validateExtensionConfig(config, configPath);\n } catch (error) {\n throw new Error(`Error loading ${configPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n const jsonPath = path.join(rootDir, 'sammi.config.json');\n if (fs.existsSync(jsonPath)) {\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const config = JSON.parse(raw) as unknown;\n return validateExtensionConfig(config, jsonPath);\n } catch (error) {\n throw new Error(`Error loading ${jsonPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n throw new Error('SAMMI Next extension config file not found in the root dir.');\n}\n\n\nfunction validateExtensionConfig(config: unknown, configPath: string): ExtensionConfig {\n if (!configValidator(config)) {\n const errors = configValidator.errors?.map(err => ` - ${err.instancePath} ${err.message}`).join('\\n');\n throw new Error(`Invalid config from ${configPath}:\\n${errors}`);\n }\n\n return config;\n}\n\nexport function resolveExtensionConfig(config: ExtensionConfig, rootDir: string): ResolvedExtensionConfig {\n const resolved: ResolvedExtensionConfig = {\n id: config.id,\n name: config.name,\n version: config.version,\n info: config.info || '',\n entry: path.resolve(rootDir, config.entry),\n external: config.external ? path.resolve(rootDir, config.external) : '',\n over: config.over ? path.resolve(rootDir, config.over) : '',\n out: {\n dir: config.out?.dir || 'dist',\n js: config.out?.js || 'extension.js',\n sef: config.out?.sef || 'extension.sef',\n },\n };\n\n if (!fs.existsSync(resolved.entry))\n throw new Error(`Entry file not found: ${resolved.entry}`);\n\n if (resolved.external && !fs.existsSync(resolved.external))\n throw new Error(`External file not found: ${resolved.external}`);\n\n if (resolved.over && !fs.existsSync(resolved.over))\n throw new Error(`Over file not found: ${resolved.over}`);\n\n return resolved;\n}\n\nexport async function resolveBuildConfig(\n root: string | undefined,\n command: string,\n build_cli: BuildCLIOptions,\n) {\n const mode = BuildModes.findIndex(m => {\n return m.toLowerCase() === command.toLowerCase();\n });\n if (mode < 0)\n throw new Error(`Invalid mode: ${command}. It must be one of: ${BuildModes.join(', ')}`);\n\n const rootDir = root ?? process.cwd();\n const config = await loadConfig(rootDir);\n\n config.out ??= {};\n\n config.out.dir = build_cli.outDir ?? config.out.dir;\n config.out.js = build_cli.outJs ?? config.out.js;\n config.out.sef = build_cli.outSef ?? config.out.sef;\n\n const resolvedConfig = resolveExtensionConfig(config, rootDir);\n\n const resolved: ResolvedBuildOptions = {\n rootDir,\n mode,\n config: resolvedConfig\n }\n return resolved;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../../src/node/config.ts"],"sourcesContent":["\n\nimport { ExtensionConfig, ResolvedExtensionConfig } from \"@shared/config-types\";\nimport Ajv, { JSONSchemaType } from \"ajv\";\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { DEFAULT_CONFIG_EXTENSIONS } from \"./constants\";\nimport { BuildCLIOptions } from \"./cli\";\nimport { BuildModes, ResolvedBuildOptions } from \"./build\";\n\nconst ajv = new Ajv();\n\najv.addKeyword({\n keyword: \"fileExists\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n validate: (_schema: any, data: any) => {\n if (!data) return true;\n\n return fs.existsSync(data as string);\n },\n errors: false\n});\n\nconst schema: JSONSchemaType<ExtensionConfig> = {\n type: \"object\",\n properties: {\n id: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[a-zA-Z0-9-_]+$\",\n },\n name: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[a-zA-Z0-9 -_]+$\",\n },\n info: {\n type: \"string\",\n default: \"\",\n nullable: true,\n },\n version: {\n type: \"string\",\n minLength: 1,\n pattern: \"^\\\\d+(?:\\\\.\\\\d+)*(?:-.*)?$\",\n },\n entry: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n },\n external: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n nullable: true,\n },\n over: {\n type: \"string\",\n minLength: 1,\n fileExists: true,\n nullable: true,\n },\n out: {\n type: \"object\",\n properties: {\n dir: {\n type: \"string\",\n minLength: 1,\n pattern: \"^[^<>:\\\"|?*]+$\",\n default: \"dist\",\n nullable: true,\n },\n js: {\n type: \"string\",\n minLength: 4,\n pattern: \"^[\\\\w\\\\-. ]+\\\\.js$\",\n default: \"extension.js\",\n nullable: true,\n },\n sef: {\n type: \"string\",\n minLength: 5,\n pattern: \"^[\\\\w\\\\-. ]+\\\\.sef$\",\n default: \"extension.sef\",\n nullable: true,\n }\n },\n required: [],\n nullable: true,\n additionalProperties: false,\n }\n },\n required: [\"name\", \"id\", \"version\", \"entry\"],\n additionalProperties: false,\n};\n\nconst configValidator = ajv.compile(schema);\n\nexport async function loadConfig(rootDir: string) {\n for (const ext of DEFAULT_CONFIG_EXTENSIONS) {\n const configPath = path.join(rootDir, `sammi.config${ext}`);\n\n if (!fs.existsSync(configPath)) continue;\n\n try {\n const { createJiti } = await import('jiti');\n const jiti = createJiti(rootDir, {\n interopDefault: true,\n moduleCache: true,\n });\n\n const config = await jiti.import(configPath, { default: true });\n\n return validateExtensionConfig(config, configPath);\n } catch (error) {\n throw new Error(`Error loading ${configPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n const jsonPath = path.join(rootDir, 'sammi.config.json');\n if (fs.existsSync(jsonPath)) {\n try {\n const raw = fs.readFileSync(jsonPath, 'utf-8');\n const config = JSON.parse(raw) as unknown;\n return validateExtensionConfig(config, jsonPath);\n } catch (error) {\n throw new Error(`Error loading ${jsonPath}: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n\n throw new Error('SAMMI Next extension config file not found in the root dir.');\n}\n\n\nfunction validateExtensionConfig(config: unknown, configPath: string): ExtensionConfig {\n if (!configValidator(config)) {\n const errors = configValidator.errors?.map(err => ` - ${err.instancePath} ${err.message}`).join('\\n');\n throw new Error(`Invalid config from ${configPath}:\\n${errors}`);\n }\n\n return config;\n}\n\nexport function resolveExtensionConfig(config: ExtensionConfig, rootDir: string): ResolvedExtensionConfig {\n const resolved: ResolvedExtensionConfig = {\n id: config.id,\n name: config.name,\n version: config.version,\n info: config.info || '',\n entry: path.resolve(rootDir, config.entry),\n external: config.external ? path.resolve(rootDir, config.external) : '',\n over: config.over ? path.resolve(rootDir, config.over) : '',\n out: {\n dir: config.out?.dir || 'dist',\n js: config.out?.js || 'extension.js',\n sef: config.out?.sef || 'extension.sef',\n },\n };\n\n if (!fs.existsSync(resolved.entry))\n throw new Error(`Entry file not found: ${resolved.entry}`);\n\n if (resolved.external && !fs.existsSync(resolved.external))\n throw new Error(`External file not found: ${resolved.external}`);\n\n if (resolved.over && !fs.existsSync(resolved.over))\n throw new Error(`Over file not found: ${resolved.over}`);\n\n return resolved;\n}\n\nexport async function resolveBuildConfig(\n root: string | undefined,\n command: string,\n build_cli: BuildCLIOptions,\n) {\n const mode = BuildModes.findIndex(m => {\n return m.toLowerCase() === command.toLowerCase();\n });\n if (mode < 0)\n throw new Error(`Invalid mode: ${command}. It must be one of: ${BuildModes.join(', ')}`);\n\n const rootDir = root ?? process.cwd();\n const config = await loadConfig(rootDir);\n\n config.out ??= {};\n\n config.out.dir = build_cli.outDir ?? config.out.dir;\n config.out.js = build_cli.outJs ?? config.out.js;\n config.out.sef = build_cli.outSef ?? config.out.sef;\n\n const resolvedConfig = resolveExtensionConfig(config, rootDir);\n\n const resolved: ResolvedBuildOptions = {\n rootDir,\n mode,\n config: resolvedConfig\n }\n return resolved;\n}\n"],"mappings":"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"}
@@ -1,7 +1,5 @@
1
- import { ExtensionConfig, SAMMINextExtension } from "./types.mjs";
2
- import "./global.mjs";
1
+ import { n as SAMMINextExtension, t as ExtensionConfig } from "../global-BaL6-Y6j.mjs";
3
2
  import { ExtensionConfig as ExtensionConfig$1 } from "../shared/config-types.mjs";
4
- import "sammi-bridge-types";
5
3
 
6
4
  //#region src/runtime/index.d.ts
7
5
  interface initExtensionOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/runtime/index.ts"],"mappings":";;;;;;UAOU,oBAAA;;;AALgC;;;;;EAatC,YAAA;AAAA;;;;;;;;;;;;;;AAgFJ;iBA7DgB,aAAA,CAEZ,MAAA,EAAQ,MAAA,eACR,OAAA,GAAS,oBAAA,GAGV,eAAA;;;;AAyDF;;;;;AA4DD;;;;;iBA9DgB,kBAAA,CAAmB,YAAA,WAAuB,cAAA;AAAA,UAIhD,2BAAA;EA+DL;;;;;;;EAvDD,kBAAA;;;;;;;EAOA,sBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2CY,oBAAA,CACZ,QAAA,cACA,OAAA,GAAS,2BAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/runtime/index.ts"],"mappings":";;;;UAOU,oBAAA;EAAA;;;;;AA2BV;;EAnBI,YAAA;AAAA;;;;;;;;;;;;AAgFJ;;;iBA7DgB,aAAA,CAEZ,MAAA,EAAQ,MAAA,eACR,OAAA,GAAS,oBAAA,GAGV,eAAA;;AAyDF;;;;;AA4DD;;;;;;;iBA9DgB,kBAAA,CAAmB,YAAA,WAAuB,cAAA;AAAA,UAIhD,2BAAA;;;;;;;;EAQN,kBAAA;;;;;;;EAOA,sBAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2CY,oBAAA,CACZ,QAAA,cACA,OAAA,GAAS,2BAAA"}
@@ -1,5 +1,4 @@
1
- import "./global.d.mts";
2
- import "sammi-bridge-types";
1
+ import "../global-BaL6-Y6j.d.mts";
3
2
 
4
3
  //#region src/runtime/index.ts
5
4
  const PROXY_PREFIX = "[SAMMI-NEXT-PROXY]";
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/runtime/index.ts"],"sourcesContent":["import \"sammi-bridge-types\";\nimport \"./global.d.ts\";\nimport { ExtensionConfig } from \"./types\";\n\n\nconst PROXY_PREFIX = \"[SAMMI-NEXT-PROXY]\";\n\ninterface initExtensionOptions {\n /**\n * Whether to skip the process of proxying your extension.\n *\n * Warning: this allows other scripts to modify your exports.\n *\n * @default false\n */\n skipProxying?: boolean\n}\nconst defaultInitExtensionOptions: initExtensionOptions = {\n skipProxying: false,\n}\n/**\n * Removes unnecessary data from a raw extension config object and parses it into an ExtensionConfig.\n *\n * Exports the config through the `SAMMIExtensions` namespace with the `_config` key.\n *\n * Generates a Proxy of the extension object to avoid other scripts trying to overwrite it.\n *\n * @example\n * const extension_config = SAMMIExtensions['extension-id']._config;\n *\n * @param config Unparsed config object.\n * @param options Whether to skip the process of proxying your extension (allowing other scripts to modify your exports).\n * @returns Parsed and cleaned config.\n */\nexport function initExtension(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n config: Record<string, any>,\n options: initExtensionOptions = {\n skipProxying: false,\n }\n): ExtensionConfig {\n let response: ExtensionConfig = {\n id: config.id as string,\n name: config.name as string,\n version: config.version as string,\n info: config.info as string | undefined,\n };\n\n window.SAMMIExtensions = window.SAMMIExtensions || {};\n SAMMIExtensions[response.id] = SAMMIExtensions[response.id] || {};\n if (SAMMIExtensions[response.id]?._config)\n throw new Error('The extension with the provided id was already initialized');\n\n const settings = Object.assign(defaultInitExtensionOptions, options);\n if (!settings.skipProxying)\n response = Object.freeze(response);\n\n // @ts-expect-error This is before proxying the extension, so no error.\n SAMMIExtensions[response.id]!._config ??= response;\n if (settings.skipProxying) return response;\n\n SAMMIExtensions[response.id] = new Proxy(SAMMIExtensions[response.id]!, {\n set(target, prop) {\n console.error(PROXY_PREFIX, \": Blocked setting value of:\", prop, \"on:\", target._config?.id);\n return true;\n },\n defineProperty(target, property) {\n console.error(PROXY_PREFIX, \": Blocked property redefinition of:\", property, \"on:\", target._config?.id);\n return true;\n },\n deleteProperty(target, p) {\n console.error(PROXY_PREFIX, \": Blocked deletion of:\", p, \"on:\", target._config?.id);\n return true;\n },\n setPrototypeOf(target) {\n console.error(PROXY_PREFIX, \": Blocked changing prototype of:\", target._config?.id);\n return true;\n },\n });\n return response;\n}\n\n/**\n * Retrieves an [insert_external] section by its extension id.\n *\n * ### Original documentation from https://sammi.solutions/extensions/build\n * This section appears inside the extension’s tab in Bridge, and it provides a visual interface for the extension if needed. It’s written in HTML and CSS.\n *\n * @example\n * const EXTERNAL = getExternalSection(config.id);\n * EXTERNAL.querySelector(\"button\")?.addEventListener('click', () => console.log('Hello world!'));\n *\n * @param extension_id The id of the SAMMI Next extension to retrieve its [insert_external] section.\n * @returns the div element that wraps your extension.\n */\nexport function getExternalSection(extension_id: string): HTMLDivElement {\n return document.getElementById(`${extension_id}-external`) as HTMLDivElement;\n}\n\ninterface insertCommandSectionOptions {\n /**\n * Whether to wait for `sammiclient` to exist.\n * This is enabled by default because every extension that uses `SAMMI` depends on `sammiclient`.\n * You can disable it if your [insert_command] section doesn't use neither `SAMMI` nor `sammiclient`.\n *\n * @default true\n */\n waitForSammiclient?: boolean;\n /**\n * Whether to wait for `SAMMIExtensions` to exist.\n * You must set this to `true` if you use the `SAMMIExtensions` namespace inside your [insert_command] section.\n *\n * @default false\n */\n waitForSAMMIExtensions?: boolean;\n}\nconst defaultInsertCommandSectionOptions: insertCommandSectionOptions = {\n waitForSammiclient: true,\n waitForSAMMIExtensions: false,\n}\n/**\n * Generates your [insert_command] section.\n * This should be used in the default export of your extension.\n *\n * By default, it wraps your callback to wait for `sammiclient` and `SAMMI` are initialized.\n * Its behavior can be changed in the options param.\n *\n * ### Original documentation from https://sammi.solutions/extensions/build\n * In this section, you can define Extension Commands.\n * These commands will be available to users in SAMMI Core when they install your extension.\n * You can define multiple commands in this section.\n * Refer to the SAMMI Bridge documentation for Extension Command details.\n * In this section, you can also automatically call your main extension function that should run as soon as SAMMI connects to Bridge.\n *\n * @example\n * export default insertCommandSection(() => {\n * SAMMI.extCommand(\"Extension Sample Command\", 3355443, 52).catch(e => console.error(e));\n * sammiclient.on(\"Extension Sample Command\", () => {\n * const handler = async () => {\n * await SAMMI.notification('Command Sample');\n * };\n * handler().catch((e) => console.error(e));\n * });\n * });\n * export default insertCommandSection(\n * () => console.log(\"Hello world\"),\n * { waitForSammiclient: false }\n * );\n * export default insertCommandSection(\n * () => console.log(SAMMIExtensions[\"extension-id\"]),\n * { waitForSAMMIExtensions: true }\n * );\n *\n * @param callback A callback with the logic that you will insert in your [insert_command] section.\n * @param options The initialization options.\n * @returns wrapped export default callback\n */\nexport function insertCommandSection(\n callback: () => void,\n options: insertCommandSectionOptions = {\n waitForSammiclient: true,\n waitForSAMMIExtensions: false,\n },\n): () => void {\n const settings = Object.assign(defaultInsertCommandSectionOptions, options);\n\n const wrapper = () => {\n if (!sammiclient && settings.waitForSammiclient) {\n setTimeout(wrapper, 0);\n return;\n }\n\n if (!SAMMIExtensions && settings.waitForSAMMIExtensions) {\n setTimeout(wrapper, 0);\n return;\n }\n\n callback();\n };\n\n return wrapper;\n}\n\nexport type { SAMMINextExtension } from \"./types\";\nexport type { ExtensionConfig as FullExtensionConfig } from '@shared/config-types';\nexport type { ExtensionConfig };\n"],"mappings":";;;;AAKA,MAAM,eAAe;AAYrB,MAAM,8BAAoD,EACtD,cAAc,OACjB;;;;;;;;;;;;;;;AAeD,SAAgB,cAEZ,QACA,UAAgC,EAC5B,cAAc,OACjB,EACc;CACf,IAAI,WAA4B;EAC5B,IAAI,OAAO;EACX,MAAM,OAAO;EACb,SAAS,OAAO;EAChB,MAAM,OAAO;EAChB;AAED,QAAO,kBAAkB,OAAO,mBAAmB,EAAE;AACrD,iBAAgB,SAAS,MAAM,gBAAgB,SAAS,OAAO,EAAE;AACjE,KAAI,gBAAgB,SAAS,KAAK,QAC9B,OAAM,IAAI,MAAM,6DAA6D;CAEjF,MAAM,WAAW,OAAO,OAAO,6BAA6B,QAAQ;AACpE,KAAI,CAAC,SAAS,aACV,YAAW,OAAO,OAAO,SAAS;AAGtC,iBAAgB,SAAS,IAAK,YAAY;AAC1C,KAAI,SAAS,aAAc,QAAO;AAElC,iBAAgB,SAAS,MAAM,IAAI,MAAM,gBAAgB,SAAS,KAAM;EACpE,IAAI,QAAQ,MAAM;AACd,WAAQ,MAAM,cAAc,+BAA+B,MAAM,OAAO,OAAO,SAAS,GAAG;AAC3F,UAAO;;EAEX,eAAe,QAAQ,UAAU;AAC7B,WAAQ,MAAM,cAAc,uCAAuC,UAAU,OAAO,OAAO,SAAS,GAAG;AACvG,UAAO;;EAEX,eAAe,QAAQ,GAAG;AACtB,WAAQ,MAAM,cAAc,0BAA0B,GAAG,OAAO,OAAO,SAAS,GAAG;AACnF,UAAO;;EAEX,eAAe,QAAQ;AACnB,WAAQ,MAAM,cAAc,oCAAoC,OAAO,SAAS,GAAG;AACnF,UAAO;;EAEd,CAAC;AACF,QAAO;;;;;;;;;;;;;;;AAgBX,SAAgB,mBAAmB,cAAsC;AACrE,QAAO,SAAS,eAAe,GAAG,aAAa,WAAW;;AAoB9D,MAAM,qCAAkE;CACpE,oBAAoB;CACpB,wBAAwB;CAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCD,SAAgB,qBACZ,UACA,UAAuC;CACnC,oBAAoB;CACpB,wBAAwB;CAC3B,EACS;CACV,MAAM,WAAW,OAAO,OAAO,oCAAoC,QAAQ;CAE3E,MAAM,gBAAgB;AAClB,MAAI,CAAC,eAAe,SAAS,oBAAoB;AAC7C,cAAW,SAAS,EAAE;AACtB;;AAGJ,MAAI,CAAC,mBAAmB,SAAS,wBAAwB;AACrD,cAAW,SAAS,EAAE;AACtB;;AAGJ,YAAU;;AAGd,QAAO"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/runtime/index.ts"],"sourcesContent":["import \"sammi-bridge-types\";\nimport \"./global.d.ts\";\nimport { ExtensionConfig } from \"./types\";\n\n\nconst PROXY_PREFIX = \"[SAMMI-NEXT-PROXY]\";\n\ninterface initExtensionOptions {\n /**\n * Whether to skip the process of proxying your extension.\n *\n * Warning: this allows other scripts to modify your exports.\n *\n * @default false\n */\n skipProxying?: boolean\n}\nconst defaultInitExtensionOptions: initExtensionOptions = {\n skipProxying: false,\n}\n/**\n * Removes unnecessary data from a raw extension config object and parses it into an ExtensionConfig.\n *\n * Exports the config through the `SAMMIExtensions` namespace with the `_config` key.\n *\n * Generates a Proxy of the extension object to avoid other scripts trying to overwrite it.\n *\n * @example\n * const extension_config = SAMMIExtensions['extension-id']._config;\n *\n * @param config Unparsed config object.\n * @param options Whether to skip the process of proxying your extension (allowing other scripts to modify your exports).\n * @returns Parsed and cleaned config.\n */\nexport function initExtension(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n config: Record<string, any>,\n options: initExtensionOptions = {\n skipProxying: false,\n }\n): ExtensionConfig {\n let response: ExtensionConfig = {\n id: config.id as string,\n name: config.name as string,\n version: config.version as string,\n info: config.info as string | undefined,\n };\n\n window.SAMMIExtensions = window.SAMMIExtensions || {};\n SAMMIExtensions[response.id] = SAMMIExtensions[response.id] || {};\n if (SAMMIExtensions[response.id]?._config)\n throw new Error('The extension with the provided id was already initialized');\n\n const settings = Object.assign(defaultInitExtensionOptions, options);\n if (!settings.skipProxying)\n response = Object.freeze(response);\n\n // @ts-expect-error This is before proxying the extension, so no error.\n SAMMIExtensions[response.id]!._config ??= response;\n if (settings.skipProxying) return response;\n\n SAMMIExtensions[response.id] = new Proxy(SAMMIExtensions[response.id]!, {\n set(target, prop) {\n console.error(PROXY_PREFIX, \": Blocked setting value of:\", prop, \"on:\", target._config?.id);\n return true;\n },\n defineProperty(target, property) {\n console.error(PROXY_PREFIX, \": Blocked property redefinition of:\", property, \"on:\", target._config?.id);\n return true;\n },\n deleteProperty(target, p) {\n console.error(PROXY_PREFIX, \": Blocked deletion of:\", p, \"on:\", target._config?.id);\n return true;\n },\n setPrototypeOf(target) {\n console.error(PROXY_PREFIX, \": Blocked changing prototype of:\", target._config?.id);\n return true;\n },\n });\n return response;\n}\n\n/**\n * Retrieves an [insert_external] section by its extension id.\n *\n * ### Original documentation from https://sammi.solutions/extensions/build\n * This section appears inside the extension’s tab in Bridge, and it provides a visual interface for the extension if needed. It’s written in HTML and CSS.\n *\n * @example\n * const EXTERNAL = getExternalSection(config.id);\n * EXTERNAL.querySelector(\"button\")?.addEventListener('click', () => console.log('Hello world!'));\n *\n * @param extension_id The id of the SAMMI Next extension to retrieve its [insert_external] section.\n * @returns the div element that wraps your extension.\n */\nexport function getExternalSection(extension_id: string): HTMLDivElement {\n return document.getElementById(`${extension_id}-external`) as HTMLDivElement;\n}\n\ninterface insertCommandSectionOptions {\n /**\n * Whether to wait for `sammiclient` to exist.\n * This is enabled by default because every extension that uses `SAMMI` depends on `sammiclient`.\n * You can disable it if your [insert_command] section doesn't use neither `SAMMI` nor `sammiclient`.\n *\n * @default true\n */\n waitForSammiclient?: boolean;\n /**\n * Whether to wait for `SAMMIExtensions` to exist.\n * You must set this to `true` if you use the `SAMMIExtensions` namespace inside your [insert_command] section.\n *\n * @default false\n */\n waitForSAMMIExtensions?: boolean;\n}\nconst defaultInsertCommandSectionOptions: insertCommandSectionOptions = {\n waitForSammiclient: true,\n waitForSAMMIExtensions: false,\n}\n/**\n * Generates your [insert_command] section.\n * This should be used in the default export of your extension.\n *\n * By default, it wraps your callback to wait for `sammiclient` and `SAMMI` are initialized.\n * Its behavior can be changed in the options param.\n *\n * ### Original documentation from https://sammi.solutions/extensions/build\n * In this section, you can define Extension Commands.\n * These commands will be available to users in SAMMI Core when they install your extension.\n * You can define multiple commands in this section.\n * Refer to the SAMMI Bridge documentation for Extension Command details.\n * In this section, you can also automatically call your main extension function that should run as soon as SAMMI connects to Bridge.\n *\n * @example\n * export default insertCommandSection(() => {\n * SAMMI.extCommand(\"Extension Sample Command\", 3355443, 52).catch(e => console.error(e));\n * sammiclient.on(\"Extension Sample Command\", () => {\n * const handler = async () => {\n * await SAMMI.notification('Command Sample');\n * };\n * handler().catch((e) => console.error(e));\n * });\n * });\n * export default insertCommandSection(\n * () => console.log(\"Hello world\"),\n * { waitForSammiclient: false }\n * );\n * export default insertCommandSection(\n * () => console.log(SAMMIExtensions[\"extension-id\"]),\n * { waitForSAMMIExtensions: true }\n * );\n *\n * @param callback A callback with the logic that you will insert in your [insert_command] section.\n * @param options The initialization options.\n * @returns wrapped export default callback\n */\nexport function insertCommandSection(\n callback: () => void,\n options: insertCommandSectionOptions = {\n waitForSammiclient: true,\n waitForSAMMIExtensions: false,\n },\n): () => void {\n const settings = Object.assign(defaultInsertCommandSectionOptions, options);\n\n const wrapper = () => {\n if (!sammiclient && settings.waitForSammiclient) {\n setTimeout(wrapper, 0);\n return;\n }\n\n if (!SAMMIExtensions && settings.waitForSAMMIExtensions) {\n setTimeout(wrapper, 0);\n return;\n }\n\n callback();\n };\n\n return wrapper;\n}\n\nexport type { SAMMINextExtension } from \"./types\";\nexport type { ExtensionConfig as FullExtensionConfig } from '@shared/config-types';\nexport type { ExtensionConfig };\n"],"mappings":";;;AAKA,MAAM,eAAe;AAYrB,MAAM,8BAAoD,EACtD,cAAc,OACjB;;;;;;;;;;;;;;;AAeD,SAAgB,cAEZ,QACA,UAAgC,EAC5B,cAAc,OACjB,EACc;CACf,IAAI,WAA4B;EAC5B,IAAI,OAAO;EACX,MAAM,OAAO;EACb,SAAS,OAAO;EAChB,MAAM,OAAO;EAChB;AAED,QAAO,kBAAkB,OAAO,mBAAmB,EAAE;AACrD,iBAAgB,SAAS,MAAM,gBAAgB,SAAS,OAAO,EAAE;AACjE,KAAI,gBAAgB,SAAS,KAAK,QAC9B,OAAM,IAAI,MAAM,6DAA6D;CAEjF,MAAM,WAAW,OAAO,OAAO,6BAA6B,QAAQ;AACpE,KAAI,CAAC,SAAS,aACV,YAAW,OAAO,OAAO,SAAS;AAGtC,iBAAgB,SAAS,IAAK,YAAY;AAC1C,KAAI,SAAS,aAAc,QAAO;AAElC,iBAAgB,SAAS,MAAM,IAAI,MAAM,gBAAgB,SAAS,KAAM;EACpE,IAAI,QAAQ,MAAM;AACd,WAAQ,MAAM,cAAc,+BAA+B,MAAM,OAAO,OAAO,SAAS,GAAG;AAC3F,UAAO;;EAEX,eAAe,QAAQ,UAAU;AAC7B,WAAQ,MAAM,cAAc,uCAAuC,UAAU,OAAO,OAAO,SAAS,GAAG;AACvG,UAAO;;EAEX,eAAe,QAAQ,GAAG;AACtB,WAAQ,MAAM,cAAc,0BAA0B,GAAG,OAAO,OAAO,SAAS,GAAG;AACnF,UAAO;;EAEX,eAAe,QAAQ;AACnB,WAAQ,MAAM,cAAc,oCAAoC,OAAO,SAAS,GAAG;AACnF,UAAO;;EAEd,CAAC;AACF,QAAO;;;;;;;;;;;;;;;AAgBX,SAAgB,mBAAmB,cAAsC;AACrE,QAAO,SAAS,eAAe,GAAG,aAAa,WAAW;;AAoB9D,MAAM,qCAAkE;CACpE,oBAAoB;CACpB,wBAAwB;CAC3B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCD,SAAgB,qBACZ,UACA,UAAuC;CACnC,oBAAoB;CACpB,wBAAwB;CAC3B,EACS;CACV,MAAM,WAAW,OAAO,OAAO,oCAAoC,QAAQ;CAE3E,MAAM,gBAAgB;AAClB,MAAI,CAAC,eAAe,SAAS,oBAAoB;AAC7C,cAAW,SAAS,EAAE;AACtB;;AAGJ,MAAI,CAAC,mBAAmB,SAAS,wBAAwB;AACrD,cAAW,SAAS,EAAE;AACtB;;AAGJ,YAAU;;AAGd,QAAO"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sammi-next",
3
- "version": "1.2.2",
3
+ "version": "1.4.0",
4
4
  "author": {
5
5
  "name": "Benjas333",
6
6
  "url": "https://github.com/Benjas333"
@@ -22,7 +22,6 @@
22
22
  "chokidar": "^5.0.0",
23
23
  "jiti": "^2.6.1",
24
24
  "picocolors": "^1.1.1",
25
- "sammi-bridge-types": "sammi-bridge-types",
26
25
  "tsdown": "^0.20.0-beta.4"
27
26
  },
28
27
  "exports": {
@@ -61,6 +60,7 @@
61
60
  "type": "module",
62
61
  "types": "./dist/runtime/index.d.mts",
63
62
  "devDependencies": {
64
- "@types/node": "^25.0.9"
63
+ "@types/node": "^25.0.9",
64
+ "sammi-bridge-types": "sammi-bridge-types"
65
65
  }
66
66
  }
@@ -1 +0,0 @@
1
- {"version":3,"file":"build.mjs","names":["path","VERSION","res"],"sources":["../../src/node/build.ts"],"sourcesContent":["import fs from 'node:fs';\nimport path from 'node:path';\nimport colors from 'picocolors';\nimport chokidar from 'chokidar';\nimport { ResolvedExtensionConfig } from \"@shared/config-types\";\nimport { build, TsdownBundle } from \"tsdown\";\nimport { BUILD_PREFIX, GLOBAL_NAME, GREEN_CHECK, RED_X, SAMMI_NEXT_PACKAGE_DIR, VERSION } from \"./constants\";\nimport { displayTime } from './utils';\n\nexport enum BuildMode {\n DEV,\n PRODUCTION,\n}\n\nexport const BuildModes = Object.keys(BuildMode).filter(key => isNaN(Number(key)));\n\nexport interface BuildOptions {\n config: ResolvedExtensionConfig;\n rootDir: string;\n mode?: BuildMode;\n}\n\nexport type ResolvedBuildOptions = Required<BuildOptions>;\n\nfunction readOptionalFile(path: string): string | undefined {\n if (!fs.existsSync(path)) return;\n\n return fs.readFileSync(path, 'utf-8');\n}\n\nconst CommandRE = /\\w+\\(\\w+,\\s*{\\s*default:/gm;\n\nfunction generateSEF(options: ResolvedBuildOptions): string {\n const { config, mode } = options;\n const content = [];\n\n const required_files: {\n header: string,\n content: string,\n }[] = [\n {\n header: \"extension_name\",\n content: config.name,\n },\n {\n header: \"extension_info\",\n content: config.info,\n },\n {\n header: \"extension_version\",\n content: config.version,\n },\n ]\n\n for (const field of required_files) {\n content.push(`[${field.header}]`, field.content, \"\");\n }\n\n const external = readOptionalFile(config.external);\n content.push(\"[insert_external]\", external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\", \"\");\n\n const script = fs.readFileSync(config.entry, \"utf-8\");\n content.push(\"[insert_command]\", CommandRE.test(script) ? `${GLOBAL_NAME}.${config.id}.default()` : \"\", \"\");\n content.push(\"[insert_hook]\", \"\", \"\") // TODO: maybe add hook retro-compatibility\n content.push(\"[insert_script]\", script, \"\");\n\n let over = readOptionalFile(config.over);\n if (over && mode === BuildMode.PRODUCTION) {\n over = JSON.stringify(JSON.parse(over));\n }\n content.push(\"[insert_over]\", over && over != \"{}\" ? over : \"\", \"\");\n return content.join(\"\\n\");\n}\n\nfunction generatePreview(options: ResolvedBuildOptions): string {\n const { config } = options;\n\n const external = readOptionalFile(config.external);\n const script = fs.readFileSync(config.entry, \"utf-8\");\n return fs\n .readFileSync(path.join(SAMMI_NEXT_PACKAGE_DIR, \".sammi\", \"preview.blueprint.html\"), \"utf-8\")\n .replace(/{{EXTERNAL}}/g, external ? `<div id=\"${config.id}-external\">${external}</div>` : \"\")\n .replace(/{{SCRIPT}}/g, script);\n}\n\nasync function buildOnce(options: ResolvedBuildOptions) {\n const { config, rootDir, mode } = options;\n\n const startTime = Date.now();\n const bundle = await build({\n entry: [config.entry],\n outDir: path.join(rootDir, config.out.dir),\n platform: 'browser',\n format: 'iife',\n target: ['es2022'],\n sourcemap: false,\n minify: mode === BuildMode.PRODUCTION,\n banner: {\n js: `/* ${config.name} v${config.version} - Built with SAMMI Next v${VERSION} */`,\n },\n noExternal: ['**'],\n outputOptions: {\n entryFileNames: config.out.js,\n extend: true,\n name: `${GLOBAL_NAME}.${config.id}`,\n exports: 'named',\n },\n });\n const tsdownTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.js} in ${displayTime(tsdownTime - startTime)}`);\n\n fs.writeFileSync(path.join(rootDir, config.out.dir, config.out.sef), generateSEF(options), 'utf-8');\n const sefTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built ${config.out.sef} in ${displayTime(sefTime - tsdownTime)}`);\n\n fs.writeFileSync(path.join(rootDir, config.out.dir, \"preview.html\"), generatePreview(options), 'utf-8');\n const previewTime = Date.now();\n console.info(GREEN_CHECK, BUILD_PREFIX, `built preview.html in ${displayTime(previewTime - sefTime)}`);\n return { bundle, startTime };\n}\n\nexport async function buildExtension(options: ResolvedBuildOptions) {\n const { config, mode } = options;\n\n console.info(\n colors.cyan(\n `SAMMI Next v${VERSION} ${colors.green(\n `building \"${config.name}\" extension in ${BuildMode[mode].toLowerCase()} mode...`\n )}`\n ),\n );\n\n let bundle: TsdownBundle[] | undefined;\n let startTime: number | undefined;\n\n try {\n const res = await buildOnce(options);\n bundle = res.bundle;\n startTime = res.startTime;\n\n if (options.mode !== BuildMode.DEV) return bundle;\n\n console.info(BUILD_PREFIX, colors.cyan(\"watching for file changes...\"));\n\n const watchPaths = [\n path.dirname(config.entry),\n config.external,\n config.over,\n ].filter(Boolean);\n\n const watcher = chokidar.watch(watchPaths, { ignoreInitial: true });\n let timer: NodeJS.Timeout | null = null;\n\n watcher.on('all', (event, p) => {\n console.info(colors.cyan(`${event}: ${p}`));\n if (timer)\n clearTimeout(timer);\n\n timer = setTimeout(() => {\n buildOnce(options).then(res => {\n bundle = res.bundle;\n startTime = res.startTime;\n }).catch(e => console.error(e));\n }, 100);\n });\n\n process.on('SIGINT', () => {\n console.info(\"\\nStopping watch mode...\");\n watcher\n .close()\n .then(() => process.exit(0))\n .catch(e => {\n console.error(e);\n process.exit(1);\n });\n });\n return watcher;\n } catch (error) {\n if (startTime) {\n console.error(RED_X, BUILD_PREFIX, `Build failed in ${displayTime(Date.now() - startTime)}`);\n startTime = undefined;\n }\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -1,21 +0,0 @@
1
- import { version } from "../package.mjs";
2
- import path from "node:path";
3
- import colors from "picocolors";
4
- import { fileURLToPath } from "node:url";
5
-
6
- //#region src/node/constants.ts
7
- const DEFAULT_CONFIG_EXTENSIONS = [
8
- ".mjs",
9
- ".js",
10
- ".mts",
11
- ".ts"
12
- ];
13
- const GLOBAL_NAME = "SAMMIExtensions";
14
- const BUILD_PREFIX = colors.blue("[sammi-next]");
15
- const GREEN_CHECK = colors.green("✔");
16
- const RED_X = colors.red("✗");
17
- const SAMMI_NEXT_PACKAGE_DIR = path.resolve(fileURLToPath(import.meta.url), "../../..");
18
-
19
- //#endregion
20
- export { BUILD_PREFIX, DEFAULT_CONFIG_EXTENSIONS, GLOBAL_NAME, GREEN_CHECK, RED_X, SAMMI_NEXT_PACKAGE_DIR };
21
- //# sourceMappingURL=constants.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.mjs","names":[],"sources":["../../src/node/constants.ts"],"sourcesContent":["import path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport colors from 'picocolors'\n\nexport { version as VERSION } from '../../package.json';\n\nexport const DEFAULT_CONFIG_EXTENSIONS: string[] = [\n '.mjs',\n '.js',\n '.mts',\n '.ts',\n]\n\nexport const GLOBAL_NAME = \"SAMMIExtensions\";\n\nexport const BUILD_PREFIX = colors.blue(\"[sammi-next]\");\nexport const GREEN_CHECK = colors.green('✔');\nexport const RED_X = colors.red('✗');\n\nexport const SAMMI_NEXT_PACKAGE_DIR = path.resolve(\n fileURLToPath(import.meta.url),\n '../../..',\n);\n"],"mappings":";;;;;;AAMA,MAAa,4BAAsC;CAC/C;CACA;CACA;CACA;CACH;AAED,MAAa,cAAc;AAE3B,MAAa,eAAe,OAAO,KAAK,eAAe;AACvD,MAAa,cAAc,OAAO,MAAM,IAAI;AAC5C,MAAa,QAAQ,OAAO,IAAI,IAAI;AAEpC,MAAa,yBAAyB,KAAK,QACvC,cAAc,OAAO,KAAK,IAAI,EAC9B,WACH"}
@@ -1,14 +0,0 @@
1
- //#region src/node/utils.ts
2
- function displayTime(time) {
3
- if (time < 1e3) return `${time}ms`;
4
- time = time / 1e3;
5
- if (time < 60) return `${time.toFixed(2)}s`;
6
- const mins = Math.floor(time / 60);
7
- const seconds = Math.round(time % 60);
8
- if (seconds === 60) return `${mins + 1}m`;
9
- return `${mins}m${seconds < 1 ? "" : ` ${seconds}s`}`;
10
- }
11
-
12
- //#endregion
13
- export { displayTime };
14
- //# sourceMappingURL=utils.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.mjs","names":[],"sources":["../../src/node/utils.ts"],"sourcesContent":["export function displayTime(time: number): string {\n if (time < 1_000)\n return `${time}ms`;\n\n time = time / 1_000;\n\n if (time < 60)\n return `${time.toFixed(2)}s`\n\n const mins = Math.floor(time / 60);\n const seconds = Math.round(time % 60);\n\n if (seconds === 60)\n return `${mins + 1}m`\n\n return `${mins}m${seconds < 1 ? '' : ` ${seconds}s`}`;\n}\n"],"mappings":";AAAA,SAAgB,YAAY,MAAsB;AAC9C,KAAI,OAAO,IACP,QAAO,GAAG,KAAK;AAEnB,QAAO,OAAO;AAEd,KAAI,OAAO,GACP,QAAO,GAAG,KAAK,QAAQ,EAAE,CAAC;CAE9B,MAAM,OAAO,KAAK,MAAM,OAAO,GAAG;CAClC,MAAM,UAAU,KAAK,MAAM,OAAO,GAAG;AAErC,KAAI,YAAY,GACZ,QAAO,GAAG,OAAO,EAAE;AAEvB,QAAO,GAAG,KAAK,GAAG,UAAU,IAAI,KAAK,IAAI,QAAQ"}
package/dist/package.mjs DELETED
@@ -1,6 +0,0 @@
1
- //#region package.json
2
- var version = "1.2.0";
3
-
4
- //#endregion
5
- export { version };
6
- //# sourceMappingURL=package.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"package.mjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
@@ -1,10 +0,0 @@
1
- import { SAMMINextExtension } from "./types.mjs";
2
-
3
- //#region src/runtime/global.d.ts
4
- declare global {
5
- /**
6
- * Global namespace where SAMMI Next stores all the extensions.
7
- */
8
- var SAMMIExtensions: Record<string, SAMMINextExtension | undefined>;
9
- }
10
- //# sourceMappingURL=global.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"global.d.mts","names":["SAMMINextExtension","_0","Record","global","SAMMIExtensions","sideEffect"],"sources":["../../src/runtime/global.d.ts"],"mappings":";;;QAEQG,MAAAA;EAFqCF;;;EAAAA,IAMrCG,eAAAA,EAAiBF,MAAAA,SAAeF,kBAAAA;AAAAA"}
@@ -1,25 +0,0 @@
1
- //#region src/runtime/types.d.ts
2
- /**
3
- * Represents useful data from the sammi.config.json. Friendly to export.
4
- */
5
- interface ExtensionConfig {
6
- /** This section names your extension, and is visible in SAMMI Bridge and SAMMI Core. Please use alphanumeric characters and spaces only. */
7
- name: string;
8
- /** Specify a unique id for your extension here. Please use alphanumeric characters, dashes, and underscores only. */
9
- id: string;
10
- /** This section is for descriptive text about the extension, e.g. what the extension does. This information is displayed to the users in SAMMI Bridge-Extensions tab when they hover over the extension name inside the list of installed extensions. */
11
- info?: string;
12
- /** Specify your extension version here, using numbers and dots (e.g., 2.01). This is crucial for the automatic version checker in Bridge, which can notify users of updates. */
13
- version: string;
14
- }
15
- /**
16
- * Interface that represents most of the structures built with SAMMI Next.
17
- */
18
- interface SAMMINextExtension {
19
- readonly default?: () => void;
20
- readonly _config?: ExtensionConfig;
21
- readonly [key: string]: unknown;
22
- }
23
- //#endregion
24
- export { ExtensionConfig, SAMMINextExtension };
25
- //# sourceMappingURL=types.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/runtime/types.ts"],"mappings":";;AAIA;;UAAiB,eAAA;EAAe;EAE5B,IAAA;EAEA;EAAA,EAAA;EAIA;EAFA,IAAA;EAEO;EAAP,OAAA;AAAA;;;;UAMa,kBAAA;EAAA,SACJ,OAAA;EAAA,SACA,OAAA,GAAU,eAAA;EAAA,UACT,GAAA;AAAA"}