@autter/runtime-cli 0.0.0-stage → 1.0.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 +91 -2
- package/dist/build-BXFh_jbP.d.cts +187 -0
- package/dist/build-BXFh_jbP.d.ts +187 -0
- package/dist/chunk-GGHHEUPQ.js +41 -0
- package/dist/chunk-SIRFO2QU.js +524 -0
- package/dist/cli.js +622 -0
- package/dist/index.cjs +581 -0
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +64 -0
- package/dist/next.cjs +628 -0
- package/dist/next.d.cts +23 -0
- package/dist/next.d.ts +23 -0
- package/dist/next.js +84 -0
- package/dist/vite.cjs +576 -0
- package/dist/vite.d.cts +54 -0
- package/dist/vite.d.ts +54 -0
- package/dist/vite.js +57 -0
- package/dist/webpack.cjs +559 -0
- package/dist/webpack.d.cts +46 -0
- package/dist/webpack.d.ts +46 -0
- package/dist/webpack.js +11 -0
- package/package.json +97 -5
package/dist/vite.cjs
ADDED
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/vite.ts
|
|
21
|
+
var vite_exports = {};
|
|
22
|
+
__export(vite_exports, {
|
|
23
|
+
autterSourceMaps: () => autterSourceMaps,
|
|
24
|
+
default: () => vite_default
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(vite_exports);
|
|
27
|
+
var import_node_path2 = require("path");
|
|
28
|
+
|
|
29
|
+
// src/inject.ts
|
|
30
|
+
var import_promises2 = require("fs/promises");
|
|
31
|
+
|
|
32
|
+
// src/debug-id.ts
|
|
33
|
+
var import_node_crypto = require("crypto");
|
|
34
|
+
var DEBUG_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
35
|
+
function normalizeDebugId(value) {
|
|
36
|
+
if (typeof value !== "string") return null;
|
|
37
|
+
const id = value.trim().toLowerCase();
|
|
38
|
+
return DEBUG_ID_RE.test(id) ? id : null;
|
|
39
|
+
}
|
|
40
|
+
function debugIdFor(bytes) {
|
|
41
|
+
const hash = (0, import_node_crypto.createHash)("sha256").update(bytes).digest();
|
|
42
|
+
hash[6] = hash[6] & 15 | 64;
|
|
43
|
+
hash[8] = hash[8] & 63 | 128;
|
|
44
|
+
const hex = hash.subarray(0, 16).toString("hex");
|
|
45
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
|
|
46
|
+
}
|
|
47
|
+
var DEBUG_ID_COMMENT_RE = /^\/\/# debugId=([0-9a-fA-F-]{36})[ \t]*\r?$/gm;
|
|
48
|
+
function readDebugIdComment(code) {
|
|
49
|
+
let found = null;
|
|
50
|
+
for (const match of code.matchAll(DEBUG_ID_COMMENT_RE)) found = normalizeDebugId(match[1]) ?? found;
|
|
51
|
+
return found;
|
|
52
|
+
}
|
|
53
|
+
var DEBUG_ID_REGISTRY = "_autterDebugIds";
|
|
54
|
+
function debugIdSnippet(id) {
|
|
55
|
+
return `;!function(){try{var g="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof self?self:{},s=(new g.Error).stack;s&&((g.${DEBUG_ID_REGISTRY}=g.${DEBUG_ID_REGISTRY}||{})[s]="${id}")}catch(e){}}();`;
|
|
56
|
+
}
|
|
57
|
+
var SNIPPET_RE = /\(g\._autterDebugIds=g\._autterDebugIds\|\|\{\}\)\[s\]="[0-9a-f]{8}-/;
|
|
58
|
+
function hasDebugIdSnippet(code) {
|
|
59
|
+
return SNIPPET_RE.test(code);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/files.ts
|
|
63
|
+
var import_node_fs = require("fs");
|
|
64
|
+
var import_promises = require("fs/promises");
|
|
65
|
+
var import_node_path = require("path");
|
|
66
|
+
var BUNDLE_RE = /\.[cm]?js$/;
|
|
67
|
+
var SOURCE_MAPPING_URL_RE = /^[ \t]*\/\/[#@] sourceMappingURL=([^\s'"]+)[ \t]*\r?$/gm;
|
|
68
|
+
function readSourceMappingUrl(code) {
|
|
69
|
+
let found = null;
|
|
70
|
+
for (const match of code.matchAll(SOURCE_MAPPING_URL_RE)) found = match[1];
|
|
71
|
+
return found;
|
|
72
|
+
}
|
|
73
|
+
function stripSourceMappingUrl(code) {
|
|
74
|
+
const lines = code.split("\n");
|
|
75
|
+
for (let i = lines.length - 1; i >= 0; i--) {
|
|
76
|
+
const line = lines[i].trim();
|
|
77
|
+
if (line === "") continue;
|
|
78
|
+
if (/^\/\/[#@] sourceMappingURL=/.test(line)) {
|
|
79
|
+
lines.splice(i, 1);
|
|
80
|
+
return lines.join("\n");
|
|
81
|
+
}
|
|
82
|
+
if (!line.startsWith("//#")) break;
|
|
83
|
+
}
|
|
84
|
+
return code;
|
|
85
|
+
}
|
|
86
|
+
function mapPathFor(js, code) {
|
|
87
|
+
const url = readSourceMappingUrl(code);
|
|
88
|
+
if (url && !/^[a-z][\w+.-]*:/i.test(url) && !url.startsWith("/")) {
|
|
89
|
+
let decoded = url.split(/[?#]/)[0];
|
|
90
|
+
try {
|
|
91
|
+
decoded = decodeURIComponent(decoded);
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
const candidate = (0, import_node_path.resolve)((0, import_node_path.dirname)(js), decoded);
|
|
95
|
+
if ((0, import_node_fs.existsSync)(candidate)) return candidate;
|
|
96
|
+
}
|
|
97
|
+
const sibling = `${js}.map`;
|
|
98
|
+
return (0, import_node_fs.existsSync)(sibling) ? sibling : null;
|
|
99
|
+
}
|
|
100
|
+
async function walk(dir, out) {
|
|
101
|
+
let entries;
|
|
102
|
+
try {
|
|
103
|
+
entries = await (0, import_promises.readdir)(dir, { withFileTypes: true });
|
|
104
|
+
} catch {
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
for (const entry of entries) {
|
|
108
|
+
if (entry.name === "node_modules") continue;
|
|
109
|
+
const full = (0, import_node_path.join)(dir, entry.name);
|
|
110
|
+
if (entry.isDirectory()) await walk(full, out);
|
|
111
|
+
else if (entry.isFile() && BUNDLE_RE.test(entry.name)) out.push(full);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function findBundles(dir, files) {
|
|
115
|
+
const root = (0, import_node_path.resolve)(dir);
|
|
116
|
+
const candidates = [];
|
|
117
|
+
if (files) {
|
|
118
|
+
for (const file of files) if (BUNDLE_RE.test(file)) candidates.push((0, import_node_path.resolve)(root, file));
|
|
119
|
+
} else {
|
|
120
|
+
await walk(root, candidates);
|
|
121
|
+
}
|
|
122
|
+
const bundles = [];
|
|
123
|
+
for (const js of [...new Set(candidates)].sort()) {
|
|
124
|
+
let code;
|
|
125
|
+
try {
|
|
126
|
+
code = await (0, import_promises.readFile)(js, "utf8");
|
|
127
|
+
} catch {
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const map = mapPathFor(js, code);
|
|
131
|
+
if (map) bundles.push({ js, map, path: (0, import_node_path.relative)(root, js).split(import_node_path.sep).join("/") });
|
|
132
|
+
}
|
|
133
|
+
return bundles;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// src/inject.ts
|
|
137
|
+
var SNIPPET_LINE_KEY = "x_autter_snippet_line";
|
|
138
|
+
function snippetLine(code) {
|
|
139
|
+
let line = 0;
|
|
140
|
+
let i = 0;
|
|
141
|
+
if (code.startsWith("#!")) {
|
|
142
|
+
const nl = code.indexOf("\n");
|
|
143
|
+
if (nl < 0) return -1;
|
|
144
|
+
line = 1;
|
|
145
|
+
i = nl + 1;
|
|
146
|
+
}
|
|
147
|
+
for (; ; ) {
|
|
148
|
+
while (i < code.length && /\s/.test(code[i])) i++;
|
|
149
|
+
if (code.startsWith("//", i)) {
|
|
150
|
+
const nl = code.indexOf("\n", i);
|
|
151
|
+
if (nl < 0) return -1;
|
|
152
|
+
i = nl + 1;
|
|
153
|
+
} else if (code.startsWith("/*", i)) {
|
|
154
|
+
const end = code.indexOf("*/", i + 2);
|
|
155
|
+
if (end < 0) return -1;
|
|
156
|
+
i = end + 2;
|
|
157
|
+
} else {
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return code[i] === '"' || code[i] === "'" ? -1 : line;
|
|
162
|
+
}
|
|
163
|
+
function shiftMappings(mappings, at, count = 1) {
|
|
164
|
+
const lines = mappings.split(";");
|
|
165
|
+
while (lines.length < at) lines.push("");
|
|
166
|
+
lines.splice(at, 0, ...Array(count).fill(""));
|
|
167
|
+
return lines.join(";");
|
|
168
|
+
}
|
|
169
|
+
function insertBeforeTrailingComments(code, text) {
|
|
170
|
+
const lines = code.split("\n");
|
|
171
|
+
let at = lines.length;
|
|
172
|
+
while (at > 0) {
|
|
173
|
+
const line = lines[at - 1].trim();
|
|
174
|
+
if (line === "" || line.startsWith("//#") || line.startsWith("//@")) at--;
|
|
175
|
+
else break;
|
|
176
|
+
}
|
|
177
|
+
const head = lines.slice(0, at).join("\n");
|
|
178
|
+
const tail = lines.slice(at).join("\n");
|
|
179
|
+
return `${head}${head && !head.endsWith("\n") ? "\n" : ""}${text}${tail ? `
|
|
180
|
+
${tail.replace(/^\n+/, "")}` : "\n"}`;
|
|
181
|
+
}
|
|
182
|
+
async function injectBundle(bundle, options = {}) {
|
|
183
|
+
const bytes = await (0, import_promises2.readFile)(bundle.js);
|
|
184
|
+
const code = bytes.toString("utf8");
|
|
185
|
+
const base = { path: bundle.path, js: bundle.js, map: bundle.map };
|
|
186
|
+
let map;
|
|
187
|
+
try {
|
|
188
|
+
map = JSON.parse(await (0, import_promises2.readFile)(bundle.map, "utf8"));
|
|
189
|
+
if (!map || typeof map !== "object") throw new Error("not an object");
|
|
190
|
+
} catch {
|
|
191
|
+
return { ...base, debugId: "", status: "invalid-map" };
|
|
192
|
+
}
|
|
193
|
+
const existing = readDebugIdComment(code);
|
|
194
|
+
const hasSnippet = hasDebugIdSnippet(code);
|
|
195
|
+
const debugId = existing ?? debugIdFor(bytes);
|
|
196
|
+
let out = code;
|
|
197
|
+
let mapDirty = false;
|
|
198
|
+
if (!hasSnippet) {
|
|
199
|
+
const shifted = typeof map[SNIPPET_LINE_KEY] === "number" ? map[SNIPPET_LINE_KEY] : null;
|
|
200
|
+
const line = shifted ?? snippetLine(code);
|
|
201
|
+
if (line >= 0 && (shifted !== null || typeof map.mappings === "string" && !("sections" in map))) {
|
|
202
|
+
let offset = 0;
|
|
203
|
+
for (let n = 0; n < line; n++) offset = out.indexOf("\n", offset) + 1;
|
|
204
|
+
out = `${out.slice(0, offset)}${debugIdSnippet(debugId)}
|
|
205
|
+
${out.slice(offset)}`;
|
|
206
|
+
if (shifted === null) {
|
|
207
|
+
map.mappings = shiftMappings(map.mappings, line);
|
|
208
|
+
map[SNIPPET_LINE_KEY] = line;
|
|
209
|
+
mapDirty = true;
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
out = insertBeforeTrailingComments(out, debugIdSnippet(debugId));
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
if (!existing) out = `${out}${out.endsWith("\n") ? "" : "\n"}//# debugId=${debugId}
|
|
216
|
+
`;
|
|
217
|
+
if (options.stripSourceMappingUrl) out = stripSourceMappingUrl(out);
|
|
218
|
+
if (map.debugId !== debugId) {
|
|
219
|
+
map.debugId = debugId;
|
|
220
|
+
mapDirty = true;
|
|
221
|
+
}
|
|
222
|
+
const changed = mapDirty || out !== code;
|
|
223
|
+
if (changed && !options.dryRun) {
|
|
224
|
+
if (mapDirty) await (0, import_promises2.writeFile)(bundle.map, JSON.stringify(map));
|
|
225
|
+
if (out !== code) await (0, import_promises2.writeFile)(bundle.js, out);
|
|
226
|
+
}
|
|
227
|
+
return { ...base, debugId, status: changed ? "injected" : "unchanged" };
|
|
228
|
+
}
|
|
229
|
+
async function injectDir(dir, options = {}) {
|
|
230
|
+
const results = [];
|
|
231
|
+
for (const bundle of await findBundles(dir, options.files)) results.push(await injectBundle(bundle, options));
|
|
232
|
+
return results;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// src/upload.ts
|
|
236
|
+
var import_node_crypto2 = require("crypto");
|
|
237
|
+
var import_promises3 = require("fs/promises");
|
|
238
|
+
|
|
239
|
+
// src/release.ts
|
|
240
|
+
var import_node_child_process = require("child_process");
|
|
241
|
+
var RELEASE_RE = /^[a-zA-Z0-9._-]{1,200}$/;
|
|
242
|
+
var RELEASE_ENV_VARS = [
|
|
243
|
+
"GITHUB_SHA",
|
|
244
|
+
"VERCEL_GIT_COMMIT_SHA",
|
|
245
|
+
"CF_PAGES_COMMIT_SHA",
|
|
246
|
+
"GIT_SHA"
|
|
247
|
+
];
|
|
248
|
+
function gitHead(cwd = process.cwd()) {
|
|
249
|
+
try {
|
|
250
|
+
const sha = (0, import_node_child_process.execFileSync)("git", ["rev-parse", "HEAD"], {
|
|
251
|
+
cwd,
|
|
252
|
+
encoding: "utf8",
|
|
253
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
254
|
+
timeout: 1e4
|
|
255
|
+
}).trim();
|
|
256
|
+
return /^[0-9a-f]{7,64}$/.test(sha) ? sha : null;
|
|
257
|
+
} catch {
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
function resolveRelease(explicit, env = process.env, cwd = process.cwd()) {
|
|
262
|
+
const candidates = [
|
|
263
|
+
["--release", explicit],
|
|
264
|
+
...RELEASE_ENV_VARS.map((name) => [name, env[name]])
|
|
265
|
+
];
|
|
266
|
+
for (const [source, value] of candidates) {
|
|
267
|
+
const release = value?.trim();
|
|
268
|
+
if (!release) continue;
|
|
269
|
+
if (!RELEASE_RE.test(release)) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
`release "${release}" (from ${source}) is not valid: use 1-200 letters, digits, ".", "_" or "-" (a commit SHA works)`
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
return { release, source };
|
|
275
|
+
}
|
|
276
|
+
const head = gitHead(cwd);
|
|
277
|
+
if (head) return { release: head, source: "git" };
|
|
278
|
+
throw new Error(
|
|
279
|
+
`no release: pass --release <release>, or set one of ${RELEASE_ENV_VARS.join(", ")}, or run inside a git checkout`
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/upload.ts
|
|
284
|
+
var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
|
|
285
|
+
var MAX_UPLOAD_BYTES = 5 * 1024 * 1024;
|
|
286
|
+
var CHECK_BATCH = 500;
|
|
287
|
+
var MAX_ATTEMPTS = 3;
|
|
288
|
+
function resolveEndpoint(flag, env = process.env) {
|
|
289
|
+
const raw = flag || env.AUTTER_ENDPOINT || env.AUTTER_RUNTIME_ENDPOINT || env.OTEL_EXPORTER_OTLP_ENDPOINT || DEFAULT_ENDPOINT;
|
|
290
|
+
return raw.trim().replace(/\/+$/, "").replace(/\/v1\/[a-z-]+$/, "");
|
|
291
|
+
}
|
|
292
|
+
function servedFilename(urlPrefix, path) {
|
|
293
|
+
let prefix = (urlPrefix ?? "/").trim() || "/";
|
|
294
|
+
if (prefix.startsWith("~/")) prefix = prefix.slice(1);
|
|
295
|
+
if (!/^[a-z][\w+.-]*:\/\//i.test(prefix) && !prefix.startsWith("/")) prefix = `/${prefix}`;
|
|
296
|
+
return `${prefix.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
|
|
297
|
+
}
|
|
298
|
+
function storedMapJson(map) {
|
|
299
|
+
const { sourcesContent: _omitted, ...safe } = map;
|
|
300
|
+
return JSON.stringify(safe);
|
|
301
|
+
}
|
|
302
|
+
async function prepare(bundle, urlPrefix, release) {
|
|
303
|
+
let map;
|
|
304
|
+
try {
|
|
305
|
+
map = JSON.parse(await (0, import_promises3.readFile)(bundle.map, "utf8"));
|
|
306
|
+
} catch {
|
|
307
|
+
return { error: "map is not valid JSON" };
|
|
308
|
+
}
|
|
309
|
+
if (!map || map.version !== 3 || typeof map.mappings !== "string" || !Array.isArray(map.sources)) {
|
|
310
|
+
return { error: "not a version 3 source map with mappings and sources" };
|
|
311
|
+
}
|
|
312
|
+
const code = await (0, import_promises3.readFile)(bundle.js, "utf8");
|
|
313
|
+
const debugId = readDebugIdComment(code) ?? normalizeDebugId(map.debugId);
|
|
314
|
+
const json = storedMapJson(map);
|
|
315
|
+
const filename = servedFilename(urlPrefix, bundle.path);
|
|
316
|
+
const body = `{"release":${JSON.stringify(release)},"filename":${JSON.stringify(filename)},${debugId ? `"debugId":${JSON.stringify(debugId)},` : ""}"map":${json}}`;
|
|
317
|
+
return {
|
|
318
|
+
bundle,
|
|
319
|
+
body,
|
|
320
|
+
path: bundle.path,
|
|
321
|
+
filename,
|
|
322
|
+
debugId,
|
|
323
|
+
hash: (0, import_node_crypto2.createHash)("sha256").update(json).digest("hex"),
|
|
324
|
+
bytes: Buffer.byteLength(body)
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
var FatalUploadError = class extends Error {
|
|
328
|
+
};
|
|
329
|
+
function sleep(ms) {
|
|
330
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
331
|
+
}
|
|
332
|
+
async function uploadDir(dir, options = {}) {
|
|
333
|
+
const env = options.env ?? process.env;
|
|
334
|
+
const log = options.log ?? (() => {
|
|
335
|
+
});
|
|
336
|
+
const doFetch = options.fetch ?? fetch;
|
|
337
|
+
const { release, source: releaseSource } = resolveRelease(options.release, env, options.cwd);
|
|
338
|
+
const endpoint = resolveEndpoint(options.endpoint, env);
|
|
339
|
+
const summary = {
|
|
340
|
+
release,
|
|
341
|
+
releaseSource,
|
|
342
|
+
endpoint,
|
|
343
|
+
dryRun: Boolean(options.dryRun),
|
|
344
|
+
uploaded: [],
|
|
345
|
+
skipped: [],
|
|
346
|
+
failed: [],
|
|
347
|
+
legacyIngester: false,
|
|
348
|
+
deletedMaps: []
|
|
349
|
+
};
|
|
350
|
+
const items = [];
|
|
351
|
+
for (const bundle of await findBundles(dir, options.files)) {
|
|
352
|
+
const prepared = await prepare(bundle, options.urlPrefix, release);
|
|
353
|
+
if ("error" in prepared) {
|
|
354
|
+
summary.failed.push({ path: bundle.path, filename: servedFilename(options.urlPrefix, bundle.path), error: prepared.error });
|
|
355
|
+
} else if (prepared.bytes > MAX_UPLOAD_BYTES) {
|
|
356
|
+
summary.failed.push({
|
|
357
|
+
path: prepared.path,
|
|
358
|
+
filename: prepared.filename,
|
|
359
|
+
error: `map is ${(prepared.bytes / 1048576).toFixed(1)} MB without sourcesContent; the ingester accepts up to 5 MB`
|
|
360
|
+
});
|
|
361
|
+
} else {
|
|
362
|
+
items.push(prepared);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
if (options.dryRun) {
|
|
366
|
+
summary.uploaded = items.map(strip);
|
|
367
|
+
return summary;
|
|
368
|
+
}
|
|
369
|
+
const key = (options.key ?? env.AUTTER_RUNTIME_KEY ?? "").trim();
|
|
370
|
+
if (!key) throw new FatalUploadError("no ingest key: set AUTTER_RUNTIME_KEY to a server key (autter_rt_\u2026)");
|
|
371
|
+
if (key.startsWith("autter_rtc_")) {
|
|
372
|
+
throw new FatalUploadError("AUTTER_RUNTIME_KEY is a publishable client key (autter_rtc_\u2026); uploads need a server key (autter_rt_\u2026)");
|
|
373
|
+
}
|
|
374
|
+
const headers = { "content-type": "application/json", authorization: `Bearer ${key}` };
|
|
375
|
+
const skipped = /* @__PURE__ */ new Set();
|
|
376
|
+
for (let start = 0; start < items.length && !summary.legacyIngester; start += CHECK_BATCH) {
|
|
377
|
+
const batch = items.slice(start, start + CHECK_BATCH);
|
|
378
|
+
try {
|
|
379
|
+
const res = await doFetch(`${endpoint}/v1/sourcemaps/check`, {
|
|
380
|
+
method: "POST",
|
|
381
|
+
headers,
|
|
382
|
+
body: JSON.stringify({
|
|
383
|
+
release,
|
|
384
|
+
files: batch.map((item) => ({ filename: item.filename, ...item.debugId ? { debugId: item.debugId } : {}, hash: item.hash }))
|
|
385
|
+
})
|
|
386
|
+
});
|
|
387
|
+
if (res.status === 404) {
|
|
388
|
+
summary.legacyIngester = true;
|
|
389
|
+
log(
|
|
390
|
+
"warning: this ingester predates 1.6.0, so it stores no debug ids and rejects .mjs/.cjs maps. Upgrade it: docker pull ghcr.io/autter-dev/otlp-ingester:latest"
|
|
391
|
+
);
|
|
392
|
+
break;
|
|
393
|
+
}
|
|
394
|
+
if (res.status === 401 || res.status === 403) {
|
|
395
|
+
throw new FatalUploadError(`the ingester rejected the key (${res.status}): ${(await res.text()).slice(0, 300)}`);
|
|
396
|
+
}
|
|
397
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
398
|
+
const body = await res.json();
|
|
399
|
+
const present = new Set(Array.isArray(body.present) ? body.present : []);
|
|
400
|
+
batch.forEach((item, index) => {
|
|
401
|
+
if (present.has(index)) skipped.add(item);
|
|
402
|
+
});
|
|
403
|
+
} catch (err) {
|
|
404
|
+
if (err instanceof FatalUploadError) throw err;
|
|
405
|
+
log(`warning: could not check which maps the ingester already has (${err.message}); uploading all`);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
const uploaded = [];
|
|
409
|
+
let fatal = null;
|
|
410
|
+
const uploadOne = async (item) => {
|
|
411
|
+
for (let attempt = 1; ; attempt++) {
|
|
412
|
+
if (fatal) return;
|
|
413
|
+
let status = 0;
|
|
414
|
+
let detail = "";
|
|
415
|
+
try {
|
|
416
|
+
const res = await doFetch(`${endpoint}/v1/sourcemaps`, { method: "POST", headers, body: item.body });
|
|
417
|
+
status = res.status;
|
|
418
|
+
if (res.ok) {
|
|
419
|
+
uploaded.push(item);
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
detail = (await res.text()).slice(0, 300);
|
|
423
|
+
} catch (err) {
|
|
424
|
+
detail = err.message;
|
|
425
|
+
}
|
|
426
|
+
if (status === 401 || status === 403) {
|
|
427
|
+
fatal = new FatalUploadError(`the ingester rejected the key (${status}): ${detail}`);
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const retryable = status === 0 || status === 429 || status >= 500;
|
|
431
|
+
if (!retryable || attempt >= MAX_ATTEMPTS) {
|
|
432
|
+
summary.failed.push({ path: item.path, filename: item.filename, error: status ? `HTTP ${status}: ${detail}` : detail });
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
await sleep(500 * 2 ** (attempt - 1));
|
|
436
|
+
}
|
|
437
|
+
};
|
|
438
|
+
const queue = items.filter((item) => !skipped.has(item));
|
|
439
|
+
const workers = Array.from({ length: Math.max(1, Math.min(options.concurrency ?? 8, queue.length)) }, async () => {
|
|
440
|
+
for (let item = queue.shift(); item; item = queue.shift()) await uploadOne(item);
|
|
441
|
+
});
|
|
442
|
+
await Promise.all(workers);
|
|
443
|
+
if (fatal) throw fatal;
|
|
444
|
+
const order = (a, b) => items.indexOf(a) - items.indexOf(b);
|
|
445
|
+
uploaded.sort(order);
|
|
446
|
+
if (options.deleteAfterUpload) {
|
|
447
|
+
for (const item of [...uploaded, ...skipped]) {
|
|
448
|
+
await (0, import_promises3.rm)(item.bundle.map, { force: true });
|
|
449
|
+
const code = await (0, import_promises3.readFile)(item.bundle.js, "utf8");
|
|
450
|
+
const stripped = stripSourceMappingUrl(code);
|
|
451
|
+
if (stripped !== code) await (0, import_promises3.writeFile)(item.bundle.js, stripped);
|
|
452
|
+
summary.deletedMaps.push(item.bundle.map);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
summary.uploaded = uploaded.map(strip);
|
|
456
|
+
summary.skipped = [...skipped].sort(order).map(strip);
|
|
457
|
+
return summary;
|
|
458
|
+
}
|
|
459
|
+
function strip(item) {
|
|
460
|
+
const { path, filename, debugId, hash, bytes } = item;
|
|
461
|
+
return { path, filename, debugId, hash, bytes };
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/build.ts
|
|
465
|
+
function formatUploadSummary(summary) {
|
|
466
|
+
const lines = [];
|
|
467
|
+
const verb = summary.dryRun ? "would upload" : "uploaded";
|
|
468
|
+
for (const item of summary.uploaded) {
|
|
469
|
+
lines.push(`${verb} ${item.filename}${item.debugId ? ` (debug id ${item.debugId})` : ""}`);
|
|
470
|
+
}
|
|
471
|
+
for (const item of summary.skipped) lines.push(`skipped ${item.filename} (already uploaded)`);
|
|
472
|
+
for (const item of summary.failed) lines.push(`failed ${item.filename}: ${item.error}`);
|
|
473
|
+
lines.push(
|
|
474
|
+
`${summary.uploaded.length} ${verb}, ${summary.skipped.length} already uploaded, ${summary.failed.length} failed (release ${summary.release} from ${summary.releaseSource}, ${summary.endpoint})`
|
|
475
|
+
);
|
|
476
|
+
return lines;
|
|
477
|
+
}
|
|
478
|
+
async function processBuildOutput(input) {
|
|
479
|
+
const { options } = input;
|
|
480
|
+
const log = (line) => {
|
|
481
|
+
if (!options.silent) console.log(`[autter-runtime] ${line}`);
|
|
482
|
+
};
|
|
483
|
+
const result = { injected: [], upload: null };
|
|
484
|
+
try {
|
|
485
|
+
result.injected = await injectDir(input.dir, {
|
|
486
|
+
files: input.files,
|
|
487
|
+
dryRun: options.dryRun,
|
|
488
|
+
stripSourceMappingUrl: input.stripSourceMappingUrl
|
|
489
|
+
});
|
|
490
|
+
const changed = result.injected.filter((r) => r.status === "injected").length;
|
|
491
|
+
if (result.injected.length) {
|
|
492
|
+
log(`debug ids: ${changed} bundle(s) injected, ${result.injected.length - changed} already had one`);
|
|
493
|
+
}
|
|
494
|
+
for (const bad of result.injected.filter((r) => r.status === "invalid-map")) log(`skipped ${bad.path}: its map is not valid JSON`);
|
|
495
|
+
if (options.upload === false) return result;
|
|
496
|
+
const key = options.key ?? process.env.AUTTER_RUNTIME_KEY;
|
|
497
|
+
if (!key && !options.dryRun) {
|
|
498
|
+
if (result.injected.length) log("AUTTER_RUNTIME_KEY is not set: source maps were not uploaded");
|
|
499
|
+
return result;
|
|
500
|
+
}
|
|
501
|
+
if (!result.injected.some((r) => r.status !== "invalid-map")) return result;
|
|
502
|
+
result.upload = await uploadDir(input.dir, {
|
|
503
|
+
files: input.files,
|
|
504
|
+
release: options.release,
|
|
505
|
+
urlPrefix: options.urlPrefix ?? input.urlPrefix,
|
|
506
|
+
endpoint: options.endpoint,
|
|
507
|
+
key,
|
|
508
|
+
dryRun: options.dryRun,
|
|
509
|
+
concurrency: options.concurrency,
|
|
510
|
+
deleteAfterUpload: options.deleteAfterUpload ?? input.deleteAfterUpload,
|
|
511
|
+
log
|
|
512
|
+
});
|
|
513
|
+
for (const line of formatUploadSummary(result.upload)) log(line);
|
|
514
|
+
if (result.upload.failed.length && options.failOnError) {
|
|
515
|
+
throw new Error(`${result.upload.failed.length} source map upload(s) failed`);
|
|
516
|
+
}
|
|
517
|
+
} catch (err) {
|
|
518
|
+
const message = `source maps: ${err instanceof Error ? err.message : String(err)}`;
|
|
519
|
+
if (options.failOnError) throw new Error(`[autter-runtime] ${message}`);
|
|
520
|
+
if (!options.silent) console.warn(`[autter-runtime] ${message}`);
|
|
521
|
+
}
|
|
522
|
+
return result;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
// src/vite.ts
|
|
526
|
+
function autterSourceMaps(options = {}) {
|
|
527
|
+
let isVite = false;
|
|
528
|
+
let enabledMaps = false;
|
|
529
|
+
let ssr = false;
|
|
530
|
+
let base = "/";
|
|
531
|
+
return {
|
|
532
|
+
name: "autter-runtime-sourcemaps",
|
|
533
|
+
apply: "build",
|
|
534
|
+
enforce: "post",
|
|
535
|
+
config(config) {
|
|
536
|
+
isVite = true;
|
|
537
|
+
const current = config.build?.sourcemap;
|
|
538
|
+
if (current === void 0 || current === false) {
|
|
539
|
+
enabledMaps = true;
|
|
540
|
+
return { build: { sourcemap: "hidden" } };
|
|
541
|
+
}
|
|
542
|
+
return void 0;
|
|
543
|
+
},
|
|
544
|
+
configResolved(config) {
|
|
545
|
+
ssr = Boolean(config.build?.ssr);
|
|
546
|
+
if (config.base && /^(\/|[a-z][\w+.-]*:\/\/)/i.test(config.base)) base = config.base;
|
|
547
|
+
if (config.build?.sourcemap === "inline" && !options.silent) {
|
|
548
|
+
console.warn('[autter-runtime] build.sourcemap is "inline": there are no map files to upload; use "hidden"');
|
|
549
|
+
}
|
|
550
|
+
},
|
|
551
|
+
outputOptions(output) {
|
|
552
|
+
if (isVite || output.sourcemap !== void 0 && output.sourcemap !== false) return null;
|
|
553
|
+
enabledMaps = true;
|
|
554
|
+
return { ...output, sourcemap: "hidden" };
|
|
555
|
+
},
|
|
556
|
+
async writeBundle(output, bundle) {
|
|
557
|
+
const environment = this?.environment;
|
|
558
|
+
if (ssr || environment?.config?.consumer === "server") return;
|
|
559
|
+
const dir = output.dir ?? (output.file ? (0, import_node_path2.dirname)(output.file) : void 0);
|
|
560
|
+
if (!dir) return;
|
|
561
|
+
const files = Object.values(bundle).filter((file) => file.type === "chunk").map((file) => (0, import_node_path2.resolve)(dir, file.fileName));
|
|
562
|
+
await processBuildOutput({
|
|
563
|
+
dir,
|
|
564
|
+
files,
|
|
565
|
+
urlPrefix: base,
|
|
566
|
+
options,
|
|
567
|
+
deleteAfterUpload: enabledMaps
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
var vite_default = autterSourceMaps;
|
|
573
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
574
|
+
0 && (module.exports = {
|
|
575
|
+
autterSourceMaps
|
|
576
|
+
});
|
package/dist/vite.d.cts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { A as AutterSourceMapsOptions } from './build-BXFh_jbP.cjs';
|
|
2
|
+
|
|
3
|
+
type SourcemapSetting = boolean | "inline" | "hidden";
|
|
4
|
+
/** The parts of Vite's / Rollup's types this plugin touches (structural, so
|
|
5
|
+
* neither bundler is a dependency). */
|
|
6
|
+
interface UserConfigLike {
|
|
7
|
+
build?: {
|
|
8
|
+
sourcemap?: SourcemapSetting;
|
|
9
|
+
ssr?: boolean | string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
interface ResolvedConfigLike {
|
|
13
|
+
base?: string;
|
|
14
|
+
build?: {
|
|
15
|
+
sourcemap?: SourcemapSetting;
|
|
16
|
+
ssr?: boolean | string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface OutputOptionsLike {
|
|
20
|
+
dir?: string;
|
|
21
|
+
file?: string;
|
|
22
|
+
sourcemap?: SourcemapSetting;
|
|
23
|
+
}
|
|
24
|
+
interface OutputFileLike {
|
|
25
|
+
type: "chunk" | "asset";
|
|
26
|
+
fileName: string;
|
|
27
|
+
}
|
|
28
|
+
interface AutterSourceMapsPlugin {
|
|
29
|
+
name: string;
|
|
30
|
+
apply: "build";
|
|
31
|
+
enforce: "post";
|
|
32
|
+
config(config: UserConfigLike): {
|
|
33
|
+
build: {
|
|
34
|
+
sourcemap: "hidden";
|
|
35
|
+
};
|
|
36
|
+
} | undefined;
|
|
37
|
+
configResolved(config: ResolvedConfigLike): void;
|
|
38
|
+
outputOptions(options: OutputOptionsLike): OutputOptionsLike | null;
|
|
39
|
+
writeBundle(this: unknown, options: OutputOptionsLike, bundle: Record<string, OutputFileLike>): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Vite and Rollup plugin: turns on hidden source maps, gives every emitted
|
|
43
|
+
* chunk a debug id after the bundle is written, and uploads the maps when
|
|
44
|
+
* AUTTER_RUNTIME_KEY (or `key`) is set.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* // vite.config.ts
|
|
48
|
+
* import { autterSourceMaps } from "@autter/runtime-cli/vite";
|
|
49
|
+
* export default defineConfig({ plugins: [autterSourceMaps()] });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function autterSourceMaps(options?: AutterSourceMapsOptions): AutterSourceMapsPlugin;
|
|
53
|
+
|
|
54
|
+
export { AutterSourceMapsOptions, type AutterSourceMapsPlugin, autterSourceMaps, autterSourceMaps as default };
|
package/dist/vite.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { A as AutterSourceMapsOptions } from './build-BXFh_jbP.js';
|
|
2
|
+
|
|
3
|
+
type SourcemapSetting = boolean | "inline" | "hidden";
|
|
4
|
+
/** The parts of Vite's / Rollup's types this plugin touches (structural, so
|
|
5
|
+
* neither bundler is a dependency). */
|
|
6
|
+
interface UserConfigLike {
|
|
7
|
+
build?: {
|
|
8
|
+
sourcemap?: SourcemapSetting;
|
|
9
|
+
ssr?: boolean | string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
interface ResolvedConfigLike {
|
|
13
|
+
base?: string;
|
|
14
|
+
build?: {
|
|
15
|
+
sourcemap?: SourcemapSetting;
|
|
16
|
+
ssr?: boolean | string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
interface OutputOptionsLike {
|
|
20
|
+
dir?: string;
|
|
21
|
+
file?: string;
|
|
22
|
+
sourcemap?: SourcemapSetting;
|
|
23
|
+
}
|
|
24
|
+
interface OutputFileLike {
|
|
25
|
+
type: "chunk" | "asset";
|
|
26
|
+
fileName: string;
|
|
27
|
+
}
|
|
28
|
+
interface AutterSourceMapsPlugin {
|
|
29
|
+
name: string;
|
|
30
|
+
apply: "build";
|
|
31
|
+
enforce: "post";
|
|
32
|
+
config(config: UserConfigLike): {
|
|
33
|
+
build: {
|
|
34
|
+
sourcemap: "hidden";
|
|
35
|
+
};
|
|
36
|
+
} | undefined;
|
|
37
|
+
configResolved(config: ResolvedConfigLike): void;
|
|
38
|
+
outputOptions(options: OutputOptionsLike): OutputOptionsLike | null;
|
|
39
|
+
writeBundle(this: unknown, options: OutputOptionsLike, bundle: Record<string, OutputFileLike>): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Vite and Rollup plugin: turns on hidden source maps, gives every emitted
|
|
43
|
+
* chunk a debug id after the bundle is written, and uploads the maps when
|
|
44
|
+
* AUTTER_RUNTIME_KEY (or `key`) is set.
|
|
45
|
+
*
|
|
46
|
+
* ```ts
|
|
47
|
+
* // vite.config.ts
|
|
48
|
+
* import { autterSourceMaps } from "@autter/runtime-cli/vite";
|
|
49
|
+
* export default defineConfig({ plugins: [autterSourceMaps()] });
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
declare function autterSourceMaps(options?: AutterSourceMapsOptions): AutterSourceMapsPlugin;
|
|
53
|
+
|
|
54
|
+
export { AutterSourceMapsOptions, type AutterSourceMapsPlugin, autterSourceMaps, autterSourceMaps as default };
|