toolaby 1.8.2 → 1.8.3
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 +14 -4
- package/lib/manifest.js +5 -2
- package/package.json +1 -1
package/bin.mjs
CHANGED
|
@@ -44,7 +44,7 @@ import { runMcp } from './lib/mcp.js';
|
|
|
44
44
|
import { runCheck } from './lib/check.js';
|
|
45
45
|
import { inside, signInPage, devicePolling, opener, privateKind, privateContent, privateCopies, googleKey, projectRoot, gitDirectory, gitObject, gitObjects, gitFile, notAnImage, unpacked, COMPRESSED, publicLinks, privateLinks, oneLine, fetchBounded, fetchHere, readBounded, readText, SCAFFOLD_FILES } from './lib/safe.js';
|
|
46
46
|
|
|
47
|
-
const VERSION = '1.8.
|
|
47
|
+
const VERSION = '1.8.3';
|
|
48
48
|
const CLIENT_ID = 'toolaby-cli';
|
|
49
49
|
const argv = process.argv.slice(2);
|
|
50
50
|
// `--version` and `--help` are commands of their own; every other command is the first bare word.
|
|
@@ -312,7 +312,7 @@ async function wire() {
|
|
|
312
312
|
// The background the manifest names, read from inside the folder only: whether it starts the Wall, or is the Wall's.
|
|
313
313
|
const namedWorker = workerIn(manifest) ?? '';
|
|
314
314
|
const workerSource = namedWorker && has(namedWorker) && !inside(dir, namedWorker).why ? readOr(join(dir, namedWorker), '') : null;
|
|
315
|
-
const wiring = project.manifestFile && manifest ? wireManifest(manifest, { site, has, remembered, rememberedSidePanel, manifestKey, ownInFront, workerSource }) : null;
|
|
315
|
+
const wiring = project.manifestFile && manifest ? wireManifest(manifest, { site, apex: new URL(wall).host, has, remembered, rememberedSidePanel, manifestKey, ownInFront, workerSource }) : null;
|
|
316
316
|
const appPopup = wiring ? wiring.appPopup : project.wrapper ? (project.appPopup ?? remembered) : null;
|
|
317
317
|
const appSidePanel = wiring ? wiring.appSidePanel : project.wrapper ? (project.appSidePanel ?? rememberedSidePanel) : null;
|
|
318
318
|
const targets = filesToWrite(project, appPopup, appSidePanel, { popup: !!wiring?.ownPopup, sidePanel: !!wiring?.ownSidePanel });
|
|
@@ -743,6 +743,15 @@ function pack() {
|
|
|
743
743
|
const hosts = manifest.host_permissions ?? []; const ec = manifest.externally_connectable?.matches ?? [];
|
|
744
744
|
if (!hosts.includes(sitePattern(site)) || !ec.includes(sitePattern(site))) problems.push(`The manifest does not name ${oneLine(sitePattern(site))} in both host_permissions and externally_connectable: sign-in and the purchase would not reach the extension. \`npx -y toolaby@latest wire <tool-id> --live --force\` adds them.`);
|
|
745
745
|
}
|
|
746
|
+
// A host under the Wall's address that no key in the build names: another workspace's, or the other side's Test
|
|
747
|
+
// address, left by an earlier wiring or pasted by hand. The store build asks its buyers for it at install, and gains
|
|
748
|
+
// nothing: the extension talks to its own key's host alone (30 Sep 2026).
|
|
749
|
+
const walls = [...new Set(['toolaby.app', new URL(wall).hostname])];
|
|
750
|
+
const hostOf = (m) => /^(?:\*|https?|wss?):\/\/([^/]+)\//.exec(m)?.[1]?.replace(/^\*\./, '').toLowerCase() ?? null;
|
|
751
|
+
const keys = new Set([...sites].map(sitePattern));
|
|
752
|
+
const strangers = [...new Set([...(manifest.host_permissions ?? []), ...(manifest.externally_connectable?.matches ?? [])])]
|
|
753
|
+
.filter((m) => typeof m === 'string' && !keys.has(m) && walls.some((w) => { const h = hostOf(m); return !!h && (h === w || h.endsWith(`.${w}`)); }));
|
|
754
|
+
if (strangers.length && !flag('--allow-wall-hosts')) problems.push(`The manifest names ${strangers.map(oneLine).join(', ')}: the Wall's, and no key's in this build — another workspace, or the other side's Test address. A store build asks its buyers for ${strangers.length > 1 ? 'these' : 'it'} at install for nothing: take ${strangers.length > 1 ? 'them' : 'it'} out of host_permissions and externally_connectable. (--allow-wall-hosts packs it anyway.)`);
|
|
746
755
|
if (problems.length) fail(`Not packed:\n\n${problems.map((p) => ` · ${p}`).join('\n\n')}`);
|
|
747
756
|
|
|
748
757
|
const hadKey = typeof manifest.key === 'string';
|
|
@@ -785,7 +794,7 @@ function mcp() {
|
|
|
785
794
|
}
|
|
786
795
|
|
|
787
796
|
async function check() {
|
|
788
|
-
const passed = await runCheck({ mark: (tone, text) => say(` ${tone === 'ok' ? green('✓') : tone === 'warn' ? yellow('!') : red('✗')} ${plain(text)}`), dir: opt('--into') ?? positional[0] ?? '.', out, api: (path, o = {}) => api(path, o), token: storedToken, detectProject, wireManifest, listTree, readJson, browser: flag('--browser') });
|
|
797
|
+
const passed = await runCheck({ mark: (tone, text) => say(` ${tone === 'ok' ? green('✓') : tone === 'warn' ? yellow('!') : red('✗')} ${plain(text)}`), dir: opt('--into') ?? positional[0] ?? '.', out, api: (path, o = {}) => api(path, o), token: storedToken, detectProject, wireManifest: (m, o) => wireManifest(m, { apex: new URL(wall).host, ...o }), listTree, readJson, browser: flag('--browser') });
|
|
789
798
|
if (!passed) process.exit(1);
|
|
790
799
|
}
|
|
791
800
|
|
|
@@ -804,7 +813,8 @@ function help() {
|
|
|
804
813
|
--surfaces both|popup|side-panel|none what it opens (default: both)
|
|
805
814
|
tools your tools, with their ids
|
|
806
815
|
pack [folder] the zip for the Chrome Web Store: the built extension, its manifest's "key" left out;
|
|
807
|
-
refuses a Test key or
|
|
816
|
+
refuses a Test key, localhost, or another of the Wall's hosts inside
|
|
817
|
+
--out <file.zip>
|
|
808
818
|
leaves out keys, certificates, .env and credential files, source maps, secrets,
|
|
809
819
|
git's files, a build's copy of a private file (compressed, UTF-16 or base64),
|
|
810
820
|
an image that is none; refuses a build if one is a file the manifest names
|
package/lib/manifest.js
CHANGED
|
@@ -127,8 +127,11 @@ export function wireManifest(input, o) {
|
|
|
127
127
|
const pattern = sitePattern(o.site);
|
|
128
128
|
// A Test address of the Wall's that is not this key's (./test-address): left by an earlier wiring to the other side.
|
|
129
129
|
// Test's workspaces have hosts of their own, and a build wired for Test and then for Live went on asking its buyers,
|
|
130
|
-
// at install, for access to Test's host too (29 Sep 2026).
|
|
131
|
-
|
|
130
|
+
// at install, for access to Test's host too (29 Sep 2026). Only under the Wall's own address: a host of the
|
|
131
|
+
// developer's that reads like one, on a domain of theirs, was taken out of their build too (30 Sep 2026).
|
|
132
|
+
const apex = (o.apex ?? host.split('.').slice(1).join('.')).toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
133
|
+
const underWall = new RegExp(`^https://([a-z0-9-]+)\\.${apex}/\\*$`);
|
|
134
|
+
const stale = (p) => typeof p === 'string' && p !== pattern && isTestAddress(underWall.exec(p)?.[1]);
|
|
132
135
|
for (const field of ['host_permissions', 'externally_connectable']) {
|
|
133
136
|
const list = field === 'host_permissions' ? manifest.host_permissions : manifest.externally_connectable?.matches;
|
|
134
137
|
const gone = Array.isArray(list) ? list.filter(stale) : [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolaby",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
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; check it, and give coding agents the Wall as an MCP server.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|