@snaptrude/create-snaptrude-plugin 0.0.5 → 0.0.7
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/index.cjs +299 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +299 -60
- package/dist/index.js.map +1 -1
- package/dist/src/__tests__/shared.test.d.ts +2 -0
- package/dist/src/__tests__/shared.test.d.ts.map +1 -0
- package/dist/src/__tests__/update.test.d.ts +2 -0
- package/dist/src/__tests__/update.test.d.ts.map +1 -0
- package/dist/src/create.d.ts +5 -0
- package/dist/src/create.d.ts.map +1 -0
- package/dist/src/register.d.ts +9 -0
- package/dist/src/register.d.ts.map +1 -0
- package/dist/src/shared.d.ts +39 -0
- package/dist/src/shared.d.ts.map +1 -0
- package/dist/src/update.d.ts +25 -0
- package/dist/src/update.d.ts.map +1 -0
- package/package.json +8 -4
package/dist/index.cjs
CHANGED
|
@@ -23,13 +23,10 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
|
|
26
|
-
// src/index.ts
|
|
27
|
-
var import_prompts = require("@inquirer/prompts");
|
|
28
|
-
|
|
29
26
|
// package.json
|
|
30
27
|
var package_default = {
|
|
31
28
|
name: "@snaptrude/create-snaptrude-plugin",
|
|
32
|
-
version: "0.0.
|
|
29
|
+
version: "0.0.7",
|
|
33
30
|
type: "module",
|
|
34
31
|
main: "./dist/index.js",
|
|
35
32
|
module: "./dist/index.js",
|
|
@@ -45,20 +42,24 @@ var package_default = {
|
|
|
45
42
|
},
|
|
46
43
|
scripts: {
|
|
47
44
|
"check-types": "tsc --noEmit",
|
|
48
|
-
build: "tsup",
|
|
45
|
+
build: "tsup --clean",
|
|
49
46
|
dev: "tsup --watch",
|
|
50
|
-
"clean-dist": "rm -rf dist"
|
|
47
|
+
"clean-dist": "rm -rf dist",
|
|
48
|
+
test: "vitest run",
|
|
49
|
+
"test:watch": "vitest"
|
|
51
50
|
},
|
|
52
51
|
devDependencies: {
|
|
53
52
|
"@types/node": "^25.3.5",
|
|
54
53
|
tsup: "^8.5.1",
|
|
55
|
-
typescript: "^5.5.4"
|
|
54
|
+
typescript: "^5.5.4",
|
|
55
|
+
vitest: "^4.1.0"
|
|
56
56
|
},
|
|
57
57
|
dependencies: {
|
|
58
58
|
"@commander-js/extra-typings": "^14.0.0",
|
|
59
59
|
"@inquirer/prompts": "^8.3.0",
|
|
60
60
|
commander: "^14.0.3",
|
|
61
61
|
"simple-git": "^3.32.3",
|
|
62
|
+
tar: "^7.5.11",
|
|
62
63
|
"update-check": "^1.5.4"
|
|
63
64
|
}
|
|
64
65
|
};
|
|
@@ -66,23 +67,41 @@ var package_default = {
|
|
|
66
67
|
// src/index.ts
|
|
67
68
|
var import_update_check = __toESM(require("update-check"), 1);
|
|
68
69
|
var import_extra_typings = require("@commander-js/extra-typings");
|
|
70
|
+
|
|
71
|
+
// src/create.ts
|
|
72
|
+
var import_prompts = require("@inquirer/prompts");
|
|
69
73
|
var import_simple_git = __toESM(require("simple-git"), 1);
|
|
70
74
|
var import_promises = require("fs/promises");
|
|
71
75
|
var import_node_path = require("path");
|
|
72
76
|
var import_node_os = require("os");
|
|
73
|
-
var
|
|
74
|
-
var DEFAULT_VERBOSE = false;
|
|
77
|
+
var import_node_crypto = require("crypto");
|
|
75
78
|
var DEFAULT_PLUGIN_NAME = "my-plugin";
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const packageJsonObject = JSON.parse(packageJson);
|
|
80
|
-
packageJsonObject.name = pluginName;
|
|
81
|
-
await (0, import_promises.writeFile)(packageJsonPath, JSON.stringify(packageJsonObject, null, 2));
|
|
82
|
-
}
|
|
79
|
+
var EXAMPLES_REPO = "https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git";
|
|
80
|
+
var EXAMPLES_REPO_COMMIT = "bdc80a1a830396ee29a576ea67ef7482888c1468";
|
|
81
|
+
var EXAMPLE_PATH_IN_REPO = "snaptrude-plugin";
|
|
83
82
|
var UNWANTED_DIRS = [];
|
|
84
83
|
var UNWANTED_FILES = [];
|
|
85
|
-
async function
|
|
84
|
+
async function askPluginName() {
|
|
85
|
+
return (0, import_prompts.input)({
|
|
86
|
+
message: "What is the name of your plugin?",
|
|
87
|
+
required: true,
|
|
88
|
+
default: DEFAULT_PLUGIN_NAME,
|
|
89
|
+
validate: (value) => {
|
|
90
|
+
if (!/^[a-z0-9-]+$/.test(value)) {
|
|
91
|
+
return "Plugin name must only contain lowercase letters, numbers, and hyphens";
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
async function updatePkgJson(targetDir, pluginName) {
|
|
98
|
+
const pkgPath = (0, import_node_path.join)(targetDir, "package.json");
|
|
99
|
+
const pkg = JSON.parse(await (0, import_promises.readFile)(pkgPath, "utf8"));
|
|
100
|
+
pkg.name = pluginName;
|
|
101
|
+
pkg.id = (0, import_node_crypto.randomUUID)();
|
|
102
|
+
await (0, import_promises.writeFile)(pkgPath, JSON.stringify(pkg, null, 2));
|
|
103
|
+
}
|
|
104
|
+
async function removeUnwantedFiles(targetDir, verbose) {
|
|
86
105
|
if (verbose) console.log(`Removing unwanted files from ${targetDir}`);
|
|
87
106
|
for (const dir of UNWANTED_DIRS) {
|
|
88
107
|
await (0, import_promises.rm)((0, import_node_path.join)(targetDir, dir), { recursive: true, force: true });
|
|
@@ -91,10 +110,7 @@ async function removeUnwantedFiles(targetDir, verbose = true) {
|
|
|
91
110
|
await (0, import_promises.rm)((0, import_node_path.join)(targetDir, file), { force: true });
|
|
92
111
|
}
|
|
93
112
|
}
|
|
94
|
-
|
|
95
|
-
var EXAMPLES_REPO_COMMIT = "b88166fa93ec4590c9a27e7b98928ceb12e59f43";
|
|
96
|
-
var EXAMPLE_PATH_IN_REPO = "snaptrude-plugin";
|
|
97
|
-
async function createExampleRepo(targetDir, verbose = true) {
|
|
113
|
+
async function cloneExample(targetDir, verbose) {
|
|
98
114
|
if (verbose) console.log(`Creating example repo in ${targetDir}`);
|
|
99
115
|
const tmpDir = await (0, import_promises.mkdtemp)((0, import_node_path.join)((0, import_node_os.tmpdir)(), "snaptrude-plugin-"));
|
|
100
116
|
if (verbose) console.log(`Create temporary directory for clone: ${tmpDir}`);
|
|
@@ -102,14 +118,11 @@ async function createExampleRepo(targetDir, verbose = true) {
|
|
|
102
118
|
const git = (0, import_simple_git.default)(tmpDir);
|
|
103
119
|
if (verbose) console.log(`Cloning example repo to ${tmpDir}`);
|
|
104
120
|
await git.clone(EXAMPLES_REPO, ".", ["--no-checkout", "--depth=1"]);
|
|
105
|
-
if (verbose)
|
|
106
|
-
console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
121
|
+
if (verbose) console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
107
122
|
await git.fetch(["origin", EXAMPLES_REPO_COMMIT, "--depth=1"]);
|
|
108
|
-
if (verbose)
|
|
109
|
-
console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
123
|
+
if (verbose) console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
110
124
|
await git.checkout(EXAMPLES_REPO_COMMIT);
|
|
111
|
-
if (verbose)
|
|
112
|
-
console.log(`Copying example directory to target: ${targetDir}`);
|
|
125
|
+
if (verbose) console.log(`Copying example directory to target: ${targetDir}`);
|
|
113
126
|
await (0, import_promises.cp)((0, import_node_path.join)(tmpDir, EXAMPLE_PATH_IN_REPO), targetDir, { recursive: true });
|
|
114
127
|
} catch (error) {
|
|
115
128
|
console.error("Error cloning example repo:", error);
|
|
@@ -119,51 +132,277 @@ async function createExampleRepo(targetDir, verbose = true) {
|
|
|
119
132
|
await (0, import_promises.rm)(tmpDir, { recursive: true, force: true });
|
|
120
133
|
}
|
|
121
134
|
}
|
|
122
|
-
async function
|
|
123
|
-
await
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
135
|
+
async function handleCreate(opts) {
|
|
136
|
+
const pluginName = opts.name ?? await askPluginName();
|
|
137
|
+
const pluginDir = (0, import_node_path.join)(process.cwd(), pluginName);
|
|
138
|
+
if (opts.verbose) console.log(`Creating plugin: ${pluginName}`);
|
|
139
|
+
await (0, import_promises.mkdir)(pluginDir, { recursive: true });
|
|
140
|
+
await cloneExample(pluginDir, opts.verbose);
|
|
141
|
+
await removeUnwantedFiles(pluginDir, opts.verbose);
|
|
142
|
+
await updatePkgJson(pluginDir, pluginName);
|
|
143
|
+
console.log(`Plugin "${pluginName}" created successfully in ${pluginDir}`);
|
|
127
144
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
145
|
+
|
|
146
|
+
// src/register.ts
|
|
147
|
+
var import_node_path3 = require("path");
|
|
148
|
+
|
|
149
|
+
// src/shared.ts
|
|
150
|
+
var import_promises2 = require("fs/promises");
|
|
151
|
+
var import_node_path2 = require("path");
|
|
152
|
+
var import_node_crypto2 = require("crypto");
|
|
153
|
+
var import_node_child_process = require("child_process");
|
|
154
|
+
var import_tar = require("tar");
|
|
155
|
+
async function pathExists(p) {
|
|
156
|
+
try {
|
|
157
|
+
await (0, import_promises2.access)(p);
|
|
158
|
+
return true;
|
|
159
|
+
} catch {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
134
162
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
163
|
+
function createBundle(buildDir, entries, verbose) {
|
|
164
|
+
if (verbose) {
|
|
165
|
+
console.log(`Bundling ${entries.length} entries: ${entries.join(", ")}`);
|
|
166
|
+
}
|
|
167
|
+
return new Promise((res, rej) => {
|
|
168
|
+
const chunks = [];
|
|
169
|
+
const stream = (0, import_tar.create)({ gzip: true, cwd: buildDir }, entries);
|
|
170
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
171
|
+
stream.on("end", () => res(Buffer.concat(chunks)));
|
|
172
|
+
stream.on("error", rej);
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function computeChecksum(buffer) {
|
|
176
|
+
return (0, import_node_crypto2.createHash)("sha256").update(buffer).digest("hex");
|
|
177
|
+
}
|
|
178
|
+
function runBuild(verbose) {
|
|
179
|
+
const cmd = `npm run build:prod`;
|
|
180
|
+
console.log(`Building plugin (${cmd})...`);
|
|
181
|
+
try {
|
|
182
|
+
(0, import_node_child_process.execSync)(cmd, {
|
|
183
|
+
cwd: process.cwd(),
|
|
184
|
+
stdio: verbose ? "inherit" : "pipe"
|
|
185
|
+
});
|
|
186
|
+
} catch (err) {
|
|
187
|
+
console.error("Build failed:");
|
|
188
|
+
if (!verbose && err instanceof Error && "stderr" in err) {
|
|
189
|
+
console.error(err.stderr?.toString());
|
|
145
190
|
}
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, visibility) {
|
|
195
|
+
const formData = new FormData();
|
|
196
|
+
formData.append(
|
|
197
|
+
"bundle",
|
|
198
|
+
new Blob([new Uint8Array(tarBuffer)], {
|
|
199
|
+
type: "application/gzip"
|
|
200
|
+
}),
|
|
201
|
+
"bundle.tar.gz"
|
|
202
|
+
);
|
|
203
|
+
formData.append("manifest", JSON.stringify(manifest));
|
|
204
|
+
formData.append("checksum", checksum);
|
|
205
|
+
if (visibility) {
|
|
206
|
+
formData.append("visibility", visibility);
|
|
207
|
+
}
|
|
208
|
+
const res = await fetch(`${apiUrl}/plugins/register`, {
|
|
209
|
+
method: "POST",
|
|
210
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
211
|
+
body: formData
|
|
212
|
+
});
|
|
213
|
+
if (!res.ok) {
|
|
214
|
+
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
215
|
+
console.error(
|
|
216
|
+
`Error registering plugin: ${err.error}`
|
|
217
|
+
);
|
|
218
|
+
process.exit(1);
|
|
219
|
+
}
|
|
220
|
+
return await res.json();
|
|
221
|
+
}
|
|
222
|
+
async function loadManifest(buildDir) {
|
|
223
|
+
const manifestPath = (0, import_node_path2.join)(buildDir, "manifest.json");
|
|
224
|
+
if (!await pathExists(buildDir)) {
|
|
225
|
+
console.error(`Error: Build directory not found: ${buildDir}`);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
if (!await pathExists(manifestPath)) {
|
|
229
|
+
console.error(`Error: manifest.json not found in ${buildDir}`);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
const manifest = JSON.parse(
|
|
233
|
+
await (0, import_promises2.readFile)(manifestPath, "utf8")
|
|
234
|
+
);
|
|
235
|
+
if (!manifest.name || !manifest.version) {
|
|
236
|
+
console.error("Error: manifest.json must contain name and version fields");
|
|
237
|
+
process.exit(1);
|
|
238
|
+
}
|
|
239
|
+
return manifest;
|
|
240
|
+
}
|
|
241
|
+
function resolveAuth(opts) {
|
|
242
|
+
const rawToken = opts.token ?? process.env.SNAPTRUDE_TOKEN;
|
|
243
|
+
const token = rawToken?.startsWith("Bearer ") ? rawToken.slice(7) : rawToken;
|
|
244
|
+
const apiUrl = opts.apiUrl ?? process.env.SNAPTRUDE_API_URL;
|
|
245
|
+
if (!token) {
|
|
246
|
+
console.error(
|
|
247
|
+
"Error: Auth token is required. Use --token <token> or set SNAPTRUDE_TOKEN env var."
|
|
248
|
+
);
|
|
249
|
+
process.exit(1);
|
|
250
|
+
}
|
|
251
|
+
if (!apiUrl) {
|
|
252
|
+
console.error(
|
|
253
|
+
"Error: API URL is required. Use --api-url <url> or set SNAPTRUDE_API_URL env var."
|
|
254
|
+
);
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
return { token, apiUrl };
|
|
258
|
+
}
|
|
259
|
+
async function buildBundle(buildDir, verbose) {
|
|
260
|
+
console.log("Creating bundle...");
|
|
261
|
+
const entries = (await (0, import_promises2.readdir)(buildDir)).filter((e) => e !== "manifest.json");
|
|
262
|
+
if (entries.length === 0) {
|
|
263
|
+
throw new Error("No files to bundle (only manifest.json found)");
|
|
264
|
+
}
|
|
265
|
+
const tarBuffer = await createBundle(buildDir, entries, verbose);
|
|
266
|
+
const checksum = computeChecksum(tarBuffer);
|
|
267
|
+
if (verbose) {
|
|
268
|
+
console.log(
|
|
269
|
+
`Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
return { tarBuffer, checksum, entries };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/register.ts
|
|
276
|
+
async function handleRegister(opts) {
|
|
277
|
+
if (!opts.skipBuild) {
|
|
278
|
+
runBuild(opts.verbose);
|
|
279
|
+
}
|
|
280
|
+
const buildDir = (0, import_node_path3.resolve)(opts.path);
|
|
281
|
+
const { token, apiUrl } = resolveAuth(opts);
|
|
282
|
+
const manifest = await loadManifest(buildDir);
|
|
283
|
+
if (opts.verbose) console.log(`Reading build from: ${buildDir}`);
|
|
284
|
+
const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose);
|
|
285
|
+
console.log("Registering plugin...");
|
|
286
|
+
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility);
|
|
287
|
+
console.log("");
|
|
288
|
+
console.log("Plugin registered successfully!");
|
|
289
|
+
console.log(` ID: ${result.id}`);
|
|
290
|
+
console.log(` Name: ${result.name}`);
|
|
291
|
+
console.log(` Version: ${result.version}`);
|
|
292
|
+
console.log(` Bundle: ${result.bundleUrl}`);
|
|
293
|
+
console.log(` Visibility: ${result.visibility ?? "private"}`);
|
|
294
|
+
console.log(` Status: ${result.reviewStatus}`);
|
|
295
|
+
if (result.reviewStatus === "pending") {
|
|
296
|
+
console.log("");
|
|
297
|
+
console.log("Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.");
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
// src/update.ts
|
|
302
|
+
var import_node_path4 = require("path");
|
|
303
|
+
async function fetchDeployedPlugin(apiUrl, token, pluginId) {
|
|
304
|
+
const res = await fetch(`${apiUrl}/plugins/${pluginId}`, {
|
|
305
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
146
306
|
});
|
|
147
|
-
|
|
307
|
+
if (res.status === 404) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
if (!res.ok) {
|
|
311
|
+
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
312
|
+
console.error(
|
|
313
|
+
`Error fetching plugin: ${err.error}`
|
|
314
|
+
);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
return await res.json();
|
|
148
318
|
}
|
|
319
|
+
function validateManifestId(manifest) {
|
|
320
|
+
if (!manifest.id) {
|
|
321
|
+
console.error(
|
|
322
|
+
"Error: manifest.json must contain an 'id' field for updates. Run 'create-snaptrude-plugin register' first to register a new plugin."
|
|
323
|
+
);
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
async function handleUpdate(opts) {
|
|
328
|
+
if (!opts.skipBuild) {
|
|
329
|
+
runBuild(opts.verbose);
|
|
330
|
+
}
|
|
331
|
+
const buildDir = (0, import_node_path4.resolve)(opts.path);
|
|
332
|
+
const { token, apiUrl } = resolveAuth(opts);
|
|
333
|
+
const manifest = await loadManifest(buildDir);
|
|
334
|
+
validateManifestId(manifest);
|
|
335
|
+
if (opts.verbose) console.log(`Plugin ID: ${manifest.id}`);
|
|
336
|
+
console.log("Checking deployed plugin...");
|
|
337
|
+
const deployed = await fetchDeployedPlugin(apiUrl, token, manifest.id);
|
|
338
|
+
if (!deployed) {
|
|
339
|
+
console.error(
|
|
340
|
+
`Error: No deployed plugin found with ID '${manifest.id}'.
|
|
341
|
+
Use 'create-snaptrude-plugin register' to register a new plugin first.`
|
|
342
|
+
);
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
345
|
+
if (opts.verbose) {
|
|
346
|
+
console.log(`Deployed version: ${deployed.version}, checksum: ${deployed.checksum ?? "none"}`);
|
|
347
|
+
}
|
|
348
|
+
const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose);
|
|
349
|
+
console.log("Updating plugin...");
|
|
350
|
+
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility);
|
|
351
|
+
const bundleChanged = deployed.checksum !== checksum;
|
|
352
|
+
console.log("");
|
|
353
|
+
console.log("Plugin updated successfully!");
|
|
354
|
+
console.log(` ID: ${result.id}`);
|
|
355
|
+
console.log(` Name: ${result.name}`);
|
|
356
|
+
console.log(` Version: ${result.version}`);
|
|
357
|
+
console.log(` Bundle: ${bundleChanged ? "updated" : "unchanged (checksum matched)"}`);
|
|
358
|
+
console.log(` Visibility: ${result.visibility ?? "private"}`);
|
|
359
|
+
console.log(` Status: ${result.reviewStatus}`);
|
|
360
|
+
if (result.reviewStatus === "pending") {
|
|
361
|
+
console.log("");
|
|
362
|
+
console.log("Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.");
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
// src/index.ts
|
|
367
|
+
var CHECK_UPDATE = false;
|
|
149
368
|
async function main() {
|
|
150
369
|
if (CHECK_UPDATE) {
|
|
151
370
|
const update = await (0, import_update_check.default)(package_default);
|
|
152
|
-
if (update)
|
|
371
|
+
if (update) {
|
|
153
372
|
console.log(
|
|
154
373
|
`Update available: ${update.latest} (current: ${package_default.version})`
|
|
155
374
|
);
|
|
375
|
+
}
|
|
156
376
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
377
|
+
const program = new import_extra_typings.Command().name("create-snaptrude-plugin").version(package_default.version).description("Snaptrude plugin CLI \u2014 scaffold and register plugins");
|
|
378
|
+
program.command("create", { isDefault: true }).description("Scaffold a new Snaptrude plugin project").addOption(new import_extra_typings.Option("-v, --verbose", "Verbose output").default(false)).addOption(new import_extra_typings.Option("-n, --name <name>", "Plugin name")).action(handleCreate);
|
|
379
|
+
program.command("register").description("Build, bundle, and register a plugin with Snaptrude").addOption(
|
|
380
|
+
new import_extra_typings.Option("-p, --path <dir>", "Path to the build output directory").default("./dist")
|
|
381
|
+
).addOption(new import_extra_typings.Option("-t, --token <token>", "Auth token (or set SNAPTRUDE_TOKEN env var)")).addOption(
|
|
382
|
+
new import_extra_typings.Option(
|
|
383
|
+
"--api-url <url>",
|
|
384
|
+
"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)"
|
|
385
|
+
).default("http://localhost:6012")
|
|
386
|
+
).addOption(new import_extra_typings.Option("--skip-build", "Skip the build step").default(false)).addOption(
|
|
387
|
+
new import_extra_typings.Option(
|
|
388
|
+
"--visibility <level>",
|
|
389
|
+
"Visibility: private (default) or public"
|
|
390
|
+
).choices(["private", "public"])
|
|
391
|
+
).addOption(new import_extra_typings.Option("-v, --verbose", "Verbose output").default(false)).action(handleRegister);
|
|
392
|
+
program.command("update").description("Update an existing plugin (manifest and bundle)").addOption(
|
|
393
|
+
new import_extra_typings.Option("-p, --path <dir>", "Path to the build output directory").default("./dist")
|
|
394
|
+
).addOption(new import_extra_typings.Option("-t, --token <token>", "Auth token (or set SNAPTRUDE_TOKEN env var)")).addOption(
|
|
395
|
+
new import_extra_typings.Option(
|
|
396
|
+
"--api-url <url>",
|
|
397
|
+
"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)"
|
|
398
|
+
).default("http://localhost:6012")
|
|
399
|
+
).addOption(new import_extra_typings.Option("--skip-build", "Skip the build step").default(false)).addOption(new import_extra_typings.Option("-f, --force", "Force update even if checksum has not changed").default(false)).addOption(
|
|
400
|
+
new import_extra_typings.Option(
|
|
401
|
+
"--visibility <level>",
|
|
402
|
+
"Visibility: private or public"
|
|
403
|
+
).choices(["private", "public"])
|
|
404
|
+
).addOption(new import_extra_typings.Option("-v, --verbose", "Verbose output").default(false)).action(handleUpdate);
|
|
405
|
+
await program.parseAsync();
|
|
167
406
|
}
|
|
168
407
|
main();
|
|
169
408
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\n\nimport { input } from \"@inquirer/prompts\"\nimport packageJson from \"../package.json\"\nimport updateCheck from \"update-check\"\nimport { Command, Option } from \"@commander-js/extra-typings\"\nimport simpleGit from \"simple-git\"\nimport { cp, mkdir, readFile, rm, writeFile, mkdtemp } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { tmpdir } from \"node:os\"\n\n/**\n * Check for updates.\n */\nconst CHECK_UPDATE = false\n\nconst DEFAULT_VERBOSE = false\nconst DEFAULT_PLUGIN_NAME = \"my-plugin\"\n\nasync function updatePackageJson(targetDir: string, pluginName: string) {\n const packageJsonPath = join(targetDir, \"package.json\")\n const packageJson = await readFile(packageJsonPath, \"utf8\")\n const packageJsonObject = JSON.parse(packageJson)\n packageJsonObject.name = pluginName\n await writeFile(packageJsonPath, JSON.stringify(packageJsonObject, null, 2))\n}\n\nconst UNWANTED_DIRS: string[] = []\nconst UNWANTED_FILES: string[] = []\n\nasync function removeUnwantedFiles(targetDir: string, verbose: boolean = true) {\n if (verbose) console.log(`Removing unwanted files from ${targetDir}`)\n for (const dir of UNWANTED_DIRS) {\n await rm(join(targetDir, dir), { recursive: true, force: true })\n }\n for (const file of UNWANTED_FILES) {\n await rm(join(targetDir, file), { force: true })\n }\n}\n\nconst EXAMPLES_REPO =\n \"https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git\"\nconst EXAMPLES_REPO_COMMIT = \"b88166fa93ec4590c9a27e7b98928ceb12e59f43\"\nconst EXAMPLE_PATH_IN_REPO = \"snaptrude-plugin\"\n\nasync function createExampleRepo(targetDir: string, verbose: boolean = true) {\n if (verbose) console.log(`Creating example repo in ${targetDir}`)\n const tmpDir = await mkdtemp(join(tmpdir(), \"snaptrude-plugin-\"))\n if (verbose) console.log(`Create temporary directory for clone: ${tmpDir}`)\n try {\n const git = simpleGit(tmpDir)\n if (verbose) console.log(`Cloning example repo to ${tmpDir}`)\n // Shallow clone the repo into the temp directory\n await git.clone(EXAMPLES_REPO, \".\", [\"--no-checkout\", \"--depth=1\"])\n\n if (verbose)\n console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.fetch([\"origin\", EXAMPLES_REPO_COMMIT, \"--depth=1\"])\n if (verbose)\n console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.checkout(EXAMPLES_REPO_COMMIT)\n if (verbose)\n console.log(`Copying example directory to target: ${targetDir}`)\n await cp(join(tmpDir, EXAMPLE_PATH_IN_REPO), targetDir, { recursive: true })\n } catch (error) {\n console.error(\"Error cloning example repo:\", error)\n throw error\n } finally {\n if (verbose) console.log(`Cleaning up temporary directory: ${tmpDir}`)\n await rm(tmpDir, { recursive: true, force: true })\n }\n}\n\nasync function createPlugin(\n targetDir: string,\n pluginName: string,\n verbose: boolean = true,\n) {\n await createExampleRepo(targetDir, verbose)\n await removeUnwantedFiles(targetDir, verbose)\n await updatePackageJson(targetDir, pluginName)\n if (verbose) console.log(`Plugin created successfully in ${targetDir}`)\n}\n\nasync function runCliMode() {\n const program = new Command()\n .version(packageJson.version)\n .addOption(\n new Option(\"-v, --verbose\", \"Verbose output\").default(DEFAULT_VERBOSE),\n )\n .addOption(new Option(\"-n, --name <name>\", \"The name of the plugin\"))\n program.parse()\n return program.opts()\n}\n\nasync function runInteractiveMode() {\n const pluginName = await input({\n message: \"What is the name of your plugin?\",\n required: true,\n default: DEFAULT_PLUGIN_NAME,\n validate: (value) => {\n if (!/^[a-z0-9-]+$/.test(value)) {\n return \"Plugin name must only contain lowercase letters, numbers, and hyphens\"\n }\n return true\n },\n })\n return { pluginName }\n}\n\nasync function main() {\n if (CHECK_UPDATE) {\n const update = await updateCheck(packageJson)\n if (update)\n console.log(\n `Update available: ${update.latest} (current: ${packageJson.version})`,\n )\n }\n console.log(`${packageJson.name} v${packageJson.version}`)\n\n const cliOpts = await runCliMode()\n const cwd = process.cwd()\n if (cliOpts.verbose) console.log(\"Verbose output enabled\")\n if (cliOpts.verbose) console.log(\"Current working directory:\", cwd)\n const pluginName = cliOpts.name ?? (await runInteractiveMode()).pluginName\n const pluginDir = join(cwd, pluginName)\n if (cliOpts.verbose) console.log(`Creating plugin: ${pluginName}`)\n await mkdir(pluginDir, { recursive: true })\n await createPlugin(pluginDir, pluginName, cliOpts.verbose)\n}\n\nmain()\n","{\n \"name\": \"@snaptrude/create-snaptrude-plugin\",\n \"version\": \"0.0.5\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"create-snaptrude-plugin\": \"dist/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"check-types\": \"tsc --noEmit\",\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"clean-dist\": \"rm -rf dist\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.3.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.5.4\"\n },\n \"dependencies\": {\n \"@commander-js/extra-typings\": \"^14.0.0\",\n \"@inquirer/prompts\": \"^8.3.0\",\n \"commander\": \"^14.0.3\",\n \"simple-git\": \"^3.32.3\",\n \"update-check\": \"^1.5.4\"\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,qBAAsB;;;ACFtB;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,MAAQ;AAAA,EACR,MAAQ;AAAA,EACR,QAAU;AAAA,EACV,OAAS;AAAA,EACT,KAAO;AAAA,IACL,2BAA2B;AAAA,EAC7B;AAAA,EACA,OAAS;AAAA,IACP;AAAA,EACF;AAAA,EACA,eAAiB;AAAA,IACf,QAAU;AAAA,EACZ;AAAA,EACA,SAAW;AAAA,IACT,eAAe;AAAA,IACf,OAAS;AAAA,IACT,KAAO;AAAA,IACP,cAAc;AAAA,EAChB;AAAA,EACA,iBAAmB;AAAA,IACjB,eAAe;AAAA,IACf,MAAQ;AAAA,IACR,YAAc;AAAA,EAChB;AAAA,EACA,cAAgB;AAAA,IACd,+BAA+B;AAAA,IAC/B,qBAAqB;AAAA,IACrB,WAAa;AAAA,IACb,cAAc;AAAA,IACd,gBAAgB;AAAA,EAClB;AACF;;;AD9BA,0BAAwB;AACxB,2BAAgC;AAChC,wBAAsB;AACtB,sBAA4D;AAC5D,uBAAqB;AACrB,qBAAuB;AAKvB,IAAM,eAAe;AAErB,IAAM,kBAAkB;AACxB,IAAM,sBAAsB;AAE5B,eAAe,kBAAkB,WAAmB,YAAoB;AACtE,QAAM,sBAAkB,uBAAK,WAAW,cAAc;AACtD,QAAM,cAAc,UAAM,0BAAS,iBAAiB,MAAM;AAC1D,QAAM,oBAAoB,KAAK,MAAM,WAAW;AAChD,oBAAkB,OAAO;AACzB,YAAM,2BAAU,iBAAiB,KAAK,UAAU,mBAAmB,MAAM,CAAC,CAAC;AAC7E;AAEA,IAAM,gBAA0B,CAAC;AACjC,IAAM,iBAA2B,CAAC;AAElC,eAAe,oBAAoB,WAAmB,UAAmB,MAAM;AAC7E,MAAI,QAAS,SAAQ,IAAI,gCAAgC,SAAS,EAAE;AACpE,aAAW,OAAO,eAAe;AAC/B,cAAM,wBAAG,uBAAK,WAAW,GAAG,GAAG,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACjE;AACA,aAAW,QAAQ,gBAAgB;AACjC,cAAM,wBAAG,uBAAK,WAAW,IAAI,GAAG,EAAE,OAAO,KAAK,CAAC;AAAA,EACjD;AACF;AAEA,IAAM,gBACJ;AACF,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAE7B,eAAe,kBAAkB,WAAmB,UAAmB,MAAM;AAC3E,MAAI,QAAS,SAAQ,IAAI,4BAA4B,SAAS,EAAE;AAChE,QAAM,SAAS,UAAM,6BAAQ,2BAAK,uBAAO,GAAG,mBAAmB,CAAC;AAChE,MAAI,QAAS,SAAQ,IAAI,yCAAyC,MAAM,EAAE;AAC1E,MAAI;AACF,UAAM,UAAM,kBAAAA,SAAU,MAAM;AAC5B,QAAI,QAAS,SAAQ,IAAI,2BAA2B,MAAM,EAAE;AAE5D,UAAM,IAAI,MAAM,eAAe,KAAK,CAAC,iBAAiB,WAAW,CAAC;AAElE,QAAI;AACF,cAAQ,IAAI,6BAA6B,oBAAoB,EAAE;AACjE,UAAM,IAAI,MAAM,CAAC,UAAU,sBAAsB,WAAW,CAAC;AAC7D,QAAI;AACF,cAAQ,IAAI,iCAAiC,oBAAoB,EAAE;AACrE,UAAM,IAAI,SAAS,oBAAoB;AACvC,QAAI;AACF,cAAQ,IAAI,wCAAwC,SAAS,EAAE;AACjE,cAAM,wBAAG,uBAAK,QAAQ,oBAAoB,GAAG,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,EAC7E,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAM;AAAA,EACR,UAAE;AACA,QAAI,QAAS,SAAQ,IAAI,oCAAoC,MAAM,EAAE;AACrE,cAAM,oBAAG,QAAQ,EAAE,WAAW,MAAM,OAAO,KAAK,CAAC;AAAA,EACnD;AACF;AAEA,eAAe,aACb,WACA,YACA,UAAmB,MACnB;AACA,QAAM,kBAAkB,WAAW,OAAO;AAC1C,QAAM,oBAAoB,WAAW,OAAO;AAC5C,QAAM,kBAAkB,WAAW,UAAU;AAC7C,MAAI,QAAS,SAAQ,IAAI,kCAAkC,SAAS,EAAE;AACxE;AAEA,eAAe,aAAa;AAC1B,QAAM,UAAU,IAAI,6BAAQ,EACzB,QAAQ,gBAAY,OAAO,EAC3B;AAAA,IACC,IAAI,4BAAO,iBAAiB,gBAAgB,EAAE,QAAQ,eAAe;AAAA,EACvE,EACC,UAAU,IAAI,4BAAO,qBAAqB,wBAAwB,CAAC;AACtE,UAAQ,MAAM;AACd,SAAO,QAAQ,KAAK;AACtB;AAEA,eAAe,qBAAqB;AAClC,QAAM,aAAa,UAAM,sBAAM;AAAA,IAC7B,SAAS;AAAA,IACT,UAAU;AAAA,IACV,SAAS;AAAA,IACT,UAAU,CAAC,UAAU;AACnB,UAAI,CAAC,eAAe,KAAK,KAAK,GAAG;AAC/B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,EACF,CAAC;AACD,SAAO,EAAE,WAAW;AACtB;AAEA,eAAe,OAAO;AACpB,MAAI,cAAc;AAChB,UAAM,SAAS,UAAM,oBAAAC,SAAY,eAAW;AAC5C,QAAI;AACF,cAAQ;AAAA,QACN,qBAAqB,OAAO,MAAM,cAAc,gBAAY,OAAO;AAAA,MACrE;AAAA,EACJ;AACA,UAAQ,IAAI,GAAG,gBAAY,IAAI,KAAK,gBAAY,OAAO,EAAE;AAEzD,QAAM,UAAU,MAAM,WAAW;AACjC,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,QAAQ,QAAS,SAAQ,IAAI,wBAAwB;AACzD,MAAI,QAAQ,QAAS,SAAQ,IAAI,8BAA8B,GAAG;AAClE,QAAM,aAAa,QAAQ,SAAS,MAAM,mBAAmB,GAAG;AAChE,QAAM,gBAAY,uBAAK,KAAK,UAAU;AACtC,MAAI,QAAQ,QAAS,SAAQ,IAAI,oBAAoB,UAAU,EAAE;AACjE,YAAM,uBAAM,WAAW,EAAE,WAAW,KAAK,CAAC;AAC1C,QAAM,aAAa,WAAW,YAAY,QAAQ,OAAO;AAC3D;AAEA,KAAK;","names":["simpleGit","updateCheck"]}
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/index.ts","../src/create.ts","../src/register.ts","../src/shared.ts","../src/update.ts"],"sourcesContent":["{\n \"name\": \"@snaptrude/create-snaptrude-plugin\",\n \"version\": \"0.0.7\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"create-snaptrude-plugin\": \"dist/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"check-types\": \"tsc --noEmit\",\n \"build\": \"tsup --clean\",\n \"dev\": \"tsup --watch\",\n \"clean-dist\": \"rm -rf dist\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.3.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.5.4\",\n \"vitest\": \"^4.1.0\"\n },\n \"dependencies\": {\n \"@commander-js/extra-typings\": \"^14.0.0\",\n \"@inquirer/prompts\": \"^8.3.0\",\n \"commander\": \"^14.0.3\",\n \"simple-git\": \"^3.32.3\",\n \"tar\": \"^7.5.11\",\n \"update-check\": \"^1.5.4\"\n }\n}\n","#!/usr/bin/env node\n\nimport packageJson from \"../package.json\"\nimport updateCheck from \"update-check\"\nimport { Command, Option } from \"@commander-js/extra-typings\"\nimport { handleCreate } from \"./create\"\nimport { handleRegister } from \"./register\"\nimport { handleUpdate } from \"./update\"\n\nconst CHECK_UPDATE = false\n\nasync function main() {\n if (CHECK_UPDATE) {\n const update = await updateCheck(packageJson)\n if (update) {\n console.log(\n `Update available: ${update.latest} (current: ${packageJson.version})`,\n )\n }\n }\n\n const program = new Command()\n .name(\"create-snaptrude-plugin\")\n .version(packageJson.version)\n .description(\"Snaptrude plugin CLI — scaffold and register plugins\")\n\n program\n .command(\"create\", { isDefault: true })\n .description(\"Scaffold a new Snaptrude plugin project\")\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .addOption(new Option(\"-n, --name <name>\", \"Plugin name\"))\n .action(handleCreate)\n\n program\n .command(\"register\")\n .description(\"Build, bundle, and register a plugin with Snaptrude\")\n .addOption(\n new Option(\"-p, --path <dir>\", \"Path to the build output directory\").default(\"./dist\"),\n )\n .addOption(new Option(\"-t, --token <token>\", \"Auth token (or set SNAPTRUDE_TOKEN env var)\"))\n .addOption(\n new Option(\n \"--api-url <url>\",\n \"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)\",\n ).default(\"http://localhost:6012\"),\n )\n .addOption(new Option(\"--skip-build\", \"Skip the build step\").default(false))\n .addOption(\n new Option(\n \"--visibility <level>\",\n \"Visibility: private (default) or public\",\n ).choices([\"private\", \"public\"]),\n )\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .action(handleRegister)\n\n program\n .command(\"update\")\n .description(\"Update an existing plugin (manifest and bundle)\")\n .addOption(\n new Option(\"-p, --path <dir>\", \"Path to the build output directory\").default(\"./dist\"),\n )\n .addOption(new Option(\"-t, --token <token>\", \"Auth token (or set SNAPTRUDE_TOKEN env var)\"))\n .addOption(\n new Option(\n \"--api-url <url>\",\n \"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)\",\n ).default(\"http://localhost:6012\"),\n )\n .addOption(new Option(\"--skip-build\", \"Skip the build step\").default(false))\n .addOption(new Option(\"-f, --force\", \"Force update even if checksum has not changed\").default(false))\n .addOption(\n new Option(\n \"--visibility <level>\",\n \"Visibility: private or public\",\n ).choices([\"private\", \"public\"]),\n )\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .action(handleUpdate)\n\n await program.parseAsync()\n}\n\nmain()\n","import { input } from \"@inquirer/prompts\"\nimport simpleGit from \"simple-git\"\nimport { cp, mkdir, readFile, rm, writeFile, mkdtemp } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { tmpdir } from \"node:os\"\nimport { randomUUID } from \"node:crypto\"\n\nconst DEFAULT_PLUGIN_NAME = \"my-plugin\"\n\nconst EXAMPLES_REPO =\n \"https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git\"\nconst EXAMPLES_REPO_COMMIT = \"bdc80a1a830396ee29a576ea67ef7482888c1468\"\nconst EXAMPLE_PATH_IN_REPO = \"snaptrude-plugin\"\n\nconst UNWANTED_DIRS: string[] = []\nconst UNWANTED_FILES: string[] = []\n\nasync function askPluginName(): Promise<string> {\n return input({\n message: \"What is the name of your plugin?\",\n required: true,\n default: DEFAULT_PLUGIN_NAME,\n validate: (value) => {\n if (!/^[a-z0-9-]+$/.test(value)) {\n return \"Plugin name must only contain lowercase letters, numbers, and hyphens\"\n }\n return true\n },\n })\n}\n\nasync function updatePkgJson(targetDir: string, pluginName: string) {\n const pkgPath = join(targetDir, \"package.json\")\n const pkg = JSON.parse(await readFile(pkgPath, \"utf8\"))\n pkg.name = pluginName\n pkg.id = randomUUID()\n await writeFile(pkgPath, JSON.stringify(pkg, null, 2))\n}\n\nasync function removeUnwantedFiles(targetDir: string, verbose: boolean) {\n if (verbose) console.log(`Removing unwanted files from ${targetDir}`)\n for (const dir of UNWANTED_DIRS) {\n await rm(join(targetDir, dir), { recursive: true, force: true })\n }\n for (const file of UNWANTED_FILES) {\n await rm(join(targetDir, file), { force: true })\n }\n}\n\nasync function cloneExample(targetDir: string, verbose: boolean) {\n if (verbose) console.log(`Creating example repo in ${targetDir}`)\n const tmpDir = await mkdtemp(join(tmpdir(), \"snaptrude-plugin-\"))\n if (verbose) console.log(`Create temporary directory for clone: ${tmpDir}`)\n try {\n const git = simpleGit(tmpDir)\n if (verbose) console.log(`Cloning example repo to ${tmpDir}`)\n await git.clone(EXAMPLES_REPO, \".\", [\"--no-checkout\", \"--depth=1\"])\n if (verbose) console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.fetch([\"origin\", EXAMPLES_REPO_COMMIT, \"--depth=1\"])\n if (verbose) console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.checkout(EXAMPLES_REPO_COMMIT)\n if (verbose) console.log(`Copying example directory to target: ${targetDir}`)\n await cp(join(tmpDir, EXAMPLE_PATH_IN_REPO), targetDir, { recursive: true })\n } catch (error) {\n console.error(\"Error cloning example repo:\", error)\n throw error\n } finally {\n if (verbose) console.log(`Cleaning up temporary directory: ${tmpDir}`)\n await rm(tmpDir, { recursive: true, force: true })\n }\n}\n\nexport async function handleCreate(opts: { verbose: boolean; name?: string }) {\n const pluginName = opts.name ?? (await askPluginName())\n const pluginDir = join(process.cwd(), pluginName)\n\n if (opts.verbose) console.log(`Creating plugin: ${pluginName}`)\n await mkdir(pluginDir, { recursive: true })\n await cloneExample(pluginDir, opts.verbose)\n await removeUnwantedFiles(pluginDir, opts.verbose)\n await updatePkgJson(pluginDir, pluginName)\n\n console.log(`Plugin \"${pluginName}\" created successfully in ${pluginDir}`)\n}\n","import { resolve } from \"node:path\"\nimport {\n runBuild,\n loadManifest,\n resolveAuth,\n buildBundle,\n uploadBundle,\n} from \"./shared\"\n\nexport async function handleRegister(opts: {\n path: string\n token?: string\n apiUrl: string\n verbose: boolean\n skipBuild: boolean\n visibility?: string\n}) {\n if (!opts.skipBuild) {\n runBuild(opts.verbose)\n }\n\n const buildDir = resolve(opts.path)\n const { token, apiUrl } = resolveAuth(opts)\n const manifest = await loadManifest(buildDir)\n\n if (opts.verbose) console.log(`Reading build from: ${buildDir}`)\n\n const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose)\n\n console.log(\"Registering plugin...\")\n const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility)\n\n console.log(\"\")\n console.log(\"Plugin registered successfully!\")\n console.log(` ID: ${result.id}`)\n console.log(` Name: ${result.name}`)\n console.log(` Version: ${result.version}`)\n console.log(` Bundle: ${result.bundleUrl}`)\n console.log(` Visibility: ${result.visibility ?? \"private\"}`)\n console.log(` Status: ${result.reviewStatus}`)\n\n if (result.reviewStatus === \"pending\") {\n console.log(\"\")\n console.log(\"Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.\")\n }\n}\n","import { readFile, readdir, access } from \"node:fs/promises\"\nimport { join, resolve } from \"node:path\"\nimport { createHash } from \"node:crypto\"\nimport { execSync } from \"node:child_process\"\nimport { create as tarCreate } from \"tar\"\n\nexport interface PluginManifest {\n name: string\n version: string\n description?: string\n apiVersion?: string\n workerUrl?: string\n uiUrl?: string\n id?: string\n bundleUrl?: string\n checksum?: string\n [key: string]: unknown\n}\n\nexport interface RegisterResult {\n id: string\n name: string\n version: string\n bundleUrl: string\n reviewStatus: string\n visibility?: string\n}\n\nexport async function pathExists(p: string): Promise<boolean> {\n try {\n await access(p)\n return true\n } catch {\n return false\n }\n}\n\nexport function createBundle(\n buildDir: string,\n entries: string[],\n verbose: boolean,\n): Promise<Buffer> {\n if (verbose) {\n console.log(`Bundling ${entries.length} entries: ${entries.join(\", \")}`)\n }\n\n return new Promise<Buffer>((res, rej) => {\n const chunks: Buffer[] = []\n const stream = tarCreate({ gzip: true, cwd: buildDir }, entries)\n stream.on(\"data\", (chunk: Buffer) => chunks.push(chunk))\n stream.on(\"end\", () => res(Buffer.concat(chunks)))\n stream.on(\"error\", rej)\n })\n}\n\nexport function computeChecksum(buffer: Buffer): string {\n return createHash(\"sha256\").update(buffer).digest(\"hex\")\n}\n\nexport function runBuild(verbose: boolean) {\n const cmd = `npm run build:prod`\n console.log(`Building plugin (${cmd})...`)\n try {\n execSync(cmd, {\n cwd: process.cwd(),\n stdio: verbose ? \"inherit\" : \"pipe\",\n })\n } catch (err) {\n console.error(\"Build failed:\")\n if (!verbose && err instanceof Error && \"stderr\" in err) {\n console.error((err as { stderr: Buffer }).stderr?.toString())\n }\n process.exit(1)\n }\n}\n\nexport async function uploadBundle(\n apiUrl: string,\n token: string,\n manifest: PluginManifest,\n tarBuffer: Buffer,\n checksum: string,\n visibility?: string,\n): Promise<RegisterResult> {\n const formData = new FormData()\n formData.append(\n \"bundle\",\n new Blob([new Uint8Array(tarBuffer) as unknown as ArrayBuffer], {\n type: \"application/gzip\",\n }),\n \"bundle.tar.gz\",\n )\n formData.append(\"manifest\", JSON.stringify(manifest))\n formData.append(\"checksum\", checksum)\n\n if (visibility) {\n formData.append(\"visibility\", visibility)\n }\n\n const res = await fetch(`${apiUrl}/plugins/register`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}` },\n body: formData,\n })\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: res.statusText }))\n console.error(\n `Error registering plugin: ${(err as { error: string }).error}`,\n )\n process.exit(1)\n }\n\n return (await res.json()) as RegisterResult\n}\n\nexport async function loadManifest(buildDir: string): Promise<PluginManifest> {\n const manifestPath = join(buildDir, \"manifest.json\")\n if (!(await pathExists(buildDir))) {\n console.error(`Error: Build directory not found: ${buildDir}`)\n process.exit(1)\n }\n if (!(await pathExists(manifestPath))) {\n console.error(`Error: manifest.json not found in ${buildDir}`)\n process.exit(1)\n }\n\n const manifest: PluginManifest = JSON.parse(\n await readFile(manifestPath, \"utf8\"),\n )\n if (!manifest.name || !manifest.version) {\n console.error(\"Error: manifest.json must contain name and version fields\")\n process.exit(1)\n }\n\n return manifest\n}\n\nexport function resolveAuth(opts: { token?: string; apiUrl: string }) {\n const rawToken = opts.token ?? process.env.SNAPTRUDE_TOKEN\n const token = rawToken?.startsWith(\"Bearer \") ? rawToken.slice(7) : rawToken\n const apiUrl = opts.apiUrl ?? process.env.SNAPTRUDE_API_URL\n\n if (!token) {\n console.error(\n \"Error: Auth token is required. Use --token <token> or set SNAPTRUDE_TOKEN env var.\",\n )\n process.exit(1)\n }\n if (!apiUrl) {\n console.error(\n \"Error: API URL is required. Use --api-url <url> or set SNAPTRUDE_API_URL env var.\",\n )\n process.exit(1)\n }\n\n return { token, apiUrl }\n}\n\nexport async function buildBundle(\n buildDir: string,\n verbose: boolean,\n): Promise<{ tarBuffer: Buffer; checksum: string; entries: string[] }> {\n console.log(\"Creating bundle...\")\n const entries = (await readdir(buildDir)).filter((e) => e !== \"manifest.json\")\n if (entries.length === 0) {\n throw new Error(\"No files to bundle (only manifest.json found)\")\n }\n\n const tarBuffer = await createBundle(buildDir, entries, verbose)\n const checksum = computeChecksum(tarBuffer)\n if (verbose) {\n console.log(\n `Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`,\n )\n }\n\n return { tarBuffer, checksum, entries }\n}\n","import { resolve } from \"node:path\"\nimport type { PluginManifest } from \"./shared\"\nimport {\n runBuild,\n loadManifest,\n resolveAuth,\n buildBundle,\n uploadBundle,\n} from \"./shared\"\n\ninterface DeployedPlugin {\n id: string\n name: string\n version: string\n bundleUrl?: string\n checksum?: string\n visibility?: string\n [key: string]: unknown\n}\n\nexport async function fetchDeployedPlugin(\n apiUrl: string,\n token: string,\n pluginId: string,\n): Promise<DeployedPlugin | null> {\n const res = await fetch(`${apiUrl}/plugins/${pluginId}`, {\n headers: { Authorization: `Bearer ${token}` },\n })\n\n if (res.status === 404) {\n return null\n }\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: res.statusText }))\n console.error(\n `Error fetching plugin: ${(err as { error: string }).error}`,\n )\n process.exit(1)\n }\n\n return (await res.json()) as DeployedPlugin\n}\n\nexport function validateManifestId(\n manifest: PluginManifest,\n): asserts manifest is PluginManifest & { id: string } {\n if (!manifest.id) {\n console.error(\n \"Error: manifest.json must contain an 'id' field for updates. \" +\n \"Run 'create-snaptrude-plugin register' first to register a new plugin.\",\n )\n process.exit(1)\n }\n}\n\nexport async function handleUpdate(opts: {\n path: string\n token?: string\n apiUrl: string\n verbose: boolean\n skipBuild: boolean\n force: boolean\n visibility?: string\n}) {\n if (!opts.skipBuild) {\n runBuild(opts.verbose)\n }\n\n const buildDir = resolve(opts.path)\n const { token, apiUrl } = resolveAuth(opts)\n const manifest = await loadManifest(buildDir)\n\n validateManifestId(manifest)\n\n if (opts.verbose) console.log(`Plugin ID: ${manifest.id}`)\n\n console.log(\"Checking deployed plugin...\")\n const deployed = await fetchDeployedPlugin(apiUrl, token, manifest.id)\n\n if (!deployed) {\n console.error(\n `Error: No deployed plugin found with ID '${manifest.id}'.\\n` +\n \"Use 'create-snaptrude-plugin register' to register a new plugin first.\",\n )\n process.exit(1)\n }\n\n if (opts.verbose) {\n console.log(`Deployed version: ${deployed.version}, checksum: ${deployed.checksum ?? \"none\"}`)\n }\n\n const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose)\n\n console.log(\"Updating plugin...\")\n const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility)\n\n const bundleChanged = deployed.checksum !== checksum\n\n console.log(\"\")\n console.log(\"Plugin updated successfully!\")\n console.log(` ID: ${result.id}`)\n console.log(` Name: ${result.name}`)\n console.log(` Version: ${result.version}`)\n console.log(` Bundle: ${bundleChanged ? \"updated\" : \"unchanged (checksum matched)\"}`)\n console.log(` Visibility: ${result.visibility ?? \"private\"}`)\n console.log(` Status: ${result.reviewStatus}`)\n\n if (result.reviewStatus === \"pending\") {\n console.log(\"\")\n console.log(\"Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.\")\n }\n}\n"],"mappings":"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","names":["simpleGit","import_node_path","import_promises","import_node_path","import_node_crypto","tarCreate","import_node_path","updateCheck"]}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// src/index.ts
|
|
4
|
-
import { input } from "@inquirer/prompts";
|
|
5
|
-
|
|
6
3
|
// package.json
|
|
7
4
|
var package_default = {
|
|
8
5
|
name: "@snaptrude/create-snaptrude-plugin",
|
|
9
|
-
version: "0.0.
|
|
6
|
+
version: "0.0.7",
|
|
10
7
|
type: "module",
|
|
11
8
|
main: "./dist/index.js",
|
|
12
9
|
module: "./dist/index.js",
|
|
@@ -22,20 +19,24 @@ var package_default = {
|
|
|
22
19
|
},
|
|
23
20
|
scripts: {
|
|
24
21
|
"check-types": "tsc --noEmit",
|
|
25
|
-
build: "tsup",
|
|
22
|
+
build: "tsup --clean",
|
|
26
23
|
dev: "tsup --watch",
|
|
27
|
-
"clean-dist": "rm -rf dist"
|
|
24
|
+
"clean-dist": "rm -rf dist",
|
|
25
|
+
test: "vitest run",
|
|
26
|
+
"test:watch": "vitest"
|
|
28
27
|
},
|
|
29
28
|
devDependencies: {
|
|
30
29
|
"@types/node": "^25.3.5",
|
|
31
30
|
tsup: "^8.5.1",
|
|
32
|
-
typescript: "^5.5.4"
|
|
31
|
+
typescript: "^5.5.4",
|
|
32
|
+
vitest: "^4.1.0"
|
|
33
33
|
},
|
|
34
34
|
dependencies: {
|
|
35
35
|
"@commander-js/extra-typings": "^14.0.0",
|
|
36
36
|
"@inquirer/prompts": "^8.3.0",
|
|
37
37
|
commander: "^14.0.3",
|
|
38
38
|
"simple-git": "^3.32.3",
|
|
39
|
+
tar: "^7.5.11",
|
|
39
40
|
"update-check": "^1.5.4"
|
|
40
41
|
}
|
|
41
42
|
};
|
|
@@ -43,23 +44,41 @@ var package_default = {
|
|
|
43
44
|
// src/index.ts
|
|
44
45
|
import updateCheck from "update-check";
|
|
45
46
|
import { Command, Option } from "@commander-js/extra-typings";
|
|
47
|
+
|
|
48
|
+
// src/create.ts
|
|
49
|
+
import { input } from "@inquirer/prompts";
|
|
46
50
|
import simpleGit from "simple-git";
|
|
47
51
|
import { cp, mkdir, readFile, rm, writeFile, mkdtemp } from "fs/promises";
|
|
48
52
|
import { join } from "path";
|
|
49
53
|
import { tmpdir } from "os";
|
|
50
|
-
|
|
51
|
-
var DEFAULT_VERBOSE = false;
|
|
54
|
+
import { randomUUID } from "crypto";
|
|
52
55
|
var DEFAULT_PLUGIN_NAME = "my-plugin";
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const packageJsonObject = JSON.parse(packageJson);
|
|
57
|
-
packageJsonObject.name = pluginName;
|
|
58
|
-
await writeFile(packageJsonPath, JSON.stringify(packageJsonObject, null, 2));
|
|
59
|
-
}
|
|
56
|
+
var EXAMPLES_REPO = "https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git";
|
|
57
|
+
var EXAMPLES_REPO_COMMIT = "bdc80a1a830396ee29a576ea67ef7482888c1468";
|
|
58
|
+
var EXAMPLE_PATH_IN_REPO = "snaptrude-plugin";
|
|
60
59
|
var UNWANTED_DIRS = [];
|
|
61
60
|
var UNWANTED_FILES = [];
|
|
62
|
-
async function
|
|
61
|
+
async function askPluginName() {
|
|
62
|
+
return input({
|
|
63
|
+
message: "What is the name of your plugin?",
|
|
64
|
+
required: true,
|
|
65
|
+
default: DEFAULT_PLUGIN_NAME,
|
|
66
|
+
validate: (value) => {
|
|
67
|
+
if (!/^[a-z0-9-]+$/.test(value)) {
|
|
68
|
+
return "Plugin name must only contain lowercase letters, numbers, and hyphens";
|
|
69
|
+
}
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async function updatePkgJson(targetDir, pluginName) {
|
|
75
|
+
const pkgPath = join(targetDir, "package.json");
|
|
76
|
+
const pkg = JSON.parse(await readFile(pkgPath, "utf8"));
|
|
77
|
+
pkg.name = pluginName;
|
|
78
|
+
pkg.id = randomUUID();
|
|
79
|
+
await writeFile(pkgPath, JSON.stringify(pkg, null, 2));
|
|
80
|
+
}
|
|
81
|
+
async function removeUnwantedFiles(targetDir, verbose) {
|
|
63
82
|
if (verbose) console.log(`Removing unwanted files from ${targetDir}`);
|
|
64
83
|
for (const dir of UNWANTED_DIRS) {
|
|
65
84
|
await rm(join(targetDir, dir), { recursive: true, force: true });
|
|
@@ -68,10 +87,7 @@ async function removeUnwantedFiles(targetDir, verbose = true) {
|
|
|
68
87
|
await rm(join(targetDir, file), { force: true });
|
|
69
88
|
}
|
|
70
89
|
}
|
|
71
|
-
|
|
72
|
-
var EXAMPLES_REPO_COMMIT = "b88166fa93ec4590c9a27e7b98928ceb12e59f43";
|
|
73
|
-
var EXAMPLE_PATH_IN_REPO = "snaptrude-plugin";
|
|
74
|
-
async function createExampleRepo(targetDir, verbose = true) {
|
|
90
|
+
async function cloneExample(targetDir, verbose) {
|
|
75
91
|
if (verbose) console.log(`Creating example repo in ${targetDir}`);
|
|
76
92
|
const tmpDir = await mkdtemp(join(tmpdir(), "snaptrude-plugin-"));
|
|
77
93
|
if (verbose) console.log(`Create temporary directory for clone: ${tmpDir}`);
|
|
@@ -79,14 +95,11 @@ async function createExampleRepo(targetDir, verbose = true) {
|
|
|
79
95
|
const git = simpleGit(tmpDir);
|
|
80
96
|
if (verbose) console.log(`Cloning example repo to ${tmpDir}`);
|
|
81
97
|
await git.clone(EXAMPLES_REPO, ".", ["--no-checkout", "--depth=1"]);
|
|
82
|
-
if (verbose)
|
|
83
|
-
console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
98
|
+
if (verbose) console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
84
99
|
await git.fetch(["origin", EXAMPLES_REPO_COMMIT, "--depth=1"]);
|
|
85
|
-
if (verbose)
|
|
86
|
-
console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
100
|
+
if (verbose) console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`);
|
|
87
101
|
await git.checkout(EXAMPLES_REPO_COMMIT);
|
|
88
|
-
if (verbose)
|
|
89
|
-
console.log(`Copying example directory to target: ${targetDir}`);
|
|
102
|
+
if (verbose) console.log(`Copying example directory to target: ${targetDir}`);
|
|
90
103
|
await cp(join(tmpDir, EXAMPLE_PATH_IN_REPO), targetDir, { recursive: true });
|
|
91
104
|
} catch (error) {
|
|
92
105
|
console.error("Error cloning example repo:", error);
|
|
@@ -96,51 +109,277 @@ async function createExampleRepo(targetDir, verbose = true) {
|
|
|
96
109
|
await rm(tmpDir, { recursive: true, force: true });
|
|
97
110
|
}
|
|
98
111
|
}
|
|
99
|
-
async function
|
|
100
|
-
await
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
112
|
+
async function handleCreate(opts) {
|
|
113
|
+
const pluginName = opts.name ?? await askPluginName();
|
|
114
|
+
const pluginDir = join(process.cwd(), pluginName);
|
|
115
|
+
if (opts.verbose) console.log(`Creating plugin: ${pluginName}`);
|
|
116
|
+
await mkdir(pluginDir, { recursive: true });
|
|
117
|
+
await cloneExample(pluginDir, opts.verbose);
|
|
118
|
+
await removeUnwantedFiles(pluginDir, opts.verbose);
|
|
119
|
+
await updatePkgJson(pluginDir, pluginName);
|
|
120
|
+
console.log(`Plugin "${pluginName}" created successfully in ${pluginDir}`);
|
|
104
121
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
|
|
123
|
+
// src/register.ts
|
|
124
|
+
import { resolve as resolve2 } from "path";
|
|
125
|
+
|
|
126
|
+
// src/shared.ts
|
|
127
|
+
import { readFile as readFile2, readdir, access } from "fs/promises";
|
|
128
|
+
import { join as join2 } from "path";
|
|
129
|
+
import { createHash } from "crypto";
|
|
130
|
+
import { execSync } from "child_process";
|
|
131
|
+
import { create as tarCreate } from "tar";
|
|
132
|
+
async function pathExists(p) {
|
|
133
|
+
try {
|
|
134
|
+
await access(p);
|
|
135
|
+
return true;
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
111
139
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
140
|
+
function createBundle(buildDir, entries, verbose) {
|
|
141
|
+
if (verbose) {
|
|
142
|
+
console.log(`Bundling ${entries.length} entries: ${entries.join(", ")}`);
|
|
143
|
+
}
|
|
144
|
+
return new Promise((res, rej) => {
|
|
145
|
+
const chunks = [];
|
|
146
|
+
const stream = tarCreate({ gzip: true, cwd: buildDir }, entries);
|
|
147
|
+
stream.on("data", (chunk) => chunks.push(chunk));
|
|
148
|
+
stream.on("end", () => res(Buffer.concat(chunks)));
|
|
149
|
+
stream.on("error", rej);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
function computeChecksum(buffer) {
|
|
153
|
+
return createHash("sha256").update(buffer).digest("hex");
|
|
154
|
+
}
|
|
155
|
+
function runBuild(verbose) {
|
|
156
|
+
const cmd = `npm run build:prod`;
|
|
157
|
+
console.log(`Building plugin (${cmd})...`);
|
|
158
|
+
try {
|
|
159
|
+
execSync(cmd, {
|
|
160
|
+
cwd: process.cwd(),
|
|
161
|
+
stdio: verbose ? "inherit" : "pipe"
|
|
162
|
+
});
|
|
163
|
+
} catch (err) {
|
|
164
|
+
console.error("Build failed:");
|
|
165
|
+
if (!verbose && err instanceof Error && "stderr" in err) {
|
|
166
|
+
console.error(err.stderr?.toString());
|
|
122
167
|
}
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, visibility) {
|
|
172
|
+
const formData = new FormData();
|
|
173
|
+
formData.append(
|
|
174
|
+
"bundle",
|
|
175
|
+
new Blob([new Uint8Array(tarBuffer)], {
|
|
176
|
+
type: "application/gzip"
|
|
177
|
+
}),
|
|
178
|
+
"bundle.tar.gz"
|
|
179
|
+
);
|
|
180
|
+
formData.append("manifest", JSON.stringify(manifest));
|
|
181
|
+
formData.append("checksum", checksum);
|
|
182
|
+
if (visibility) {
|
|
183
|
+
formData.append("visibility", visibility);
|
|
184
|
+
}
|
|
185
|
+
const res = await fetch(`${apiUrl}/plugins/register`, {
|
|
186
|
+
method: "POST",
|
|
187
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
188
|
+
body: formData
|
|
189
|
+
});
|
|
190
|
+
if (!res.ok) {
|
|
191
|
+
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
192
|
+
console.error(
|
|
193
|
+
`Error registering plugin: ${err.error}`
|
|
194
|
+
);
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
return await res.json();
|
|
198
|
+
}
|
|
199
|
+
async function loadManifest(buildDir) {
|
|
200
|
+
const manifestPath = join2(buildDir, "manifest.json");
|
|
201
|
+
if (!await pathExists(buildDir)) {
|
|
202
|
+
console.error(`Error: Build directory not found: ${buildDir}`);
|
|
203
|
+
process.exit(1);
|
|
204
|
+
}
|
|
205
|
+
if (!await pathExists(manifestPath)) {
|
|
206
|
+
console.error(`Error: manifest.json not found in ${buildDir}`);
|
|
207
|
+
process.exit(1);
|
|
208
|
+
}
|
|
209
|
+
const manifest = JSON.parse(
|
|
210
|
+
await readFile2(manifestPath, "utf8")
|
|
211
|
+
);
|
|
212
|
+
if (!manifest.name || !manifest.version) {
|
|
213
|
+
console.error("Error: manifest.json must contain name and version fields");
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
return manifest;
|
|
217
|
+
}
|
|
218
|
+
function resolveAuth(opts) {
|
|
219
|
+
const rawToken = opts.token ?? process.env.SNAPTRUDE_TOKEN;
|
|
220
|
+
const token = rawToken?.startsWith("Bearer ") ? rawToken.slice(7) : rawToken;
|
|
221
|
+
const apiUrl = opts.apiUrl ?? process.env.SNAPTRUDE_API_URL;
|
|
222
|
+
if (!token) {
|
|
223
|
+
console.error(
|
|
224
|
+
"Error: Auth token is required. Use --token <token> or set SNAPTRUDE_TOKEN env var."
|
|
225
|
+
);
|
|
226
|
+
process.exit(1);
|
|
227
|
+
}
|
|
228
|
+
if (!apiUrl) {
|
|
229
|
+
console.error(
|
|
230
|
+
"Error: API URL is required. Use --api-url <url> or set SNAPTRUDE_API_URL env var."
|
|
231
|
+
);
|
|
232
|
+
process.exit(1);
|
|
233
|
+
}
|
|
234
|
+
return { token, apiUrl };
|
|
235
|
+
}
|
|
236
|
+
async function buildBundle(buildDir, verbose) {
|
|
237
|
+
console.log("Creating bundle...");
|
|
238
|
+
const entries = (await readdir(buildDir)).filter((e) => e !== "manifest.json");
|
|
239
|
+
if (entries.length === 0) {
|
|
240
|
+
throw new Error("No files to bundle (only manifest.json found)");
|
|
241
|
+
}
|
|
242
|
+
const tarBuffer = await createBundle(buildDir, entries, verbose);
|
|
243
|
+
const checksum = computeChecksum(tarBuffer);
|
|
244
|
+
if (verbose) {
|
|
245
|
+
console.log(
|
|
246
|
+
`Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
return { tarBuffer, checksum, entries };
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/register.ts
|
|
253
|
+
async function handleRegister(opts) {
|
|
254
|
+
if (!opts.skipBuild) {
|
|
255
|
+
runBuild(opts.verbose);
|
|
256
|
+
}
|
|
257
|
+
const buildDir = resolve2(opts.path);
|
|
258
|
+
const { token, apiUrl } = resolveAuth(opts);
|
|
259
|
+
const manifest = await loadManifest(buildDir);
|
|
260
|
+
if (opts.verbose) console.log(`Reading build from: ${buildDir}`);
|
|
261
|
+
const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose);
|
|
262
|
+
console.log("Registering plugin...");
|
|
263
|
+
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility);
|
|
264
|
+
console.log("");
|
|
265
|
+
console.log("Plugin registered successfully!");
|
|
266
|
+
console.log(` ID: ${result.id}`);
|
|
267
|
+
console.log(` Name: ${result.name}`);
|
|
268
|
+
console.log(` Version: ${result.version}`);
|
|
269
|
+
console.log(` Bundle: ${result.bundleUrl}`);
|
|
270
|
+
console.log(` Visibility: ${result.visibility ?? "private"}`);
|
|
271
|
+
console.log(` Status: ${result.reviewStatus}`);
|
|
272
|
+
if (result.reviewStatus === "pending") {
|
|
273
|
+
console.log("");
|
|
274
|
+
console.log("Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.");
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// src/update.ts
|
|
279
|
+
import { resolve as resolve3 } from "path";
|
|
280
|
+
async function fetchDeployedPlugin(apiUrl, token, pluginId) {
|
|
281
|
+
const res = await fetch(`${apiUrl}/plugins/${pluginId}`, {
|
|
282
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
123
283
|
});
|
|
124
|
-
|
|
284
|
+
if (res.status === 404) {
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
if (!res.ok) {
|
|
288
|
+
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
289
|
+
console.error(
|
|
290
|
+
`Error fetching plugin: ${err.error}`
|
|
291
|
+
);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
}
|
|
294
|
+
return await res.json();
|
|
125
295
|
}
|
|
296
|
+
function validateManifestId(manifest) {
|
|
297
|
+
if (!manifest.id) {
|
|
298
|
+
console.error(
|
|
299
|
+
"Error: manifest.json must contain an 'id' field for updates. Run 'create-snaptrude-plugin register' first to register a new plugin."
|
|
300
|
+
);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
async function handleUpdate(opts) {
|
|
305
|
+
if (!opts.skipBuild) {
|
|
306
|
+
runBuild(opts.verbose);
|
|
307
|
+
}
|
|
308
|
+
const buildDir = resolve3(opts.path);
|
|
309
|
+
const { token, apiUrl } = resolveAuth(opts);
|
|
310
|
+
const manifest = await loadManifest(buildDir);
|
|
311
|
+
validateManifestId(manifest);
|
|
312
|
+
if (opts.verbose) console.log(`Plugin ID: ${manifest.id}`);
|
|
313
|
+
console.log("Checking deployed plugin...");
|
|
314
|
+
const deployed = await fetchDeployedPlugin(apiUrl, token, manifest.id);
|
|
315
|
+
if (!deployed) {
|
|
316
|
+
console.error(
|
|
317
|
+
`Error: No deployed plugin found with ID '${manifest.id}'.
|
|
318
|
+
Use 'create-snaptrude-plugin register' to register a new plugin first.`
|
|
319
|
+
);
|
|
320
|
+
process.exit(1);
|
|
321
|
+
}
|
|
322
|
+
if (opts.verbose) {
|
|
323
|
+
console.log(`Deployed version: ${deployed.version}, checksum: ${deployed.checksum ?? "none"}`);
|
|
324
|
+
}
|
|
325
|
+
const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose);
|
|
326
|
+
console.log("Updating plugin...");
|
|
327
|
+
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility);
|
|
328
|
+
const bundleChanged = deployed.checksum !== checksum;
|
|
329
|
+
console.log("");
|
|
330
|
+
console.log("Plugin updated successfully!");
|
|
331
|
+
console.log(` ID: ${result.id}`);
|
|
332
|
+
console.log(` Name: ${result.name}`);
|
|
333
|
+
console.log(` Version: ${result.version}`);
|
|
334
|
+
console.log(` Bundle: ${bundleChanged ? "updated" : "unchanged (checksum matched)"}`);
|
|
335
|
+
console.log(` Visibility: ${result.visibility ?? "private"}`);
|
|
336
|
+
console.log(` Status: ${result.reviewStatus}`);
|
|
337
|
+
if (result.reviewStatus === "pending") {
|
|
338
|
+
console.log("");
|
|
339
|
+
console.log("Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.");
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// src/index.ts
|
|
344
|
+
var CHECK_UPDATE = false;
|
|
126
345
|
async function main() {
|
|
127
346
|
if (CHECK_UPDATE) {
|
|
128
347
|
const update = await updateCheck(package_default);
|
|
129
|
-
if (update)
|
|
348
|
+
if (update) {
|
|
130
349
|
console.log(
|
|
131
350
|
`Update available: ${update.latest} (current: ${package_default.version})`
|
|
132
351
|
);
|
|
352
|
+
}
|
|
133
353
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
354
|
+
const program = new Command().name("create-snaptrude-plugin").version(package_default.version).description("Snaptrude plugin CLI \u2014 scaffold and register plugins");
|
|
355
|
+
program.command("create", { isDefault: true }).description("Scaffold a new Snaptrude plugin project").addOption(new Option("-v, --verbose", "Verbose output").default(false)).addOption(new Option("-n, --name <name>", "Plugin name")).action(handleCreate);
|
|
356
|
+
program.command("register").description("Build, bundle, and register a plugin with Snaptrude").addOption(
|
|
357
|
+
new Option("-p, --path <dir>", "Path to the build output directory").default("./dist")
|
|
358
|
+
).addOption(new Option("-t, --token <token>", "Auth token (or set SNAPTRUDE_TOKEN env var)")).addOption(
|
|
359
|
+
new Option(
|
|
360
|
+
"--api-url <url>",
|
|
361
|
+
"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)"
|
|
362
|
+
).default("http://localhost:6012")
|
|
363
|
+
).addOption(new Option("--skip-build", "Skip the build step").default(false)).addOption(
|
|
364
|
+
new Option(
|
|
365
|
+
"--visibility <level>",
|
|
366
|
+
"Visibility: private (default) or public"
|
|
367
|
+
).choices(["private", "public"])
|
|
368
|
+
).addOption(new Option("-v, --verbose", "Verbose output").default(false)).action(handleRegister);
|
|
369
|
+
program.command("update").description("Update an existing plugin (manifest and bundle)").addOption(
|
|
370
|
+
new Option("-p, --path <dir>", "Path to the build output directory").default("./dist")
|
|
371
|
+
).addOption(new Option("-t, --token <token>", "Auth token (or set SNAPTRUDE_TOKEN env var)")).addOption(
|
|
372
|
+
new Option(
|
|
373
|
+
"--api-url <url>",
|
|
374
|
+
"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)"
|
|
375
|
+
).default("http://localhost:6012")
|
|
376
|
+
).addOption(new Option("--skip-build", "Skip the build step").default(false)).addOption(new Option("-f, --force", "Force update even if checksum has not changed").default(false)).addOption(
|
|
377
|
+
new Option(
|
|
378
|
+
"--visibility <level>",
|
|
379
|
+
"Visibility: private or public"
|
|
380
|
+
).choices(["private", "public"])
|
|
381
|
+
).addOption(new Option("-v, --verbose", "Verbose output").default(false)).action(handleUpdate);
|
|
382
|
+
await program.parseAsync();
|
|
144
383
|
}
|
|
145
384
|
main();
|
|
146
385
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../package.json"],"sourcesContent":["#!/usr/bin/env node\n\nimport { input } from \"@inquirer/prompts\"\nimport packageJson from \"../package.json\"\nimport updateCheck from \"update-check\"\nimport { Command, Option } from \"@commander-js/extra-typings\"\nimport simpleGit from \"simple-git\"\nimport { cp, mkdir, readFile, rm, writeFile, mkdtemp } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { tmpdir } from \"node:os\"\n\n/**\n * Check for updates.\n */\nconst CHECK_UPDATE = false\n\nconst DEFAULT_VERBOSE = false\nconst DEFAULT_PLUGIN_NAME = \"my-plugin\"\n\nasync function updatePackageJson(targetDir: string, pluginName: string) {\n const packageJsonPath = join(targetDir, \"package.json\")\n const packageJson = await readFile(packageJsonPath, \"utf8\")\n const packageJsonObject = JSON.parse(packageJson)\n packageJsonObject.name = pluginName\n await writeFile(packageJsonPath, JSON.stringify(packageJsonObject, null, 2))\n}\n\nconst UNWANTED_DIRS: string[] = []\nconst UNWANTED_FILES: string[] = []\n\nasync function removeUnwantedFiles(targetDir: string, verbose: boolean = true) {\n if (verbose) console.log(`Removing unwanted files from ${targetDir}`)\n for (const dir of UNWANTED_DIRS) {\n await rm(join(targetDir, dir), { recursive: true, force: true })\n }\n for (const file of UNWANTED_FILES) {\n await rm(join(targetDir, file), { force: true })\n }\n}\n\nconst EXAMPLES_REPO =\n \"https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git\"\nconst EXAMPLES_REPO_COMMIT = \"b88166fa93ec4590c9a27e7b98928ceb12e59f43\"\nconst EXAMPLE_PATH_IN_REPO = \"snaptrude-plugin\"\n\nasync function createExampleRepo(targetDir: string, verbose: boolean = true) {\n if (verbose) console.log(`Creating example repo in ${targetDir}`)\n const tmpDir = await mkdtemp(join(tmpdir(), \"snaptrude-plugin-\"))\n if (verbose) console.log(`Create temporary directory for clone: ${tmpDir}`)\n try {\n const git = simpleGit(tmpDir)\n if (verbose) console.log(`Cloning example repo to ${tmpDir}`)\n // Shallow clone the repo into the temp directory\n await git.clone(EXAMPLES_REPO, \".\", [\"--no-checkout\", \"--depth=1\"])\n\n if (verbose)\n console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.fetch([\"origin\", EXAMPLES_REPO_COMMIT, \"--depth=1\"])\n if (verbose)\n console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.checkout(EXAMPLES_REPO_COMMIT)\n if (verbose)\n console.log(`Copying example directory to target: ${targetDir}`)\n await cp(join(tmpDir, EXAMPLE_PATH_IN_REPO), targetDir, { recursive: true })\n } catch (error) {\n console.error(\"Error cloning example repo:\", error)\n throw error\n } finally {\n if (verbose) console.log(`Cleaning up temporary directory: ${tmpDir}`)\n await rm(tmpDir, { recursive: true, force: true })\n }\n}\n\nasync function createPlugin(\n targetDir: string,\n pluginName: string,\n verbose: boolean = true,\n) {\n await createExampleRepo(targetDir, verbose)\n await removeUnwantedFiles(targetDir, verbose)\n await updatePackageJson(targetDir, pluginName)\n if (verbose) console.log(`Plugin created successfully in ${targetDir}`)\n}\n\nasync function runCliMode() {\n const program = new Command()\n .version(packageJson.version)\n .addOption(\n new Option(\"-v, --verbose\", \"Verbose output\").default(DEFAULT_VERBOSE),\n )\n .addOption(new Option(\"-n, --name <name>\", \"The name of the plugin\"))\n program.parse()\n return program.opts()\n}\n\nasync function runInteractiveMode() {\n const pluginName = await input({\n message: \"What is the name of your plugin?\",\n required: true,\n default: DEFAULT_PLUGIN_NAME,\n validate: (value) => {\n if (!/^[a-z0-9-]+$/.test(value)) {\n return \"Plugin name must only contain lowercase letters, numbers, and hyphens\"\n }\n return true\n },\n })\n return { pluginName }\n}\n\nasync function main() {\n if (CHECK_UPDATE) {\n const update = await updateCheck(packageJson)\n if (update)\n console.log(\n `Update available: ${update.latest} (current: ${packageJson.version})`,\n )\n }\n console.log(`${packageJson.name} v${packageJson.version}`)\n\n const cliOpts = await runCliMode()\n const cwd = process.cwd()\n if (cliOpts.verbose) console.log(\"Verbose output enabled\")\n if (cliOpts.verbose) console.log(\"Current working directory:\", cwd)\n const pluginName = cliOpts.name ?? (await runInteractiveMode()).pluginName\n const pluginDir = join(cwd, pluginName)\n if (cliOpts.verbose) console.log(`Creating plugin: ${pluginName}`)\n await mkdir(pluginDir, { recursive: true })\n await createPlugin(pluginDir, pluginName, cliOpts.verbose)\n}\n\nmain()\n","{\n \"name\": \"@snaptrude/create-snaptrude-plugin\",\n \"version\": \"0.0.5\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"create-snaptrude-plugin\": \"dist/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"check-types\": \"tsc --noEmit\",\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"clean-dist\": \"rm -rf dist\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.3.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.5.4\"\n },\n \"dependencies\": {\n \"@commander-js/extra-typings\": \"^14.0.0\",\n \"@inquirer/prompts\": \"^8.3.0\",\n \"commander\": \"^14.0.3\",\n \"simple-git\": \"^3.32.3\",\n \"update-check\": \"^1.5.4\"\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../package.json","../src/index.ts","../src/create.ts","../src/register.ts","../src/shared.ts","../src/update.ts"],"sourcesContent":["{\n \"name\": \"@snaptrude/create-snaptrude-plugin\",\n \"version\": \"0.0.7\",\n \"type\": \"module\",\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"bin\": {\n \"create-snaptrude-plugin\": \"dist/index.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"scripts\": {\n \"check-types\": \"tsc --noEmit\",\n \"build\": \"tsup --clean\",\n \"dev\": \"tsup --watch\",\n \"clean-dist\": \"rm -rf dist\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^25.3.5\",\n \"tsup\": \"^8.5.1\",\n \"typescript\": \"^5.5.4\",\n \"vitest\": \"^4.1.0\"\n },\n \"dependencies\": {\n \"@commander-js/extra-typings\": \"^14.0.0\",\n \"@inquirer/prompts\": \"^8.3.0\",\n \"commander\": \"^14.0.3\",\n \"simple-git\": \"^3.32.3\",\n \"tar\": \"^7.5.11\",\n \"update-check\": \"^1.5.4\"\n }\n}\n","#!/usr/bin/env node\n\nimport packageJson from \"../package.json\"\nimport updateCheck from \"update-check\"\nimport { Command, Option } from \"@commander-js/extra-typings\"\nimport { handleCreate } from \"./create\"\nimport { handleRegister } from \"./register\"\nimport { handleUpdate } from \"./update\"\n\nconst CHECK_UPDATE = false\n\nasync function main() {\n if (CHECK_UPDATE) {\n const update = await updateCheck(packageJson)\n if (update) {\n console.log(\n `Update available: ${update.latest} (current: ${packageJson.version})`,\n )\n }\n }\n\n const program = new Command()\n .name(\"create-snaptrude-plugin\")\n .version(packageJson.version)\n .description(\"Snaptrude plugin CLI — scaffold and register plugins\")\n\n program\n .command(\"create\", { isDefault: true })\n .description(\"Scaffold a new Snaptrude plugin project\")\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .addOption(new Option(\"-n, --name <name>\", \"Plugin name\"))\n .action(handleCreate)\n\n program\n .command(\"register\")\n .description(\"Build, bundle, and register a plugin with Snaptrude\")\n .addOption(\n new Option(\"-p, --path <dir>\", \"Path to the build output directory\").default(\"./dist\"),\n )\n .addOption(new Option(\"-t, --token <token>\", \"Auth token (or set SNAPTRUDE_TOKEN env var)\"))\n .addOption(\n new Option(\n \"--api-url <url>\",\n \"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)\",\n ).default(\"http://localhost:6012\"),\n )\n .addOption(new Option(\"--skip-build\", \"Skip the build step\").default(false))\n .addOption(\n new Option(\n \"--visibility <level>\",\n \"Visibility: private (default) or public\",\n ).choices([\"private\", \"public\"]),\n )\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .action(handleRegister)\n\n program\n .command(\"update\")\n .description(\"Update an existing plugin (manifest and bundle)\")\n .addOption(\n new Option(\"-p, --path <dir>\", \"Path to the build output directory\").default(\"./dist\"),\n )\n .addOption(new Option(\"-t, --token <token>\", \"Auth token (or set SNAPTRUDE_TOKEN env var)\"))\n .addOption(\n new Option(\n \"--api-url <url>\",\n \"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)\",\n ).default(\"http://localhost:6012\"),\n )\n .addOption(new Option(\"--skip-build\", \"Skip the build step\").default(false))\n .addOption(new Option(\"-f, --force\", \"Force update even if checksum has not changed\").default(false))\n .addOption(\n new Option(\n \"--visibility <level>\",\n \"Visibility: private or public\",\n ).choices([\"private\", \"public\"]),\n )\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .action(handleUpdate)\n\n await program.parseAsync()\n}\n\nmain()\n","import { input } from \"@inquirer/prompts\"\nimport simpleGit from \"simple-git\"\nimport { cp, mkdir, readFile, rm, writeFile, mkdtemp } from \"node:fs/promises\"\nimport { join } from \"node:path\"\nimport { tmpdir } from \"node:os\"\nimport { randomUUID } from \"node:crypto\"\n\nconst DEFAULT_PLUGIN_NAME = \"my-plugin\"\n\nconst EXAMPLES_REPO =\n \"https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git\"\nconst EXAMPLES_REPO_COMMIT = \"bdc80a1a830396ee29a576ea67ef7482888c1468\"\nconst EXAMPLE_PATH_IN_REPO = \"snaptrude-plugin\"\n\nconst UNWANTED_DIRS: string[] = []\nconst UNWANTED_FILES: string[] = []\n\nasync function askPluginName(): Promise<string> {\n return input({\n message: \"What is the name of your plugin?\",\n required: true,\n default: DEFAULT_PLUGIN_NAME,\n validate: (value) => {\n if (!/^[a-z0-9-]+$/.test(value)) {\n return \"Plugin name must only contain lowercase letters, numbers, and hyphens\"\n }\n return true\n },\n })\n}\n\nasync function updatePkgJson(targetDir: string, pluginName: string) {\n const pkgPath = join(targetDir, \"package.json\")\n const pkg = JSON.parse(await readFile(pkgPath, \"utf8\"))\n pkg.name = pluginName\n pkg.id = randomUUID()\n await writeFile(pkgPath, JSON.stringify(pkg, null, 2))\n}\n\nasync function removeUnwantedFiles(targetDir: string, verbose: boolean) {\n if (verbose) console.log(`Removing unwanted files from ${targetDir}`)\n for (const dir of UNWANTED_DIRS) {\n await rm(join(targetDir, dir), { recursive: true, force: true })\n }\n for (const file of UNWANTED_FILES) {\n await rm(join(targetDir, file), { force: true })\n }\n}\n\nasync function cloneExample(targetDir: string, verbose: boolean) {\n if (verbose) console.log(`Creating example repo in ${targetDir}`)\n const tmpDir = await mkdtemp(join(tmpdir(), \"snaptrude-plugin-\"))\n if (verbose) console.log(`Create temporary directory for clone: ${tmpDir}`)\n try {\n const git = simpleGit(tmpDir)\n if (verbose) console.log(`Cloning example repo to ${tmpDir}`)\n await git.clone(EXAMPLES_REPO, \".\", [\"--no-checkout\", \"--depth=1\"])\n if (verbose) console.log(`Fetching specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.fetch([\"origin\", EXAMPLES_REPO_COMMIT, \"--depth=1\"])\n if (verbose) console.log(`Checking out specific commit: ${EXAMPLES_REPO_COMMIT}`)\n await git.checkout(EXAMPLES_REPO_COMMIT)\n if (verbose) console.log(`Copying example directory to target: ${targetDir}`)\n await cp(join(tmpDir, EXAMPLE_PATH_IN_REPO), targetDir, { recursive: true })\n } catch (error) {\n console.error(\"Error cloning example repo:\", error)\n throw error\n } finally {\n if (verbose) console.log(`Cleaning up temporary directory: ${tmpDir}`)\n await rm(tmpDir, { recursive: true, force: true })\n }\n}\n\nexport async function handleCreate(opts: { verbose: boolean; name?: string }) {\n const pluginName = opts.name ?? (await askPluginName())\n const pluginDir = join(process.cwd(), pluginName)\n\n if (opts.verbose) console.log(`Creating plugin: ${pluginName}`)\n await mkdir(pluginDir, { recursive: true })\n await cloneExample(pluginDir, opts.verbose)\n await removeUnwantedFiles(pluginDir, opts.verbose)\n await updatePkgJson(pluginDir, pluginName)\n\n console.log(`Plugin \"${pluginName}\" created successfully in ${pluginDir}`)\n}\n","import { resolve } from \"node:path\"\nimport {\n runBuild,\n loadManifest,\n resolveAuth,\n buildBundle,\n uploadBundle,\n} from \"./shared\"\n\nexport async function handleRegister(opts: {\n path: string\n token?: string\n apiUrl: string\n verbose: boolean\n skipBuild: boolean\n visibility?: string\n}) {\n if (!opts.skipBuild) {\n runBuild(opts.verbose)\n }\n\n const buildDir = resolve(opts.path)\n const { token, apiUrl } = resolveAuth(opts)\n const manifest = await loadManifest(buildDir)\n\n if (opts.verbose) console.log(`Reading build from: ${buildDir}`)\n\n const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose)\n\n console.log(\"Registering plugin...\")\n const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility)\n\n console.log(\"\")\n console.log(\"Plugin registered successfully!\")\n console.log(` ID: ${result.id}`)\n console.log(` Name: ${result.name}`)\n console.log(` Version: ${result.version}`)\n console.log(` Bundle: ${result.bundleUrl}`)\n console.log(` Visibility: ${result.visibility ?? \"private\"}`)\n console.log(` Status: ${result.reviewStatus}`)\n\n if (result.reviewStatus === \"pending\") {\n console.log(\"\")\n console.log(\"Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.\")\n }\n}\n","import { readFile, readdir, access } from \"node:fs/promises\"\nimport { join, resolve } from \"node:path\"\nimport { createHash } from \"node:crypto\"\nimport { execSync } from \"node:child_process\"\nimport { create as tarCreate } from \"tar\"\n\nexport interface PluginManifest {\n name: string\n version: string\n description?: string\n apiVersion?: string\n workerUrl?: string\n uiUrl?: string\n id?: string\n bundleUrl?: string\n checksum?: string\n [key: string]: unknown\n}\n\nexport interface RegisterResult {\n id: string\n name: string\n version: string\n bundleUrl: string\n reviewStatus: string\n visibility?: string\n}\n\nexport async function pathExists(p: string): Promise<boolean> {\n try {\n await access(p)\n return true\n } catch {\n return false\n }\n}\n\nexport function createBundle(\n buildDir: string,\n entries: string[],\n verbose: boolean,\n): Promise<Buffer> {\n if (verbose) {\n console.log(`Bundling ${entries.length} entries: ${entries.join(\", \")}`)\n }\n\n return new Promise<Buffer>((res, rej) => {\n const chunks: Buffer[] = []\n const stream = tarCreate({ gzip: true, cwd: buildDir }, entries)\n stream.on(\"data\", (chunk: Buffer) => chunks.push(chunk))\n stream.on(\"end\", () => res(Buffer.concat(chunks)))\n stream.on(\"error\", rej)\n })\n}\n\nexport function computeChecksum(buffer: Buffer): string {\n return createHash(\"sha256\").update(buffer).digest(\"hex\")\n}\n\nexport function runBuild(verbose: boolean) {\n const cmd = `npm run build:prod`\n console.log(`Building plugin (${cmd})...`)\n try {\n execSync(cmd, {\n cwd: process.cwd(),\n stdio: verbose ? \"inherit\" : \"pipe\",\n })\n } catch (err) {\n console.error(\"Build failed:\")\n if (!verbose && err instanceof Error && \"stderr\" in err) {\n console.error((err as { stderr: Buffer }).stderr?.toString())\n }\n process.exit(1)\n }\n}\n\nexport async function uploadBundle(\n apiUrl: string,\n token: string,\n manifest: PluginManifest,\n tarBuffer: Buffer,\n checksum: string,\n visibility?: string,\n): Promise<RegisterResult> {\n const formData = new FormData()\n formData.append(\n \"bundle\",\n new Blob([new Uint8Array(tarBuffer) as unknown as ArrayBuffer], {\n type: \"application/gzip\",\n }),\n \"bundle.tar.gz\",\n )\n formData.append(\"manifest\", JSON.stringify(manifest))\n formData.append(\"checksum\", checksum)\n\n if (visibility) {\n formData.append(\"visibility\", visibility)\n }\n\n const res = await fetch(`${apiUrl}/plugins/register`, {\n method: \"POST\",\n headers: { Authorization: `Bearer ${token}` },\n body: formData,\n })\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: res.statusText }))\n console.error(\n `Error registering plugin: ${(err as { error: string }).error}`,\n )\n process.exit(1)\n }\n\n return (await res.json()) as RegisterResult\n}\n\nexport async function loadManifest(buildDir: string): Promise<PluginManifest> {\n const manifestPath = join(buildDir, \"manifest.json\")\n if (!(await pathExists(buildDir))) {\n console.error(`Error: Build directory not found: ${buildDir}`)\n process.exit(1)\n }\n if (!(await pathExists(manifestPath))) {\n console.error(`Error: manifest.json not found in ${buildDir}`)\n process.exit(1)\n }\n\n const manifest: PluginManifest = JSON.parse(\n await readFile(manifestPath, \"utf8\"),\n )\n if (!manifest.name || !manifest.version) {\n console.error(\"Error: manifest.json must contain name and version fields\")\n process.exit(1)\n }\n\n return manifest\n}\n\nexport function resolveAuth(opts: { token?: string; apiUrl: string }) {\n const rawToken = opts.token ?? process.env.SNAPTRUDE_TOKEN\n const token = rawToken?.startsWith(\"Bearer \") ? rawToken.slice(7) : rawToken\n const apiUrl = opts.apiUrl ?? process.env.SNAPTRUDE_API_URL\n\n if (!token) {\n console.error(\n \"Error: Auth token is required. Use --token <token> or set SNAPTRUDE_TOKEN env var.\",\n )\n process.exit(1)\n }\n if (!apiUrl) {\n console.error(\n \"Error: API URL is required. Use --api-url <url> or set SNAPTRUDE_API_URL env var.\",\n )\n process.exit(1)\n }\n\n return { token, apiUrl }\n}\n\nexport async function buildBundle(\n buildDir: string,\n verbose: boolean,\n): Promise<{ tarBuffer: Buffer; checksum: string; entries: string[] }> {\n console.log(\"Creating bundle...\")\n const entries = (await readdir(buildDir)).filter((e) => e !== \"manifest.json\")\n if (entries.length === 0) {\n throw new Error(\"No files to bundle (only manifest.json found)\")\n }\n\n const tarBuffer = await createBundle(buildDir, entries, verbose)\n const checksum = computeChecksum(tarBuffer)\n if (verbose) {\n console.log(\n `Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`,\n )\n }\n\n return { tarBuffer, checksum, entries }\n}\n","import { resolve } from \"node:path\"\nimport type { PluginManifest } from \"./shared\"\nimport {\n runBuild,\n loadManifest,\n resolveAuth,\n buildBundle,\n uploadBundle,\n} from \"./shared\"\n\ninterface DeployedPlugin {\n id: string\n name: string\n version: string\n bundleUrl?: string\n checksum?: string\n visibility?: string\n [key: string]: unknown\n}\n\nexport async function fetchDeployedPlugin(\n apiUrl: string,\n token: string,\n pluginId: string,\n): Promise<DeployedPlugin | null> {\n const res = await fetch(`${apiUrl}/plugins/${pluginId}`, {\n headers: { Authorization: `Bearer ${token}` },\n })\n\n if (res.status === 404) {\n return null\n }\n\n if (!res.ok) {\n const err = await res.json().catch(() => ({ error: res.statusText }))\n console.error(\n `Error fetching plugin: ${(err as { error: string }).error}`,\n )\n process.exit(1)\n }\n\n return (await res.json()) as DeployedPlugin\n}\n\nexport function validateManifestId(\n manifest: PluginManifest,\n): asserts manifest is PluginManifest & { id: string } {\n if (!manifest.id) {\n console.error(\n \"Error: manifest.json must contain an 'id' field for updates. \" +\n \"Run 'create-snaptrude-plugin register' first to register a new plugin.\",\n )\n process.exit(1)\n }\n}\n\nexport async function handleUpdate(opts: {\n path: string\n token?: string\n apiUrl: string\n verbose: boolean\n skipBuild: boolean\n force: boolean\n visibility?: string\n}) {\n if (!opts.skipBuild) {\n runBuild(opts.verbose)\n }\n\n const buildDir = resolve(opts.path)\n const { token, apiUrl } = resolveAuth(opts)\n const manifest = await loadManifest(buildDir)\n\n validateManifestId(manifest)\n\n if (opts.verbose) console.log(`Plugin ID: ${manifest.id}`)\n\n console.log(\"Checking deployed plugin...\")\n const deployed = await fetchDeployedPlugin(apiUrl, token, manifest.id)\n\n if (!deployed) {\n console.error(\n `Error: No deployed plugin found with ID '${manifest.id}'.\\n` +\n \"Use 'create-snaptrude-plugin register' to register a new plugin first.\",\n )\n process.exit(1)\n }\n\n if (opts.verbose) {\n console.log(`Deployed version: ${deployed.version}, checksum: ${deployed.checksum ?? \"none\"}`)\n }\n\n const { tarBuffer, checksum } = await buildBundle(buildDir, opts.verbose)\n\n console.log(\"Updating plugin...\")\n const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility)\n\n const bundleChanged = deployed.checksum !== checksum\n\n console.log(\"\")\n console.log(\"Plugin updated successfully!\")\n console.log(` ID: ${result.id}`)\n console.log(` Name: ${result.name}`)\n console.log(` Version: ${result.version}`)\n console.log(` Bundle: ${bundleChanged ? \"updated\" : \"unchanged (checksum matched)\"}`)\n console.log(` Visibility: ${result.visibility ?? \"private\"}`)\n console.log(` Status: ${result.reviewStatus}`)\n\n if (result.reviewStatus === \"pending\") {\n console.log(\"\")\n console.log(\"Your plugin has been submitted for review. An admin will approve it before it becomes publicly visible.\")\n }\n}\n"],"mappings":"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","names":["resolve","readFile","join","resolve","resolve","resolve"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/shared.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/update.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/create.ts"],"names":[],"mappings":"AAwEA,wBAAsB,YAAY,CAAC,IAAI,EAAE;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,iBAW3E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/register.ts"],"names":[],"mappings":"AASA,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,iBA6BA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export interface PluginManifest {
|
|
2
|
+
name: string;
|
|
3
|
+
version: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
apiVersion?: string;
|
|
6
|
+
workerUrl?: string;
|
|
7
|
+
uiUrl?: string;
|
|
8
|
+
id?: string;
|
|
9
|
+
bundleUrl?: string;
|
|
10
|
+
checksum?: string;
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface RegisterResult {
|
|
14
|
+
id: string;
|
|
15
|
+
name: string;
|
|
16
|
+
version: string;
|
|
17
|
+
bundleUrl: string;
|
|
18
|
+
reviewStatus: string;
|
|
19
|
+
visibility?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function pathExists(p: string): Promise<boolean>;
|
|
22
|
+
export declare function createBundle(buildDir: string, entries: string[], verbose: boolean): Promise<Buffer>;
|
|
23
|
+
export declare function computeChecksum(buffer: Buffer): string;
|
|
24
|
+
export declare function runBuild(verbose: boolean): void;
|
|
25
|
+
export declare function uploadBundle(apiUrl: string, token: string, manifest: PluginManifest, tarBuffer: Buffer, checksum: string, visibility?: string): Promise<RegisterResult>;
|
|
26
|
+
export declare function loadManifest(buildDir: string): Promise<PluginManifest>;
|
|
27
|
+
export declare function resolveAuth(opts: {
|
|
28
|
+
token?: string;
|
|
29
|
+
apiUrl: string;
|
|
30
|
+
}): {
|
|
31
|
+
token: string;
|
|
32
|
+
apiUrl: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function buildBundle(buildDir: string, verbose: boolean): Promise<{
|
|
35
|
+
tarBuffer: Buffer;
|
|
36
|
+
checksum: string;
|
|
37
|
+
entries: string[];
|
|
38
|
+
}>;
|
|
39
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/shared.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO5D;AAED,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EAAE,EACjB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,QAexC;AAED,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,cAAc,EACxB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,cAAc,CAAC,CA+BzB;AAED,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAoB5E;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE;;;EAmBnE;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,GACf,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAgBrE"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { PluginManifest } from "./shared";
|
|
2
|
+
interface DeployedPlugin {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
version: string;
|
|
6
|
+
bundleUrl?: string;
|
|
7
|
+
checksum?: string;
|
|
8
|
+
visibility?: string;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
export declare function fetchDeployedPlugin(apiUrl: string, token: string, pluginId: string): Promise<DeployedPlugin | null>;
|
|
12
|
+
export declare function validateManifestId(manifest: PluginManifest): asserts manifest is PluginManifest & {
|
|
13
|
+
id: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function handleUpdate(opts: {
|
|
16
|
+
path: string;
|
|
17
|
+
token?: string;
|
|
18
|
+
apiUrl: string;
|
|
19
|
+
verbose: boolean;
|
|
20
|
+
skipBuild: boolean;
|
|
21
|
+
force: boolean;
|
|
22
|
+
visibility?: string;
|
|
23
|
+
}): Promise<void>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/update.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAS9C,UAAU,cAAc;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAsB,mBAAmB,CACvC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAkBhC;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,cAAc,GACvB,OAAO,CAAC,QAAQ,IAAI,cAAc,GAAG;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,CAQrD;AAED,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,OAAO,CAAA;IAClB,KAAK,EAAE,OAAO,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,iBAgDA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snaptrude/create-snaptrude-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -17,19 +17,23 @@
|
|
|
17
17
|
"devDependencies": {
|
|
18
18
|
"@types/node": "^25.3.5",
|
|
19
19
|
"tsup": "^8.5.1",
|
|
20
|
-
"typescript": "^5.5.4"
|
|
20
|
+
"typescript": "^5.5.4",
|
|
21
|
+
"vitest": "^4.1.0"
|
|
21
22
|
},
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"@commander-js/extra-typings": "^14.0.0",
|
|
24
25
|
"@inquirer/prompts": "^8.3.0",
|
|
25
26
|
"commander": "^14.0.3",
|
|
26
27
|
"simple-git": "^3.32.3",
|
|
28
|
+
"tar": "^7.5.11",
|
|
27
29
|
"update-check": "^1.5.4"
|
|
28
30
|
},
|
|
29
31
|
"scripts": {
|
|
30
32
|
"check-types": "tsc --noEmit",
|
|
31
|
-
"build": "tsup",
|
|
33
|
+
"build": "tsup --clean",
|
|
32
34
|
"dev": "tsup --watch",
|
|
33
|
-
"clean-dist": "rm -rf dist"
|
|
35
|
+
"clean-dist": "rm -rf dist",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest"
|
|
34
38
|
}
|
|
35
39
|
}
|