Commit 84e484a

Anton Golub <antongolub@antongolub.com>
2025-08-26 11:38:03
feat: expose bus api (#1332)
* chore: update tsx to v4.20.5 * feat: expose internal api registry * chore: improve jsr types * refactor: conceal `bus.store`
1 parent 72b5604
build/core.cjs
@@ -20,6 +20,7 @@ __export(core_exports, {
   Fail: () => Fail,
   ProcessOutput: () => ProcessOutput,
   ProcessPromise: () => ProcessPromise,
+  bus: () => import_internals.bus,
   cd: () => cd,
   chalk: () => import_vendor_core3.chalk,
   defaults: () => defaults,
@@ -392,6 +393,7 @@ function formatCmd(cmd) {
 // src/core.ts
 var import_vendor_core2 = require("./vendor-core.cjs");
 var import_util = require("./util.cjs");
+var import_internals = require("./internals.cjs");
 var import_node_path = __toESM(require("path"), 1);
 var os = __toESM(require("os"), 1);
 var import_vendor_core3 = require("./vendor-core.cjs");
@@ -1145,6 +1147,7 @@ function resolveDefaults(defs = defaults, prefix = ENV_PREFIX, env = import_node
   Fail,
   ProcessOutput,
   ProcessPromise,
+  bus,
   cd,
   chalk,
   defaults,
build/core.d.ts
@@ -11,6 +11,7 @@ import { Fail } from './error.js';
 import { log } from './log.js';
 import { type TSpawnStore } from './vendor-core.js';
 import { type Duration, quote } from './util.js';
+export { bus } from './internals.js';
 export { default as path } from 'node:path';
 export * as os from 'node:os';
 export { Fail } from './error.js';
build/core.js
@@ -6,6 +6,7 @@ const {
   Fail,
   ProcessOutput,
   ProcessPromise,
+  bus,
   cd,
   chalk,
   defaults,
@@ -29,6 +30,7 @@ export {
   Fail,
   ProcessOutput,
   ProcessPromise,
+  bus,
   cd,
   chalk,
   defaults,
build/index.cjs
@@ -41,6 +41,7 @@ __export(index_exports, {
   versions: () => versions
 });
 module.exports = __toCommonJS(index_exports);
+var import_core2 = require("./core.cjs");
 
 // src/goods.ts
 var import_node_buffer = require("buffer");
@@ -251,6 +252,7 @@ function spinner(title, callback) {
 // src/index.ts
 __reExport(index_exports, require("./core.cjs"), module.exports);
 var import_vendor2 = require("./vendor.cjs");
+import_core2.bus.lock();
 var VERSION = versions.zx || "0.0.0";
 var version = VERSION;
 function nothrow(promise) {
build/index.js
@@ -32,6 +32,7 @@ const {
   Fail,
   ProcessOutput,
   ProcessPromise,
+  bus,
   cd,
   chalk,
   defaults,
@@ -81,6 +82,7 @@ export {
   Fail,
   ProcessOutput,
   ProcessPromise,
+  bus,
   cd,
   chalk,
   defaults,
build/internals.cjs
@@ -11,9 +11,12 @@ __export(internals_exports, {
   bus: () => bus
 });
 module.exports = __toCommonJS(internals_exports);
+var locked = false;
+var lock = () => locked = true;
 var store = /* @__PURE__ */ new Map();
 var override = store.set.bind(store);
-var wrap = (name, api) => {
+function wrap(name, api) {
+  if (locked) throw new Error("bus is locked");
   override(name, api);
   return new Proxy(api, {
     get(_, key) {
@@ -24,11 +27,11 @@ var wrap = (name, api) => {
       return store.get(name).apply(self, args);
     }
   });
-};
+}
 var bus = {
   override,
-  store,
-  wrap
+  wrap,
+  lock
 };
 /* c8 ignore next 100 */
 // Annotate the CommonJS export names for ESM import in node:
build/internals.d.ts
@@ -0,0 +1,12 @@
+declare function wrap<T extends object>(name: string, api: T): T;
+/**
+ * @internal
+ * @private
+ * @protected
+ */
+export declare const bus: {
+    override: (key: string, value: any) => Map<string, any>;
+    wrap: typeof wrap;
+    lock: () => void;
+};
+export {};
scripts/build-clean.mjs
@@ -18,10 +18,7 @@ import fs from 'node:fs'
 import glob from 'fast-glob'
 
 const redundants = await glob(
-  [
-    'build/{repl,globals-jsr,internals}.d.ts',
-    'build/{deps,internals,util,vendor*}.js',
-  ],
+  ['build/{repl,globals-jsr}.d.ts', 'build/{deps,internals,util,vendor*}.js'],
   {
     onlyFiles: true,
     absolute: true,
src/core.ts
@@ -58,6 +58,7 @@ import {
   bufArrJoin,
 } from './util.ts'
 
+export { bus } from './internals.ts'
 export { default as path } from 'node:path'
 export * as os from 'node:os'
 export { Fail } from './error.ts'
src/index.ts
@@ -12,9 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-import { type ProcessPromise } from './core.ts'
+import { type ProcessPromise, bus } from './core.ts'
 import { versions } from './goods.ts'
 
+bus.lock()
+
 export * from './core.ts'
 export * from './goods.ts'
 export { minimist, dotenv, fs, YAML, glob, glob as globby } from './vendor.ts'
src/internals.ts
@@ -14,9 +14,13 @@
 
 type TCallable = (...args: any[]) => any
 
-const store = new Map<string, any>()
-const override = store.set.bind(store)
-const wrap = <T extends object>(name: string, api: T): T => {
+let locked = false
+const lock: () => void = () => (locked = true)
+
+const store: Map<string, any> = new Map()
+const override: (typeof store)['set'] = store.set.bind(store)
+function wrap<T extends object>(name: string, api: T): T {
+  if (locked) throw new Error('bus is locked')
   override(name, api)
   return new Proxy<T>(api, {
     get(_, key) {
@@ -28,8 +32,13 @@ const wrap = <T extends object>(name: string, api: T): T => {
   })
 }
 
+/**
+ * @internal
+ * @private
+ * @protected
+ */
 export const bus = {
   override,
-  store,
   wrap,
+  lock,
 }
test/it/build-npm.test.js
@@ -105,6 +105,7 @@ describe('npm artifact', () => {
             'build/index.d.ts',
             'build/index.js',
             'build/internals.cjs',
+            'build/internals.d.ts',
             'build/log.d.ts',
             'build/md.d.ts',
             'build/util.cjs',
@@ -175,6 +176,7 @@ describe('npm artifact', () => {
             'build/error.d.ts',
             'build/esblib.cjs',
             'build/internals.cjs',
+            'build/internals.d.ts',
             'build/log.d.ts',
             'build/util.cjs',
             'build/util.d.ts',
test/export.test.js
@@ -34,6 +34,10 @@ describe('core', () => {
     assert.equal(typeof core.ProcessPromise, 'function', 'core.ProcessPromise')
     assert.equal(typeof core.ProcessPromise.bus, 'object', 'core.ProcessPromise.bus')
     assert.equal(typeof core.ProcessPromise.promisifyStream, 'function', 'core.ProcessPromise.promisifyStream')
+    assert.equal(typeof core.bus, 'object', 'core.bus')
+    assert.equal(typeof core.bus.lock, 'function', 'core.bus.lock')
+    assert.equal(typeof core.bus.override, 'function', 'core.bus.override')
+    assert.equal(typeof core.bus.wrap, 'function', 'core.bus.wrap')
     assert.equal(typeof core.cd, 'function', 'core.cd')
     assert.equal(typeof core.chalk, 'function', 'core.chalk')
     assert.equal(typeof core.chalk.level, 'number', 'core.chalk.level')
@@ -196,6 +200,10 @@ describe('index', () => {
     assert.equal(typeof index.YAML.visitAsync, 'function', 'index.YAML.visitAsync')
     assert.equal(typeof index.argv, 'object', 'index.argv')
     assert.equal(typeof index.argv._, 'object', 'index.argv._')
+    assert.equal(typeof index.bus, 'object', 'index.bus')
+    assert.equal(typeof index.bus.lock, 'function', 'index.bus.lock')
+    assert.equal(typeof index.bus.override, 'function', 'index.bus.override')
+    assert.equal(typeof index.bus.wrap, 'function', 'index.bus.wrap')
     assert.equal(typeof index.cd, 'function', 'index.cd')
     assert.equal(typeof index.chalk, 'function', 'index.chalk')
     assert.equal(typeof index.chalk.level, 'number', 'index.chalk.level')
test/index.test.js
@@ -15,6 +15,7 @@
 import assert from 'node:assert'
 import { describe, test } from 'node:test'
 import {
+  bus,
   nothrow,
   quiet,
   versions,
@@ -119,4 +120,8 @@ describe('index', () => {
     assert(tmpfile)
     assert(tempfile)
   })
+
+  test('bus is locked', () => {
+    assert.throws(() => bus.wrap('test', () => {}), /locked/)
+  })
 })
.size-limit.json
@@ -10,6 +10,7 @@
       "build/error.d.ts",
       "build/esblib.cjs",
       "build/internals.cjs",
+      "build/internals.d.ts",
       "build/log.d.ts",
       "build/util.cjs",
       "build/util.d.ts",
@@ -18,7 +19,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "127.66 kB",
+    "limit": "128.17 kB",
     "brotli": false,
     "gzip": false
   },
@@ -32,14 +33,14 @@
       "build/globals.js",
       "build/deno.js"
     ],
-    "limit": "814.901 kB",
+    "limit": "815.20 kB",
     "brotli": false,
     "gzip": false
   },
   {
     "name": "libdefs",
     "path": "build/*.d.ts",
-    "limit": "40.35 kB",
+    "limit": "40.65 kB",
     "brotli": false,
     "gzip": false
   },
@@ -65,7 +66,7 @@
       "README.md",
       "LICENSE"
     ],
-    "limit": "872.10 kB",
+    "limit": "872.75 kB",
     "brotli": false,
     "gzip": false
   }
package-lock.json
@@ -48,7 +48,7 @@
         "size-limit": "11.2.0",
         "ts-node": "10.9.2",
         "tsd": "0.33.0",
-        "tsx": "4.20.4",
+        "tsx": "4.20.5",
         "typescript": "5.9.2",
         "vitepress": "1.6.4",
         "which": "5.0.0",
@@ -7687,9 +7687,9 @@
       }
     },
     "node_modules/tsx": {
-      "version": "4.20.4",
-      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.4.tgz",
-      "integrity": "sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==",
+      "version": "4.20.5",
+      "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.5.tgz",
+      "integrity": "sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==",
       "dev": true,
       "license": "MIT",
       "dependencies": {
package.json
@@ -70,7 +70,7 @@
     "fmt": "prettier --write .",
     "fmt:check": "prettier --check .",
     "prebuild": "rm -rf build",
-    "build": "npm run build:versions && npm run build:js && npm run build:dts && npm run build:tests && npm run build:manifest",
+    "build": "npm run build:versions && npm run build:js && npm run build:dts && npm run build:tests",
     "build:js": "node scripts/build-js.mjs --format=cjs --hybrid --entry='src/{cli,core,deps,globals,index,internals,util,vendor*}.ts' && npm run build:vendor",
     "build:vendor": "node scripts/build-js.mjs --format=cjs --entry=src/vendor-*.ts --bundle=all --external='./internals.ts'",
     "build:versions": "node scripts/build-versions.mjs",
@@ -81,7 +81,7 @@
     "build:lite": "node scripts/build-pkgjson-lite.mjs",
     "build:pkgjson": "node scripts/build-pkgjson-main.mjs",
     "build:manifest": "npm run build:pkgjson && npm run build:lite && npm run build:jsr",
-    "postbuild": "node scripts/build-clean.mjs",
+    "postbuild": "node scripts/build-clean.mjs && npm run build:manifest",
     "docs:dev": "vitepress dev docs",
     "docs:build": "vitepress build docs",
     "docs:preview": "vitepress preview docs",
@@ -145,7 +145,7 @@
     "size-limit": "11.2.0",
     "ts-node": "10.9.2",
     "tsd": "0.33.0",
-    "tsx": "4.20.4",
+    "tsx": "4.20.5",
     "typescript": "5.9.2",
     "vitepress": "1.6.4",
     "which": "5.0.0",