@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 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.6",
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 = "9bb0b4d1d1a76217437f838ff23613bde2e3e79e";
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
- async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum) {
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(`Error registering plugin: ${err.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 runBuild(verbose) {
193
- const cmd = `npm run build:prod`;
194
- console.log(`Building plugin (${cmd})...`);
195
- try {
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
- async function handleRegister(opts) {
209
- if (!opts.skipBuild) {
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 buildDir = (0, import_node_path2.resolve)(opts.path);
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
- const manifestPath = (0, import_node_path2.join)(buildDir, "manifest.json");
229
- if (!await pathExists(buildDir)) {
230
- console.error(`Error: Build directory not found: ${buildDir}`);
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, opts.verbose);
251
- const checksum = (0, import_node_crypto2.createHash)("sha256").update(tarBuffer).digest("hex");
252
- if (opts.verbose) {
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: ${result.id}`);
262
- console.log(` Name: ${result.name}`);
263
- console.log(` Version: ${result.version}`);
264
- console.log(` Bundle: ${result.bundleUrl}`);
265
- console.log(` Status: ${result.reviewStatus}`);
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("https://save2.snaptru.de")
288
- ).addOption(new import_extra_typings.Option("--skip-build", "Skip the build step").default(false)).addOption(new import_extra_typings.Option("-v, --verbose", "Verbose output").default(false)).action(handleRegister);
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();
@@ -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",
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 = "9bb0b4d1d1a76217437f838ff23613bde2e3e79e";
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, resolve } from "path";
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
- async function uploadBundle(apiUrl, token, manifest, tarBuffer, checksum) {
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(`Error registering plugin: ${err.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 runBuild(verbose) {
170
- const cmd = `npm run build:prod`;
171
- console.log(`Building plugin (${cmd})...`);
172
- try {
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
- async function handleRegister(opts) {
186
- if (!opts.skipBuild) {
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 buildDir = resolve(opts.path);
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
- const manifestPath = join2(buildDir, "manifest.json");
206
- if (!await pathExists(buildDir)) {
207
- console.error(`Error: Build directory not found: ${buildDir}`);
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, opts.verbose);
228
- const checksum = createHash("sha256").update(tarBuffer).digest("hex");
229
- if (opts.verbose) {
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: ${result.id}`);
239
- console.log(` Name: ${result.name}`);
240
- console.log(` Version: ${result.version}`);
241
- console.log(` Bundle: ${result.bundleUrl}`);
242
- console.log(` Status: ${result.reviewStatus}`);
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("https://save2.snaptru.de")
265
- ).addOption(new Option("--skip-build", "Skip the build step").default(false)).addOption(new Option("-v, --verbose", "Verbose output").default(false)).action(handleRegister);
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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=shared.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/shared.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=update.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/update.test.ts"],"names":[],"mappings":""}
@@ -4,5 +4,6 @@ export declare function handleRegister(opts: {
4
4
  apiUrl: string;
5
5
  verbose: boolean;
6
6
  skipBuild: boolean;
7
+ visibility?: string;
7
8
  }): Promise<void>;
8
9
  //# sourceMappingURL=register.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../src/register.ts"],"names":[],"mappings":"AAqHA,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;CACnB,iBAmEA"}
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.6",
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
  }