@bubblydoo/uxp-cli 0.0.2

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.d.ts ADDED
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
package/dist/bin.js ADDED
@@ -0,0 +1,205 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'fs/promises';
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ import { setupDevtoolsUrl, setupCdpSession, waitForExecutionContextCreated, setupCdpSessionWithDefaults } from '@bubblydoo/uxp-cli-common';
6
+ import arg from 'arg';
7
+ import { spawn } from 'child_process';
8
+
9
+ function getChromeCommand() {
10
+ const platform = process.platform;
11
+ switch (platform) {
12
+ case "darwin":
13
+ return { command: "open", args: ["-a", "Google Chrome"] };
14
+ case "win32":
15
+ return { command: "cmd", args: ["/c", "start", "chrome"] };
16
+ case "linux":
17
+ return { command: "google-chrome", args: [] };
18
+ default:
19
+ throw new Error(`Unsupported platform: ${platform}`);
20
+ }
21
+ }
22
+ function openDevtoolsSessionInChrome(cdtUrl) {
23
+ const url = new URL("devtools://devtools/bundled/inspector.html");
24
+ url.searchParams.set("ws", cdtUrl.replace("ws://", ""));
25
+ return new Promise((resolve, reject) => {
26
+ const { command, args: args2 } = getChromeCommand();
27
+ const proc = spawn(command, [...args2, url.toString()], {
28
+ shell: process.platform === "win32"
29
+ });
30
+ proc.on("error", (err) => {
31
+ reject(new Error(`Failed to launch Chrome: ${err.message}`));
32
+ });
33
+ proc.on("close", (code) => {
34
+ if (code === 0) {
35
+ resolve(true);
36
+ } else {
37
+ reject(new Error("Failed to open devtools session"));
38
+ }
39
+ });
40
+ });
41
+ }
42
+
43
+ // src/bin.ts
44
+ Error.stackTraceLimit = Infinity;
45
+ var __dirname2 = path.dirname(fileURLToPath(import.meta.url));
46
+ function showHelp() {
47
+ console.log(`
48
+ Usage: uxp-cli <action> [options]
49
+
50
+ Actions:
51
+ open-devtools Open Chrome DevTools for a UXP plugin
52
+ dump-object Dump object properties to dump.json (always uses fake plugin)
53
+
54
+ Options:
55
+ --plugin-path, -p <path> Path to the UXP plugin directory
56
+ --plugin-id, -i <id> Plugin ID
57
+ --help, -h Show this help message
58
+
59
+ Examples:
60
+ # Open devtools with fake plugin
61
+ uxp-cli open-devtools
62
+
63
+ # Open devtools with custom plugin
64
+ uxp-cli open-devtools --plugin-path ./my-plugin --plugin-id com.example.myplugin
65
+
66
+ # Dump object properties (always uses fake plugin)
67
+ uxp-cli dump-object
68
+ `);
69
+ }
70
+ var args = arg({
71
+ "--help": Boolean,
72
+ "-h": "--help"
73
+ }, {
74
+ permissive: true
75
+ });
76
+ if (args["--help"] || args._.length === 0) {
77
+ showHelp();
78
+ process.exit(args["--help"] ? 0 : 1);
79
+ }
80
+ var action = args._[0];
81
+ if (!["open-devtools", "dump-object"].includes(action)) {
82
+ console.error(`Error: Unknown action "${action}"
83
+ `);
84
+ showHelp();
85
+ process.exit(1);
86
+ }
87
+ var actionArgs = arg({
88
+ "--plugin-path": String,
89
+ "--plugin-id": String,
90
+ "--help": Boolean,
91
+ "-p": "--plugin-path",
92
+ "-i": "--plugin-id",
93
+ "-h": "--help"
94
+ }, {
95
+ argv: args._.slice(1)
96
+ });
97
+ if (actionArgs["--help"]) {
98
+ showHelp();
99
+ process.exit(0);
100
+ }
101
+ async function getPluginInfo(useFakePlugin) {
102
+ const fakePluginPath = path.resolve(__dirname2, "../../uxp-cli-common/fake-plugin");
103
+ const fakePluginId = "co.bubblydoo.fake-plugin";
104
+ if (useFakePlugin) {
105
+ console.log("Using fake plugin:");
106
+ console.log(` Plugin Path: ${fakePluginPath}`);
107
+ console.log(` Plugin ID: ${fakePluginId}`);
108
+ return { pluginPath: fakePluginPath, pluginId: fakePluginId };
109
+ }
110
+ let pluginPath = actionArgs["--plugin-path"];
111
+ let pluginId = actionArgs["--plugin-id"];
112
+ if (!pluginPath || !pluginId) {
113
+ pluginPath = pluginPath || fakePluginPath;
114
+ pluginId = pluginId || fakePluginId;
115
+ console.log("Using default fake plugin:");
116
+ console.log(` Plugin Path: ${pluginPath}`);
117
+ console.log(` Plugin ID: ${pluginId}`);
118
+ }
119
+ if (!path.isAbsolute(pluginPath)) {
120
+ pluginPath = path.resolve(process.cwd(), pluginPath);
121
+ }
122
+ try {
123
+ await fs.access(pluginPath);
124
+ } catch {
125
+ console.error(`Error: Plugin directory not found: ${pluginPath}`);
126
+ process.exit(1);
127
+ }
128
+ return { pluginPath, pluginId };
129
+ }
130
+ async function openDevtools() {
131
+ const { pluginPath, pluginId } = await getPluginInfo(false);
132
+ console.log("\nSetting up devtools URL...");
133
+ const cdtUrl = await setupDevtoolsUrl(pluginPath, pluginId);
134
+ console.log(`DevTools URL: ${cdtUrl}
135
+ `);
136
+ await openDevtoolsSessionInChrome(cdtUrl);
137
+ console.log("Chrome DevTools opened");
138
+ console.log("\nPress Ctrl+C to exit...");
139
+ await new Promise(() => {
140
+ });
141
+ }
142
+ async function dumpObject() {
143
+ const { pluginPath, pluginId } = await getPluginInfo(true);
144
+ console.log("\nSetting up devtools URL...");
145
+ const cdtUrl = await setupDevtoolsUrl(pluginPath, pluginId);
146
+ console.log(`DevTools URL: ${cdtUrl}
147
+ `);
148
+ console.log("Setting up CDP session...");
149
+ const cdp = await setupCdpSession(cdtUrl);
150
+ const executionContextCreatedPromise = waitForExecutionContextCreated(cdp);
151
+ await setupCdpSessionWithDefaults(cdp);
152
+ console.log("Waiting for execution context...");
153
+ const executionContext = await executionContextCreatedPromise;
154
+ console.log("Evaluating expression...");
155
+ const result = await cdp.Runtime.evaluate({
156
+ expression: `
157
+ (() => {
158
+ const app = require("photoshop").app;
159
+ const activeDocumentGetter = Object.getOwnPropertyDescriptor(Reflect.getPrototypeOf(app), "activeDocument").get;
160
+ return activeDocumentGetter;
161
+ })();
162
+ `,
163
+ uniqueContextId: executionContext.uniqueId
164
+ });
165
+ console.log("Getting properties...");
166
+ const properties = await cdp.Runtime.getProperties({
167
+ objectId: result.result.objectId,
168
+ accessorPropertiesOnly: false,
169
+ generatePreview: false,
170
+ nonIndexedPropertiesOnly: false,
171
+ ownProperties: false
172
+ });
173
+ properties.internalProperties?.find((property) => property.name === "[[FunctionLocation]]")?.value;
174
+ const scopes = properties.internalProperties?.find((property) => property.name === "[[Scopes]]")?.value;
175
+ const scopesProperties = await cdp.Runtime.getProperties({
176
+ objectId: scopes.objectId,
177
+ ownProperties: true
178
+ });
179
+ const allScopesResolved = await Promise.all(
180
+ scopesProperties.result.map((property) => cdp.Runtime.getProperties({
181
+ objectId: property.value.objectId,
182
+ ownProperties: true
183
+ }))
184
+ );
185
+ const dump = {
186
+ subject: result.result,
187
+ properties,
188
+ scopes: allScopesResolved
189
+ };
190
+ const dumpPath = path.resolve(process.cwd(), "dump.json");
191
+ await fs.writeFile(dumpPath, JSON.stringify(dump, null, 2));
192
+ console.log(`
193
+ Dump written to: ${dumpPath}`);
194
+ }
195
+ if (action === "open-devtools") {
196
+ await openDevtools();
197
+ } else if (action === "dump-object") {
198
+ await dumpObject();
199
+ }
200
+ process.on("SIGINT", () => {
201
+ console.log("\nReceived SIGINT, exiting...");
202
+ process.exit(0);
203
+ });
204
+ //# sourceMappingURL=bin.js.map
205
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/open-devtools-session.ts","../src/bin.ts"],"names":["args","__dirname"],"mappings":"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","file":"bin.js","sourcesContent":["import { spawn } from 'node:child_process';\n\n// devtools://devtools/bundled/inspector.html?ws=127.0.0.1:14003/socket/cdt/2676d6dd-528c-4453-ac0d-c5dddf78c4d7\n\nfunction getChromeCommand(): { command: string; args: string[] } {\n const platform = process.platform;\n\n switch (platform) {\n case 'darwin':\n return { command: 'open', args: ['-a', 'Google Chrome'] };\n case 'win32':\n return { command: 'cmd', args: ['/c', 'start', 'chrome'] };\n case 'linux':\n // Try common Chrome executable names on Linux\n return { command: 'google-chrome', args: [] };\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n}\n\nexport function openDevtoolsSessionInChrome(cdtUrl: string) {\n const url = new URL('devtools://devtools/bundled/inspector.html');\n url.searchParams.set('ws', cdtUrl.replace('ws://', ''));\n\n return new Promise((resolve, reject) => {\n const { command, args } = getChromeCommand();\n const proc = spawn(command, [...args, url.toString()], {\n shell: process.platform === 'win32',\n });\n proc.on('error', (err) => {\n reject(new Error(`Failed to launch Chrome: ${err.message}`));\n });\n proc.on('close', (code) => {\n if (code === 0) {\n resolve(true);\n }\n else {\n reject(new Error('Failed to open devtools session'));\n }\n });\n });\n}\n","#!/usr/bin/env node\n/* eslint-disable antfu/no-top-level-await */\n/* eslint-disable no-console */\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { setupCdpSession, setupCdpSessionWithDefaults, setupDevtoolsUrl, waitForExecutionContextCreated } from '@bubblydoo/uxp-cli-common';\nimport arg from 'arg';\nimport { openDevtoolsSessionInChrome } from './open-devtools-session';\n\nError.stackTraceLimit = Infinity;\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\nfunction showHelp() {\n console.log(`\nUsage: uxp-cli <action> [options]\n\nActions:\n open-devtools Open Chrome DevTools for a UXP plugin\n dump-object Dump object properties to dump.json (always uses fake plugin)\n\nOptions:\n --plugin-path, -p <path> Path to the UXP plugin directory\n --plugin-id, -i <id> Plugin ID\n --help, -h Show this help message\n\nExamples:\n # Open devtools with fake plugin\n uxp-cli open-devtools\n\n # Open devtools with custom plugin\n uxp-cli open-devtools --plugin-path ./my-plugin --plugin-id com.example.myplugin\n\n # Dump object properties (always uses fake plugin)\n uxp-cli dump-object\n`);\n}\n\n// Parse action\nconst args = arg({\n '--help': Boolean,\n '-h': '--help',\n}, {\n permissive: true,\n});\n\nif (args['--help'] || args._.length === 0) {\n showHelp();\n process.exit(args['--help'] ? 0 : 1);\n}\n\nconst action = args._[0];\n\nif (!['open-devtools', 'dump-object'].includes(action)) {\n console.error(`Error: Unknown action \"${action}\"\\n`);\n showHelp();\n process.exit(1);\n}\n\n// Parse action-specific options\nconst actionArgs = arg({\n '--plugin-path': String,\n '--plugin-id': String,\n '--help': Boolean,\n '-p': '--plugin-path',\n '-i': '--plugin-id',\n '-h': '--help',\n}, {\n argv: args._.slice(1),\n});\n\nif (actionArgs['--help']) {\n showHelp();\n process.exit(0);\n}\n\nasync function getPluginInfo(useFakePlugin: boolean) {\n const fakePluginPath = path.resolve(__dirname, '../../uxp-cli-common/fake-plugin');\n const fakePluginId = 'co.bubblydoo.fake-plugin';\n\n if (useFakePlugin) {\n console.log('Using fake plugin:');\n console.log(` Plugin Path: ${fakePluginPath}`);\n console.log(` Plugin ID: ${fakePluginId}`);\n return { pluginPath: fakePluginPath, pluginId: fakePluginId };\n }\n\n let pluginPath = actionArgs['--plugin-path'];\n let pluginId = actionArgs['--plugin-id'];\n\n // Default to fake-plugin if not provided\n if (!pluginPath || !pluginId) {\n pluginPath = pluginPath || fakePluginPath;\n pluginId = pluginId || fakePluginId;\n\n console.log('Using default fake plugin:');\n console.log(` Plugin Path: ${pluginPath}`);\n console.log(` Plugin ID: ${pluginId}`);\n }\n\n // Ensure plugin path is absolute\n if (!path.isAbsolute(pluginPath)) {\n pluginPath = path.resolve(process.cwd(), pluginPath);\n }\n\n // Verify plugin directory exists\n try {\n await fs.access(pluginPath);\n }\n catch {\n console.error(`Error: Plugin directory not found: ${pluginPath}`);\n process.exit(1);\n }\n\n return { pluginPath, pluginId };\n}\n\nasync function openDevtools() {\n const { pluginPath, pluginId } = await getPluginInfo(false);\n\n console.log('\\nSetting up devtools URL...');\n const cdtUrl = await setupDevtoolsUrl(pluginPath, pluginId);\n console.log(`DevTools URL: ${cdtUrl}\\n`);\n\n await openDevtoolsSessionInChrome(cdtUrl);\n console.log('Chrome DevTools opened');\n\n console.log('\\nPress Ctrl+C to exit...');\n await new Promise(() => {});\n}\n\nasync function dumpObject() {\n const { pluginPath, pluginId } = await getPluginInfo(true);\n\n console.log('\\nSetting up devtools URL...');\n const cdtUrl = await setupDevtoolsUrl(pluginPath, pluginId);\n console.log(`DevTools URL: ${cdtUrl}\\n`);\n\n console.log('Setting up CDP session...');\n const cdp = await setupCdpSession(cdtUrl);\n\n const executionContextCreatedPromise = waitForExecutionContextCreated(cdp);\n\n await setupCdpSessionWithDefaults(cdp);\n\n console.log('Waiting for execution context...');\n const executionContext = await executionContextCreatedPromise;\n\n console.log('Evaluating expression...');\n const result = await cdp.Runtime.evaluate({\n expression: `\n (() => {\n const app = require(\"photoshop\").app;\n const activeDocumentGetter = Object.getOwnPropertyDescriptor(Reflect.getPrototypeOf(app), \"activeDocument\").get;\n return activeDocumentGetter;\n })();\n `,\n uniqueContextId: executionContext.uniqueId,\n });\n\n console.log('Getting properties...');\n const properties = await cdp.Runtime.getProperties({\n objectId: result.result.objectId!,\n accessorPropertiesOnly: false,\n generatePreview: false,\n nonIndexedPropertiesOnly: false,\n ownProperties: false,\n });\n\n const _functionLocation = properties.internalProperties?.find((property: any) => property.name === '[[FunctionLocation]]')?.value;\n const scopes = properties.internalProperties?.find((property: any) => property.name === '[[Scopes]]')?.value;\n\n const scopesProperties = await cdp.Runtime.getProperties({\n objectId: scopes!.objectId!,\n ownProperties: true,\n });\n\n const allScopesResolved = await Promise.all(\n scopesProperties.result.map((property: any) => cdp.Runtime.getProperties({\n objectId: property.value!.objectId!,\n ownProperties: true,\n })),\n );\n\n const dump = {\n subject: result.result,\n properties,\n scopes: allScopesResolved,\n };\n\n const dumpPath = path.resolve(process.cwd(), 'dump.json');\n await fs.writeFile(dumpPath, JSON.stringify(dump, null, 2));\n console.log(`\\nDump written to: ${dumpPath}`);\n}\n\n// Handle actions\nif (action === 'open-devtools') {\n await openDevtools();\n}\nelse if (action === 'dump-object') {\n await dumpObject();\n}\n\nprocess.on('SIGINT', () => {\n console.log('\\nReceived SIGINT, exiting...');\n process.exit(0);\n});\n"]}
@@ -0,0 +1,3 @@
1
+ declare function openDevtoolsSessionInChrome(cdtUrl: string): Promise<unknown>;
2
+
3
+ export { openDevtoolsSessionInChrome };
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ import { spawn } from 'child_process';
2
+
3
+ // src/open-devtools-session.ts
4
+ function getChromeCommand() {
5
+ const platform = process.platform;
6
+ switch (platform) {
7
+ case "darwin":
8
+ return { command: "open", args: ["-a", "Google Chrome"] };
9
+ case "win32":
10
+ return { command: "cmd", args: ["/c", "start", "chrome"] };
11
+ case "linux":
12
+ return { command: "google-chrome", args: [] };
13
+ default:
14
+ throw new Error(`Unsupported platform: ${platform}`);
15
+ }
16
+ }
17
+ function openDevtoolsSessionInChrome(cdtUrl) {
18
+ const url = new URL("devtools://devtools/bundled/inspector.html");
19
+ url.searchParams.set("ws", cdtUrl.replace("ws://", ""));
20
+ return new Promise((resolve, reject) => {
21
+ const { command, args } = getChromeCommand();
22
+ const proc = spawn(command, [...args, url.toString()], {
23
+ shell: process.platform === "win32"
24
+ });
25
+ proc.on("error", (err) => {
26
+ reject(new Error(`Failed to launch Chrome: ${err.message}`));
27
+ });
28
+ proc.on("close", (code) => {
29
+ if (code === 0) {
30
+ resolve(true);
31
+ } else {
32
+ reject(new Error("Failed to open devtools session"));
33
+ }
34
+ });
35
+ });
36
+ }
37
+
38
+ export { openDevtoolsSessionInChrome };
39
+ //# sourceMappingURL=index.js.map
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/open-devtools-session.ts"],"names":[],"mappings":";;;AAIA,SAAS,gBAAA,GAAwD;AAC/D,EAAA,MAAM,WAAW,OAAA,CAAQ,QAAA;AAEzB,EAAA,QAAQ,QAAA;AAAU,IAChB,KAAK,QAAA;AACH,MAAA,OAAO,EAAE,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAC,IAAA,EAAM,eAAe,CAAA,EAAE;AAAA,IAC1D,KAAK,OAAA;AACH,MAAA,OAAO,EAAE,SAAS,KAAA,EAAO,IAAA,EAAM,CAAC,IAAA,EAAM,OAAA,EAAS,QAAQ,CAAA,EAAE;AAAA,IAC3D,KAAK,OAAA;AAEH,MAAA,OAAO,EAAE,OAAA,EAAS,eAAA,EAAiB,IAAA,EAAM,EAAC,EAAE;AAAA,IAC9C;AACE,MAAA,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,QAAQ,CAAA,CAAE,CAAA;AAAA;AAEzD;AAEO,SAAS,4BAA4B,MAAA,EAAgB;AAC1D,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,4CAA4C,CAAA;AAChE,EAAA,GAAA,CAAI,aAAa,GAAA,CAAI,IAAA,EAAM,OAAO,OAAA,CAAQ,OAAA,EAAS,EAAE,CAAC,CAAA;AAEtD,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAK,GAAI,gBAAA,EAAiB;AAC3C,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,EAAS,CAAC,GAAG,IAAA,EAAM,GAAA,CAAI,QAAA,EAAU,CAAA,EAAG;AAAA,MACrD,KAAA,EAAO,QAAQ,QAAA,KAAa;AAAA,KAC7B,CAAA;AACD,IAAA,IAAA,CAAK,EAAA,CAAG,OAAA,EAAS,CAAC,GAAA,KAAQ;AACxB,MAAA,MAAA,CAAO,IAAI,KAAA,CAAM,CAAA,yBAAA,EAA4B,GAAA,CAAI,OAAO,EAAE,CAAC,CAAA;AAAA,IAC7D,CAAC,CAAA;AACD,IAAA,IAAA,CAAK,EAAA,CAAG,OAAA,EAAS,CAAC,IAAA,KAAS;AACzB,MAAA,IAAI,SAAS,CAAA,EAAG;AACd,QAAA,OAAA,CAAQ,IAAI,CAAA;AAAA,MACd,CAAA,MACK;AACH,QAAA,MAAA,CAAO,IAAI,KAAA,CAAM,iCAAiC,CAAC,CAAA;AAAA,MACrD;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAC,CAAA;AACH","file":"index.js","sourcesContent":["import { spawn } from 'node:child_process';\n\n// devtools://devtools/bundled/inspector.html?ws=127.0.0.1:14003/socket/cdt/2676d6dd-528c-4453-ac0d-c5dddf78c4d7\n\nfunction getChromeCommand(): { command: string; args: string[] } {\n const platform = process.platform;\n\n switch (platform) {\n case 'darwin':\n return { command: 'open', args: ['-a', 'Google Chrome'] };\n case 'win32':\n return { command: 'cmd', args: ['/c', 'start', 'chrome'] };\n case 'linux':\n // Try common Chrome executable names on Linux\n return { command: 'google-chrome', args: [] };\n default:\n throw new Error(`Unsupported platform: ${platform}`);\n }\n}\n\nexport function openDevtoolsSessionInChrome(cdtUrl: string) {\n const url = new URL('devtools://devtools/bundled/inspector.html');\n url.searchParams.set('ws', cdtUrl.replace('ws://', ''));\n\n return new Promise((resolve, reject) => {\n const { command, args } = getChromeCommand();\n const proc = spawn(command, [...args, url.toString()], {\n shell: process.platform === 'win32',\n });\n proc.on('error', (err) => {\n reject(new Error(`Failed to launch Chrome: ${err.message}`));\n });\n proc.on('close', (code) => {\n if (code === 0) {\n resolve(true);\n }\n else {\n reject(new Error('Failed to open devtools session'));\n }\n });\n });\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@bubblydoo/uxp-cli",
3
+ "type": "module",
4
+ "version": "0.0.2",
5
+ "exports": {
6
+ ".": {
7
+ "types": "./dist/index.d.ts",
8
+ "import": "./dist/index.js"
9
+ },
10
+ "./package.json": "./package.json"
11
+ },
12
+ "publishConfig": {
13
+ "access": "public"
14
+ },
15
+ "bin": {
16
+ "uxp-cli": "./dist/bin.js"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "dependencies": {
22
+ "arg": "^5.0.2",
23
+ "chrome-remote-interface": "^0.33.3",
24
+ "@bubblydoo/uxp-cli-common": "0.0.2"
25
+ },
26
+ "devDependencies": {
27
+ "@types/chrome-remote-interface": "^0.33.0",
28
+ "@types/node": "^20.8.7",
29
+ "tsup": "^8.3.5",
30
+ "typescript": "^5.8.3",
31
+ "@bubblydoo/tsconfig": "0.0.3"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "dev": "tsup --watch"
36
+ }
37
+ }