toolaby 1.4.4 → 1.4.5
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/bin.mjs +12 -6
- package/lib/project.js +18 -4
- package/package.json +1 -1
package/bin.mjs
CHANGED
|
@@ -32,9 +32,9 @@ import { homedir } from 'node:os';
|
|
|
32
32
|
import { spawn } from 'node:child_process';
|
|
33
33
|
import { createHmac, randomBytes } from 'node:crypto';
|
|
34
34
|
import { wireManifest, WORKER_LINES } from './lib/manifest.js';
|
|
35
|
-
import { detectProject, CODE_FILES, filesToWrite, fillPages, scaffoldManifest, STALE_FILES, BUILD_COPY_NOTE } from './lib/project.js';
|
|
35
|
+
import { detectProject, CODE_FILES, filesToWrite, fillPages, scaffoldManifest, scaffoldFilesFor, surfacesOf, hasPopup, hasSidePanel, SURFACES, STALE_FILES, BUILD_COPY_NOTE } from './lib/project.js';
|
|
36
36
|
|
|
37
|
-
const VERSION = '1.4.
|
|
37
|
+
const VERSION = '1.4.5';
|
|
38
38
|
const CLIENT_ID = 'toolaby-cli';
|
|
39
39
|
const argv = process.argv.slice(2);
|
|
40
40
|
// `--version` and `--help` are commands of their own; every other command is the first bare word.
|
|
@@ -259,20 +259,25 @@ async function create() {
|
|
|
259
259
|
// The scaffold's own files as the Wall names them (older Walls did not, hence the list): a Wall that adds one to the
|
|
260
260
|
// minimal extension is written by this command too, instead of a manifest naming a file that never arrived.
|
|
261
261
|
const scaffold = Array.isArray(plan.scaffold) && plan.scaffold.length ? plan.scaffold : ['manifest.json', 'background.js', 'popup.html', 'sidepanel.html', 'popup.css', 'popup.js', 'README.md'];
|
|
262
|
-
|
|
262
|
+
// Which surfaces this extension is made with: both (the default), one of them, or none at all for a tool that works
|
|
263
|
+
// from the background. Asked for once here, rather than written and then deleted by hand.
|
|
264
|
+
const asked = opt('--surfaces');
|
|
265
|
+
if (asked && !SURFACES.includes(asked)) fail(`--surfaces takes ${SURFACES.join(', ')} — not "${asked}".`);
|
|
266
|
+
const surfaces = surfacesOf(asked);
|
|
267
|
+
const wanted = [...CODE_FILES, ...scaffoldFilesFor(surfaces, scaffold)];
|
|
263
268
|
const absent = wanted.filter((f) => typeof plan.files[f] !== 'string');
|
|
264
269
|
if (absent.length) fail(`The Wall at ${wall} named ${absent.join(', ')} for a new extension but did not hand ${absent.length > 1 ? 'them' : 'it'} over.\n Nothing was written. Update this command: npm install -g toolaby@latest — or run the Wall's own copy: npx --yes ${wall}/toolaby.tgz create ${slug}`);
|
|
265
270
|
// Both surfaces, and the panel drawn inside them: no page of the Wall's stands in front, so both names stay empty.
|
|
266
271
|
for (const f of wanted) write(f, fillPages(plan.files[f]));
|
|
267
272
|
// The manifest names the side panel only now that the page is beside it — an extension whose side_panel points at a
|
|
268
273
|
// missing file does not load at all, so a Wall that stops serving the page must not leave the key behind either.
|
|
269
|
-
|
|
270
|
-
write('manifest.json', JSON.stringify(scaffoldManifest(JSON.parse(readFileSync(join(dir, 'manifest.json'), 'utf8')), { sidePanel: wroteSidePanel }), null, 2) + '\n');
|
|
274
|
+
write('manifest.json', JSON.stringify(scaffoldManifest(JSON.parse(readFileSync(join(dir, 'manifest.json'), 'utf8')), { sidePanel: hasSidePanel(surfaces), popup: hasPopup(surfaces) }), null, 2) + '\n');
|
|
271
275
|
for (const s of [16, 48, 128]) {
|
|
272
276
|
const res = await fetch(`${wall}/boilerplate/icons/icon${s}.png`);
|
|
273
277
|
write(join('icons', `icon${s}.png`), Buffer.from(await res.arrayBuffer()));
|
|
274
278
|
}
|
|
275
|
-
|
|
279
|
+
const clicking = { both: 'Click the icon: the popup shows what the Free plan holds. Open side panel, in it, is the same page at the panel\'s width', popup: 'Click the icon: the popup shows what the Free plan holds', 'side-panel': 'Click the icon: the side panel opens — it has no popup, so the click is the panel\'s', none: 'No popup and no side panel: nothing opens on a click. Your code says when to sell — toolaby.openPaymentPage()' }[surfaces];
|
|
280
|
+
out(`\n ${plan.name} → ${dir}${surfaces === 'both' ? '' : ` (--surfaces ${surfaces})`}\n\n 1. chrome://extensions → Developer mode → Load unpacked → ${dir}\n 2. ${clicking}; Buy opens ${plan.site}/tools/${slug}\n\n Edit background.js: your work goes behind toolaby.gate().\n Surfaces, and how to add or drop one later: ${plan.site}/docs/surfaces\n`);
|
|
276
281
|
}
|
|
277
282
|
|
|
278
283
|
// ── webhooks: the catalogue, and a delivery on demand ───────────────────────────────────────────────────────────────
|
|
@@ -368,6 +373,7 @@ function help() {
|
|
|
368
373
|
--into <folder> another folder --force replace the platform's files
|
|
369
374
|
toolaby upgrade <tool-id> the platform's files replaced with the current ones — the popup, the client — yours untouched
|
|
370
375
|
toolaby create <tool-id> a new, minimal extension for your tool, in <tool-id>/ --dir <folder>
|
|
376
|
+
--surfaces both|popup|side-panel|none what it opens (default: both)
|
|
371
377
|
toolaby tools your tools, with their ids
|
|
372
378
|
toolaby webhooks events the six events, with an example of each
|
|
373
379
|
toolaby webhooks trigger <event> an example delivery to your endpoints; --to <url> sends it to a local server instead
|
package/lib/project.js
CHANGED
|
@@ -19,18 +19,32 @@ export const filesToWrite = (p, appPopup, appSidePanel = null) => [
|
|
|
19
19
|
...(appSidePanel ? SIDE_PANEL_FILES.map((f) => `${p.popupDir}${f}`) : []),
|
|
20
20
|
...(p.extraFiles ?? []).map((f) => f.to),
|
|
21
21
|
];
|
|
22
|
+
export const SURFACES = ['both', 'popup', 'side-panel', 'none'];
|
|
23
|
+
export const surfacesOf = (v) => SURFACES.includes(v ?? '') ? v : 'both';
|
|
24
|
+
export const hasPopup = (s) => s === 'both' || s === 'popup';
|
|
25
|
+
export const hasSidePanel = (s) => s === 'both' || s === 'side-panel';
|
|
26
|
+
/** The scaffold's own files for those surfaces: the manifest and the background always, the pages as asked for. */
|
|
27
|
+
export const scaffoldFilesFor = (s, all) => all.filter((f) => (f === 'popup.html' ? hasPopup(s) : f === 'sidepanel.html' ? hasSidePanel(s) : f === 'popup.js' || f === 'popup.css' ? s !== 'none' : true));
|
|
22
28
|
/**
|
|
23
29
|
* The scaffold's manifest, once it is known which pages were really written. Chrome refuses to load an extension
|
|
24
30
|
* whose `side_panel.default_path` names a file that is not there — the whole extension, not just the panel — so the
|
|
25
|
-
* minimal extension ships a manifest that names only its popup, and whatever writes the
|
|
31
|
+
* minimal extension ships a manifest that names only its popup, and whatever writes the pages settles it here: the
|
|
32
|
+
* side panel added with its page, the popup taken out when there is none (the icon stays; the click then opens the
|
|
33
|
+
* side panel, or nothing, which is what a background-only tool wants).
|
|
26
34
|
*/
|
|
27
35
|
export function scaffoldManifest(manifest, wrote) {
|
|
36
|
+
const out = { ...manifest };
|
|
37
|
+
if (wrote.popup === false) {
|
|
38
|
+
const action = { ...out.action };
|
|
39
|
+
delete action.default_popup;
|
|
40
|
+
out.action = action;
|
|
41
|
+
}
|
|
28
42
|
if (!wrote.sidePanel)
|
|
29
|
-
return
|
|
30
|
-
const permissions = Array.isArray(
|
|
43
|
+
return out;
|
|
44
|
+
const permissions = Array.isArray(out.permissions) ? [...out.permissions] : [];
|
|
31
45
|
if (!permissions.includes('sidePanel'))
|
|
32
46
|
permissions.push('sidePanel');
|
|
33
|
-
return { ...
|
|
47
|
+
return { ...out, permissions, side_panel: { default_path: 'sidepanel.html' } };
|
|
34
48
|
}
|
|
35
49
|
/**
|
|
36
50
|
* The last two placeholders in a handed-out file — the extension's own popup and side panel, which only the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolaby",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
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": {
|