@snaptrude/create-snaptrude-plugin 0.0.6 → 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 +169 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +170 -54
- 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/register.d.ts +1 -0
- package/dist/src/register.d.ts.map +1 -1
- 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 +7 -4
package/dist/index.cjs
CHANGED
|
@@ -26,7 +26,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// package.json
|
|
27
27
|
var package_default = {
|
|
28
28
|
name: "@snaptrude/create-snaptrude-plugin",
|
|
29
|
-
version: "0.0.
|
|
29
|
+
version: "0.0.7",
|
|
30
30
|
type: "module",
|
|
31
31
|
main: "./dist/index.js",
|
|
32
32
|
module: "./dist/index.js",
|
|
@@ -42,14 +42,17 @@ var package_default = {
|
|
|
42
42
|
},
|
|
43
43
|
scripts: {
|
|
44
44
|
"check-types": "tsc --noEmit",
|
|
45
|
-
build: "tsup",
|
|
45
|
+
build: "tsup --clean",
|
|
46
46
|
dev: "tsup --watch",
|
|
47
|
-
"clean-dist": "rm -rf dist"
|
|
47
|
+
"clean-dist": "rm -rf dist",
|
|
48
|
+
test: "vitest run",
|
|
49
|
+
"test:watch": "vitest"
|
|
48
50
|
},
|
|
49
51
|
devDependencies: {
|
|
50
52
|
"@types/node": "^25.3.5",
|
|
51
53
|
tsup: "^8.5.1",
|
|
52
|
-
typescript: "^5.5.4"
|
|
54
|
+
typescript: "^5.5.4",
|
|
55
|
+
vitest: "^4.1.0"
|
|
53
56
|
},
|
|
54
57
|
dependencies: {
|
|
55
58
|
"@commander-js/extra-typings": "^14.0.0",
|
|
@@ -74,7 +77,7 @@ var import_node_os = require("os");
|
|
|
74
77
|
var import_node_crypto = require("crypto");
|
|
75
78
|
var DEFAULT_PLUGIN_NAME = "my-plugin";
|
|
76
79
|
var EXAMPLES_REPO = "https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git";
|
|
77
|
-
var EXAMPLES_REPO_COMMIT = "
|
|
80
|
+
var EXAMPLES_REPO_COMMIT = "bdc80a1a830396ee29a576ea67ef7482888c1468";
|
|
78
81
|
var EXAMPLE_PATH_IN_REPO = "snaptrude-plugin";
|
|
79
82
|
var UNWANTED_DIRS = [];
|
|
80
83
|
var UNWANTED_FILES = [];
|
|
@@ -141,6 +144,9 @@ async function handleCreate(opts) {
|
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
// src/register.ts
|
|
147
|
+
var import_node_path3 = require("path");
|
|
148
|
+
|
|
149
|
+
// src/shared.ts
|
|
144
150
|
var import_promises2 = require("fs/promises");
|
|
145
151
|
var import_node_path2 = require("path");
|
|
146
152
|
var import_node_crypto2 = require("crypto");
|
|
@@ -166,7 +172,26 @@ function createBundle(buildDir, entries, verbose) {
|
|
|
166
172
|
stream.on("error", rej);
|
|
167
173
|
});
|
|
168
174
|
}
|
|
169
|
-
|
|
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());
|
|
190
|
+
}
|
|
191
|
+
process.exit(1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, visibility) {
|
|
170
195
|
const formData = new FormData();
|
|
171
196
|
formData.append(
|
|
172
197
|
"bundle",
|
|
@@ -177,6 +202,9 @@ async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum) {
|
|
|
177
202
|
);
|
|
178
203
|
formData.append("manifest", JSON.stringify(manifest));
|
|
179
204
|
formData.append("checksum", checksum);
|
|
205
|
+
if (visibility) {
|
|
206
|
+
formData.append("visibility", visibility);
|
|
207
|
+
}
|
|
180
208
|
const res = await fetch(`${apiUrl}/plugins/register`, {
|
|
181
209
|
method: "POST",
|
|
182
210
|
headers: { Authorization: `Bearer ${token}` },
|
|
@@ -184,32 +212,33 @@ async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum) {
|
|
|
184
212
|
});
|
|
185
213
|
if (!res.ok) {
|
|
186
214
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
187
|
-
console.error(
|
|
215
|
+
console.error(
|
|
216
|
+
`Error registering plugin: ${err.error}`
|
|
217
|
+
);
|
|
188
218
|
process.exit(1);
|
|
189
219
|
}
|
|
190
220
|
return await res.json();
|
|
191
221
|
}
|
|
192
|
-
function
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
(0, import_node_child_process.execSync)(cmd, {
|
|
197
|
-
cwd: process.cwd(),
|
|
198
|
-
stdio: verbose ? "inherit" : "pipe"
|
|
199
|
-
});
|
|
200
|
-
} catch (err) {
|
|
201
|
-
console.error("Build failed:");
|
|
202
|
-
if (!verbose && err instanceof Error && "stderr" in err) {
|
|
203
|
-
console.error(err.stderr?.toString());
|
|
204
|
-
}
|
|
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}`);
|
|
205
226
|
process.exit(1);
|
|
206
227
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
runBuild(opts.verbose);
|
|
228
|
+
if (!await pathExists(manifestPath)) {
|
|
229
|
+
console.error(`Error: manifest.json not found in ${buildDir}`);
|
|
230
|
+
process.exit(1);
|
|
211
231
|
}
|
|
212
|
-
const
|
|
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) {
|
|
213
242
|
const rawToken = opts.token ?? process.env.SNAPTRUDE_TOKEN;
|
|
214
243
|
const token = rawToken?.startsWith("Bearer ") ? rawToken.slice(7) : rawToken;
|
|
215
244
|
const apiUrl = opts.apiUrl ?? process.env.SNAPTRUDE_API_URL;
|
|
@@ -225,44 +254,113 @@ async function handleRegister(opts) {
|
|
|
225
254
|
);
|
|
226
255
|
process.exit(1);
|
|
227
256
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
process.exit(1);
|
|
232
|
-
}
|
|
233
|
-
if (!await pathExists(manifestPath)) {
|
|
234
|
-
console.error(`Error: manifest.json not found in ${buildDir}`);
|
|
235
|
-
process.exit(1);
|
|
236
|
-
}
|
|
237
|
-
const manifest = JSON.parse(
|
|
238
|
-
await (0, import_promises2.readFile)(manifestPath, "utf8")
|
|
239
|
-
);
|
|
240
|
-
if (!manifest.name || !manifest.version) {
|
|
241
|
-
console.error("Error: manifest.json must contain name and version fields");
|
|
242
|
-
process.exit(1);
|
|
243
|
-
}
|
|
244
|
-
if (opts.verbose) console.log(`Reading build from: ${buildDir}`);
|
|
257
|
+
return { token, apiUrl };
|
|
258
|
+
}
|
|
259
|
+
async function buildBundle(buildDir, verbose) {
|
|
245
260
|
console.log("Creating bundle...");
|
|
246
261
|
const entries = (await (0, import_promises2.readdir)(buildDir)).filter((e) => e !== "manifest.json");
|
|
247
262
|
if (entries.length === 0) {
|
|
248
263
|
throw new Error("No files to bundle (only manifest.json found)");
|
|
249
264
|
}
|
|
250
|
-
const tarBuffer = await createBundle(buildDir, entries,
|
|
251
|
-
const checksum = (
|
|
252
|
-
if (
|
|
265
|
+
const tarBuffer = await createBundle(buildDir, entries, verbose);
|
|
266
|
+
const checksum = computeChecksum(tarBuffer);
|
|
267
|
+
if (verbose) {
|
|
253
268
|
console.log(
|
|
254
269
|
`Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`
|
|
255
270
|
);
|
|
256
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);
|
|
257
285
|
console.log("Registering plugin...");
|
|
258
|
-
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum);
|
|
286
|
+
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility);
|
|
259
287
|
console.log("");
|
|
260
288
|
console.log("Plugin registered successfully!");
|
|
261
|
-
console.log(` ID:
|
|
262
|
-
console.log(` Name:
|
|
263
|
-
console.log(` Version:
|
|
264
|
-
console.log(` Bundle:
|
|
265
|
-
console.log(`
|
|
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}` }
|
|
306
|
+
});
|
|
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();
|
|
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
|
+
}
|
|
266
364
|
}
|
|
267
365
|
|
|
268
366
|
// src/index.ts
|
|
@@ -284,8 +382,26 @@ async function main() {
|
|
|
284
382
|
new import_extra_typings.Option(
|
|
285
383
|
"--api-url <url>",
|
|
286
384
|
"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)"
|
|
287
|
-
).default("
|
|
288
|
-
).addOption(new import_extra_typings.Option("--skip-build", "Skip the build step").default(false)).addOption(
|
|
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);
|
|
289
405
|
await program.parseAsync();
|
|
290
406
|
}
|
|
291
407
|
main();
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../package.json","../src/index.ts","../src/create.ts","../src/register.ts"],"sourcesContent":["{\n \"name\": \"@snaptrude/create-snaptrude-plugin\",\n \"version\": \"0.0.6\",\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 \"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\"\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(\"https://save2.snaptru.de\"),\n )\n .addOption(new Option(\"--skip-build\", \"Skip the build step\").default(false))\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .action(handleRegister)\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 = \"9bb0b4d1d1a76217437f838ff23613bde2e3e79e\"\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 { 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\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await access(p)\n return true\n } catch {\n return false\n }\n}\n\nfunction createBundle(buildDir: string, entries: string[], verbose: boolean): 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\ninterface 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 [key: string]: unknown\n}\n\ninterface RegisterResult {\n id: string\n name: string\n version: string\n bundleUrl: string\n reviewStatus: string\n}\n\nasync function uploadBundle(\n apiUrl: string,\n token: string,\n manifest: PluginManifest,\n tarBuffer: Buffer,\n checksum: 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 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(`Error registering plugin: ${(err as { error: string }).error}`)\n process.exit(1)\n }\n\n return (await res.json()) as RegisterResult\n}\n\n// function detectPackageManager(): \"pnpm\" | \"yarn\" | \"npm\" {\n// for (const [lockfile, pm] of [\n// [\"pnpm-lock.yaml\", \"pnpm\"],\n// [\"yarn.lock\", \"yarn\"],\n// [\"package-lock.json\", \"npm\"],\n// ] as const) {\n// try {\n// const fullPath = join(process.cwd(), lockfile)\n// require(\"node:fs\").accessSync(fullPath)\n// return pm\n// } catch {\n// // not found, try next\n// }\n// }\n// return \"npm\"\n// }\n\nfunction runBuild(verbose: boolean) {\n // const pm = detectPackageManager()\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 handleRegister(opts: {\n path: string\n token?: string\n apiUrl: string\n verbose: boolean\n skipBuild: boolean\n}) {\n if (!opts.skipBuild) {\n runBuild(opts.verbose)\n }\n\n const buildDir = resolve(opts.path)\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 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 if (opts.verbose) console.log(`Reading build from: ${buildDir}`)\n\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, opts.verbose)\n const checksum = createHash(\"sha256\").update(tarBuffer).digest(\"hex\")\n if (opts.verbose) {\n console.log(\n `Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`,\n )\n }\n\n console.log(\"Registering plugin...\")\n const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum)\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(` Status: ${result.reviewStatus}`)\n}\n"],"mappings":"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","names":["simpleGit","import_promises","import_node_path","import_node_crypto","tarCreate","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
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// package.json
|
|
4
4
|
var package_default = {
|
|
5
5
|
name: "@snaptrude/create-snaptrude-plugin",
|
|
6
|
-
version: "0.0.
|
|
6
|
+
version: "0.0.7",
|
|
7
7
|
type: "module",
|
|
8
8
|
main: "./dist/index.js",
|
|
9
9
|
module: "./dist/index.js",
|
|
@@ -19,14 +19,17 @@ var package_default = {
|
|
|
19
19
|
},
|
|
20
20
|
scripts: {
|
|
21
21
|
"check-types": "tsc --noEmit",
|
|
22
|
-
build: "tsup",
|
|
22
|
+
build: "tsup --clean",
|
|
23
23
|
dev: "tsup --watch",
|
|
24
|
-
"clean-dist": "rm -rf dist"
|
|
24
|
+
"clean-dist": "rm -rf dist",
|
|
25
|
+
test: "vitest run",
|
|
26
|
+
"test:watch": "vitest"
|
|
25
27
|
},
|
|
26
28
|
devDependencies: {
|
|
27
29
|
"@types/node": "^25.3.5",
|
|
28
30
|
tsup: "^8.5.1",
|
|
29
|
-
typescript: "^5.5.4"
|
|
31
|
+
typescript: "^5.5.4",
|
|
32
|
+
vitest: "^4.1.0"
|
|
30
33
|
},
|
|
31
34
|
dependencies: {
|
|
32
35
|
"@commander-js/extra-typings": "^14.0.0",
|
|
@@ -51,7 +54,7 @@ import { tmpdir } from "os";
|
|
|
51
54
|
import { randomUUID } from "crypto";
|
|
52
55
|
var DEFAULT_PLUGIN_NAME = "my-plugin";
|
|
53
56
|
var EXAMPLES_REPO = "https://bitbucket.org/snaptrude/snaptrude-plugin-examples.git";
|
|
54
|
-
var EXAMPLES_REPO_COMMIT = "
|
|
57
|
+
var EXAMPLES_REPO_COMMIT = "bdc80a1a830396ee29a576ea67ef7482888c1468";
|
|
55
58
|
var EXAMPLE_PATH_IN_REPO = "snaptrude-plugin";
|
|
56
59
|
var UNWANTED_DIRS = [];
|
|
57
60
|
var UNWANTED_FILES = [];
|
|
@@ -118,8 +121,11 @@ async function handleCreate(opts) {
|
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// src/register.ts
|
|
124
|
+
import { resolve as resolve2 } from "path";
|
|
125
|
+
|
|
126
|
+
// src/shared.ts
|
|
121
127
|
import { readFile as readFile2, readdir, access } from "fs/promises";
|
|
122
|
-
import { join as join2
|
|
128
|
+
import { join as join2 } from "path";
|
|
123
129
|
import { createHash } from "crypto";
|
|
124
130
|
import { execSync } from "child_process";
|
|
125
131
|
import { create as tarCreate } from "tar";
|
|
@@ -143,7 +149,26 @@ function createBundle(buildDir, entries, verbose) {
|
|
|
143
149
|
stream.on("error", rej);
|
|
144
150
|
});
|
|
145
151
|
}
|
|
146
|
-
|
|
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());
|
|
167
|
+
}
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, visibility) {
|
|
147
172
|
const formData = new FormData();
|
|
148
173
|
formData.append(
|
|
149
174
|
"bundle",
|
|
@@ -154,6 +179,9 @@ async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum) {
|
|
|
154
179
|
);
|
|
155
180
|
formData.append("manifest", JSON.stringify(manifest));
|
|
156
181
|
formData.append("checksum", checksum);
|
|
182
|
+
if (visibility) {
|
|
183
|
+
formData.append("visibility", visibility);
|
|
184
|
+
}
|
|
157
185
|
const res = await fetch(`${apiUrl}/plugins/register`, {
|
|
158
186
|
method: "POST",
|
|
159
187
|
headers: { Authorization: `Bearer ${token}` },
|
|
@@ -161,32 +189,33 @@ async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum) {
|
|
|
161
189
|
});
|
|
162
190
|
if (!res.ok) {
|
|
163
191
|
const err = await res.json().catch(() => ({ error: res.statusText }));
|
|
164
|
-
console.error(
|
|
192
|
+
console.error(
|
|
193
|
+
`Error registering plugin: ${err.error}`
|
|
194
|
+
);
|
|
165
195
|
process.exit(1);
|
|
166
196
|
}
|
|
167
197
|
return await res.json();
|
|
168
198
|
}
|
|
169
|
-
function
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
execSync(cmd, {
|
|
174
|
-
cwd: process.cwd(),
|
|
175
|
-
stdio: verbose ? "inherit" : "pipe"
|
|
176
|
-
});
|
|
177
|
-
} catch (err) {
|
|
178
|
-
console.error("Build failed:");
|
|
179
|
-
if (!verbose && err instanceof Error && "stderr" in err) {
|
|
180
|
-
console.error(err.stderr?.toString());
|
|
181
|
-
}
|
|
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}`);
|
|
182
203
|
process.exit(1);
|
|
183
204
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
runBuild(opts.verbose);
|
|
205
|
+
if (!await pathExists(manifestPath)) {
|
|
206
|
+
console.error(`Error: manifest.json not found in ${buildDir}`);
|
|
207
|
+
process.exit(1);
|
|
188
208
|
}
|
|
189
|
-
const
|
|
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) {
|
|
190
219
|
const rawToken = opts.token ?? process.env.SNAPTRUDE_TOKEN;
|
|
191
220
|
const token = rawToken?.startsWith("Bearer ") ? rawToken.slice(7) : rawToken;
|
|
192
221
|
const apiUrl = opts.apiUrl ?? process.env.SNAPTRUDE_API_URL;
|
|
@@ -202,44 +231,113 @@ async function handleRegister(opts) {
|
|
|
202
231
|
);
|
|
203
232
|
process.exit(1);
|
|
204
233
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
process.exit(1);
|
|
209
|
-
}
|
|
210
|
-
if (!await pathExists(manifestPath)) {
|
|
211
|
-
console.error(`Error: manifest.json not found in ${buildDir}`);
|
|
212
|
-
process.exit(1);
|
|
213
|
-
}
|
|
214
|
-
const manifest = JSON.parse(
|
|
215
|
-
await readFile2(manifestPath, "utf8")
|
|
216
|
-
);
|
|
217
|
-
if (!manifest.name || !manifest.version) {
|
|
218
|
-
console.error("Error: manifest.json must contain name and version fields");
|
|
219
|
-
process.exit(1);
|
|
220
|
-
}
|
|
221
|
-
if (opts.verbose) console.log(`Reading build from: ${buildDir}`);
|
|
234
|
+
return { token, apiUrl };
|
|
235
|
+
}
|
|
236
|
+
async function buildBundle(buildDir, verbose) {
|
|
222
237
|
console.log("Creating bundle...");
|
|
223
238
|
const entries = (await readdir(buildDir)).filter((e) => e !== "manifest.json");
|
|
224
239
|
if (entries.length === 0) {
|
|
225
240
|
throw new Error("No files to bundle (only manifest.json found)");
|
|
226
241
|
}
|
|
227
|
-
const tarBuffer = await createBundle(buildDir, entries,
|
|
228
|
-
const checksum =
|
|
229
|
-
if (
|
|
242
|
+
const tarBuffer = await createBundle(buildDir, entries, verbose);
|
|
243
|
+
const checksum = computeChecksum(tarBuffer);
|
|
244
|
+
if (verbose) {
|
|
230
245
|
console.log(
|
|
231
246
|
`Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`
|
|
232
247
|
);
|
|
233
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);
|
|
234
262
|
console.log("Registering plugin...");
|
|
235
|
-
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum);
|
|
263
|
+
const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum, opts.visibility);
|
|
236
264
|
console.log("");
|
|
237
265
|
console.log("Plugin registered successfully!");
|
|
238
|
-
console.log(` ID:
|
|
239
|
-
console.log(` Name:
|
|
240
|
-
console.log(` Version:
|
|
241
|
-
console.log(` Bundle:
|
|
242
|
-
console.log(`
|
|
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}` }
|
|
283
|
+
});
|
|
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();
|
|
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
|
+
}
|
|
243
341
|
}
|
|
244
342
|
|
|
245
343
|
// src/index.ts
|
|
@@ -261,8 +359,26 @@ async function main() {
|
|
|
261
359
|
new Option(
|
|
262
360
|
"--api-url <url>",
|
|
263
361
|
"Snaptrude API base URL (or set SNAPTRUDE_API_URL env var)"
|
|
264
|
-
).default("
|
|
265
|
-
).addOption(new Option("--skip-build", "Skip the build step").default(false)).addOption(
|
|
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);
|
|
266
382
|
await program.parseAsync();
|
|
267
383
|
}
|
|
268
384
|
main();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../package.json","../src/index.ts","../src/create.ts","../src/register.ts"],"sourcesContent":["{\n \"name\": \"@snaptrude/create-snaptrude-plugin\",\n \"version\": \"0.0.6\",\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 \"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\"\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(\"https://save2.snaptru.de\"),\n )\n .addOption(new Option(\"--skip-build\", \"Skip the build step\").default(false))\n .addOption(new Option(\"-v, --verbose\", \"Verbose output\").default(false))\n .action(handleRegister)\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 = \"9bb0b4d1d1a76217437f838ff23613bde2e3e79e\"\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 { 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\nasync function pathExists(p: string): Promise<boolean> {\n try {\n await access(p)\n return true\n } catch {\n return false\n }\n}\n\nfunction createBundle(buildDir: string, entries: string[], verbose: boolean): 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\ninterface 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 [key: string]: unknown\n}\n\ninterface RegisterResult {\n id: string\n name: string\n version: string\n bundleUrl: string\n reviewStatus: string\n}\n\nasync function uploadBundle(\n apiUrl: string,\n token: string,\n manifest: PluginManifest,\n tarBuffer: Buffer,\n checksum: 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 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(`Error registering plugin: ${(err as { error: string }).error}`)\n process.exit(1)\n }\n\n return (await res.json()) as RegisterResult\n}\n\n// function detectPackageManager(): \"pnpm\" | \"yarn\" | \"npm\" {\n// for (const [lockfile, pm] of [\n// [\"pnpm-lock.yaml\", \"pnpm\"],\n// [\"yarn.lock\", \"yarn\"],\n// [\"package-lock.json\", \"npm\"],\n// ] as const) {\n// try {\n// const fullPath = join(process.cwd(), lockfile)\n// require(\"node:fs\").accessSync(fullPath)\n// return pm\n// } catch {\n// // not found, try next\n// }\n// }\n// return \"npm\"\n// }\n\nfunction runBuild(verbose: boolean) {\n // const pm = detectPackageManager()\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 handleRegister(opts: {\n path: string\n token?: string\n apiUrl: string\n verbose: boolean\n skipBuild: boolean\n}) {\n if (!opts.skipBuild) {\n runBuild(opts.verbose)\n }\n\n const buildDir = resolve(opts.path)\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 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 if (opts.verbose) console.log(`Reading build from: ${buildDir}`)\n\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, opts.verbose)\n const checksum = createHash(\"sha256\").update(tarBuffer).digest(\"hex\")\n if (opts.verbose) {\n console.log(\n `Bundle size: ${(tarBuffer.length / 1024).toFixed(1)} KB, checksum: ${checksum}`,\n )\n }\n\n console.log(\"Registering plugin...\")\n const result = await uploadBundle(apiUrl, token, manifest, tarBuffer, checksum)\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(` Status: ${result.reviewStatus}`)\n}\n"],"mappings":"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","names":["readFile","join"]}
|
|
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":""}
|
package/dist/src/register.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/register.ts"],"names":[],"mappings":"
|
|
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,7 +17,8 @@
|
|
|
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",
|
|
@@ -29,8 +30,10 @@
|
|
|
29
30
|
},
|
|
30
31
|
"scripts": {
|
|
31
32
|
"check-types": "tsc --noEmit",
|
|
32
|
-
"build": "tsup",
|
|
33
|
+
"build": "tsup --clean",
|
|
33
34
|
"dev": "tsup --watch",
|
|
34
|
-
"clean-dist": "rm -rf dist"
|
|
35
|
+
"clean-dist": "rm -rf dist",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest"
|
|
35
38
|
}
|
|
36
39
|
}
|