toolaby 1.3.0 → 1.4.1

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.
Files changed (2) hide show
  1. package/bin.mjs +40 -7
  2. package/package.json +1 -1
package/bin.mjs CHANGED
@@ -7,6 +7,9 @@
7
7
  // toolaby tools your tools, with the ids the commands want
8
8
  // toolaby webhooks events the six events, with an example of each
9
9
  // toolaby webhooks trigger <event> send an example delivery: to your registered endpoints, or with --to straight to a local server
10
+ // toolaby webhooks endpoints the workspace's endpoints
11
+ // toolaby webhooks add <url> register an endpoint; the secret is printed once
12
+ // toolaby webhooks remove <id> remove one
10
13
  // toolaby whoami · logout · help
11
14
  //
12
15
  // Test and live, as Stripe's command line has them: every command acts on
@@ -31,7 +34,7 @@ import { createHmac, randomBytes } from 'node:crypto';
31
34
  import { wireManifest, WORKER_LINES } from './lib/manifest.js';
32
35
  import { detectProject, CODE_FILES, filesToWrite, BUILD_COPY_NOTE } from './lib/project.js';
33
36
 
34
- const VERSION = '1.3.0';
37
+ const VERSION = '1.4.1';
35
38
  const CLIENT_ID = 'toolaby-cli';
36
39
  const argv = process.argv.slice(2);
37
40
  // `--version` and `--help` are commands of their own; every other command is the first bare word.
@@ -39,7 +42,8 @@ const command = argv.find((a) => ['--version', '-v', '--help', '-h'].includes(a)
39
42
  const rest = argv.filter((a) => a !== command);
40
43
  const positional = rest.filter((a) => !a.startsWith('--'));
41
44
  const opt = (k, d = null) => { const i = rest.indexOf(k); return i >= 0 && rest[i + 1] && !rest[i + 1].startsWith('--') ? rest[i + 1] : d; };
42
- const flag = (k) => rest.includes(k);
45
+ // `upgrade` is `wire --force`: the platform's files replaced with the current ones, the extension's own untouched.
46
+ const flag = (k) => rest.includes(k) || (k === '--force' && command === 'upgrade');
43
47
  const WALLS = { test: 'https://test.toolaby.app', live: 'https://toolaby.app' };
44
48
  const live = flag('--live');
45
49
  const wall = (opt('--wall') ?? process.env.TOOLABY_WALL ?? (live ? WALLS.live : WALLS.test)).replace(/\/$/, '');
@@ -183,7 +187,7 @@ async function filesFor(slug, scaffold, manifestKey = null) {
183
187
 
184
188
  async function wire() {
185
189
  const slug = positional[0];
186
- if (!isId(slug)) fail('usage: toolaby wire <tool-id> [--into <folder>] [--force] — `toolaby tools` lists your ids');
190
+ if (!isId(slug)) fail(command === 'upgrade' ? 'usage: toolaby upgrade <tool-id> [--into <folder>] — `toolaby tools` lists your ids' : 'usage: toolaby wire <tool-id> [--into <folder>] [--force] — `toolaby tools` lists your ids');
187
191
  const dir = resolve(opt('--into') ?? '.');
188
192
  if (!existsSync(dir)) fail(`${dir} does not exist`);
189
193
  const tree = listTree(dir, 3);
@@ -279,9 +283,9 @@ async function webhooks() {
279
283
  if (!type) fail('usage: toolaby webhooks trigger <event> [--to <url>] [--secret <whsec_…>] — `toolaby webhooks events` lists them');
280
284
  const to = opt('--to');
281
285
  if (!to) {
282
- const res = await api('/api/cli/webhooks/trigger', { method: 'POST', body: { type }, token: await tokenOrLogin() });
286
+ const res = await api('/api/cli/webhooks/trigger', { method: 'POST', body: { type, workspace: opt('--workspace') ?? undefined }, token: await tokenOrLogin() });
283
287
  if (!res.ok) fail(res.json.message ?? `The Wall answered HTTP ${res.status}.`);
284
- out(`\n Sent ${res.json.sent} to every endpoint of ${res.json.workspace} · ${side}. Its id is ${res.json.id}; the delivery log is under Configure → API.\n`);
288
+ out(`\n Sent ${res.json.sent} to every endpoint of ${res.json.workspace} · ${side}. Its id is ${res.json.id}; the delivery log is under Configure → Webhooks.\n`);
285
289
  return;
286
290
  }
287
291
  const events = await catalogue();
@@ -303,7 +307,34 @@ async function webhooks() {
303
307
  if (res.status >= 300) out(' A real delivery would be retried until your server answers 2xx.\n');
304
308
  return;
305
309
  }
306
- fail('usage: toolaby webhooks events | trigger <event> [--to <url>] [--secret <whsec_…>]');
310
+ if (sub === 'endpoints') {
311
+ const ws = opt('--workspace');
312
+ const res = await api(`/api/cli/webhooks/endpoints${ws ? `?workspace=${encodeURIComponent(ws)}` : ''}`, { token: await tokenOrLogin() });
313
+ if (!res.ok) fail(res.json.message ?? `The Wall answered HTTP ${res.status}.`);
314
+ out(`\n ${res.json.workspace} · ${side}\n`);
315
+ if (res.json.endpoints.length === 0) out(' None yet. `toolaby webhooks add <url>` registers one.');
316
+ for (const e of res.json.endpoints) out(` ${e.id} ${e.disabled ? 'paused ' : 'on '} ${e.url}${e.description ? ` — ${e.description}` : ''}${e.events.length ? ` (${e.events.join(', ')})` : ''}`);
317
+ out();
318
+ return;
319
+ }
320
+ if (sub === 'add') {
321
+ const url = positional[1];
322
+ if (!url) fail('usage: toolaby webhooks add <url> [--description <text>] [--events a.b,c.d] [--workspace <slug>]');
323
+ const events = (opt('--events') ?? '').split(',').map((e) => e.trim()).filter(Boolean);
324
+ const res = await api('/api/cli/webhooks/endpoints', { method: 'POST', body: { url, description: opt('--description') ?? '', events, workspace: opt('--workspace') ?? undefined }, token: await tokenOrLogin() });
325
+ if (!res.ok) fail(res.json.message ?? `The Wall answered HTTP ${res.status}.`);
326
+ out(`\n Added ${res.json.id} → ${res.json.url} · ${res.json.workspace} · ${side}\n\n Signing secret, shown once — keep it where your server keeps secrets:\n\n ${res.json.secret}\n`);
327
+ return;
328
+ }
329
+ if (sub === 'remove') {
330
+ const id = positional[1];
331
+ if (!id) fail('usage: toolaby webhooks remove <ep_…> [--workspace <slug>] — `toolaby webhooks endpoints` lists them');
332
+ const res = await api('/api/cli/webhooks/endpoints', { method: 'DELETE', body: { id, workspace: opt('--workspace') ?? undefined }, token: await tokenOrLogin() });
333
+ if (!res.ok) fail(res.json.message ?? `The Wall answered HTTP ${res.status}.`);
334
+ out(`\n Removed ${res.json.removed} · ${res.json.workspace} · ${side}. Deliveries to it stop at once.\n`);
335
+ return;
336
+ }
337
+ fail('usage: toolaby webhooks events | trigger <event> [--to <url>] | endpoints | add <url> | remove <id>');
307
338
  }
308
339
 
309
340
  function help() {
@@ -313,10 +344,12 @@ function help() {
313
344
  toolaby wire <tool-id> wire the extension in this folder to your tool, on Test
314
345
  toolaby wire <tool-id> --live the same, on Live: the store build
315
346
  --into <folder> another folder --force replace the platform's files
347
+ toolaby upgrade <tool-id> the platform's files replaced with the current ones — the popup, the client — yours untouched
316
348
  toolaby create <tool-id> a new, minimal extension for your tool, in <tool-id>/ --dir <folder>
317
349
  toolaby tools your tools, with their ids
318
350
  toolaby webhooks events the six events, with an example of each
319
351
  toolaby webhooks trigger <event> an example delivery to your endpoints; --to <url> sends it to a local server instead
352
+ toolaby webhooks endpoints your endpoints; add <url> registers one (secret shown once), remove <id> removes one
320
353
  toolaby login · whoami · logout the session, per side; a command that needs one signs you in itself
321
354
 
322
355
  Every command acts on Test (test.toolaby.app) unless told --live (toolaby.app).
@@ -324,7 +357,7 @@ function help() {
324
357
  `);
325
358
  }
326
359
 
327
- const commands = { login: async () => { await login(); }, logout, whoami, tools, wire, create, webhooks, help, '--help': help, '-h': help, '--version': () => out(VERSION), '-v': () => out(VERSION) };
360
+ const commands = { login: async () => { await login(); }, logout, whoami, tools, wire, upgrade: wire, create, webhooks, help, '--help': help, '-h': help, '--version': () => out(VERSION), '-v': () => out(VERSION) };
328
361
  const run = commands[command];
329
362
  if (!run) { console.error(`\n Unknown command "${command}".`); help(); process.exit(1); }
330
363
  Promise.resolve().then(run).catch((e) => fail(e.message));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolaby",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "The Toolaby command line: sign in once, then wire any Chrome extension to your tool on the Wall — sign-in, the Free plan, licences and subscriptions — or start a new one.",
5
5
  "type": "module",
6
6
  "bin": {