@autter/runtime-cli 1.1.0 → 1.2.0
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 +85 -13
- package/dist/{build-CPXR9Xd3.d.cts → build-BqjqqeLg.d.cts} +10 -3
- package/dist/{build-CPXR9Xd3.d.ts → build-BqjqqeLg.d.ts} +10 -3
- package/dist/{chunk-DQLLM2NT.js → chunk-KIQRQY3X.js} +16 -7
- package/dist/{chunk-I2743JCN.js → chunk-SIL3WZZ3.js} +1 -1
- package/dist/cli.js +1867 -36
- package/dist/index.cjs +273 -14
- package/dist/index.d.cts +56 -2
- package/dist/index.d.ts +56 -2
- package/dist/index.js +253 -2
- package/dist/next.cjs +11 -7
- package/dist/next.d.cts +1 -1
- package/dist/next.d.ts +1 -1
- package/dist/next.js +2 -2
- package/dist/vite.cjs +11 -7
- package/dist/vite.d.cts +1 -1
- package/dist/vite.d.ts +1 -1
- package/dist/vite.js +1 -1
- package/dist/webpack.cjs +11 -7
- package/dist/webpack.d.cts +1 -1
- package/dist/webpack.d.ts +1 -1
- package/dist/webpack.js +2 -2
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -21,23 +21,29 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
BUNDLE_RE: () => BUNDLE_RE,
|
|
24
|
+
CLIENT_KEY_PREFIX: () => CLIENT_KEY_PREFIX,
|
|
24
25
|
DEBUG_ID_RE: () => DEBUG_ID_RE,
|
|
25
26
|
DEBUG_ID_REGISTRY: () => DEBUG_ID_REGISTRY,
|
|
26
27
|
DEFAULT_ENDPOINT: () => DEFAULT_ENDPOINT,
|
|
27
28
|
FatalUploadError: () => FatalUploadError,
|
|
29
|
+
KEY_ADVICE: () => KEY_ADVICE,
|
|
28
30
|
MAX_MAP_CHARS: () => MAX_MAP_CHARS,
|
|
29
31
|
MAX_UPLOAD_BYTES: () => MAX_UPLOAD_BYTES,
|
|
30
32
|
RELEASE_ENV_VARS: () => RELEASE_ENV_VARS,
|
|
31
33
|
RELEASE_RE: () => RELEASE_RE,
|
|
32
34
|
SCOPES_KEY: () => SCOPES_KEY,
|
|
33
35
|
SCOPES_VERSION: () => SCOPES_VERSION,
|
|
36
|
+
SERVER_KEY_PREFIX: () => SERVER_KEY_PREFIX,
|
|
34
37
|
SNIPPET_LINE_KEY: () => SNIPPET_LINE_KEY,
|
|
38
|
+
UPLOAD_KEY_PREFIX: () => UPLOAD_KEY_PREFIX,
|
|
35
39
|
computeScopes: () => computeScopes,
|
|
36
40
|
debugIdFor: () => debugIdFor,
|
|
37
41
|
debugIdSnippet: () => debugIdSnippet,
|
|
38
42
|
findBundles: () => findBundles,
|
|
39
43
|
formatUploadSummary: () => formatUploadSummary,
|
|
44
|
+
formatVerify: () => formatVerify,
|
|
40
45
|
gitHead: () => gitHead,
|
|
46
|
+
globToRegExp: () => globToRegExp,
|
|
41
47
|
hasDebugIdSnippet: () => hasDebugIdSnippet,
|
|
42
48
|
injectBundle: () => injectBundle,
|
|
43
49
|
injectDir: () => injectDir,
|
|
@@ -53,7 +59,8 @@ __export(src_exports, {
|
|
|
53
59
|
snippetLine: () => snippetLine,
|
|
54
60
|
storedMapJson: () => storedMapJson,
|
|
55
61
|
stripSourceMappingUrl: () => stripSourceMappingUrl,
|
|
56
|
-
uploadDir: () => uploadDir
|
|
62
|
+
uploadDir: () => uploadDir,
|
|
63
|
+
verifyDir: () => verifyDir
|
|
57
64
|
});
|
|
58
65
|
module.exports = __toCommonJS(src_exports);
|
|
59
66
|
|
|
@@ -723,6 +730,10 @@ var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
|
|
|
723
730
|
var MAX_MAP_CHARS = 32 * 1024 * 1024;
|
|
724
731
|
var MAX_UPLOAD_BYTES = MAX_MAP_CHARS + 1024 * 1024;
|
|
725
732
|
var LEGACY_MAX_BYTES = 5 * 1024 * 1024;
|
|
733
|
+
var UPLOAD_KEY_PREFIX = "autter_rtu_";
|
|
734
|
+
var SERVER_KEY_PREFIX = "autter_rt_";
|
|
735
|
+
var CLIENT_KEY_PREFIX = "autter_rtc_";
|
|
736
|
+
var KEY_ADVICE = "set AUTTER_RUNTIME_KEY to an upload-only key (autter_rtu_\u2026, recommended for CI: it can only upload source maps) or the full server key (autter_rt_\u2026, also works)";
|
|
726
737
|
var gzip = (0, import_node_util.promisify)(import_node_zlib.gzip);
|
|
727
738
|
var CHECK_BATCH = 500;
|
|
728
739
|
var MAX_ATTEMPTS = 3;
|
|
@@ -791,7 +802,7 @@ async function prepare(bundle, urlPrefix, release, log, compress) {
|
|
|
791
802
|
var FatalUploadError = class extends Error {
|
|
792
803
|
};
|
|
793
804
|
function sleep(ms) {
|
|
794
|
-
return new Promise((
|
|
805
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
795
806
|
}
|
|
796
807
|
async function uploadDir(dir, options = {}) {
|
|
797
808
|
const env = options.env ?? process.env;
|
|
@@ -831,10 +842,13 @@ async function uploadDir(dir, options = {}) {
|
|
|
831
842
|
return summary;
|
|
832
843
|
}
|
|
833
844
|
const key = (options.key ?? env.AUTTER_RUNTIME_KEY ?? "").trim();
|
|
834
|
-
if (!key) throw new FatalUploadError(
|
|
835
|
-
if (key.startsWith(
|
|
836
|
-
throw new FatalUploadError(
|
|
845
|
+
if (!key) throw new FatalUploadError(`no ingest key: ${KEY_ADVICE}`);
|
|
846
|
+
if (key.startsWith(CLIENT_KEY_PREFIX)) {
|
|
847
|
+
throw new FatalUploadError(`AUTTER_RUNTIME_KEY is a publishable client key (autter_rtc_\u2026), which cannot upload source maps: ${KEY_ADVICE}`);
|
|
837
848
|
}
|
|
849
|
+
const rejected = (status, detail) => new FatalUploadError(
|
|
850
|
+
`the ingester rejected the key (${status}): ${detail}` + (key.startsWith(UPLOAD_KEY_PREFIX) ? " (upload keys, autter_rtu_\u2026, need ingester 1.7.0 or later; the server key works with any)" : "")
|
|
851
|
+
);
|
|
838
852
|
const headers = { "content-type": "application/json", authorization: `Bearer ${key}` };
|
|
839
853
|
const uploadHeaders = { ...headers, "content-encoding": "gzip" };
|
|
840
854
|
const skipped = /* @__PURE__ */ new Set();
|
|
@@ -856,9 +870,7 @@ async function uploadDir(dir, options = {}) {
|
|
|
856
870
|
);
|
|
857
871
|
break;
|
|
858
872
|
}
|
|
859
|
-
if (res.status === 401 || res.status === 403)
|
|
860
|
-
throw new FatalUploadError(`the ingester rejected the key (${res.status}): ${(await res.text()).slice(0, 300)}`);
|
|
861
|
-
}
|
|
873
|
+
if (res.status === 401 || res.status === 403) throw rejected(res.status, (await res.text()).slice(0, 300));
|
|
862
874
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
863
875
|
const body = await res.json();
|
|
864
876
|
const present = new Set(Array.isArray(body.present) ? body.present : []);
|
|
@@ -889,7 +901,7 @@ async function uploadDir(dir, options = {}) {
|
|
|
889
901
|
detail = err.message;
|
|
890
902
|
}
|
|
891
903
|
if (status === 401 || status === 403) {
|
|
892
|
-
fatal =
|
|
904
|
+
fatal = rejected(status, detail);
|
|
893
905
|
return;
|
|
894
906
|
}
|
|
895
907
|
const retryable = status === 0 || status === 429 || status >= 500;
|
|
@@ -930,9 +942,249 @@ function strip(item) {
|
|
|
930
942
|
return { path, filename, debugId, hash, bytes };
|
|
931
943
|
}
|
|
932
944
|
|
|
933
|
-
// src/
|
|
945
|
+
// src/verify.ts
|
|
934
946
|
var import_node_fs2 = require("fs");
|
|
947
|
+
var import_promises4 = require("fs/promises");
|
|
935
948
|
var import_node_path2 = require("path");
|
|
949
|
+
var CHECK_BATCH2 = 500;
|
|
950
|
+
var SNIPPET_ID_RE = /\(g\._autterDebugIds=g\._autterDebugIds\|\|\{\}\)\[s\]="([0-9a-f-]{36})"/;
|
|
951
|
+
var NOT_BUNDLES = [
|
|
952
|
+
[/(^|\/)_(build|ssg|middleware|clientMiddleware)Manifest\.js$/, "Next.js build manifest"],
|
|
953
|
+
[/(^|\/)chunks\/polyfills-[\w-]+\.js$/, "Next.js polyfills, copied prebuilt without a source map"],
|
|
954
|
+
[/(^|\/)(sw|service-worker|serviceWorker|firebase-messaging-sw|mockServiceWorker)\.js$/, "service worker (the browser SDK doesn't run there)"],
|
|
955
|
+
[/(^|\/)workbox-[\w-]+\.js$/, "service worker runtime (the browser SDK doesn't run there)"]
|
|
956
|
+
];
|
|
957
|
+
function globToRegExp(glob) {
|
|
958
|
+
let re = "";
|
|
959
|
+
for (let i = 0; i < glob.length; i++) {
|
|
960
|
+
const ch = glob[i];
|
|
961
|
+
if (ch === "*" && glob[i + 1] === "*") {
|
|
962
|
+
re += glob[i + 2] === "/" ? "(?:.*/)?" : ".*";
|
|
963
|
+
i += glob[i + 2] === "/" ? 2 : 1;
|
|
964
|
+
} else if (ch === "*") re += "[^/]*";
|
|
965
|
+
else if (ch === "?") re += "[^/]";
|
|
966
|
+
else re += ch.replace(/[.+^${}()|[\]\\]/g, "\\$&");
|
|
967
|
+
}
|
|
968
|
+
return new RegExp(glob.includes("/") ? `^${re.replace(/^\.\//, "")}$` : `(^|/)${re}$`);
|
|
969
|
+
}
|
|
970
|
+
async function walk2(dir, out) {
|
|
971
|
+
let entries;
|
|
972
|
+
try {
|
|
973
|
+
entries = await (0, import_promises4.readdir)(dir, { withFileTypes: true });
|
|
974
|
+
} catch {
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
for (const entry of entries) {
|
|
978
|
+
if (entry.name === "node_modules") continue;
|
|
979
|
+
const full = (0, import_node_path2.join)(dir, entry.name);
|
|
980
|
+
if (entry.isDirectory()) await walk2(full, out);
|
|
981
|
+
else if (entry.isFile()) out.push(full);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function staticRoots(dir) {
|
|
985
|
+
for (let current = (0, import_node_path2.dirname)(dir); (0, import_node_path2.dirname)(current) !== current; current = (0, import_node_path2.dirname)(current)) {
|
|
986
|
+
if ((0, import_node_fs2.existsSync)((0, import_node_path2.join)(current, "package.json"))) return ["public", "static", "src"].map((name) => (0, import_node_path2.join)(current, name));
|
|
987
|
+
}
|
|
988
|
+
return [];
|
|
989
|
+
}
|
|
990
|
+
async function verifyDir(dir, options = {}) {
|
|
991
|
+
const root = (0, import_node_path2.resolve)(dir);
|
|
992
|
+
const env = options.env ?? process.env;
|
|
993
|
+
const files = [];
|
|
994
|
+
await walk2(root, files);
|
|
995
|
+
files.sort();
|
|
996
|
+
const relPath = (path) => (0, import_node_path2.relative)(root, path).split(import_node_path2.sep).join("/");
|
|
997
|
+
const ignore = (options.ignore ?? []).map(globToRegExp);
|
|
998
|
+
const roots = staticRoots(root);
|
|
999
|
+
const result = {
|
|
1000
|
+
dir: root,
|
|
1001
|
+
ok: true,
|
|
1002
|
+
bundles: [],
|
|
1003
|
+
maps: [],
|
|
1004
|
+
upload: { status: "unverified", endpoint: null, reason: null, checked: 0, missing: 0 },
|
|
1005
|
+
failures: []
|
|
1006
|
+
};
|
|
1007
|
+
const fail = (path, reason) => result.failures.push({ path, reason });
|
|
1008
|
+
for (const file of files) {
|
|
1009
|
+
const path = relPath(file);
|
|
1010
|
+
if (file.endsWith(".map")) {
|
|
1011
|
+
result.maps.push(path);
|
|
1012
|
+
if (!options.allowMaps) {
|
|
1013
|
+
fail(path, "source map in the deploy output: it exposes your original source. Delete it after upload (upload --delete-after-upload, or the bundler plugin) or keep it out of the deploy");
|
|
1014
|
+
}
|
|
1015
|
+
continue;
|
|
1016
|
+
}
|
|
1017
|
+
if (!BUNDLE_RE.test(file)) continue;
|
|
1018
|
+
const bytes = await (0, import_promises4.readFile)(file);
|
|
1019
|
+
const bundle = { path, status: "ok", debugId: null, reasons: [], uploaded: null };
|
|
1020
|
+
result.bundles.push(bundle);
|
|
1021
|
+
const skip = (reason) => {
|
|
1022
|
+
bundle.status = "skipped";
|
|
1023
|
+
bundle.reasons.push(reason);
|
|
1024
|
+
};
|
|
1025
|
+
if (ignore.some((re) => re.test(path))) {
|
|
1026
|
+
skip("matches --ignore");
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
1029
|
+
const known = NOT_BUNDLES.find(([re]) => re.test(path));
|
|
1030
|
+
if (known) {
|
|
1031
|
+
skip(known[1]);
|
|
1032
|
+
continue;
|
|
1033
|
+
}
|
|
1034
|
+
let copied = null;
|
|
1035
|
+
for (const staticRoot of roots) {
|
|
1036
|
+
const candidate = (0, import_node_path2.join)(staticRoot, path);
|
|
1037
|
+
if ((0, import_node_fs2.existsSync)(candidate) && (await (0, import_promises4.readFile)(candidate)).equals(bytes)) copied = (0, import_node_path2.relative)((0, import_node_path2.dirname)(staticRoot), candidate).split(import_node_path2.sep).join("/");
|
|
1038
|
+
}
|
|
1039
|
+
if (copied) {
|
|
1040
|
+
skip(`copied unchanged from ${copied}, not built`);
|
|
1041
|
+
continue;
|
|
1042
|
+
}
|
|
1043
|
+
const code = bytes.toString("utf8");
|
|
1044
|
+
const commentId = readDebugIdComment(code);
|
|
1045
|
+
const snippetId = SNIPPET_ID_RE.exec(code)?.[1] ?? null;
|
|
1046
|
+
bundle.debugId = commentId;
|
|
1047
|
+
if (!commentId && !hasDebugIdSnippet(code)) {
|
|
1048
|
+
bundle.reasons.push(
|
|
1049
|
+
"no debug id: its errors can't be matched to a source map. Run `autter-runtime sourcemaps inject` on the build output (or use the bundler plugin with AUTTER_RUNTIME_KEY set) before deploying"
|
|
1050
|
+
);
|
|
1051
|
+
} else if (!commentId) {
|
|
1052
|
+
bundle.reasons.push("has the debug id snippet but no //# debugId= comment: run `autter-runtime sourcemaps inject` on it again");
|
|
1053
|
+
} else if (!hasDebugIdSnippet(code)) {
|
|
1054
|
+
bundle.reasons.push(
|
|
1055
|
+
"has a //# debugId= comment but no registration snippet, so the browser SDK can't report its id: run `autter-runtime sourcemaps inject` on it"
|
|
1056
|
+
);
|
|
1057
|
+
} else if (snippetId && snippetId !== commentId) {
|
|
1058
|
+
bundle.reasons.push(`its snippet registers debug id ${snippetId} but its comment says ${commentId}: run inject on the original build output`);
|
|
1059
|
+
}
|
|
1060
|
+
const url = readSourceMappingUrl(code);
|
|
1061
|
+
if (url?.startsWith("data:")) {
|
|
1062
|
+
bundle.reasons.push("carries an inline source map (data: URL): your original source ships with the bundle. Use hidden or external maps");
|
|
1063
|
+
} else if (url && !/^[a-z][\w+.-]*:/i.test(url) && !url.startsWith("/")) {
|
|
1064
|
+
let target = url.split(/[?#]/)[0];
|
|
1065
|
+
try {
|
|
1066
|
+
target = decodeURIComponent(target);
|
|
1067
|
+
} catch {
|
|
1068
|
+
}
|
|
1069
|
+
if (!(0, import_node_fs2.existsSync)((0, import_node_path2.resolve)((0, import_node_path2.dirname)(file), target))) {
|
|
1070
|
+
bundle.reasons.push(
|
|
1071
|
+
`its sourceMappingURL points at ${url}, which is not in the output (browsers' devtools request it and get a 404). Remove the comment: upload --delete-after-upload does`
|
|
1072
|
+
);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (bundle.reasons.length) {
|
|
1076
|
+
bundle.status = "failed";
|
|
1077
|
+
for (const reason of bundle.reasons) fail(path, reason);
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
const counted = result.bundles.filter((b) => b.status !== "skipped");
|
|
1081
|
+
if (!counted.length) fail(".", `no .js/.mjs/.cjs bundles under ${dir}: is this the build output?`);
|
|
1082
|
+
await checkUploads(result, counted, options, env);
|
|
1083
|
+
result.ok = result.failures.length === 0;
|
|
1084
|
+
return result;
|
|
1085
|
+
}
|
|
1086
|
+
async function checkUploads(result, bundles, options, env) {
|
|
1087
|
+
const upload = result.upload;
|
|
1088
|
+
const key = (options.key ?? env.AUTTER_RUNTIME_KEY ?? "").trim();
|
|
1089
|
+
if (!key) {
|
|
1090
|
+
upload.reason = "AUTTER_RUNTIME_KEY is not set: only the local checks ran";
|
|
1091
|
+
return;
|
|
1092
|
+
}
|
|
1093
|
+
upload.endpoint = resolveEndpoint(options.endpoint, env);
|
|
1094
|
+
if (key.startsWith(CLIENT_KEY_PREFIX)) {
|
|
1095
|
+
upload.status = "error";
|
|
1096
|
+
upload.reason = "AUTTER_RUNTIME_KEY is a publishable client key (autter_rtc_\u2026), which can't check source maps: use an upload key (autter_rtu_\u2026) or the server key (autter_rt_\u2026)";
|
|
1097
|
+
result.failures.push({ path: ".", reason: upload.reason });
|
|
1098
|
+
return;
|
|
1099
|
+
}
|
|
1100
|
+
const withIds = bundles.filter((b) => b.debugId);
|
|
1101
|
+
if (!withIds.length) {
|
|
1102
|
+
upload.reason = "no bundle has a debug id to check";
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
let release = "verify";
|
|
1106
|
+
try {
|
|
1107
|
+
release = resolveRelease(options.release, env, options.cwd).release;
|
|
1108
|
+
} catch {
|
|
1109
|
+
}
|
|
1110
|
+
const doFetch = options.fetch ?? fetch;
|
|
1111
|
+
const missing = [];
|
|
1112
|
+
for (let start = 0; start < withIds.length; start += CHECK_BATCH2) {
|
|
1113
|
+
const batch = withIds.slice(start, start + CHECK_BATCH2);
|
|
1114
|
+
let res;
|
|
1115
|
+
try {
|
|
1116
|
+
res = await doFetch(`${upload.endpoint}/v1/sourcemaps/check`, {
|
|
1117
|
+
method: "POST",
|
|
1118
|
+
headers: { "content-type": "application/json", authorization: `Bearer ${key}` },
|
|
1119
|
+
body: JSON.stringify({ release, files: batch.map((b) => ({ filename: servedFilename(options.urlPrefix, b.path), debugId: b.debugId })) })
|
|
1120
|
+
});
|
|
1121
|
+
} catch (err) {
|
|
1122
|
+
upload.status = "error";
|
|
1123
|
+
upload.reason = `could not reach the ingester: ${err.message}`;
|
|
1124
|
+
result.failures.push({ path: ".", reason: upload.reason });
|
|
1125
|
+
return;
|
|
1126
|
+
}
|
|
1127
|
+
if (res.status === 404 || res.status === 400) {
|
|
1128
|
+
upload.status = "unverified";
|
|
1129
|
+
upload.reason = res.status === 404 ? "the ingester predates 1.6.0 (no /v1/sourcemaps/check), so uploads can't be checked: upgrade it" : "the ingester predates 1.7.0, which checks maps by debug id alone, so uploads can't be checked after the maps were deleted: upgrade it";
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
if (res.status === 401 || res.status === 403) {
|
|
1133
|
+
upload.status = "error";
|
|
1134
|
+
upload.reason = `the ingester rejected the key (${res.status}): ${(await res.text()).slice(0, 300)}` + (key.startsWith(UPLOAD_KEY_PREFIX) ? " (upload keys, autter_rtu_\u2026, need ingester 1.7.0 or later)" : "");
|
|
1135
|
+
result.failures.push({ path: ".", reason: upload.reason });
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
if (!res.ok) {
|
|
1139
|
+
upload.status = "error";
|
|
1140
|
+
upload.reason = `the source map check failed: HTTP ${res.status}`;
|
|
1141
|
+
result.failures.push({ path: ".", reason: upload.reason });
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
const body = await res.json();
|
|
1145
|
+
const present = new Set(Array.isArray(body.present) ? body.present : []);
|
|
1146
|
+
batch.forEach((bundle, index) => {
|
|
1147
|
+
bundle.uploaded = present.has(index);
|
|
1148
|
+
if (!bundle.uploaded) missing.push(bundle);
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
upload.checked = withIds.length;
|
|
1152
|
+
upload.missing = missing.length;
|
|
1153
|
+
upload.status = missing.length ? "missing" : "verified";
|
|
1154
|
+
upload.reason = missing.length ? `${missing.length} of ${withIds.length} bundle(s) have no map on the ingester` : null;
|
|
1155
|
+
for (const bundle of missing) {
|
|
1156
|
+
const reason = `no map with debug id ${bundle.debugId} on the ingester for this key's repository: upload this build's maps (autter-runtime sourcemaps upload, or the bundler plugin with AUTTER_RUNTIME_KEY set)`;
|
|
1157
|
+
bundle.status = "failed";
|
|
1158
|
+
bundle.reasons.push(reason);
|
|
1159
|
+
result.failures.push({ path: bundle.path, reason });
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
function formatVerify(result) {
|
|
1163
|
+
const lines = [];
|
|
1164
|
+
for (const bundle of result.bundles) {
|
|
1165
|
+
if (bundle.status === "ok") lines.push(`ok ${bundle.path} (debug id ${bundle.debugId}${bundle.uploaded ? ", map uploaded" : ""})`);
|
|
1166
|
+
else if (bundle.status === "skipped") lines.push(`skipped ${bundle.path}: ${bundle.reasons.join("; ")}`);
|
|
1167
|
+
else for (const reason of bundle.reasons) lines.push(`FAILED ${bundle.path}: ${reason}`);
|
|
1168
|
+
}
|
|
1169
|
+
for (const map of result.maps) {
|
|
1170
|
+
const failure = result.failures.find((f) => f.path === map);
|
|
1171
|
+
lines.push(failure ? `FAILED ${map}: ${failure.reason}` : `warning ${map}: source map in the output (allowed by --allow-maps; remove it before deploying)`);
|
|
1172
|
+
}
|
|
1173
|
+
for (const failure of result.failures.filter((f) => f.path === ".")) lines.push(`FAILED ${failure.reason}`);
|
|
1174
|
+
const u = result.upload;
|
|
1175
|
+
lines.push(
|
|
1176
|
+
u.status === "verified" ? `upload: verified, ${u.checked} bundle map(s) on the ingester (${u.endpoint})` : u.status === "missing" ? `upload: ${u.reason} (${u.endpoint})` : `upload: ${u.status}${u.reason ? `, ${u.reason}` : ""}`
|
|
1177
|
+
);
|
|
1178
|
+
const counted = result.bundles.filter((b) => b.status !== "skipped");
|
|
1179
|
+
lines.push(
|
|
1180
|
+
result.ok ? `ok: ${counted.length} bundle(s) with debug ids, ${result.maps.length ? `${result.maps.length} source map(s) left (--allow-maps)` : "no source maps left"}${u.status === "unverified" ? ", upload not verified" : ""}` : `${result.failures.length} problem(s) in ${result.dir}`
|
|
1181
|
+
);
|
|
1182
|
+
return lines;
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// src/build.ts
|
|
1186
|
+
var import_node_fs3 = require("fs");
|
|
1187
|
+
var import_node_path3 = require("path");
|
|
936
1188
|
function buildKey(options) {
|
|
937
1189
|
const key = (options.key ?? process.env.AUTTER_RUNTIME_KEY ?? "").trim();
|
|
938
1190
|
return key || null;
|
|
@@ -1017,9 +1269,9 @@ async function processBuildOutput(input) {
|
|
|
1017
1269
|
async function cleanUp() {
|
|
1018
1270
|
if (!input.ownMaps) return;
|
|
1019
1271
|
const maps = /* @__PURE__ */ new Set([...input.maps ?? [], ...owners.keys()]);
|
|
1020
|
-
const rel = (path) => (0,
|
|
1272
|
+
const rel = (path) => (0, import_node_path3.relative)(input.dir, path).split(import_node_path3.sep).join("/");
|
|
1021
1273
|
if (options.upload === false || options.deleteAfterUpload === false) {
|
|
1022
|
-
const kept = [...maps].filter((map) => (0,
|
|
1274
|
+
const kept = [...maps].filter((map) => (0, import_node_fs3.existsSync)(map));
|
|
1023
1275
|
if (kept.length) {
|
|
1024
1276
|
log(
|
|
1025
1277
|
`kept ${kept.length} source map(s) this plugin generated (${options.upload === false ? "upload: false" : "deleteAfterUpload: false"}): they expose your source, so upload them with \`autter-runtime sourcemaps upload --delete-after-upload\` or keep them out of the deploy`
|
|
@@ -1034,7 +1286,7 @@ async function processBuildOutput(input) {
|
|
|
1034
1286
|
if (options.failOnError) throw new Error(`[autter-runtime] ${message}`);
|
|
1035
1287
|
if (!options.silent) console.warn(`[autter-runtime] ${message}`);
|
|
1036
1288
|
}
|
|
1037
|
-
result.removedMaps = [...maps].filter((map) => !(0,
|
|
1289
|
+
result.removedMaps = [...maps].filter((map) => !(0, import_node_fs3.existsSync)(map)).map(rel).sort();
|
|
1038
1290
|
if (result.removedMaps.length) {
|
|
1039
1291
|
log(`removed ${result.removedMaps.length} source map(s) this plugin generated, so they are not deployed: ${outcome}`);
|
|
1040
1292
|
}
|
|
@@ -1043,23 +1295,29 @@ async function processBuildOutput(input) {
|
|
|
1043
1295
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1044
1296
|
0 && (module.exports = {
|
|
1045
1297
|
BUNDLE_RE,
|
|
1298
|
+
CLIENT_KEY_PREFIX,
|
|
1046
1299
|
DEBUG_ID_RE,
|
|
1047
1300
|
DEBUG_ID_REGISTRY,
|
|
1048
1301
|
DEFAULT_ENDPOINT,
|
|
1049
1302
|
FatalUploadError,
|
|
1303
|
+
KEY_ADVICE,
|
|
1050
1304
|
MAX_MAP_CHARS,
|
|
1051
1305
|
MAX_UPLOAD_BYTES,
|
|
1052
1306
|
RELEASE_ENV_VARS,
|
|
1053
1307
|
RELEASE_RE,
|
|
1054
1308
|
SCOPES_KEY,
|
|
1055
1309
|
SCOPES_VERSION,
|
|
1310
|
+
SERVER_KEY_PREFIX,
|
|
1056
1311
|
SNIPPET_LINE_KEY,
|
|
1312
|
+
UPLOAD_KEY_PREFIX,
|
|
1057
1313
|
computeScopes,
|
|
1058
1314
|
debugIdFor,
|
|
1059
1315
|
debugIdSnippet,
|
|
1060
1316
|
findBundles,
|
|
1061
1317
|
formatUploadSummary,
|
|
1318
|
+
formatVerify,
|
|
1062
1319
|
gitHead,
|
|
1320
|
+
globToRegExp,
|
|
1063
1321
|
hasDebugIdSnippet,
|
|
1064
1322
|
injectBundle,
|
|
1065
1323
|
injectDir,
|
|
@@ -1075,5 +1333,6 @@ async function processBuildOutput(input) {
|
|
|
1075
1333
|
snippetLine,
|
|
1076
1334
|
storedMapJson,
|
|
1077
1335
|
stripSourceMappingUrl,
|
|
1078
|
-
uploadDir
|
|
1336
|
+
uploadDir,
|
|
1337
|
+
verifyDir
|
|
1079
1338
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AutterSourceMapsOptions, B as BUNDLE_RE, a as BuildOutputResult, b as BundleWithMap, D as DEFAULT_ENDPOINT, F as FatalUploadError, I as InjectOptions, c as InjectResult, M as MAX_MAP_CHARS, d as MAX_UPLOAD_BYTES, S as SNIPPET_LINE_KEY, U as UploadItem,
|
|
1
|
+
export { A as AutterSourceMapsOptions, B as BUNDLE_RE, a as BuildOutputResult, b as BundleWithMap, C as CLIENT_KEY_PREFIX, D as DEFAULT_ENDPOINT, F as FatalUploadError, I as InjectOptions, c as InjectResult, K as KEY_ADVICE, M as MAX_MAP_CHARS, d as MAX_UPLOAD_BYTES, S as SERVER_KEY_PREFIX, e as SNIPPET_LINE_KEY, U as UPLOAD_KEY_PREFIX, f as UploadItem, g as UploadOptions, h as UploadSummary, i as findBundles, j as formatUploadSummary, k as injectBundle, l as injectDir, m as mapPathFor, p as processBuildOutput, r as readSourceMappingUrl, n as resolveEndpoint, s as servedFilename, o as shiftMappings, q as snippetLine, t as storedMapJson, u as stripSourceMappingUrl, v as uploadDir } from './build-BqjqqeLg.cjs';
|
|
2
2
|
|
|
3
3
|
/** 8-4-4-4-12 hex: the debug id shape shared with Rollup, Turbopack, esbuild
|
|
4
4
|
* and Sentry tooling, and what the ingester accepts. */
|
|
@@ -28,6 +28,60 @@ declare function debugIdSnippet(id: string): string;
|
|
|
28
28
|
* contains it too.) */
|
|
29
29
|
declare function hasDebugIdSnippet(code: string): boolean;
|
|
30
30
|
|
|
31
|
+
interface VerifyOptions {
|
|
32
|
+
/** Ingester base URL (default as for upload). */
|
|
33
|
+
endpoint?: string;
|
|
34
|
+
/** Default: $AUTTER_RUNTIME_KEY. */
|
|
35
|
+
key?: string;
|
|
36
|
+
/** Sent with the check (a debug id check ignores it). */
|
|
37
|
+
release?: string;
|
|
38
|
+
urlPrefix?: string;
|
|
39
|
+
/** Globs (relative to the directory) of JS files that are not bundles. */
|
|
40
|
+
ignore?: string[];
|
|
41
|
+
/** Report leftover .map files without failing (a step that runs before they are removed). */
|
|
42
|
+
allowMaps?: boolean;
|
|
43
|
+
env?: NodeJS.ProcessEnv;
|
|
44
|
+
cwd?: string;
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
}
|
|
47
|
+
interface VerifyBundle {
|
|
48
|
+
/** Relative to the directory. */
|
|
49
|
+
path: string;
|
|
50
|
+
status: "ok" | "failed" | "skipped";
|
|
51
|
+
debugId: string | null;
|
|
52
|
+
/** Why it failed, or why it was skipped. */
|
|
53
|
+
reasons: string[];
|
|
54
|
+
/** Whether the ingester has a map for its debug id (null: not checked). */
|
|
55
|
+
uploaded: boolean | null;
|
|
56
|
+
}
|
|
57
|
+
interface VerifyResult {
|
|
58
|
+
dir: string;
|
|
59
|
+
ok: boolean;
|
|
60
|
+
bundles: VerifyBundle[];
|
|
61
|
+
/** `.map` files in the directory (deploy risks unless allowMaps). */
|
|
62
|
+
maps: string[];
|
|
63
|
+
upload: {
|
|
64
|
+
/** verified: every checked bundle's map is on the ingester; missing: some are not;
|
|
65
|
+
* unverified: not checked (no key, or an ingester that can't answer); error: the check failed. */
|
|
66
|
+
status: "verified" | "missing" | "unverified" | "error";
|
|
67
|
+
endpoint: string | null;
|
|
68
|
+
reason: string | null;
|
|
69
|
+
checked: number;
|
|
70
|
+
missing: number;
|
|
71
|
+
};
|
|
72
|
+
/** Every failure, one per file and reason. */
|
|
73
|
+
failures: Array<{
|
|
74
|
+
path: string;
|
|
75
|
+
reason: string;
|
|
76
|
+
}>;
|
|
77
|
+
}
|
|
78
|
+
/** A tiny glob: `**` any path, `*` any name part, `?` one character. A
|
|
79
|
+
* pattern without "/" matches the file name anywhere. */
|
|
80
|
+
declare function globToRegExp(glob: string): RegExp;
|
|
81
|
+
declare function verifyDir(dir: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
82
|
+
/** Human-readable report. */
|
|
83
|
+
declare function formatVerify(result: VerifyResult): string[];
|
|
84
|
+
|
|
31
85
|
/**
|
|
32
86
|
* Function scopes for scope-based frame names (like Sentry's
|
|
33
87
|
* js-source-scopes and PostHog cymbal's `token.scope()`).
|
|
@@ -102,4 +156,4 @@ declare function gitHead(cwd?: string): string | null;
|
|
|
102
156
|
*/
|
|
103
157
|
declare function resolveRelease(explicit?: string | null, env?: NodeJS.ProcessEnv, cwd?: string): ResolvedRelease;
|
|
104
158
|
|
|
105
|
-
export { DEBUG_ID_RE, DEBUG_ID_REGISTRY, RELEASE_ENV_VARS, RELEASE_RE, type ResolvedRelease, SCOPES_KEY, SCOPES_VERSION, type ScopesResult, type SourceMapScopes, computeScopes, debugIdFor, debugIdSnippet, gitHead, hasDebugIdSnippet, normalizeDebugId, readDebugIdComment, resolveRelease };
|
|
159
|
+
export { DEBUG_ID_RE, DEBUG_ID_REGISTRY, RELEASE_ENV_VARS, RELEASE_RE, type ResolvedRelease, SCOPES_KEY, SCOPES_VERSION, type ScopesResult, type SourceMapScopes, type VerifyBundle, type VerifyOptions, type VerifyResult, computeScopes, debugIdFor, debugIdSnippet, formatVerify, gitHead, globToRegExp, hasDebugIdSnippet, normalizeDebugId, readDebugIdComment, resolveRelease, verifyDir };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as AutterSourceMapsOptions, B as BUNDLE_RE, a as BuildOutputResult, b as BundleWithMap, D as DEFAULT_ENDPOINT, F as FatalUploadError, I as InjectOptions, c as InjectResult, M as MAX_MAP_CHARS, d as MAX_UPLOAD_BYTES, S as SNIPPET_LINE_KEY, U as UploadItem,
|
|
1
|
+
export { A as AutterSourceMapsOptions, B as BUNDLE_RE, a as BuildOutputResult, b as BundleWithMap, C as CLIENT_KEY_PREFIX, D as DEFAULT_ENDPOINT, F as FatalUploadError, I as InjectOptions, c as InjectResult, K as KEY_ADVICE, M as MAX_MAP_CHARS, d as MAX_UPLOAD_BYTES, S as SERVER_KEY_PREFIX, e as SNIPPET_LINE_KEY, U as UPLOAD_KEY_PREFIX, f as UploadItem, g as UploadOptions, h as UploadSummary, i as findBundles, j as formatUploadSummary, k as injectBundle, l as injectDir, m as mapPathFor, p as processBuildOutput, r as readSourceMappingUrl, n as resolveEndpoint, s as servedFilename, o as shiftMappings, q as snippetLine, t as storedMapJson, u as stripSourceMappingUrl, v as uploadDir } from './build-BqjqqeLg.js';
|
|
2
2
|
|
|
3
3
|
/** 8-4-4-4-12 hex: the debug id shape shared with Rollup, Turbopack, esbuild
|
|
4
4
|
* and Sentry tooling, and what the ingester accepts. */
|
|
@@ -28,6 +28,60 @@ declare function debugIdSnippet(id: string): string;
|
|
|
28
28
|
* contains it too.) */
|
|
29
29
|
declare function hasDebugIdSnippet(code: string): boolean;
|
|
30
30
|
|
|
31
|
+
interface VerifyOptions {
|
|
32
|
+
/** Ingester base URL (default as for upload). */
|
|
33
|
+
endpoint?: string;
|
|
34
|
+
/** Default: $AUTTER_RUNTIME_KEY. */
|
|
35
|
+
key?: string;
|
|
36
|
+
/** Sent with the check (a debug id check ignores it). */
|
|
37
|
+
release?: string;
|
|
38
|
+
urlPrefix?: string;
|
|
39
|
+
/** Globs (relative to the directory) of JS files that are not bundles. */
|
|
40
|
+
ignore?: string[];
|
|
41
|
+
/** Report leftover .map files without failing (a step that runs before they are removed). */
|
|
42
|
+
allowMaps?: boolean;
|
|
43
|
+
env?: NodeJS.ProcessEnv;
|
|
44
|
+
cwd?: string;
|
|
45
|
+
fetch?: typeof fetch;
|
|
46
|
+
}
|
|
47
|
+
interface VerifyBundle {
|
|
48
|
+
/** Relative to the directory. */
|
|
49
|
+
path: string;
|
|
50
|
+
status: "ok" | "failed" | "skipped";
|
|
51
|
+
debugId: string | null;
|
|
52
|
+
/** Why it failed, or why it was skipped. */
|
|
53
|
+
reasons: string[];
|
|
54
|
+
/** Whether the ingester has a map for its debug id (null: not checked). */
|
|
55
|
+
uploaded: boolean | null;
|
|
56
|
+
}
|
|
57
|
+
interface VerifyResult {
|
|
58
|
+
dir: string;
|
|
59
|
+
ok: boolean;
|
|
60
|
+
bundles: VerifyBundle[];
|
|
61
|
+
/** `.map` files in the directory (deploy risks unless allowMaps). */
|
|
62
|
+
maps: string[];
|
|
63
|
+
upload: {
|
|
64
|
+
/** verified: every checked bundle's map is on the ingester; missing: some are not;
|
|
65
|
+
* unverified: not checked (no key, or an ingester that can't answer); error: the check failed. */
|
|
66
|
+
status: "verified" | "missing" | "unverified" | "error";
|
|
67
|
+
endpoint: string | null;
|
|
68
|
+
reason: string | null;
|
|
69
|
+
checked: number;
|
|
70
|
+
missing: number;
|
|
71
|
+
};
|
|
72
|
+
/** Every failure, one per file and reason. */
|
|
73
|
+
failures: Array<{
|
|
74
|
+
path: string;
|
|
75
|
+
reason: string;
|
|
76
|
+
}>;
|
|
77
|
+
}
|
|
78
|
+
/** A tiny glob: `**` any path, `*` any name part, `?` one character. A
|
|
79
|
+
* pattern without "/" matches the file name anywhere. */
|
|
80
|
+
declare function globToRegExp(glob: string): RegExp;
|
|
81
|
+
declare function verifyDir(dir: string, options?: VerifyOptions): Promise<VerifyResult>;
|
|
82
|
+
/** Human-readable report. */
|
|
83
|
+
declare function formatVerify(result: VerifyResult): string[];
|
|
84
|
+
|
|
31
85
|
/**
|
|
32
86
|
* Function scopes for scope-based frame names (like Sentry's
|
|
33
87
|
* js-source-scopes and PostHog cymbal's `token.scope()`).
|
|
@@ -102,4 +156,4 @@ declare function gitHead(cwd?: string): string | null;
|
|
|
102
156
|
*/
|
|
103
157
|
declare function resolveRelease(explicit?: string | null, env?: NodeJS.ProcessEnv, cwd?: string): ResolvedRelease;
|
|
104
158
|
|
|
105
|
-
export { DEBUG_ID_RE, DEBUG_ID_REGISTRY, RELEASE_ENV_VARS, RELEASE_RE, type ResolvedRelease, SCOPES_KEY, SCOPES_VERSION, type ScopesResult, type SourceMapScopes, computeScopes, debugIdFor, debugIdSnippet, gitHead, hasDebugIdSnippet, normalizeDebugId, readDebugIdComment, resolveRelease };
|
|
159
|
+
export { DEBUG_ID_RE, DEBUG_ID_REGISTRY, RELEASE_ENV_VARS, RELEASE_RE, type ResolvedRelease, SCOPES_KEY, SCOPES_VERSION, type ScopesResult, type SourceMapScopes, type VerifyBundle, type VerifyOptions, type VerifyResult, computeScopes, debugIdFor, debugIdSnippet, formatVerify, gitHead, globToRegExp, hasDebugIdSnippet, normalizeDebugId, readDebugIdComment, resolveRelease, verifyDir };
|