mb-run 1.1.1 → 1.1.2-dev-20261017-8d2a09b
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/CHANGELOG.md +23 -0
- package/README.md +33 -36
- package/dist/cache.js +2 -2
- package/dist/dts.js +75 -2
- package/dist/esbuild.js +66 -6
- package/dist/help.js +4 -4
- package/dist/module.js +8 -3
- package/dist/pack.js +6 -1
- package/npm-shrinkwrap.json +2523 -93
- package/package.json +6 -2
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,29 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
23
23
|
|
|
24
24
|
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="120"></a>
|
|
25
25
|
|
|
26
|
+
## [1.1.2] - Dev branch
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- [esbuild]: Add the `obfuscate` keyword to `--esbuild`, which obfuscates every bundled JavaScript file with `javascript-obfuscator` (same settings as the vendored `scripts/esbuild.mjs`), keeping bin launcher shebangs.
|
|
31
|
+
- [pack]: Add the `obfuscate` keyword to `--pack`, passed through to the esbuild step.
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- [dts]: Bundle library declarations again with `rollup` and `rollup-plugin-dts` after the declaration-only emit, using `@typescript/typescript6` for the compiler API that TypeScript 7 removed.
|
|
36
|
+
- [package]: Add the `@typescript/native` alias of `typescript` 7 so `node_modules/.bin/tsc` runs TypeScript 7 instead of the TypeScript 6 pulled in by `@typescript/typescript6`.
|
|
37
|
+
- [esbuild]: Remove the per-file declarations superseded by the bundled declaration entries, so `dist` holds only bundled output.
|
|
38
|
+
- [pack]: Exclude the redirected source bin launchers from `files`, so they no longer ship in the tarball.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- [dts]: Bundle all declaration entries in one Rollup run with shared chunks in `dist/_chunks/`, so classes exported from several subpaths are declared once and stay assignable across them.
|
|
43
|
+
- [esbuild]: Keep every package import external unless it is a workspace package or listed in `automator.esbuild.bundle`, and warn about imported packages no `package.json` declares, instead of bundling a second copy of them.
|
|
44
|
+
- [dts]: Drop `--composite` (rejected by `tsc --build`, TS5094) and add `--force` to the monorepo declaration build, so monorepo libraries bundle again.
|
|
45
|
+
- [pack]: Keep the final newline when restoring `package.json` and `tsconfig*.json` files.
|
|
46
|
+
|
|
47
|
+
<a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/assets/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
|
|
48
|
+
|
|
26
49
|
## [1.1.1] - 2026-10-17
|
|
27
50
|
|
|
28
51
|
### Changed
|
package/README.md
CHANGED
|
@@ -61,34 +61,34 @@ Multiple flags can be combined. They are always executed in this fixed order reg
|
|
|
61
61
|
|
|
62
62
|
## Flags
|
|
63
63
|
|
|
64
|
-
| Flag | Description
|
|
65
|
-
| -------------------------------------- |
|
|
66
|
-
| `--install` | Runs `npm install --no-fund --no-audit`. In a Matterbridge plugin project, also runs `npm link matterbridge`.
|
|
67
|
-
| `--upgrade [keywords...]` | Upgrades the project's config and scaffolding files, then runs `npm install`. Optional keywords enable extras: `node`, `bun`, `jest`, `vitest`, `buntest`, `bundle`, `obfuscate`.
|
|
68
|
-
| `--update` | Upgrades all dependencies with `npm-check-updates` (`ncu -u`) across the root and all workspaces, then runs `npm install`. Runs after `--upgrade` so dependency updates apply to the already-upgraded `package.json`.
|
|
69
|
-
| `--reset` | Empties `.cache/` and `node_modules/` (preserving directory structure for devcontainer named volumes), then runs `npm install` and rebuilds. Implies `--install` and `--build`.
|
|
70
|
-
| `--reset --production` | Same as `--reset` but rebuilds using the production tsconfig.
|
|
71
|
-
| `--deep-clean` | Same filesystem cleanup as `--reset` but skips the install and build steps.
|
|
72
|
-
| `--clean` | Removes `dist/` and all `.tsbuildinfo` files.
|
|
73
|
-
| `--set-version [tag]` | Updates the version in `package.json` (root and all workspaces) and regenerates `package-lock.json`. Without a tag, strips any prerelease suffix back to base semver. With a tag, produces `<baseVersion>-<tag>-<yyyymmdd>-<7charSha>`.
|
|
74
|
-
| `--build` | Compiles TypeScript with `tsc`. Prefers `tsconfig.build.json` per workspace when present, falls back to `tsconfig.json`.
|
|
75
|
-
| `--build --production` | Compiles for production. Prefers `tsconfig.build.production.json`, falls back to `tsconfig.build.json`, then `tsconfig.json`.
|
|
76
|
-
| `--typecheck` | Type-checks with `tsc` using the root `tsconfig.json` and `--noEmit`.
|
|
77
|
-
| `--watch` | Runs `tsc` in watch mode using the build tsconfig.
|
|
78
|
-
| `--test [verbose\|watch\|coverage...]` | Runs each eligible test runner: Jest requires `jest.config.js` and its local binary; Vitest requires `vitest.config.ts` and its local binary. When both qualify, Jest runs first, then Vitest. The optional keywords enable verbose output, watch mode, and coverage. Jest receives `NODE_OPTIONS="--experimental-vm-modules --no-warnings"` automatically.
|
|
79
|
-
| `--format` | Formats with `oxfmt`, falling back to `prettier`.
|
|
80
|
-
| `--format --check` | Checks formatting instead of writing changes (combine `--format` with `--check`).
|
|
81
|
-
| `--lint` | Lints with `oxlint`, falling back to `eslint`.
|
|
82
|
-
| `--lint --fix` | Applies automatic lint fixes (combine `--lint` with `--fix`).
|
|
83
|
-
| `--sort` | Sorts top-level keys in all `package.json` files (root and all workspaces) using the canonical Matterbridge key order, then formats.
|
|
84
|
-
| `--pack [tag] [minify]`
|
|
85
|
-
| `--publish [tag]` | Full publish workflow: back up all `package.json` files, strip `devDependencies`/`scripts` from root and workspaces, `npm publish` root and every workspace, then restore all files. With an optional tag, first bumps the version to `<baseVersion>-<tag>-<yyyymmdd>-<7charSha>`.
|
|
86
|
-
| `--esbuild [minify]`
|
|
87
|
-
| `--info` | Prints system information: platform, hostname, memory, network interfaces, Node.js, npm, and Bun versions, plus Bun install, cache, binary, and global module locations with their related environment variables.
|
|
88
|
-
| `--dry-run` | Logs every intended action without modifying files or executing commands.
|
|
89
|
-
| `--verbose` | Prints each external command before it is executed.
|
|
90
|
-
| `--version`, `-v` | Prints the mb-run version and exits without changing any file. Use `--set-version` to update the package version.
|
|
91
|
-
| `--help`, `-h` | Prints usage text.
|
|
64
|
+
| Flag | Description |
|
|
65
|
+
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
66
|
+
| `--install` | Runs `npm install --no-fund --no-audit`. In a Matterbridge plugin project, also runs `npm link matterbridge`. |
|
|
67
|
+
| `--upgrade [keywords...]` | Upgrades the project's config and scaffolding files, then runs `npm install`. Optional keywords enable extras: `node`, `bun`, `jest`, `vitest`, `buntest`, `bundle`, `obfuscate`. |
|
|
68
|
+
| `--update` | Upgrades all dependencies with `npm-check-updates` (`ncu -u`) across the root and all workspaces, then runs `npm install`. Runs after `--upgrade` so dependency updates apply to the already-upgraded `package.json`. |
|
|
69
|
+
| `--reset` | Empties `.cache/` and `node_modules/` (preserving directory structure for devcontainer named volumes), then runs `npm install` and rebuilds. Implies `--install` and `--build`. |
|
|
70
|
+
| `--reset --production` | Same as `--reset` but rebuilds using the production tsconfig. |
|
|
71
|
+
| `--deep-clean` | Same filesystem cleanup as `--reset` but skips the install and build steps. |
|
|
72
|
+
| `--clean` | Removes `dist/` and all `.tsbuildinfo` files. |
|
|
73
|
+
| `--set-version [tag]` | Updates the version in `package.json` (root and all workspaces) and regenerates `package-lock.json`. Without a tag, strips any prerelease suffix back to base semver. With a tag, produces `<baseVersion>-<tag>-<yyyymmdd>-<7charSha>`. |
|
|
74
|
+
| `--build` | Compiles TypeScript with `tsc`. Prefers `tsconfig.build.json` per workspace when present, falls back to `tsconfig.json`. |
|
|
75
|
+
| `--build --production` | Compiles for production. Prefers `tsconfig.build.production.json`, falls back to `tsconfig.build.json`, then `tsconfig.json`. |
|
|
76
|
+
| `--typecheck` | Type-checks with `tsc` using the root `tsconfig.json` and `--noEmit`. |
|
|
77
|
+
| `--watch` | Runs `tsc` in watch mode using the build tsconfig. |
|
|
78
|
+
| `--test [verbose\|watch\|coverage...]` | Runs each eligible test runner: Jest requires `jest.config.js` and its local binary; Vitest requires `vitest.config.ts` and its local binary. When both qualify, Jest runs first, then Vitest. The optional keywords enable verbose output, watch mode, and coverage. Jest receives `NODE_OPTIONS="--experimental-vm-modules --no-warnings"` automatically. |
|
|
79
|
+
| `--format` | Formats with `oxfmt`, falling back to `prettier`. |
|
|
80
|
+
| `--format --check` | Checks formatting instead of writing changes (combine `--format` with `--check`). |
|
|
81
|
+
| `--lint` | Lints with `oxlint`, falling back to `eslint`. |
|
|
82
|
+
| `--lint --fix` | Applies automatic lint fixes (combine `--lint` with `--fix`). |
|
|
83
|
+
| `--sort` | Sorts top-level keys in all `package.json` files (root and all workspaces) using the canonical Matterbridge key order, then formats. |
|
|
84
|
+
| `--pack [tag] [minify] [obfuscate]` | Full pack workflow: back up `package.json`, clean, production build, strip `devDependencies`/`scripts`, empty `node_modules`, `npm install --omit=dev`, `npm shrinkwrap`, `npm pack`, then restore everything. With an optional tag (`dev`, `edge`, `git`, `local`, `next`, `alpha`, `beta`), first bumps the version to `<baseVersion>-<tag>-<yyyymmdd>-<7charSha>`. `minify` compresses the bundle and `obfuscate` obfuscates it. |
|
|
85
|
+
| `--publish [tag]` | Full publish workflow: back up all `package.json` files, strip `devDependencies`/`scripts` from root and workspaces, `npm publish` root and every workspace, then restore all files. With an optional tag, first bumps the version to `<baseVersion>-<tag>-<yyyymmdd>-<7charSha>`. |
|
|
86
|
+
| `--esbuild [minify] [obfuscate]` | Bundles the project with esbuild. `minify` compresses output and removes comments. `obfuscate` obfuscates every bundled JavaScript file (entries, chunks and bin launchers) with javascript-obfuscator. |
|
|
87
|
+
| `--info` | Prints system information: platform, hostname, memory, network interfaces, Node.js, npm, and Bun versions, plus Bun install, cache, binary, and global module locations with their related environment variables. |
|
|
88
|
+
| `--dry-run` | Logs every intended action without modifying files or executing commands. |
|
|
89
|
+
| `--verbose` | Prints each external command before it is executed. |
|
|
90
|
+
| `--version`, `-v` | Prints the mb-run version and exits without changing any file. Use `--set-version` to update the package version. |
|
|
91
|
+
| `--help`, `-h` | Prints usage text. |
|
|
92
92
|
|
|
93
93
|
Bundled scaffolding and fallback lint/format configurations are shipped in the `template/` directory.
|
|
94
94
|
|
|
@@ -142,9 +142,7 @@ For each operation, `mb-run` resolves the tool binary from `node_modules/.bin` i
|
|
|
142
142
|
- **Known entrypoints** (`tsc`, `jest`, `vitest`, `eslint`, `oxlint`, `prettier`) are invoked as `node <entrypoint>` for reliability on all platforms.
|
|
143
143
|
- **Other binaries** are invoked via their shim in `node_modules/.bin` (using the `.cmd` variant on Windows).
|
|
144
144
|
|
|
145
|
-
##
|
|
146
|
-
|
|
147
|
-
### Declaration bundlers on TypeScript 7
|
|
145
|
+
## Declaration bundling
|
|
148
146
|
|
|
149
147
|
`--pack`/`--publish` rebuild declaration files for library packages (`automator.library: true` or a production tsconfig with `declaration: true`) with TypeScript's declaration-only emit. Single-package projects use:
|
|
150
148
|
|
|
@@ -155,15 +153,14 @@ tsc --project tsconfig.build.json --incremental false --composite false --declar
|
|
|
155
153
|
Monorepos use project references:
|
|
156
154
|
|
|
157
155
|
```sh
|
|
158
|
-
tsc --build tsconfig.build.json --
|
|
156
|
+
tsc --build tsconfig.build.json --force --declaration --declarationMap false --emitDeclarationOnly
|
|
159
157
|
```
|
|
160
158
|
|
|
161
|
-
|
|
159
|
+
All public declaration entries (`types` and every `exports[*].types`) are then bundled in place in a single [`rollup-plugin-dts`](https://github.com/Swatinem/rollup-plugin-dts) run, inlining local workspace declarations while third-party packages stay external. Declarations shared by several entries go into common chunks under `dist/_chunks/`, so a class exported from two subpaths is declared once and stays assignable across them. The per-file declarations they supersede are then removed from `dist`, which keeps only bundled output.
|
|
162
160
|
|
|
163
|
-
|
|
161
|
+
When bundling, every package import stays external except local workspace packages and the packages listed in `automator.esbuild.bundle`. A package that is imported but declared in no `package.json` (typically a hoisted transitive dependency) is kept external and reported with a warning, instead of being bundled next to the copy its declared parent loads at runtime.
|
|
164
162
|
|
|
165
|
-
|
|
166
|
-
- [`rollup-plugin-dts` #395](https://github.com/Swatinem/rollup-plugin-dts/issues/395) has a maintainer-authored proposal and a working branch, but it is unmerged and unreleased.
|
|
163
|
+
TypeScript 7's native compiler removed the classic Program API (`ts.sys`, `ts.createProgram`, …) that declaration bundlers rely on. `rollup-plugin-dts` loads it from Microsoft's [`@typescript/typescript6`](https://www.npmjs.com/package/@typescript/typescript6) compatibility package, installed next to `typescript` 7.
|
|
167
164
|
|
|
168
165
|
## Repository toolchain
|
|
169
166
|
|
package/dist/cache.js
CHANGED
|
@@ -98,12 +98,12 @@ export async function restore(rootDir) {
|
|
|
98
98
|
logRestore(rootDir);
|
|
99
99
|
for (const [relKey, content] of tsconfigMap) {
|
|
100
100
|
const absPath = path.join(rootDir, ...relKey.split('/'));
|
|
101
|
-
await writeFile(absPath, JSON.stringify(content, null, 2));
|
|
101
|
+
await writeFile(absPath, JSON.stringify(content, null, 2) + '\n');
|
|
102
102
|
}
|
|
103
103
|
for (const [name, content] of packageJsonMap) {
|
|
104
104
|
const absPath = packageJsonPaths.get(name);
|
|
105
105
|
if (absPath) {
|
|
106
|
-
await writeFile(absPath, JSON.stringify(content, null, 2));
|
|
106
|
+
await writeFile(absPath, JSON.stringify(content, null, 2) + '\n');
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
}
|
package/dist/dts.js
CHANGED
|
@@ -1,10 +1,83 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { runBin } from './build.js';
|
|
3
|
-
import {
|
|
3
|
+
import { resolveWorkspacePackageJsonPaths } from './cache.js';
|
|
4
|
+
import { fileExists } from './clean.js';
|
|
5
|
+
import { isMonorepo, parsePackageJson } from './helpers.js';
|
|
4
6
|
export async function runDtsBuild(opts) {
|
|
5
7
|
const tsconfigPath = path.join(opts.rootDir, 'tsconfig.build.json');
|
|
6
8
|
const args = (await isMonorepo(opts.rootDir))
|
|
7
|
-
? ['--build', tsconfigPath, '--
|
|
9
|
+
? ['--build', tsconfigPath, '--force', '--declaration', '--declarationMap', 'false', '--emitDeclarationOnly']
|
|
8
10
|
: ['--project', tsconfigPath, '--incremental', 'false', '--composite', 'false', '--declaration', '--declarationMap', 'false', '--emitDeclarationOnly'];
|
|
9
11
|
await runBin('tsc', args, { rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun, mode: 'build', watch: false });
|
|
10
12
|
}
|
|
13
|
+
export async function runDtsBundle(opts) {
|
|
14
|
+
if (opts.dryRun)
|
|
15
|
+
return [];
|
|
16
|
+
const packageJson = await parsePackageJson(opts.rootDir);
|
|
17
|
+
const declarationPaths = new Set();
|
|
18
|
+
if (typeof packageJson['types'] === 'string')
|
|
19
|
+
declarationPaths.add(packageJson['types']);
|
|
20
|
+
const packageExports = packageJson['exports'];
|
|
21
|
+
if (typeof packageExports === 'object' && packageExports !== null && !Array.isArray(packageExports)) {
|
|
22
|
+
for (const exportValue of Object.values(packageExports)) {
|
|
23
|
+
if (typeof exportValue !== 'object' || exportValue === null || Array.isArray(exportValue))
|
|
24
|
+
continue;
|
|
25
|
+
const declarationPath = exportValue['types'];
|
|
26
|
+
if (typeof declarationPath === 'string')
|
|
27
|
+
declarationPaths.add(declarationPath);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const entryPoints = [];
|
|
31
|
+
for (const declarationPath of declarationPaths) {
|
|
32
|
+
const filePath = path.resolve(opts.rootDir, declarationPath);
|
|
33
|
+
if (!(await fileExists(filePath))) {
|
|
34
|
+
throw new Error(`Missing declaration file for packed library: ${declarationPath}`);
|
|
35
|
+
}
|
|
36
|
+
entryPoints.push({ filePath });
|
|
37
|
+
}
|
|
38
|
+
if (entryPoints.length === 0)
|
|
39
|
+
return [];
|
|
40
|
+
const workspaceDeclarationPaths = {};
|
|
41
|
+
for (const packageJsonPath of await resolveWorkspacePackageJsonPaths(opts.rootDir)) {
|
|
42
|
+
const workspacePackage = await parsePackageJson(path.dirname(packageJsonPath));
|
|
43
|
+
if (typeof workspacePackage['name'] !== 'string')
|
|
44
|
+
continue;
|
|
45
|
+
const workspaceName = workspacePackage['name'];
|
|
46
|
+
const workspaceDirectory = path.dirname(packageJsonPath);
|
|
47
|
+
const toDeclarationPath = (declarationPath) => path.relative(opts.rootDir, path.resolve(workspaceDirectory, declarationPath)).split(path.sep).join('/');
|
|
48
|
+
const workspaceTypes = workspacePackage['types'];
|
|
49
|
+
if (typeof workspaceTypes === 'string') {
|
|
50
|
+
workspaceDeclarationPaths[workspaceName] = [toDeclarationPath(workspaceTypes)];
|
|
51
|
+
}
|
|
52
|
+
const workspaceExports = workspacePackage['exports'];
|
|
53
|
+
if (typeof workspaceExports !== 'object' || workspaceExports === null || Array.isArray(workspaceExports))
|
|
54
|
+
continue;
|
|
55
|
+
for (const [exportPath, exportValue] of Object.entries(workspaceExports)) {
|
|
56
|
+
if (typeof exportValue !== 'object' || exportValue === null || Array.isArray(exportValue))
|
|
57
|
+
continue;
|
|
58
|
+
const declarationPath = exportValue['types'];
|
|
59
|
+
if (typeof declarationPath !== 'string')
|
|
60
|
+
continue;
|
|
61
|
+
const importPath = exportPath === '.' ? workspaceName : `${workspaceName}/${exportPath.replace(/^\.\//, '')}`;
|
|
62
|
+
workspaceDeclarationPaths[importPath] = [toDeclarationPath(declarationPath)];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const { rollup } = await import('rollup');
|
|
66
|
+
const { dts } = await import('rollup-plugin-dts');
|
|
67
|
+
const input = {};
|
|
68
|
+
for (const entryPoint of entryPoints) {
|
|
69
|
+
input[path
|
|
70
|
+
.relative(opts.rootDir, entryPoint.filePath)
|
|
71
|
+
.split(path.sep)
|
|
72
|
+
.join('/')
|
|
73
|
+
.replace(/\.d\.ts$/, '')] = entryPoint.filePath;
|
|
74
|
+
}
|
|
75
|
+
const bundle = await rollup({
|
|
76
|
+
input,
|
|
77
|
+
external: (specifier) => !specifier.startsWith('.') && !path.isAbsolute(specifier) && !Object.hasOwn(workspaceDeclarationPaths, specifier),
|
|
78
|
+
plugins: [dts({ respectExternal: true, compilerOptions: { baseUrl: opts.rootDir, paths: workspaceDeclarationPaths } })],
|
|
79
|
+
});
|
|
80
|
+
const { output } = await bundle.write({ dir: opts.rootDir, format: 'es', entryFileNames: '[name].d.ts', chunkFileNames: 'dist/_chunks/[name]-[hash].d.ts' });
|
|
81
|
+
await bundle.close();
|
|
82
|
+
return output.map((file) => path.resolve(opts.rootDir, file.fileName));
|
|
83
|
+
}
|
package/dist/esbuild.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { copyFile, mkdir, readFile, readdir, rm } from 'node:fs/promises';
|
|
1
|
+
import { copyFile, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { isBuiltin } from 'node:module';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { build } from 'esbuild';
|
|
4
5
|
import { resolveWorkspacePackageJsonPaths } from './cache.js';
|
|
5
6
|
import { fileExists } from './clean.js';
|
|
6
|
-
import { runDtsBuild } from './dts.js';
|
|
7
|
+
import { runDtsBuild, runDtsBundle } from './dts.js';
|
|
7
8
|
import { isLibrary, isPlugin, parsePackageJson } from './helpers.js';
|
|
8
|
-
import { logEsbuild, logEsbuildAction, logEsbuildOptions } from './logger.js';
|
|
9
|
+
import { logEsbuild, logEsbuildAction, logEsbuildOptions, logWarning } from './logger.js';
|
|
9
10
|
async function resolveDeclaredCopyEntries(packageJson, rootDir) {
|
|
10
11
|
const automator = packageJson['automator'];
|
|
11
12
|
if (typeof automator !== 'object' || automator === null || Array.isArray(automator))
|
|
@@ -73,6 +74,25 @@ async function copyDeclaredEntries(entries, rootDir) {
|
|
|
73
74
|
}
|
|
74
75
|
return copiedPaths;
|
|
75
76
|
}
|
|
77
|
+
async function obfuscateOutputs(filePaths, rootDir) {
|
|
78
|
+
const { default: JavaScriptObfuscator } = await import('javascript-obfuscator');
|
|
79
|
+
for (const filePath of filePaths) {
|
|
80
|
+
logEsbuildAction('obfuscate', [filePath], rootDir);
|
|
81
|
+
const code = await readFile(filePath, 'utf8');
|
|
82
|
+
const shebang = /^#![^\n]*\n/.exec(code)?.[0] ?? '';
|
|
83
|
+
const obfuscated = JavaScriptObfuscator.obfuscate(code.slice(shebang.length), {
|
|
84
|
+
compact: true,
|
|
85
|
+
renameGlobals: false,
|
|
86
|
+
identifierNamesGenerator: 'hexadecimal',
|
|
87
|
+
stringArray: true,
|
|
88
|
+
stringArrayThreshold: 0.8,
|
|
89
|
+
splitStrings: true,
|
|
90
|
+
splitStringsChunkLength: 10,
|
|
91
|
+
sourceMap: false,
|
|
92
|
+
}).getObfuscatedCode();
|
|
93
|
+
await writeFile(filePath, `${shebang}${obfuscated}\n`, 'utf8');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
76
96
|
async function pruneUnproducedDistFiles(distDir, keepPaths) {
|
|
77
97
|
if (!(await fileExists(distDir)))
|
|
78
98
|
return;
|
|
@@ -154,6 +174,34 @@ function resolveDeclaredPackageSpecifiers(packageJson, field) {
|
|
|
154
174
|
}
|
|
155
175
|
return packageSpecifiers;
|
|
156
176
|
}
|
|
177
|
+
function toPackageName(specifier) {
|
|
178
|
+
const parts = specifier.split('/');
|
|
179
|
+
return specifier.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
|
180
|
+
}
|
|
181
|
+
function matchesPackagePattern(specifier, patterns) {
|
|
182
|
+
for (const pattern of patterns) {
|
|
183
|
+
if (pattern.endsWith('*') ? specifier.startsWith(pattern.slice(0, -1)) : specifier === pattern || toPackageName(specifier) === pattern)
|
|
184
|
+
return true;
|
|
185
|
+
}
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
function createExternalPackagesPlugin(localNames, bundledPatterns, declaredPatterns, undeclaredPackages) {
|
|
189
|
+
return {
|
|
190
|
+
name: 'mb-run-external-packages',
|
|
191
|
+
setup(build) {
|
|
192
|
+
build.onResolve({ filter: /^[^./]/ }, (args) => {
|
|
193
|
+
if (args.kind === 'entry-point' || path.isAbsolute(args.path))
|
|
194
|
+
return undefined;
|
|
195
|
+
const packageName = toPackageName(args.path);
|
|
196
|
+
if (localNames.has(packageName) || matchesPackagePattern(args.path, bundledPatterns))
|
|
197
|
+
return undefined;
|
|
198
|
+
if (!args.path.includes(':') && !isBuiltin(args.path) && !matchesPackagePattern(args.path, declaredPatterns))
|
|
199
|
+
undeclaredPackages.add(packageName);
|
|
200
|
+
return { path: args.path, external: true };
|
|
201
|
+
});
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
}
|
|
157
205
|
function createOwnOutputRedirectPlugin() {
|
|
158
206
|
return {
|
|
159
207
|
name: 'redirect-own-dist-outputs',
|
|
@@ -197,7 +245,8 @@ export async function runEsbuild(opts) {
|
|
|
197
245
|
if (await isPlugin(opts.rootDir))
|
|
198
246
|
externalSet.add('matterbridge');
|
|
199
247
|
const rootPkg = (await parsePackageJson(opts.rootDir));
|
|
200
|
-
|
|
248
|
+
const bundledPatterns = resolveDeclaredPackageSpecifiers(rootPkg, 'bundle');
|
|
249
|
+
for (const packageName of bundledPatterns) {
|
|
201
250
|
externalSet.delete(packageName);
|
|
202
251
|
}
|
|
203
252
|
for (const packageName of resolveDeclaredPackageSpecifiers(rootPkg, 'external')) {
|
|
@@ -287,10 +336,11 @@ export async function runEsbuild(opts) {
|
|
|
287
336
|
entryPoints.push(declaredEntryPoint);
|
|
288
337
|
}
|
|
289
338
|
const allEntryPoints = [...entryPoints, ...resolvedBinEntries];
|
|
339
|
+
const undeclaredPackages = new Set();
|
|
290
340
|
logEsbuild(allEntryPoints, opts.rootDir);
|
|
291
341
|
const esbuildOptions = {
|
|
292
342
|
entryPoints: allEntryPoints,
|
|
293
|
-
plugins: [createOwnOutputRedirectPlugin()],
|
|
343
|
+
plugins: [createOwnOutputRedirectPlugin(), createExternalPackagesPlugin(localNames, bundledPatterns, new Set([...externalSet, ...localNames]), undeclaredPackages)],
|
|
294
344
|
bundle: true,
|
|
295
345
|
format: 'esm',
|
|
296
346
|
platform: 'node',
|
|
@@ -315,9 +365,19 @@ export async function runEsbuild(opts) {
|
|
|
315
365
|
return;
|
|
316
366
|
}
|
|
317
367
|
const result = await build(esbuildOptions);
|
|
368
|
+
if (undeclaredPackages.size > 0) {
|
|
369
|
+
logWarning(`Imported but not declared in any package.json dependencies, kept external: ${[...undeclaredPackages].toSorted().join(', ')}. Declare them so npm installs them.`);
|
|
370
|
+
}
|
|
318
371
|
const copiedPaths = await copyDeclaredEntries(declaredCopyEntries, opts.rootDir);
|
|
372
|
+
if (opts.obfuscate) {
|
|
373
|
+
const javascriptOutputs = Object.keys(result.metafile.outputs).filter((outputPath) => outputPath.endsWith('.js'));
|
|
374
|
+
await obfuscateOutputs(javascriptOutputs.map((outputPath) => path.resolve(opts.rootDir, outputPath)), opts.rootDir);
|
|
375
|
+
}
|
|
319
376
|
const keepPaths = new Set([...Object.keys(result.metafile.outputs).map((outputPath) => path.resolve(opts.rootDir, outputPath)), ...copiedPaths]);
|
|
320
377
|
await pruneUnproducedDistFiles(path.join(opts.rootDir, 'dist'), keepPaths);
|
|
321
|
-
if (await isLibrary(opts.rootDir))
|
|
378
|
+
if (await isLibrary(opts.rootDir)) {
|
|
322
379
|
await runDtsBuild({ rootDir: opts.rootDir, isWindows: opts.isWindows, dryRun: opts.dryRun });
|
|
380
|
+
const bundledDeclarations = await runDtsBundle({ rootDir: opts.rootDir, dryRun: opts.dryRun });
|
|
381
|
+
await pruneUnproducedDistFiles(path.join(opts.rootDir, 'dist'), new Set([...keepPaths, ...bundledDeclarations]));
|
|
382
|
+
}
|
|
323
383
|
}
|
package/dist/help.js
CHANGED
|
@@ -33,9 +33,9 @@ ${brightYellow('Options:')}
|
|
|
33
33
|
${f('--sort')}sort top-level keys in all package.json files
|
|
34
34
|
${f('--update')}run ncu -u across all workspaces then npm install
|
|
35
35
|
${f('--upgrade', '[keywords...]')}upgrade config files; keywords: node | bun | jest | vitest | buntest | bundle | obfuscate | promiserules | typeaware | experimental
|
|
36
|
-
${f('--pack', '[tag] [minify]')}back up, clean, build, npm pack, and restore; bumps version first if tag is provided
|
|
36
|
+
${f('--pack', '[tag] [minify] [obfuscate]')}back up, clean, build, npm pack, and restore; bumps version first if tag is provided
|
|
37
37
|
${f('--publish', '[tag]')}back up, npm publish for root and all workspaces, and restore; bumps version first if tag is provided
|
|
38
|
-
${f('--esbuild', '[minify]')}bundle with esbuild; minify compresses output and removes comments
|
|
38
|
+
${f('--esbuild', '[minify] [obfuscate]')}bundle with esbuild; minify compresses output and removes comments, obfuscate obfuscates the bundled JavaScript
|
|
39
39
|
${f('--set-version', '[tag]')}update versions for the current package and all workspaces
|
|
40
40
|
${f('--dry-run')}log intended actions without executing commands or writing files
|
|
41
41
|
${f('--verbose')}print each command before it is executed
|
|
@@ -61,10 +61,10 @@ export function printVersionUsage() {
|
|
|
61
61
|
}
|
|
62
62
|
export function printPackUsage() {
|
|
63
63
|
const msg = [
|
|
64
|
-
`${brightYellow('Usage:')} ${green('mb-run')} ${green('--pack')} [dev|edge|git|local|next|alpha|beta] [minify]`,
|
|
64
|
+
`${brightYellow('Usage:')} ${green('mb-run')} ${green('--pack')} [dev|edge|git|local|next|alpha|beta] [minify] [obfuscate]`,
|
|
65
65
|
`${cyan('Runs')} the full pack workflow. With an optional tag, first bumps the version to:`,
|
|
66
66
|
` ${brightBlack('<baseVersion>-<dev|edge|git|local|next|alpha|beta>-<yyyymmdd>-<7charSha>')}`,
|
|
67
|
-
`Then backs up package.json, builds for production, packs, and restores. Add ${brightBlack('minify')} to compress the esbuild output.`,
|
|
67
|
+
`Then backs up package.json, builds for production, packs, and restores. Add ${brightBlack('minify')} to compress the esbuild output and ${brightBlack('obfuscate')} to obfuscate it.`,
|
|
68
68
|
].join('\n');
|
|
69
69
|
log(msg);
|
|
70
70
|
}
|
package/dist/module.js
CHANGED
|
@@ -90,6 +90,7 @@ export async function main() {
|
|
|
90
90
|
const packArgIndices = new Set();
|
|
91
91
|
let rawPackTag;
|
|
92
92
|
let packMinify = false;
|
|
93
|
+
let packObfuscate = false;
|
|
93
94
|
if (packIndex >= 0) {
|
|
94
95
|
for (let i = packIndex + 1; i < rawArgs.length; i++) {
|
|
95
96
|
const packArg = rawArgs[i];
|
|
@@ -99,6 +100,10 @@ export async function main() {
|
|
|
99
100
|
packMinify = true;
|
|
100
101
|
packArgIndices.add(i);
|
|
101
102
|
}
|
|
103
|
+
else if (packArg === 'obfuscate') {
|
|
104
|
+
packObfuscate = true;
|
|
105
|
+
packArgIndices.add(i);
|
|
106
|
+
}
|
|
102
107
|
else if (rawPackTag === undefined) {
|
|
103
108
|
rawPackTag = packArg;
|
|
104
109
|
packArgIndices.add(i);
|
|
@@ -137,7 +142,7 @@ export async function main() {
|
|
|
137
142
|
}
|
|
138
143
|
}
|
|
139
144
|
const esbuildIndex = rawArgs.indexOf('--esbuild');
|
|
140
|
-
const esbuildValidKeywords = new Set(['minify']);
|
|
145
|
+
const esbuildValidKeywords = new Set(['minify', 'obfuscate']);
|
|
141
146
|
const esbuildArgIndices = new Set();
|
|
142
147
|
const esbuildArgs = new Set();
|
|
143
148
|
if (esbuildIndex >= 0) {
|
|
@@ -347,7 +352,7 @@ export async function main() {
|
|
|
347
352
|
}
|
|
348
353
|
if (want.pack) {
|
|
349
354
|
log(`${savePos()}⏳ Packing...`);
|
|
350
|
-
await runPack({ ...buildOpts, tag: packTag, minify: packMinify });
|
|
355
|
+
await runPack({ ...buildOpts, tag: packTag, minify: packMinify, obfuscate: packObfuscate });
|
|
351
356
|
log(`${restorePos(0)}${green('✅')} Pack complete in ${getElapsed()}.${clearEnd()}`);
|
|
352
357
|
}
|
|
353
358
|
if (want.publish) {
|
|
@@ -362,7 +367,7 @@ export async function main() {
|
|
|
362
367
|
}
|
|
363
368
|
if (want.esbuild) {
|
|
364
369
|
log(`${savePos()}⏳ Bundling with esbuild...`);
|
|
365
|
-
await runEsbuild({ ...buildOpts, minify: esbuildArgs.has('minify') });
|
|
370
|
+
await runEsbuild({ ...buildOpts, minify: esbuildArgs.has('minify'), obfuscate: esbuildArgs.has('obfuscate') });
|
|
366
371
|
log(`${restorePos()}${green('✅')} Esbuild complete in ${getElapsed()}.${clearEnd()}`);
|
|
367
372
|
}
|
|
368
373
|
if (want.watch) {
|
package/dist/pack.js
CHANGED
|
@@ -44,6 +44,7 @@ export async function runPack(opts) {
|
|
|
44
44
|
dryRun: opts.dryRun,
|
|
45
45
|
verbose: opts.verbose,
|
|
46
46
|
minify: opts.minify,
|
|
47
|
+
obfuscate: opts.obfuscate,
|
|
47
48
|
});
|
|
48
49
|
const workspacePkgPaths = await resolveWorkspacePackageJsonPaths(opts.rootDir);
|
|
49
50
|
logWriteFile(packageJsonPath);
|
|
@@ -55,11 +56,15 @@ export async function runPack(opts) {
|
|
|
55
56
|
const packageBin = pkg['bin'];
|
|
56
57
|
if (typeof packageBin === 'object' && packageBin !== null && !Array.isArray(packageBin)) {
|
|
57
58
|
const packageBinEntries = packageBin;
|
|
59
|
+
const packageFiles = pkg['files'];
|
|
58
60
|
for (const [binName, binPath] of Object.entries(packageBinEntries)) {
|
|
59
61
|
if (typeof binPath !== 'string' || binPath.startsWith('dist/'))
|
|
60
62
|
continue;
|
|
61
63
|
if (await fileExists(path.join(opts.rootDir, binPath))) {
|
|
62
|
-
|
|
64
|
+
const sourceLauncher = binPath.replace(/^\.\//, '');
|
|
65
|
+
packageBinEntries[binName] = `dist/${sourceLauncher}`;
|
|
66
|
+
if (Array.isArray(packageFiles) && !packageFiles.includes(`!${sourceLauncher}`))
|
|
67
|
+
packageFiles.push(`!${sourceLauncher}`);
|
|
63
68
|
}
|
|
64
69
|
}
|
|
65
70
|
}
|