afterpack 0.2.2 → 0.2.4
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/README.md +27 -6
- package/SKILL.md +30 -10
- package/dist/cli.js +140 -73
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -31,13 +31,27 @@ Nested `node_modules/` folders are skipped. Pass [`--paths.include`][paths.inclu
|
|
|
31
31
|
|
|
32
32
|
Each run writes:
|
|
33
33
|
|
|
34
|
-
- `.afterpack
|
|
34
|
+
- `.afterpack/receipts/<output dir>.json` (`.afterpack/receipts/dist.json` for `dist`), the receipt
|
|
35
|
+
that `afterpack verify` checks.
|
|
35
36
|
- `.afterpack/backup/`, a copy of the original files, so `afterpack restore` can undo the run.
|
|
36
37
|
Turn it off with [`--build.backup`][build.backup]`=false`.
|
|
37
38
|
- `.afterpack/protectionMap.html`, the [Protection Map](https://www.afterpack.dev/docs/protection-map),
|
|
38
39
|
when your build has source maps.
|
|
39
|
-
- `.map` files next to the output, when
|
|
40
|
-
build.
|
|
40
|
+
- `.map` files next to the output, only when you ask for them with
|
|
41
|
+
[`--sourceMap.enabled`][sourceMap.enabled] or run with `--build.mode=development` (or
|
|
42
|
+
`NODE_ENV=development`) on a build that has source maps.
|
|
43
|
+
|
|
44
|
+
Every other run is a production run: it deletes your build's own source maps, hidden ones included,
|
|
45
|
+
and the `sourceMappingURL` comments that name them, so no original source ships beside the output.
|
|
46
|
+
|
|
47
|
+
`.afterpack/` sits next to your project's lockfile, `afterpack.json` or `.git` (failing those, its
|
|
48
|
+
`package.json`), otherwise beside the build directory, never inside it: `cd public && npx afterpack
|
|
49
|
+
.` keeps it beside `public/`, and a `package.json` your build emits, such as Nitro's
|
|
50
|
+
`.output/server/package.json`, never moves it. A single file in a project root that holds a
|
|
51
|
+
lockfile, `afterpack.json` or `.git` keeps it in that root. The same place holds every run's files
|
|
52
|
+
whatever directory you run from, so a second run over the same output, or over the same file, is
|
|
53
|
+
refused from anywhere. A run fails if it finds a `.afterpack/` inside the output, and removes a
|
|
54
|
+
`.afterpack-protection.json` an older version left there.
|
|
41
55
|
|
|
42
56
|
The backup and the Protection Map contain your original source. `.afterpack/` carries its own
|
|
43
57
|
`.gitignore` and self-ignores. Never deploy or commit them.
|
|
@@ -49,13 +63,18 @@ runs. It never prompts.
|
|
|
49
63
|
|
|
50
64
|
## `afterpack verify [dir]`
|
|
51
65
|
|
|
52
|
-
Checks a build against its protection receipt
|
|
66
|
+
Checks a build against its protection receipt in `.afterpack/receipts/`. Run it in your deploy
|
|
67
|
+
step.
|
|
53
68
|
|
|
54
69
|
```sh
|
|
55
70
|
npx afterpack@latest verify . # looks in ./ and ./.next/
|
|
56
71
|
npx afterpack@latest verify dist
|
|
72
|
+
npx afterpack@latest verify build # SvelteKit's adapter copy; also .output/public, out/
|
|
57
73
|
```
|
|
58
74
|
|
|
75
|
+
A directory a framework copied from its build output, such as SvelteKit's `build/`, Nuxt's
|
|
76
|
+
`.output/public/` or Next's `out/`, is checked against the receipt of the directory it copied.
|
|
77
|
+
|
|
59
78
|
It exits `1` when the receipt is missing, belongs to a different build, or a file changed after it
|
|
60
79
|
was obfuscated. The CLI and the plugins for Vite, Next.js, webpack, Rollup, esbuild and Angular all
|
|
61
80
|
write a receipt.
|
|
@@ -104,8 +123,8 @@ the [configuration reference](https://www.afterpack.dev/docs/config). The
|
|
|
104
123
|
[identifiers.reserved]: https://www.afterpack.dev/docs/config#identifiers-reserved
|
|
105
124
|
[build.backup]: https://www.afterpack.dev/docs/config#build-backup
|
|
106
125
|
[protectionMap.enabled]: https://www.afterpack.dev/docs/config#protectionMap-enabled
|
|
126
|
+
[sourceMap.enabled]: https://www.afterpack.dev/docs/config#sourceMap-enabled
|
|
107
127
|
[diagnostics.format]: https://www.afterpack.dev/docs/config#diagnostics-format
|
|
108
|
-
[allowUnobfuscated]: https://www.afterpack.dev/docs/config#allowUnobfuscated
|
|
109
128
|
[inflation.max]: https://www.afterpack.dev/docs/config#inflation-max
|
|
110
129
|
[key]: https://www.afterpack.dev/docs/config#key
|
|
111
130
|
|
|
@@ -136,8 +155,10 @@ Pro](https://www.afterpack.dev/docs/pro).
|
|
|
136
155
|
| --- | --- |
|
|
137
156
|
| `0` | Success. |
|
|
138
157
|
| `1` | Failure. Nothing was changed, or `verify`, `restore` or `audit` failed. |
|
|
139
|
-
| `2` |
|
|
158
|
+
| `2` | Partial. Reserved for a quota-exhausted build; no build returns it today. |
|
|
140
159
|
| `3` | The size limit ([`inflation.max`][inflation.max]) stopped AfterPack before it reached the protection level. |
|
|
160
|
+
| `4` | A region directive that raises protection needs a Pro key. |
|
|
161
|
+
| `5` | A runtime-reflection pattern was not acknowledged. |
|
|
141
162
|
| `6` | An update is required. The CLI prints the install command to run. |
|
|
142
163
|
| `64` | Misuse: an unknown option or command, or a malformed value. |
|
|
143
164
|
|
package/SKILL.md
CHANGED
|
@@ -67,11 +67,26 @@ Rules:
|
|
|
67
67
|
|
|
68
68
|
## What a run writes
|
|
69
69
|
|
|
70
|
-
- `.afterpack
|
|
70
|
+
- `.afterpack/receipts/<output dir>.json` (`.afterpack/receipts/dist.json` for `dist`): the receipt
|
|
71
|
+
`afterpack verify` checks.
|
|
71
72
|
- `.afterpack/backup/`: the original files, on by default for the CLI, so `afterpack restore` can
|
|
72
73
|
undo the run. `--build.backup=false` turns it off.
|
|
73
74
|
- `.afterpack/protectionMap.html`: the Protection Map report, when the build has source maps.
|
|
74
|
-
- `.map` files beside the output,
|
|
75
|
+
- `.map` files beside the output, only with `--sourceMap.enabled` or on a development run
|
|
76
|
+
(`--build.mode=development` or `NODE_ENV=development`) when an input map exists.
|
|
77
|
+
|
|
78
|
+
Every other run is a production run, `CI` and an unset `NODE_ENV` included. It deletes the build's
|
|
79
|
+
own source maps, hidden ones included, and the `sourceMappingURL` comments that name them.
|
|
80
|
+
|
|
81
|
+
Every front door puts `.afterpack/` next to the nearest lockfile, `afterpack.json` or `.git` above
|
|
82
|
+
the build directory, failing those the nearest `package.json`, otherwise beside the build
|
|
83
|
+
directory, never inside it (`cd public && npx afterpack .` keeps it beside `public/`). A
|
|
84
|
+
`package.json` the build emits, such as Nitro's `.output/server/package.json` or a dual package's
|
|
85
|
+
`dist/cjs/package.json`, never moves it. For a single file, the file's own directory counts when it
|
|
86
|
+
holds a lockfile, `afterpack.json` or `.git`, so `npx afterpack app.js` in such a root keeps
|
|
87
|
+
`.afterpack/` there. The place does not depend on the working directory, so a re-run over the same
|
|
88
|
+
output or the same file is refused from anywhere. A run fails if it finds a `.afterpack/` inside
|
|
89
|
+
the output, and removes a `.afterpack-protection.json` an older version left there.
|
|
75
90
|
|
|
76
91
|
The backup and the Protection Map contain the original source. `.afterpack/` carries its own
|
|
77
92
|
`.gitignore` and self-ignores. Never deploy, publish or commit them.
|
|
@@ -103,11 +118,10 @@ minification.
|
|
|
103
118
|
| [`paths.include`][paths.include] | globs to add back to the walk | `[]` |
|
|
104
119
|
| [`identifiers.reserved`][identifiers.reserved] | names never to rename | `[]` |
|
|
105
120
|
| [`build.backup`][build.backup] | keep originals in `.afterpack/backup/` | `true` for the CLI, `false` in plugins |
|
|
106
|
-
| [`sourceMap.enabled`][sourceMap.enabled] | write `.map` files | on when an input map exists
|
|
121
|
+
| [`sourceMap.enabled`][sourceMap.enabled] | write `.map` files | off; on in development mode when an input map exists |
|
|
107
122
|
| [`protectionMap.enabled`][protectionMap.enabled] | write the Protection Map | on when an input map exists |
|
|
108
123
|
| [`diagnostics.format`][diagnostics.format] | `text` or `json` | `text` |
|
|
109
124
|
| [`diagnostics.level`][diagnostics.level] | `summary`, `all` or `none` (errors still print) | `summary` |
|
|
110
|
-
| [`allowUnobfuscated`][allowUnobfuscated] | ship a file that could not be processed, instead of failing (exit `2`) | `false` |
|
|
111
125
|
| [`build.autorun`][build.autorun] | `false` turns AfterPack off for the project, CLI and plugins alike | `true` |
|
|
112
126
|
| [`telemetry.enabled`][telemetry.enabled] | anonymous diagnostics, sent only when a build is refused or partial | `true` |
|
|
113
127
|
|
|
@@ -126,7 +140,6 @@ https://www.afterpack.dev/docs/config
|
|
|
126
140
|
[protectionMap.enabled]: https://www.afterpack.dev/docs/config#protectionMap-enabled
|
|
127
141
|
[diagnostics.format]: https://www.afterpack.dev/docs/config#diagnostics-format
|
|
128
142
|
[diagnostics.level]: https://www.afterpack.dev/docs/config#diagnostics-level
|
|
129
|
-
[allowUnobfuscated]: https://www.afterpack.dev/docs/config#allowUnobfuscated
|
|
130
143
|
[build.autorun]: https://www.afterpack.dev/docs/config#build-autorun
|
|
131
144
|
[telemetry.enabled]: https://www.afterpack.dev/docs/config#telemetry-enabled
|
|
132
145
|
[inflation.max]: https://www.afterpack.dev/docs/config#inflation-max
|
|
@@ -164,7 +177,7 @@ it too. Add `--diagnostics.level=none` for a run that prints nothing else.
|
|
|
164
177
|
}
|
|
165
178
|
```
|
|
166
179
|
|
|
167
|
-
`status` is `obfuscated`, `unchanged
|
|
180
|
+
`status` is `obfuscated`, `unchanged` or `failed`. A failure is a document too,
|
|
168
181
|
with the same exit code and a `fix` field to act on:
|
|
169
182
|
|
|
170
183
|
```json
|
|
@@ -196,15 +209,20 @@ Details: https://www.afterpack.dev/docs/pro
|
|
|
196
209
|
|
|
197
210
|
## `afterpack verify [dir]`
|
|
198
211
|
|
|
199
|
-
Add this to the deploy step. It
|
|
212
|
+
Add this to the deploy step. It reads the receipt for `[dir]` from `.afterpack/receipts/`, found
|
|
213
|
+
by the same rule as above, and re-hashes every file that receipt names.
|
|
200
214
|
|
|
201
215
|
```bash
|
|
202
216
|
npx afterpack@latest verify . # looks in ./ and ./.next/
|
|
203
217
|
npx afterpack@latest verify dist
|
|
218
|
+
npx afterpack@latest verify build # SvelteKit's adapter copy; also .output/public, out/
|
|
204
219
|
```
|
|
205
220
|
|
|
206
|
-
|
|
207
|
-
|
|
221
|
+
When `[dir]` has no receipt of its own, verify looks for the project receipt whose files `[dir]`
|
|
222
|
+
holds, at the same relative paths or under one prefix, so a framework's copy of its build output
|
|
223
|
+
(SvelteKit's `build/`, Nuxt's `.output/public/`, Next's `out/`) is checked against the receipt of
|
|
224
|
+
the directory it copied. It exits `1` when the receipt is missing, belongs to a different build,
|
|
225
|
+
or a file changed after it was obfuscated. A missing receipt is a failure. `verify` reads no configuration and takes only
|
|
208
226
|
`--diagnostics.format` and `--diagnostics.level`.
|
|
209
227
|
|
|
210
228
|
## `afterpack restore [dir]`
|
|
@@ -231,8 +249,10 @@ exits `1`. Anonymous use is rate-limited per 24 hours. Docs: https://www.afterpa
|
|
|
231
249
|
| --- | --- |
|
|
232
250
|
| `0` | Success. Also `--help` and `--version`. |
|
|
233
251
|
| `1` | Failure: bad path, no JavaScript found, an engine error, an already-obfuscated tree, a failed `verify`, `restore` or scan, or an unreachable cloud on a Pro build. |
|
|
234
|
-
| `2` | Partial
|
|
252
|
+
| `2` | Partial. Reserved for a quota-exhausted build; no build returns it today. |
|
|
235
253
|
| `3` | Size cap: [`inflation.max`][inflation.max] stopped the run before it reached the protection level. |
|
|
254
|
+
| `4` | Pro required: a region directive that raises protection needs a Pro key (`DIAG_PRO_DIRECTIVE_REQUIRES_KEY`). |
|
|
255
|
+
| `5` | Reflection: a runtime-reflection pattern was not acknowledged (`DIAG_REFLECTION_NOT_ACKNOWLEDGED`). |
|
|
236
256
|
| `6` | Update required. Run the install command it prints, for example `npm install afterpack@latest @afterpack/core@<version>`. Nothing was written. |
|
|
237
257
|
| `64` | Misuse: unknown flag or command, malformed value, or two path arguments. |
|
|
238
258
|
|
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { processBatch, version } from "@afterpack/core";
|
|
4
|
-
import { AlreadyObfuscatedError, CLOUD_REFUSAL_SUMMARY, CONFIG_KEYS, CORE_FLOOR_SUMMARY, CloudApiError, CoreVersionError, DIAG_ALREADY_OBFUSCATED,
|
|
4
|
+
import { AFTERPACK_DIR, AfterpackFilesError, AlreadyObfuscatedError, CLOUD_REFUSAL_SUMMARY, CONFIG_KEYS, CORE_FLOOR_SUMMARY, CloudApiError, CoreVersionError, DIAG_ALREADY_OBFUSCATED, PROTECTION_RECEIPTS_DIR, UnreadableReceiptError, afterpackHome, collectJsFiles, createTelemetryReporter, ensureAfterpackGitignore, getPath, installedRequiredLine, loadConfigFile, locateProtectionReceipt, mergeConfig, npxAlternative, parseCliOptions, parseEnvOptions, protectionReceiptPath, resolveClientIdentity, resolvePluginConfig, runObfuscationPass, serverAddsInfo, sha256Of, toEngineConfig, toPluginOptions, verifyProtectionReceipt } from "@afterpack/integration-utils";
|
|
5
5
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
6
6
|
import { createHash } from "node:crypto";
|
|
7
7
|
|
|
@@ -170,20 +170,28 @@ const EXIT = {
|
|
|
170
170
|
usage: 64
|
|
171
171
|
};
|
|
172
172
|
const SIZE_CAP_CODE = "DIAG_SIZE_CAP_REACHED";
|
|
173
|
+
const PRO_REQUIRED_CODE = "DIAG_PRO_DIRECTIVE_REQUIRES_KEY";
|
|
174
|
+
const REFLECTION_CODE = "DIAG_REFLECTION_NOT_ACKNOWLEDGED";
|
|
173
175
|
const EXIT_CODE_HELP = `Exit codes:
|
|
174
176
|
0 success — every collected file was obfuscated and written
|
|
175
177
|
1 total failure — nothing usable was produced (also: a Pro build whose
|
|
176
178
|
cloud call failed; it never falls back to a local build)
|
|
177
|
-
2 partial —
|
|
178
|
-
\`--allowUnobfuscated\`
|
|
179
|
+
2 partial — reserved for a quota-exhausted build; no build returns it today
|
|
179
180
|
3 size cap — \`inflation.max\` could not reach the complexity target
|
|
180
181
|
(${SIZE_CAP_CODE})
|
|
182
|
+
4 Pro required — a region directive that raises protection needs a Pro key
|
|
183
|
+
(${PRO_REQUIRED_CODE})
|
|
184
|
+
5 reflection — a runtime-reflection pattern was not acknowledged
|
|
185
|
+
(${REFLECTION_CODE})
|
|
181
186
|
6 update required — the AfterPack cloud API, or this afterpack, needs a
|
|
182
187
|
newer @afterpack/core; nothing was written
|
|
183
188
|
64 misuse — an unknown flag or command, or a malformed value`;
|
|
184
189
|
function failureExitCode(diagnostics) {
|
|
185
|
-
const
|
|
186
|
-
|
|
190
|
+
const has = (code) => diagnostics.some((d) => d.code === code && d.severity !== "info");
|
|
191
|
+
if (has(PRO_REQUIRED_CODE)) return EXIT.proRequired;
|
|
192
|
+
if (has(REFLECTION_CODE)) return EXIT.reflection;
|
|
193
|
+
if (has(SIZE_CAP_CODE)) return EXIT.sizeCap;
|
|
194
|
+
return EXIT.failure;
|
|
187
195
|
}
|
|
188
196
|
|
|
189
197
|
//#endregion
|
|
@@ -482,6 +490,13 @@ function reportingLogger(logger, mode) {
|
|
|
482
490
|
error: (m) => logger.error(m)
|
|
483
491
|
};
|
|
484
492
|
}
|
|
493
|
+
function realDir(path) {
|
|
494
|
+
try {
|
|
495
|
+
return realpathSync.native(path);
|
|
496
|
+
} catch {
|
|
497
|
+
return path;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
485
500
|
function documentPath(cwd, filePath) {
|
|
486
501
|
const rel = relative(cwd, filePath);
|
|
487
502
|
if (rel === "") return ".";
|
|
@@ -638,12 +653,19 @@ result, not a failure), 1 when the scan failed or the stream ended early,
|
|
|
638
653
|
${dim(CONTACT_FOOTER)}`;
|
|
639
654
|
const DEFAULT_API_BASE = "https://api.afterpack.dev";
|
|
640
655
|
const WEB_BASE = "https://www.afterpack.dev";
|
|
641
|
-
|
|
656
|
+
const LOCAL_PATH = /^(?:[\\/.~]|[A-Za-z]:[\\/]|file:)/i;
|
|
657
|
+
function isNamedHost(hostname) {
|
|
658
|
+
if (hostname === "localhost" || hostname.startsWith("[")) return true;
|
|
659
|
+
return hostname.includes(".");
|
|
660
|
+
}
|
|
661
|
+
function normalizeUrl(input, cwd) {
|
|
642
662
|
const raw = input.trim();
|
|
663
|
+
if (LOCAL_PATH.test(raw) || existsSync(resolve(cwd, raw))) return null;
|
|
643
664
|
const candidate = /^https?:\/\//i.test(raw) ? raw : `https://${raw}`;
|
|
644
665
|
try {
|
|
645
666
|
const parsed = new URL(candidate);
|
|
646
|
-
|
|
667
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return null;
|
|
668
|
+
return isNamedHost(parsed.hostname) ? parsed.toString() : null;
|
|
647
669
|
} catch {
|
|
648
670
|
return null;
|
|
649
671
|
}
|
|
@@ -771,7 +793,7 @@ function misuse(deps, code, message) {
|
|
|
771
793
|
async function audit(deps) {
|
|
772
794
|
if (deps.positionals.length === 0) return misuse(deps, "MISSING_URL", "audit needs a <url>");
|
|
773
795
|
if (deps.positionals.length > 1) return misuse(deps, "TOO_MANY_URLS", `audit takes a single <url>, got ${deps.positionals.length}`);
|
|
774
|
-
const url = normalizeUrl(deps.positionals[0]);
|
|
796
|
+
const url = normalizeUrl(deps.positionals[0], deps.cwd ?? process.cwd());
|
|
775
797
|
if (!url) return misuse(deps, "INVALID_URL", `not a URL: ${deps.positionals[0]}`);
|
|
776
798
|
const interactive = deps.mode.format !== "json" && deps.stdout.isTTY;
|
|
777
799
|
deps.report.log(header(deps.version));
|
|
@@ -865,19 +887,22 @@ async function audit(deps) {
|
|
|
865
887
|
//#endregion
|
|
866
888
|
//#region src/backup.ts
|
|
867
889
|
const BACKUP_MANIFEST_FILE = "manifest.json";
|
|
868
|
-
const BACKUP_MANIFEST_RELATIVE = join(".afterpack", "backup", BACKUP_MANIFEST_FILE);
|
|
869
|
-
function projectRootFor(cwd, configFile) {
|
|
870
|
-
return configFile ? dirname(configFile) : cwd;
|
|
871
|
-
}
|
|
872
890
|
function backupDir(projectRoot) {
|
|
873
|
-
return join(projectRoot,
|
|
891
|
+
return join(projectRoot, AFTERPACK_DIR, "backup");
|
|
874
892
|
}
|
|
875
893
|
function backupManifestPath(projectRoot) {
|
|
876
894
|
return join(backupDir(projectRoot), BACKUP_MANIFEST_FILE);
|
|
877
895
|
}
|
|
878
|
-
function
|
|
879
|
-
|
|
880
|
-
|
|
896
|
+
function homeProjectRoot(dir) {
|
|
897
|
+
try {
|
|
898
|
+
return afterpackHome(dir).projectRoot;
|
|
899
|
+
} catch {
|
|
900
|
+
return null;
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
function findBackupProjectRoot(dir) {
|
|
904
|
+
const candidates$1 = [dir, homeProjectRoot(dir)].filter((c) => c !== null);
|
|
905
|
+
return candidates$1.find((c) => existsSync(backupManifestPath(c))) ?? null;
|
|
881
906
|
}
|
|
882
907
|
function toPosixPath(value) {
|
|
883
908
|
return value.split(sep).join("/");
|
|
@@ -928,13 +953,15 @@ function readBackupManifest(projectRoot) {
|
|
|
928
953
|
}
|
|
929
954
|
function writeBackups(input) {
|
|
930
955
|
const dir = backupDir(input.projectRoot);
|
|
931
|
-
|
|
956
|
+
const previous = input.merge ? readBackupManifest(input.projectRoot) : null;
|
|
957
|
+
const replaced = new Set(input.pending.map((p) => p.relPath));
|
|
958
|
+
const files = previous?.status === "ok" && previous.manifest.protectedRoot === input.protectedRoot ? previous.manifest.files.filter((f) => !replaced.has(f.path)) : [];
|
|
959
|
+
if (files.length === 0) rmSync(dir, {
|
|
932
960
|
recursive: true,
|
|
933
961
|
force: true
|
|
934
962
|
});
|
|
935
963
|
mkdirSync(dir, { recursive: true });
|
|
936
964
|
ensureAfterpackGitignore(dir);
|
|
937
|
-
const files = [];
|
|
938
965
|
for (const pending of input.pending) {
|
|
939
966
|
const dest = absoluteFilePath(dir, pending.relPath);
|
|
940
967
|
mkdirSync(dirname(dest), { recursive: true });
|
|
@@ -1138,14 +1165,15 @@ const RESTORE_HELP = `${RESTORE_USAGE}
|
|
|
1138
1165
|
Restores the original, pre-obfuscation files that a previous \`afterpack\` run backed up to
|
|
1139
1166
|
.afterpack/backup/, undoing that run in place.
|
|
1140
1167
|
|
|
1141
|
-
|
|
1142
|
-
.
|
|
1143
|
-
|
|
1168
|
+
Finds .afterpack/backup/ where the \`afterpack\` run kept it: next to the nearest lockfile,
|
|
1169
|
+
afterpack.json or .git above the build directory (failing those the nearest package.json,
|
|
1170
|
+
otherwise beside the build directory). Point it at that project root or at the build directory
|
|
1171
|
+
itself.
|
|
1144
1172
|
|
|
1145
1173
|
Verifies every recorded file against the hash it was obfuscated to BEFORE touching anything: if
|
|
1146
1174
|
any file no longer matches, or the manifest itself is unreadable, restore changes nothing and
|
|
1147
|
-
fails closed. On success it deletes the backup and the stale protection receipt it recorded
|
|
1148
|
-
leaving .afterpack/ itself in place.
|
|
1175
|
+
fails closed. On success it deletes the backup and the stale protection receipt it recorded in
|
|
1176
|
+
.afterpack/receipts/, leaving .afterpack/ itself in place.
|
|
1149
1177
|
|
|
1150
1178
|
Arguments:
|
|
1151
1179
|
[dir] a directory at or beneath the project root that holds
|
|
@@ -1164,7 +1192,8 @@ function fail$1(deps, exitCode, code, message, fix, detail = []) {
|
|
|
1164
1192
|
return commandFailure(deps, "restore", exitCode, code, message, fix, detail);
|
|
1165
1193
|
}
|
|
1166
1194
|
function isRecordedReceipt(projectRoot, receiptPath) {
|
|
1167
|
-
if (basename(receiptPath) !==
|
|
1195
|
+
if (basename(dirname(receiptPath)) !== PROTECTION_RECEIPTS_DIR) return false;
|
|
1196
|
+
if (!receiptPath.endsWith(".json")) return false;
|
|
1168
1197
|
const rel = relative(projectRoot, receiptPath);
|
|
1169
1198
|
return rel !== "" && !rel.startsWith("..") && !isAbsolute(rel) && existsSync(receiptPath);
|
|
1170
1199
|
}
|
|
@@ -1173,9 +1202,9 @@ function restore(deps) {
|
|
|
1173
1202
|
const { cwd, positionals } = deps;
|
|
1174
1203
|
if (positionals.length > 1) return fail$1(deps, EXIT.usage, "TOO_MANY_ARGUMENTS", `expected a single [dir], got ${positionals.length}`, RESTORE_USAGE);
|
|
1175
1204
|
const requested = positionals[0] ?? ".";
|
|
1176
|
-
const
|
|
1177
|
-
if (!existsSync(
|
|
1178
|
-
const projectRoot = findBackupProjectRoot(
|
|
1205
|
+
const requestedPath = isAbsolute(requested) ? requested : resolve(cwd, requested);
|
|
1206
|
+
if (!existsSync(requestedPath)) return fail$1(deps, EXIT.failure, "PATH_NOT_FOUND", `path not found: ${requested}`, "Point restore at the project root that holds .afterpack/backup/, or a directory beneath it.");
|
|
1207
|
+
const projectRoot = findBackupProjectRoot(realDir(requestedPath));
|
|
1179
1208
|
if (projectRoot === null) return fail$1(deps, EXIT.failure, "NOTHING_TO_RESTORE", "Nothing to restore", NOTHING_TO_RESTORE_FIX);
|
|
1180
1209
|
const manifestResult = readBackupManifest(projectRoot);
|
|
1181
1210
|
if (manifestResult.status === "corrupt") return fail$1(deps, EXIT.failure, "BACKUP_MANIFEST_CORRUPT", "Backup manifest is unreadable", `Delete ${documentPath(cwd, manifestResult.path)} and run \`afterpack <path>\` again — a corrupt manifest cannot be restored from.`);
|
|
@@ -1346,15 +1375,18 @@ const VERIFY_USAGE = "usage: afterpack verify [dir] [--diagnostics.format=text|j
|
|
|
1346
1375
|
const VERIFY_HELP = `${VERIFY_USAGE}
|
|
1347
1376
|
|
|
1348
1377
|
Re-checks a build output tree against the protection receipt the build wrote
|
|
1349
|
-
|
|
1350
|
-
|
|
1378
|
+
for it in .afterpack/receipts/, next to the nearest lockfile, afterpack.json or
|
|
1379
|
+
.git above the tree (failing those the nearest package.json, otherwise beside
|
|
1380
|
+
the tree): every recorded file must still
|
|
1381
|
+
hash to the value it was obfuscated to. Run it in the deploy step, after the
|
|
1382
|
+
build and before the upload.
|
|
1351
1383
|
|
|
1352
1384
|
A MISSING receipt FAILS. This command is only ever run by someone who expects a
|
|
1353
1385
|
protected tree, so "there was nothing to check" is not a pass.
|
|
1354
1386
|
|
|
1355
1387
|
Arguments:
|
|
1356
|
-
[dir] the build output, or a project root whose
|
|
1357
|
-
|
|
1388
|
+
[dir] the build output, or a Next.js project root whose
|
|
1389
|
+
.next/ was protected (default: the working directory)
|
|
1358
1390
|
|
|
1359
1391
|
Options:
|
|
1360
1392
|
--diagnostics.format=<text|json> json prints ONE document on stdout
|
|
@@ -1390,11 +1422,17 @@ function verify(deps) {
|
|
|
1390
1422
|
const { cwd, positionals } = deps;
|
|
1391
1423
|
if (positionals.length > 1) return fail(deps, EXIT.usage, "TOO_MANY_ARGUMENTS", `expected a single [dir], got ${positionals.length}`, VERIFY_USAGE);
|
|
1392
1424
|
const requested = positionals[0] ?? ".";
|
|
1393
|
-
const
|
|
1394
|
-
if (!existsSync(
|
|
1395
|
-
const
|
|
1396
|
-
|
|
1397
|
-
const
|
|
1425
|
+
const requestedPath = isAbsolute(requested) ? requested : resolve(cwd, requested);
|
|
1426
|
+
if (!existsSync(requestedPath)) return fail(deps, EXIT.failure, "PATH_NOT_FOUND", `path not found: ${requested}`, "Point verify at the build output directory, or at the project root above it.");
|
|
1427
|
+
const target = realDir(requestedPath);
|
|
1428
|
+
const dirs = candidates(target).filter((c) => existsSync(c));
|
|
1429
|
+
const located = dirs.map((c) => locateProtectionReceipt(c, { copies: false })).find((l) => l !== null) ?? dirs.map((c) => locateProtectionReceipt(c)).find((l) => l !== null);
|
|
1430
|
+
if (!located) {
|
|
1431
|
+
const looked = dirs.flatMap((c) => [...new Set([protectionReceiptPath(c), protectionReceiptPath(afterpackHome(c, { fileTarget: true }))])]);
|
|
1432
|
+
return fail(deps, EXIT.failure, "RECEIPT_MISSING", `no protection receipt found for ${requested}`, "A receipt is written to .afterpack/receipts/ by the run that obfuscated the tree — run `afterpack <dir>`, or build again through the framework plugin, then point verify at that output directory.", [...looked.map((path) => `looked in ${documentPath(cwd, path)}`), "and for a receipt whose files this directory holds a copy of"]);
|
|
1433
|
+
}
|
|
1434
|
+
const { dir, receiptPath, copiedFrom } = located;
|
|
1435
|
+
const { receipt, problems } = verifyProtectionReceipt(receiptPath, dir, readBuildId(dir));
|
|
1398
1436
|
if (problems.length > 0) return fail(deps, EXIT.failure, "RECEIPT_MISMATCH", `${documentPath(cwd, dir)} FAILED verification: ${problems.join("; ")}`, "Rebuild the tree with the AfterPack front door and verify the fresh output; never deploy a tree whose receipt does not match.", problems);
|
|
1399
1437
|
const files = receipt?.files ?? [];
|
|
1400
1438
|
if (deps.mode.format === "json") {
|
|
@@ -1413,6 +1451,8 @@ function verify(deps) {
|
|
|
1413
1451
|
diagnostics: [],
|
|
1414
1452
|
summary: {
|
|
1415
1453
|
directory: documentPath(cwd, dir),
|
|
1454
|
+
receipt: documentPath(cwd, receiptPath),
|
|
1455
|
+
copiedFrom: copiedFrom === null ? null : documentPath(cwd, copiedFrom),
|
|
1416
1456
|
tool: receipt?.tool ?? null,
|
|
1417
1457
|
engine: receipt?.engine ?? null,
|
|
1418
1458
|
bundler: receipt?.bundler ?? null,
|
|
@@ -1427,7 +1467,7 @@ function verify(deps) {
|
|
|
1427
1467
|
return EXIT.ok;
|
|
1428
1468
|
}
|
|
1429
1469
|
const engine = receipt?.engine === "cloud" ? " · AfterPack Pro" : "";
|
|
1430
|
-
deps.report.log(`${green("✓")} Verified ${files.length} ${files.length === 1 ? "file" : "files"} · ` + displayDir(deps.cwd, dir) + engine);
|
|
1470
|
+
deps.report.log(`${green("✓")} Verified ${files.length} ${files.length === 1 ? "file" : "files"} · ` + displayDir(deps.cwd, dir) + (copiedFrom === null ? "" : dim(` · copy of ${displayDir(deps.cwd, copiedFrom)}`)) + engine);
|
|
1431
1471
|
return EXIT.ok;
|
|
1432
1472
|
}
|
|
1433
1473
|
|
|
@@ -1452,15 +1492,10 @@ function unknownCommand(argv, cwd) {
|
|
|
1452
1492
|
};
|
|
1453
1493
|
return null;
|
|
1454
1494
|
}
|
|
1455
|
-
function
|
|
1456
|
-
return {
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
const batch = await engine.processBatch(inputs, config, buildContext);
|
|
1460
|
-
for (const file of batch.files) into.push(captureFile(file, bytesIn.get(file.path) ?? 0));
|
|
1461
|
-
return batch;
|
|
1462
|
-
},
|
|
1463
|
-
...engine.version ? { version: () => engine.version() } : {}
|
|
1495
|
+
function captureBatch(into) {
|
|
1496
|
+
return (inputs, batch) => {
|
|
1497
|
+
const bytesIn = new Map(inputs.map((i) => [i.path, Buffer.byteLength(i.source)]));
|
|
1498
|
+
for (const file of batch.files) into.push(captureFile(file, bytesIn.get(file.path) ?? 0));
|
|
1464
1499
|
};
|
|
1465
1500
|
}
|
|
1466
1501
|
function captureFile(file, bytesIn) {
|
|
@@ -1469,7 +1504,6 @@ function captureFile(file, bytesIn) {
|
|
|
1469
1504
|
bytesIn,
|
|
1470
1505
|
bytesOut: Buffer.byteLength(file.code),
|
|
1471
1506
|
status: file.status,
|
|
1472
|
-
unobfuscated: file.unobfuscated === true,
|
|
1473
1507
|
diagnostics: sanitizeEngineDiagnostics(file.diagnostics).map((d) => ({
|
|
1474
1508
|
...d,
|
|
1475
1509
|
file: d.file ?? file.path
|
|
@@ -1481,9 +1515,28 @@ function alignRow(label, value) {
|
|
|
1481
1515
|
}
|
|
1482
1516
|
function fileStatus(file) {
|
|
1483
1517
|
if (file.status !== "success") return "failed";
|
|
1484
|
-
if (file.unobfuscated) return "unobfuscated";
|
|
1485
1518
|
return file.bytesOut === file.bytesIn && file.diagnostics.length === 0 ? "unchanged" : "obfuscated";
|
|
1486
1519
|
}
|
|
1520
|
+
function failureDetail(exitCode) {
|
|
1521
|
+
switch (exitCode) {
|
|
1522
|
+
case EXIT.sizeCap: return {
|
|
1523
|
+
code: SIZE_CAP_CODE,
|
|
1524
|
+
fix: "Raise --inflation.max, or lower --complexity, so the target fits the size budget."
|
|
1525
|
+
};
|
|
1526
|
+
case EXIT.proRequired: return {
|
|
1527
|
+
code: PRO_REQUIRED_CODE,
|
|
1528
|
+
fix: "A region directive raises protection, which needs a Pro key. Add --key=<ap_live_…>, or remove the directive."
|
|
1529
|
+
};
|
|
1530
|
+
case EXIT.reflection: return {
|
|
1531
|
+
code: REFLECTION_CODE,
|
|
1532
|
+
fix: "Acknowledge the runtime-reflection pattern with --reflection.allow=<value> (the diagnostic above names the value), carve the file out with --paths.exclude=<glob>, or (Pro) mark it with an @afterpack allow-reflection directive."
|
|
1533
|
+
};
|
|
1534
|
+
default: return {
|
|
1535
|
+
code: "BUILD_FAILED",
|
|
1536
|
+
fix: "Fix the diagnostic(s) above, or carve the file out with --paths.exclude=<glob>. Your build output was left exactly as your bundler wrote it."
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1487
1540
|
function buildDocument(input) {
|
|
1488
1541
|
const { cwd, files, result } = input;
|
|
1489
1542
|
const asJson = (d) => {
|
|
@@ -1512,7 +1565,6 @@ function buildDocument(input) {
|
|
|
1512
1565
|
summary: {
|
|
1513
1566
|
files: files.length,
|
|
1514
1567
|
transformed: input.transformed.size,
|
|
1515
|
-
unobfuscated: files.filter((f) => f.unobfuscated).length,
|
|
1516
1568
|
failed: files.filter((f) => f.status !== "success").length,
|
|
1517
1569
|
bytesIn: files.reduce((n, f) => n + f.bytesIn, 0),
|
|
1518
1570
|
bytesOut: files.reduce((n, f) => n + f.bytesOut, 0),
|
|
@@ -1687,14 +1739,16 @@ async function runObfuscationAndBackup(input) {
|
|
|
1687
1739
|
label: input.label,
|
|
1688
1740
|
work: () => runObfuscationPass({
|
|
1689
1741
|
files: input.files,
|
|
1690
|
-
engine:
|
|
1742
|
+
engine: input.engine,
|
|
1743
|
+
onBatch: captureBatch(captured),
|
|
1691
1744
|
label: "afterpack",
|
|
1692
1745
|
cwd: input.cwd,
|
|
1693
1746
|
startedAt: input.startedAt,
|
|
1694
1747
|
combinedProtectionMap: {
|
|
1695
1748
|
buildDir: input.buildDir,
|
|
1696
|
-
|
|
1749
|
+
fileTarget: input.fileTarget
|
|
1697
1750
|
},
|
|
1751
|
+
sourceMapSweepDir: input.sweepSourceMaps ? input.buildDir : null,
|
|
1698
1752
|
artifactOptions: {
|
|
1699
1753
|
...input.parsed.artifactOptions,
|
|
1700
1754
|
build: {
|
|
@@ -1728,7 +1782,8 @@ async function runObfuscationAndBackup(input) {
|
|
|
1728
1782
|
protectedRoot: input.buildDir,
|
|
1729
1783
|
cliVersion: input.version,
|
|
1730
1784
|
pending: input.pendingBackups,
|
|
1731
|
-
receiptPath: result?.receiptPath ?? null
|
|
1785
|
+
receiptPath: result?.receiptPath ?? null,
|
|
1786
|
+
merge: input.fileTarget
|
|
1732
1787
|
});
|
|
1733
1788
|
return {
|
|
1734
1789
|
captured,
|
|
@@ -1744,7 +1799,7 @@ function renderNextSteps(input) {
|
|
|
1744
1799
|
if (backupWritten !== null && backupWritten.count > 0) report.log(` backup ${documentPath(cwd, backupDir(projectRoot))}/`);
|
|
1745
1800
|
if (receiptPath || backupWritten !== null) report.log("");
|
|
1746
1801
|
if (receiptPath) {
|
|
1747
|
-
const verifyDir = documentPath(cwd,
|
|
1802
|
+
const verifyDir = documentPath(cwd, input.buildDir);
|
|
1748
1803
|
const verifyCommand = verifyDir === "." ? "afterpack verify" : `afterpack verify ${verifyDir}`;
|
|
1749
1804
|
report.log(alignRow("next", `${verifyCommand} before you deploy`));
|
|
1750
1805
|
}
|
|
@@ -1787,6 +1842,12 @@ function refusalFor(error) {
|
|
|
1787
1842
|
message: error.message,
|
|
1788
1843
|
fix: error.fix
|
|
1789
1844
|
};
|
|
1845
|
+
if (error instanceof AfterpackFilesError) return {
|
|
1846
|
+
exitCode: EXIT.failure,
|
|
1847
|
+
code: error.code,
|
|
1848
|
+
message: error.summary,
|
|
1849
|
+
fix: error.fix
|
|
1850
|
+
};
|
|
1790
1851
|
if (error instanceof UnreadableReceiptError) return {
|
|
1791
1852
|
exitCode: EXIT.failure,
|
|
1792
1853
|
code: error.code,
|
|
@@ -1840,7 +1901,8 @@ function defaultCliStdout() {
|
|
|
1840
1901
|
}
|
|
1841
1902
|
async function run(deps) {
|
|
1842
1903
|
const startedAt = Date.now();
|
|
1843
|
-
const {
|
|
1904
|
+
const { engine, logger, version: version$1 } = deps;
|
|
1905
|
+
const cwd = realDir(deps.cwd);
|
|
1844
1906
|
const env = deps.env ?? process.env;
|
|
1845
1907
|
const stdout = deps.stdout ?? defaultCliStdout();
|
|
1846
1908
|
const argv = expandShortFlags(deps.argv);
|
|
@@ -1851,6 +1913,7 @@ async function run(deps) {
|
|
|
1851
1913
|
const command = argv[0];
|
|
1852
1914
|
if (command === "verify" || command === "audit" || command === "restore") return runSubcommand(command, argv.slice(1), {
|
|
1853
1915
|
...deps,
|
|
1916
|
+
cwd,
|
|
1854
1917
|
env,
|
|
1855
1918
|
stdout,
|
|
1856
1919
|
argv
|
|
@@ -1922,12 +1985,12 @@ async function run(deps) {
|
|
|
1922
1985
|
warn: (m) => logger.warn(m),
|
|
1923
1986
|
error: (m) => logger.error(m)
|
|
1924
1987
|
};
|
|
1925
|
-
const refuseHere = (exitCode
|
|
1988
|
+
const refuseHere = (exitCode, code, message, fix, detail) => refuse({
|
|
1926
1989
|
logger,
|
|
1927
1990
|
mode,
|
|
1928
1991
|
version: version$1,
|
|
1929
1992
|
command: "obfuscate",
|
|
1930
|
-
exitCode
|
|
1993
|
+
exitCode,
|
|
1931
1994
|
code,
|
|
1932
1995
|
message,
|
|
1933
1996
|
fix,
|
|
@@ -1935,7 +1998,6 @@ async function run(deps) {
|
|
|
1935
1998
|
});
|
|
1936
1999
|
if (resolved.positionals.length > 1) return refuseHere(EXIT.usage, "TOO_MANY_PATHS", `expected a single [path], got ${resolved.positionals.length}`, "Name one directory or one .js file; run it again for the second target.");
|
|
1937
2000
|
const parsed = toRunOptions(resolved.config);
|
|
1938
|
-
const projectRoot = projectRootFor(cwd, resolved.configFile);
|
|
1939
2001
|
const backupEnabled = parsed.artifactOptions.build?.backup ?? true;
|
|
1940
2002
|
const configuredKey = getPath(resolved.config, "key");
|
|
1941
2003
|
const hasConfiguredKey = typeof configuredKey === "string" && configuredKey !== "" || typeof env.AFTERPACK_KEY === "string" && env.AFTERPACK_KEY !== "";
|
|
@@ -1985,10 +2047,18 @@ async function run(deps) {
|
|
|
1985
2047
|
requested = join(explicitTarget, bare.requested);
|
|
1986
2048
|
}
|
|
1987
2049
|
}
|
|
1988
|
-
const
|
|
1989
|
-
if (!existsSync(
|
|
2050
|
+
const requestedPath = isAbsolute(requested) ? requested : resolve(cwd, requested);
|
|
2051
|
+
if (!existsSync(requestedPath)) return refuseHere(EXIT.failure, "PATH_NOT_FOUND", `path not found: ${requested}`, "Name an existing directory or .js file, or run `afterpack` with no path to detect the build output.");
|
|
2052
|
+
const target = realDir(requestedPath);
|
|
1990
2053
|
const isDirectory = statSync(target).isDirectory();
|
|
1991
2054
|
const buildDir = isDirectory ? target : dirname(target);
|
|
2055
|
+
let projectRoot;
|
|
2056
|
+
try {
|
|
2057
|
+
projectRoot = afterpackHome(buildDir, { fileTarget: !isDirectory }).projectRoot;
|
|
2058
|
+
} catch (error) {
|
|
2059
|
+
if (!(error instanceof AfterpackFilesError)) throw error;
|
|
2060
|
+
return refuseHere(EXIT.failure, error.code, error.summary, error.fix);
|
|
2061
|
+
}
|
|
1992
2062
|
const nestedProjects = [];
|
|
1993
2063
|
const files = collectJsFiles(target, {
|
|
1994
2064
|
include: parsed.pathsInclude,
|
|
@@ -2015,6 +2085,8 @@ async function run(deps) {
|
|
|
2015
2085
|
engine,
|
|
2016
2086
|
cwd,
|
|
2017
2087
|
buildDir,
|
|
2088
|
+
fileTarget: !isDirectory,
|
|
2089
|
+
sweepSourceMaps: isDirectory,
|
|
2018
2090
|
sourceType: detectCliSourceType({
|
|
2019
2091
|
files,
|
|
2020
2092
|
buildDir
|
|
@@ -2050,27 +2122,20 @@ async function run(deps) {
|
|
|
2050
2122
|
}
|
|
2051
2123
|
const diagnostics = captured.flatMap((f) => f.diagnostics);
|
|
2052
2124
|
if (failure !== null) {
|
|
2053
|
-
const exitCode
|
|
2054
|
-
|
|
2125
|
+
const exitCode = failureExitCode(diagnostics);
|
|
2126
|
+
const { code, fix } = failureDetail(exitCode);
|
|
2127
|
+
return refuseHere(exitCode, code, failure, fix);
|
|
2055
2128
|
}
|
|
2056
|
-
const unobfuscated = captured.filter((f) => f.unobfuscated);
|
|
2057
|
-
const exitCode = unobfuscated.length > 0 ? EXIT.partial : EXIT.ok;
|
|
2058
2129
|
if (mode.format === "json") {
|
|
2059
2130
|
emitJson(logger, buildDocument({
|
|
2060
2131
|
version: version$1,
|
|
2061
2132
|
cwd,
|
|
2062
|
-
exitCode,
|
|
2133
|
+
exitCode: EXIT.ok,
|
|
2063
2134
|
files: captured,
|
|
2064
2135
|
result,
|
|
2065
2136
|
transformed: new Set(result?.transformedFiles ?? [])
|
|
2066
2137
|
}));
|
|
2067
|
-
return
|
|
2068
|
-
}
|
|
2069
|
-
if (exitCode === EXIT.partial) {
|
|
2070
|
-
logger.error(`${yellow("⚠")} ${unobfuscated.length} ${unobfuscated.length === 1 ? "file" : "files"} shipped UNOBFUSCATED — drop --allowUnobfuscated to fail closed instead.`);
|
|
2071
|
-
logger.error("");
|
|
2072
|
-
logger.error(dim(CONTACT_FOOTER));
|
|
2073
|
-
return exitCode;
|
|
2138
|
+
return EXIT.ok;
|
|
2074
2139
|
}
|
|
2075
2140
|
renderNextSteps({
|
|
2076
2141
|
report,
|
|
@@ -2078,11 +2143,12 @@ async function run(deps) {
|
|
|
2078
2143
|
env,
|
|
2079
2144
|
stdout,
|
|
2080
2145
|
projectRoot,
|
|
2146
|
+
buildDir,
|
|
2081
2147
|
receiptPath: result?.receiptPath,
|
|
2082
2148
|
backupWritten,
|
|
2083
2149
|
hasConfiguredKey
|
|
2084
2150
|
});
|
|
2085
|
-
return
|
|
2151
|
+
return EXIT.ok;
|
|
2086
2152
|
}
|
|
2087
2153
|
const SUBCOMMAND_HELP = {
|
|
2088
2154
|
verify: VERIFY_HELP,
|
|
@@ -2130,6 +2196,7 @@ async function runSubcommand(command, rest, deps) {
|
|
|
2130
2196
|
version: version$1
|
|
2131
2197
|
});
|
|
2132
2198
|
return audit({
|
|
2199
|
+
cwd,
|
|
2133
2200
|
positionals: args.positionals,
|
|
2134
2201
|
logger,
|
|
2135
2202
|
report,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "afterpack",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.4",
|
|
4
4
|
"description": "AfterPack CLI: obfuscate the JavaScript in any build output, verify a build before deploy, and scan a live site",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"dist"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@afterpack/core": "~0.2.
|
|
18
|
-
"@afterpack/integration-utils": "0.2.
|
|
17
|
+
"@afterpack/core": "~0.2.5",
|
|
18
|
+
"@afterpack/integration-utils": "0.2.4"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@biomejs/biome": "2.4.4",
|