@autter/runtime-cli 1.2.0 → 1.3.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/dist/index.js CHANGED
@@ -24,6 +24,7 @@ import {
24
24
  hasDebugIdSnippet,
25
25
  injectBundle,
26
26
  injectDir,
27
+ isInAppSource,
27
28
  mapPathFor,
28
29
  normalizeDebugId,
29
30
  processBuildOutput,
@@ -32,12 +33,14 @@ import {
32
33
  resolveEndpoint,
33
34
  resolveRelease,
34
35
  servedFilename,
36
+ serverUrlPrefix,
35
37
  shiftMappings,
36
38
  snippetLine,
37
39
  storedMapJson,
40
+ storedSourcesContent,
38
41
  stripSourceMappingUrl,
39
42
  uploadDir
40
- } from "./chunk-KIQRQY3X.js";
43
+ } from "./chunk-Q23FB5X3.js";
41
44
 
42
45
  // src/verify.ts
43
46
  import { existsSync } from "fs";
@@ -47,6 +50,9 @@ var CHECK_BATCH = 500;
47
50
  var SNIPPET_ID_RE = /\(g\._autterDebugIds=g\._autterDebugIds\|\|\{\}\)\[s\]="([0-9a-f-]{36})"/;
48
51
  var NOT_BUNDLES = [
49
52
  [/(^|\/)_(build|ssg|middleware|clientMiddleware)Manifest\.js$/, "Next.js build manifest"],
53
+ // .next/server: middleware-build-manifest.js, next-font-manifest.js,
54
+ // server-reference-manifest.js, page_client-reference-manifest.js, …
55
+ [/(^|\/)[\w.-]*[-_]manifest\.js$/, "Next.js server manifest"],
50
56
  [/(^|\/)chunks\/polyfills-[\w-]+\.js$/, "Next.js polyfills, copied prebuilt without a source map"],
51
57
  [/(^|\/)(sw|service-worker|serviceWorker|firebase-messaging-sw|mockServiceWorker)\.js$/, "service worker (the browser SDK doesn't run there)"],
52
58
  [/(^|\/)workbox-[\w-]+\.js$/, "service worker runtime (the browser SDK doesn't run there)"]
@@ -98,6 +104,7 @@ async function verifyDir(dir, options = {}) {
98
104
  ok: true,
99
105
  bundles: [],
100
106
  maps: [],
107
+ ...options.server ? { server: true } : {},
101
108
  upload: { status: "unverified", endpoint: null, reason: null, checked: 0, missing: 0 },
102
109
  failures: []
103
110
  };
@@ -106,7 +113,7 @@ async function verifyDir(dir, options = {}) {
106
113
  const path = relPath(file);
107
114
  if (file.endsWith(".map")) {
108
115
  result.maps.push(path);
109
- if (!options.allowMaps) {
116
+ if (!options.allowMaps && !options.server) {
110
117
  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");
111
118
  }
112
119
  continue;
@@ -149,14 +156,16 @@ async function verifyDir(dir, options = {}) {
149
156
  bundle.reasons.push("has the debug id snippet but no //# debugId= comment: run `autter-runtime sourcemaps inject` on it again");
150
157
  } else if (!hasDebugIdSnippet(code)) {
151
158
  bundle.reasons.push(
152
- "has a //# debugId= comment but no registration snippet, so the browser SDK can't report its id: run `autter-runtime sourcemaps inject` on it"
159
+ "has a //# debugId= comment but no registration snippet, so the SDK can't report its id: run `autter-runtime sourcemaps inject` on it"
153
160
  );
154
161
  } else if (snippetId && snippetId !== commentId) {
155
162
  bundle.reasons.push(`its snippet registers debug id ${snippetId} but its comment says ${commentId}: run inject on the original build output`);
156
163
  }
157
164
  const url = readSourceMappingUrl(code);
158
165
  if (url?.startsWith("data:")) {
159
- bundle.reasons.push("carries an inline source map (data: URL): your original source ships with the bundle. Use hidden or external maps");
166
+ if (!options.server) {
167
+ bundle.reasons.push("carries an inline source map (data: URL): your original source ships with the bundle. Use hidden or external maps");
168
+ }
160
169
  } else if (url && !/^[a-z][\w+.-]*:/i.test(url) && !url.startsWith("/")) {
161
170
  let target = url.split(/[?#]/)[0];
162
171
  try {
@@ -265,7 +274,9 @@ function formatVerify(result) {
265
274
  }
266
275
  for (const map of result.maps) {
267
276
  const failure = result.failures.find((f) => f.path === map);
268
- lines.push(failure ? `FAILED ${map}: ${failure.reason}` : `warning ${map}: source map in the output (allowed by --allow-maps; remove it before deploying)`);
277
+ lines.push(
278
+ failure ? `FAILED ${map}: ${failure.reason}` : result.server ? `note ${map}: source map in the server output (browsers never load it)` : `warning ${map}: source map in the output (allowed by --allow-maps; remove it before deploying)`
279
+ );
269
280
  }
270
281
  for (const failure of result.failures.filter((f) => f.path === ".")) lines.push(`FAILED ${failure.reason}`);
271
282
  const u = result.upload;
@@ -274,7 +285,7 @@ function formatVerify(result) {
274
285
  );
275
286
  const counted = result.bundles.filter((b) => b.status !== "skipped");
276
287
  lines.push(
277
- 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}`
288
+ result.ok ? `ok: ${counted.length} bundle(s) with debug ids, ${result.maps.length ? `${result.maps.length} source map(s) left (${result.server ? "server output" : "--allow-maps"})` : "no source maps left"}${u.status === "unverified" ? ", upload not verified" : ""}` : `${result.failures.length} problem(s) in ${result.dir}`
278
289
  );
279
290
  return lines;
280
291
  }
@@ -306,6 +317,7 @@ export {
306
317
  hasDebugIdSnippet,
307
318
  injectBundle,
308
319
  injectDir,
320
+ isInAppSource,
309
321
  mapPathFor,
310
322
  normalizeDebugId,
311
323
  processBuildOutput,
@@ -314,9 +326,11 @@ export {
314
326
  resolveEndpoint,
315
327
  resolveRelease,
316
328
  servedFilename,
329
+ serverUrlPrefix,
317
330
  shiftMappings,
318
331
  snippetLine,
319
332
  storedMapJson,
333
+ storedSourcesContent,
320
334
  stripSourceMappingUrl,
321
335
  uploadDir,
322
336
  verifyDir
package/dist/next.cjs CHANGED
@@ -721,9 +721,56 @@ function servedFilename(urlPrefix, path) {
721
721
  if (!/^[a-z][\w+.-]*:\/\//i.test(prefix) && !prefix.startsWith("/")) prefix = `/${prefix}`;
722
722
  return `${prefix.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
723
723
  }
724
- function storedMapJson(map) {
725
- const { sourcesContent: _omitted, ...safe } = map;
726
- return JSON.stringify(safe);
724
+ var NOT_IN_APP_PATH_PARTS = ["node_modules/", "/site-packages/", "/dist-packages/", "/vendor/", "/.pnpm/"];
725
+ var NOT_IN_APP_PATH_PREFIXES = ["node:", "internal/"];
726
+ var EXTENSION_SCHEMES = ["chrome-extension:", "moz-extension:", "safari-extension:", "safari-web-extension:", "webkit-masked-url:"];
727
+ function isInAppSource(path) {
728
+ if (!path) return true;
729
+ const normalized = path.replace(/\\/g, "/");
730
+ if (NOT_IN_APP_PATH_PARTS.some((part) => normalized.includes(part))) return false;
731
+ if (NOT_IN_APP_PATH_PREFIXES.some((prefix) => normalized.startsWith(prefix))) return false;
732
+ const lower = normalized.toLowerCase();
733
+ return !EXTENSION_SCHEMES.some((scheme) => lower.startsWith(scheme));
734
+ }
735
+ var SOURCES_CONTENT_WRAPPER_BYTES = Buffer.byteLength(',"sourcesContent":[]');
736
+ var NULL_ENTRY_BYTES = 4;
737
+ function storedSourcesContent(fields, baseBytes, limit = MAX_MAP_CHARS) {
738
+ const { sources, sourcesContent } = fields;
739
+ if (!Array.isArray(sources) || !Array.isArray(sourcesContent) || sources.length === 0) return null;
740
+ const ignored = /* @__PURE__ */ new Set();
741
+ for (const list of [fields.ignoreList, fields.x_google_ignoreList]) {
742
+ if (!Array.isArray(list)) continue;
743
+ for (const index of list) if (Number.isInteger(index)) ignored.add(index);
744
+ }
745
+ const count = sources.length;
746
+ const candidates = [];
747
+ for (let index = 0; index < count; index++) {
748
+ const source = sources[index];
749
+ const content = sourcesContent[index];
750
+ if (typeof source !== "string" || typeof content !== "string") continue;
751
+ if (ignored.has(index) || !isInAppSource(source)) continue;
752
+ candidates.push({ index, content, bytes: Buffer.byteLength(JSON.stringify(content)) });
753
+ }
754
+ if (candidates.length === 0) return null;
755
+ candidates.sort((a, b) => a.bytes - b.bytes || a.index - b.index);
756
+ let remaining = limit - baseBytes - SOURCES_CONTENT_WRAPPER_BYTES - NULL_ENTRY_BYTES * count - (count - 1);
757
+ const kept = new Array(count).fill(null);
758
+ let any = false;
759
+ for (const candidate of candidates) {
760
+ const extra = candidate.bytes - NULL_ENTRY_BYTES;
761
+ if (extra > remaining) break;
762
+ remaining -= extra;
763
+ kept[candidate.index] = candidate.content;
764
+ any = true;
765
+ }
766
+ return any ? kept : null;
767
+ }
768
+ function storedMapJson(map, options = {}) {
769
+ const { sourcesContent: _content, ...rest } = map;
770
+ const base = JSON.stringify(rest);
771
+ if (options.sourcesContent === false) return base;
772
+ const content = storedSourcesContent(map, Buffer.byteLength(base));
773
+ return content ? JSON.stringify({ ...rest, sourcesContent: content }) : base;
727
774
  }
728
775
  function bytesOf(buffer) {
729
776
  return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
@@ -734,7 +781,7 @@ function fits(json, body) {
734
781
  function uploadBody(release, filename, debugId, json) {
735
782
  return `{"release":${JSON.stringify(release)},"filename":${JSON.stringify(filename)},${debugId ? `"debugId":${JSON.stringify(debugId)},` : ""}"map":${json}}`;
736
783
  }
737
- async function prepare(bundle, urlPrefix, release, log, compress) {
784
+ async function prepare(bundle, urlPrefix, release, log, compress, sourcesContent) {
738
785
  let map;
739
786
  try {
740
787
  map = JSON.parse(await (0, import_promises3.readFile)(bundle.map, "utf8"));
@@ -749,9 +796,10 @@ async function prepare(bundle, urlPrefix, release, log, compress) {
749
796
  const filename = servedFilename(urlPrefix, bundle.path);
750
797
  const { [SCOPES_KEY]: _stale, ...plain } = map;
751
798
  const scopes = computeScopes(code, map);
752
- let json = storedMapJson(plain);
799
+ const stored = { sourcesContent };
800
+ let json = storedMapJson(plain, stored);
753
801
  if ("scopes" in scopes) {
754
- const scoped = storedMapJson({ ...plain, [SCOPES_KEY]: scopes.scopes });
802
+ const scoped = storedMapJson({ ...plain, [SCOPES_KEY]: scopes.scopes }, stored);
755
803
  if (fits(scoped, uploadBody(release, filename, debugId, scoped))) json = scoped;
756
804
  else if (fits(json, uploadBody(release, filename, debugId, json))) {
757
805
  log(`warning: ${bundle.path}: its map is over 32 MB with function scopes, so it is uploaded without them (frames keep call-site names)`);
@@ -798,7 +846,7 @@ async function uploadDir(dir, options = {}) {
798
846
  };
799
847
  const items = [];
800
848
  for (const bundle of await findBundles(dir, options.files)) {
801
- const prepared = await prepare(bundle, options.urlPrefix, release, log, !options.dryRun);
849
+ const prepared = await prepare(bundle, options.urlPrefix, release, log, !options.dryRun, options.sourcesContent !== false);
802
850
  if ("error" in prepared) {
803
851
  summary.failed.push({ path: bundle.path, filename: servedFilename(options.urlPrefix, bundle.path), error: prepared.error });
804
852
  } else if (prepared.mapChars > MAX_MAP_CHARS || prepared.bytes > MAX_UPLOAD_BYTES) {
@@ -917,6 +965,10 @@ function strip(item) {
917
965
  }
918
966
 
919
967
  // src/build.ts
968
+ function serverUrlPrefix(projectRoot, dir) {
969
+ const rel = (0, import_node_path2.relative)(projectRoot, dir).split(import_node_path2.sep).join("/");
970
+ return !rel || rel.startsWith("..") || (0, import_node_path2.isAbsolute)(rel) ? "/" : `/${rel.replace(/\/+$/, "")}/`;
971
+ }
920
972
  function buildKey(options) {
921
973
  const key = (options.key ?? process.env.AUTTER_RUNTIME_KEY ?? "").trim();
922
974
  return key || null;
@@ -979,12 +1031,13 @@ async function processBuildOutput(input) {
979
1031
  result.upload = await uploadDir(input.dir, {
980
1032
  files: input.files,
981
1033
  release: options.release,
982
- urlPrefix: options.urlPrefix ?? input.urlPrefix,
1034
+ urlPrefix: input.server ? input.urlPrefix : options.urlPrefix ?? input.urlPrefix,
983
1035
  endpoint: options.endpoint,
984
1036
  key: key ?? void 0,
985
1037
  dryRun: options.dryRun,
986
1038
  concurrency: options.concurrency,
987
1039
  deleteAfterUpload: options.deleteAfterUpload ?? input.deleteAfterUpload,
1040
+ ...options.sourcesContent === false ? { sourcesContent: false } : {},
988
1041
  log
989
1042
  });
990
1043
  for (const line of formatUploadSummary(result.upload)) log(line);
@@ -1036,6 +1089,11 @@ async function processBuildOutput(input) {
1036
1089
  // src/webpack.ts
1037
1090
  var import_node_path3 = require("path");
1038
1091
  var PLUGIN_NAME = "AutterSourceMapsWebpackPlugin";
1092
+ var SERVER_TARGET_RE = /^(?:async-)?node|^electron-(?:main|preload)/;
1093
+ function isServerTarget(target) {
1094
+ const targets = Array.isArray(target) ? target : [target];
1095
+ return targets.some((value) => typeof value === "string" && SERVER_TARGET_RE.test(value));
1096
+ }
1039
1097
  var AutterSourceMapsWebpackPlugin = class {
1040
1098
  constructor(options = {}, internal = {}) {
1041
1099
  this.options = options;
@@ -1046,6 +1104,8 @@ var AutterSourceMapsWebpackPlugin = class {
1046
1104
  apply(compiler) {
1047
1105
  const mode = compiler.options.mode ?? (process.env.NODE_ENV === "development" ? "development" : void 0);
1048
1106
  if (mode === "development") return;
1107
+ const server = this.internal.server ?? isServerTarget(compiler.options.target);
1108
+ if (server && this.options.serverBundles === false) return;
1049
1109
  let enabledMaps = this.internal.ownMaps ?? false;
1050
1110
  if (!compiler.options.devtool) {
1051
1111
  if (shouldGenerateMaps(this.options)) {
@@ -1059,7 +1119,7 @@ var AutterSourceMapsWebpackPlugin = class {
1059
1119
  const dir = compilation.outputOptions.path ?? compiler.outputPath;
1060
1120
  if (!dir) return;
1061
1121
  const publicPath = compilation.outputOptions.publicPath;
1062
- const urlPrefix = typeof publicPath === "string" && publicPath !== "auto" && publicPath !== "" ? publicPath : "/";
1122
+ const urlPrefix = server ? serverUrlPrefix(compiler.context ?? process.cwd(), dir) : typeof publicPath === "string" && publicPath !== "auto" && publicPath !== "" ? publicPath : "/";
1063
1123
  const assets = compilation.getAssets().map((asset) => asset.name);
1064
1124
  const files = assets.filter((name) => BUNDLE_RE.test(name)).map((name) => (0, import_node_path3.resolve)(dir, name));
1065
1125
  const maps = assets.filter((name) => name.endsWith(".map")).map((name) => (0, import_node_path3.resolve)(dir, name));
@@ -1070,7 +1130,8 @@ var AutterSourceMapsWebpackPlugin = class {
1070
1130
  urlPrefix,
1071
1131
  options: this.options,
1072
1132
  deleteAfterUpload: enabledMaps,
1073
- ownMaps: enabledMaps
1133
+ ownMaps: enabledMaps,
1134
+ ...server ? { server: true } : {}
1074
1135
  });
1075
1136
  });
1076
1137
  }
@@ -1099,6 +1160,10 @@ function wrapConfig(config, options) {
1099
1160
  const publicMaps = config.productionBrowserSourceMaps === true;
1100
1161
  const ownMaps = !publicMaps && shouldGenerateMaps(options);
1101
1162
  const deleteAfterUpload = options.deleteAfterUpload ?? !publicMaps;
1163
+ const serverBundles = options.serverBundles !== false;
1164
+ const userServerMaps = config.experimental?.serverSourceMaps !== void 0;
1165
+ const ownServerMaps = serverBundles && !userServerMaps && shouldGenerateMaps(options);
1166
+ let serverDevtoolPreset = false;
1102
1167
  let notified = false;
1103
1168
  const notifyNoMaps = () => {
1104
1169
  if (!publicMaps && !ownMaps && !notified) {
@@ -1113,8 +1178,10 @@ function wrapConfig(config, options) {
1113
1178
  const wrapped = {
1114
1179
  ...config,
1115
1180
  webpack(webpackConfig, context) {
1181
+ const nextDevtool = webpackConfig.devtool;
1116
1182
  const result = typeof userWebpack === "function" ? userWebpack(webpackConfig, context) : webpackConfig;
1117
- if (!context.isServer && !context.dev) {
1183
+ if (context.dev) return result;
1184
+ if (!context.isServer) {
1118
1185
  if (ownMaps) result.devtool = "hidden-source-map";
1119
1186
  if (!useHook) {
1120
1187
  result.plugins = [
@@ -1125,18 +1192,35 @@ function wrapConfig(config, options) {
1125
1192
  )
1126
1193
  ];
1127
1194
  }
1195
+ return result;
1196
+ }
1197
+ if (!serverBundles) return result;
1198
+ const preset = Boolean(result.devtool) && (result.devtool !== nextDevtool || !ownServerMaps);
1199
+ if (preset) serverDevtoolPreset = true;
1200
+ const turnedOn = !preset && ownServerMaps;
1201
+ if (turnedOn) result.devtool = "hidden-source-map";
1202
+ if (!useHook && (turnedOn || preset)) {
1203
+ result.plugins = [
1204
+ ...result.plugins ?? [],
1205
+ new AutterSourceMapsWebpackPlugin(
1206
+ { ...options, deleteAfterUpload: options.deleteAfterUpload ?? turnedOn },
1207
+ { ownMaps: turnedOn, server: true }
1208
+ )
1209
+ ];
1128
1210
  }
1129
1211
  return result;
1130
1212
  }
1131
1213
  };
1132
1214
  if (useHook) {
1133
1215
  if (ownMaps) wrapped.productionBrowserSourceMaps = true;
1216
+ if (ownServerMaps) wrapped.experimental = { ...config.experimental, serverSourceMaps: true };
1134
1217
  const userHook = config.compiler?.runAfterProductionCompile;
1135
1218
  wrapped.compiler = {
1136
1219
  ...config.compiler,
1137
1220
  async runAfterProductionCompile(ctx = {}) {
1138
1221
  if (typeof userHook === "function") await userHook(ctx);
1139
- const distDir = ctx.distDir ?? (0, import_node_path4.resolve)(ctx.projectDir ?? process.cwd(), String(config.distDir ?? ".next"));
1222
+ const projectDir = ctx.projectDir ?? process.cwd();
1223
+ const distDir = ctx.distDir ?? (0, import_node_path4.resolve)(projectDir, String(config.distDir ?? ".next"));
1140
1224
  const staticDir = (0, import_node_path4.join)(distDir, "static");
1141
1225
  notifyNoMaps();
1142
1226
  await processBuildOutput({
@@ -1149,6 +1233,19 @@ function wrapConfig(config, options) {
1149
1233
  // Every client map (JS and CSS): .next/static is deployed as is.
1150
1234
  maps: ownMaps ? await findMapFiles(staticDir) : void 0
1151
1235
  });
1236
+ if (!serverBundles) return;
1237
+ const serverDir = (0, import_node_path4.join)(distDir, "server");
1238
+ const ownServer = ownServerMaps && !serverDevtoolPreset;
1239
+ await processBuildOutput({
1240
+ dir: serverDir,
1241
+ urlPrefix: serverUrlPrefix(projectDir, serverDir),
1242
+ options: { ...options, deleteAfterUpload: options.deleteAfterUpload ?? ownServer },
1243
+ deleteAfterUpload: ownServer,
1244
+ stripSourceMappingUrl: ownServer,
1245
+ ownMaps: ownServer,
1246
+ maps: ownServer ? await findMapFiles(serverDir) : void 0,
1247
+ server: true
1248
+ });
1152
1249
  }
1153
1250
  };
1154
1251
  }
package/dist/next.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AutterSourceMapsOptions } from './build-BqjqqeLg.cjs';
1
+ import { A as AutterSourceMapsOptions } from './build-DGeoDkTh.cjs';
2
2
 
3
3
  type NextConfigObject = Record<string, any>;
4
4
  type NextConfigFunction = (phase: string, context: {
@@ -10,8 +10,11 @@ declare function installedNextVersion(cwd?: string): string | null;
10
10
  * Next.js config wrapper: hidden source maps for client production builds,
11
11
  * debug ids injected into every client chunk, maps uploaded after the build
12
12
  * when AUTTER_RUNTIME_KEY (or `key`) is set, then deleted whatever the
13
- * upload's outcome (without a key, no maps are turned on at all). Works with webpack builds, and
14
- * with Turbopack builds on Next.js 15.4.1+ (`compiler.runAfterProductionCompile`).
13
+ * upload's outcome (without a key, no maps are turned on at all). The server
14
+ * output (`.next/server`, Node and edge) gets the same, stored under
15
+ * `/.next/server/` (RF-05; `serverBundles: false` leaves it alone). Works
16
+ * with webpack builds, and with Turbopack builds on Next.js 15.4.1+
17
+ * (`compiler.runAfterProductionCompile`).
15
18
  *
16
19
  * ```js
17
20
  * // next.config.mjs
package/dist/next.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as AutterSourceMapsOptions } from './build-BqjqqeLg.js';
1
+ import { A as AutterSourceMapsOptions } from './build-DGeoDkTh.js';
2
2
 
3
3
  type NextConfigObject = Record<string, any>;
4
4
  type NextConfigFunction = (phase: string, context: {
@@ -10,8 +10,11 @@ declare function installedNextVersion(cwd?: string): string | null;
10
10
  * Next.js config wrapper: hidden source maps for client production builds,
11
11
  * debug ids injected into every client chunk, maps uploaded after the build
12
12
  * when AUTTER_RUNTIME_KEY (or `key`) is set, then deleted whatever the
13
- * upload's outcome (without a key, no maps are turned on at all). Works with webpack builds, and
14
- * with Turbopack builds on Next.js 15.4.1+ (`compiler.runAfterProductionCompile`).
13
+ * upload's outcome (without a key, no maps are turned on at all). The server
14
+ * output (`.next/server`, Node and edge) gets the same, stored under
15
+ * `/.next/server/` (RF-05; `serverBundles: false` leaves it alone). Works
16
+ * with webpack builds, and with Turbopack builds on Next.js 15.4.1+
17
+ * (`compiler.runAfterProductionCompile`).
15
18
  *
16
19
  * ```js
17
20
  * // next.config.mjs
package/dist/next.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import {
2
2
  AutterSourceMapsWebpackPlugin
3
- } from "./chunk-SIL3WZZ3.js";
3
+ } from "./chunk-V66S2YHN.js";
4
4
  import {
5
5
  findMapFiles,
6
6
  logMapsNotGenerated,
7
7
  processBuildOutput,
8
+ serverUrlPrefix,
8
9
  shouldGenerateMaps
9
- } from "./chunk-KIQRQY3X.js";
10
+ } from "./chunk-Q23FB5X3.js";
10
11
 
11
12
  // src/next.ts
12
13
  import { createRequire } from "module";
@@ -33,6 +34,10 @@ function wrapConfig(config, options) {
33
34
  const publicMaps = config.productionBrowserSourceMaps === true;
34
35
  const ownMaps = !publicMaps && shouldGenerateMaps(options);
35
36
  const deleteAfterUpload = options.deleteAfterUpload ?? !publicMaps;
37
+ const serverBundles = options.serverBundles !== false;
38
+ const userServerMaps = config.experimental?.serverSourceMaps !== void 0;
39
+ const ownServerMaps = serverBundles && !userServerMaps && shouldGenerateMaps(options);
40
+ let serverDevtoolPreset = false;
36
41
  let notified = false;
37
42
  const notifyNoMaps = () => {
38
43
  if (!publicMaps && !ownMaps && !notified) {
@@ -47,8 +52,10 @@ function wrapConfig(config, options) {
47
52
  const wrapped = {
48
53
  ...config,
49
54
  webpack(webpackConfig, context) {
55
+ const nextDevtool = webpackConfig.devtool;
50
56
  const result = typeof userWebpack === "function" ? userWebpack(webpackConfig, context) : webpackConfig;
51
- if (!context.isServer && !context.dev) {
57
+ if (context.dev) return result;
58
+ if (!context.isServer) {
52
59
  if (ownMaps) result.devtool = "hidden-source-map";
53
60
  if (!useHook) {
54
61
  result.plugins = [
@@ -59,18 +66,35 @@ function wrapConfig(config, options) {
59
66
  )
60
67
  ];
61
68
  }
69
+ return result;
70
+ }
71
+ if (!serverBundles) return result;
72
+ const preset = Boolean(result.devtool) && (result.devtool !== nextDevtool || !ownServerMaps);
73
+ if (preset) serverDevtoolPreset = true;
74
+ const turnedOn = !preset && ownServerMaps;
75
+ if (turnedOn) result.devtool = "hidden-source-map";
76
+ if (!useHook && (turnedOn || preset)) {
77
+ result.plugins = [
78
+ ...result.plugins ?? [],
79
+ new AutterSourceMapsWebpackPlugin(
80
+ { ...options, deleteAfterUpload: options.deleteAfterUpload ?? turnedOn },
81
+ { ownMaps: turnedOn, server: true }
82
+ )
83
+ ];
62
84
  }
63
85
  return result;
64
86
  }
65
87
  };
66
88
  if (useHook) {
67
89
  if (ownMaps) wrapped.productionBrowserSourceMaps = true;
90
+ if (ownServerMaps) wrapped.experimental = { ...config.experimental, serverSourceMaps: true };
68
91
  const userHook = config.compiler?.runAfterProductionCompile;
69
92
  wrapped.compiler = {
70
93
  ...config.compiler,
71
94
  async runAfterProductionCompile(ctx = {}) {
72
95
  if (typeof userHook === "function") await userHook(ctx);
73
- const distDir = ctx.distDir ?? resolve(ctx.projectDir ?? process.cwd(), String(config.distDir ?? ".next"));
96
+ const projectDir = ctx.projectDir ?? process.cwd();
97
+ const distDir = ctx.distDir ?? resolve(projectDir, String(config.distDir ?? ".next"));
74
98
  const staticDir = join(distDir, "static");
75
99
  notifyNoMaps();
76
100
  await processBuildOutput({
@@ -83,6 +107,19 @@ function wrapConfig(config, options) {
83
107
  // Every client map (JS and CSS): .next/static is deployed as is.
84
108
  maps: ownMaps ? await findMapFiles(staticDir) : void 0
85
109
  });
110
+ if (!serverBundles) return;
111
+ const serverDir = join(distDir, "server");
112
+ const ownServer = ownServerMaps && !serverDevtoolPreset;
113
+ await processBuildOutput({
114
+ dir: serverDir,
115
+ urlPrefix: serverUrlPrefix(projectDir, serverDir),
116
+ options: { ...options, deleteAfterUpload: options.deleteAfterUpload ?? ownServer },
117
+ deleteAfterUpload: ownServer,
118
+ stripSourceMappingUrl: ownServer,
119
+ ownMaps: ownServer,
120
+ maps: ownServer ? await findMapFiles(serverDir) : void 0,
121
+ server: true
122
+ });
86
123
  }
87
124
  };
88
125
  }
package/dist/vite.cjs CHANGED
@@ -714,9 +714,56 @@ function servedFilename(urlPrefix, path) {
714
714
  if (!/^[a-z][\w+.-]*:\/\//i.test(prefix) && !prefix.startsWith("/")) prefix = `/${prefix}`;
715
715
  return `${prefix.replace(/\/+$/, "")}/${path.replace(/^\/+/, "")}`;
716
716
  }
717
- function storedMapJson(map) {
718
- const { sourcesContent: _omitted, ...safe } = map;
719
- return JSON.stringify(safe);
717
+ var NOT_IN_APP_PATH_PARTS = ["node_modules/", "/site-packages/", "/dist-packages/", "/vendor/", "/.pnpm/"];
718
+ var NOT_IN_APP_PATH_PREFIXES = ["node:", "internal/"];
719
+ var EXTENSION_SCHEMES = ["chrome-extension:", "moz-extension:", "safari-extension:", "safari-web-extension:", "webkit-masked-url:"];
720
+ function isInAppSource(path) {
721
+ if (!path) return true;
722
+ const normalized = path.replace(/\\/g, "/");
723
+ if (NOT_IN_APP_PATH_PARTS.some((part) => normalized.includes(part))) return false;
724
+ if (NOT_IN_APP_PATH_PREFIXES.some((prefix) => normalized.startsWith(prefix))) return false;
725
+ const lower = normalized.toLowerCase();
726
+ return !EXTENSION_SCHEMES.some((scheme) => lower.startsWith(scheme));
727
+ }
728
+ var SOURCES_CONTENT_WRAPPER_BYTES = Buffer.byteLength(',"sourcesContent":[]');
729
+ var NULL_ENTRY_BYTES = 4;
730
+ function storedSourcesContent(fields, baseBytes, limit = MAX_MAP_CHARS) {
731
+ const { sources, sourcesContent } = fields;
732
+ if (!Array.isArray(sources) || !Array.isArray(sourcesContent) || sources.length === 0) return null;
733
+ const ignored = /* @__PURE__ */ new Set();
734
+ for (const list of [fields.ignoreList, fields.x_google_ignoreList]) {
735
+ if (!Array.isArray(list)) continue;
736
+ for (const index of list) if (Number.isInteger(index)) ignored.add(index);
737
+ }
738
+ const count = sources.length;
739
+ const candidates = [];
740
+ for (let index = 0; index < count; index++) {
741
+ const source = sources[index];
742
+ const content = sourcesContent[index];
743
+ if (typeof source !== "string" || typeof content !== "string") continue;
744
+ if (ignored.has(index) || !isInAppSource(source)) continue;
745
+ candidates.push({ index, content, bytes: Buffer.byteLength(JSON.stringify(content)) });
746
+ }
747
+ if (candidates.length === 0) return null;
748
+ candidates.sort((a, b) => a.bytes - b.bytes || a.index - b.index);
749
+ let remaining = limit - baseBytes - SOURCES_CONTENT_WRAPPER_BYTES - NULL_ENTRY_BYTES * count - (count - 1);
750
+ const kept = new Array(count).fill(null);
751
+ let any = false;
752
+ for (const candidate of candidates) {
753
+ const extra = candidate.bytes - NULL_ENTRY_BYTES;
754
+ if (extra > remaining) break;
755
+ remaining -= extra;
756
+ kept[candidate.index] = candidate.content;
757
+ any = true;
758
+ }
759
+ return any ? kept : null;
760
+ }
761
+ function storedMapJson(map, options = {}) {
762
+ const { sourcesContent: _content, ...rest } = map;
763
+ const base = JSON.stringify(rest);
764
+ if (options.sourcesContent === false) return base;
765
+ const content = storedSourcesContent(map, Buffer.byteLength(base));
766
+ return content ? JSON.stringify({ ...rest, sourcesContent: content }) : base;
720
767
  }
721
768
  function bytesOf(buffer) {
722
769
  return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
@@ -727,7 +774,7 @@ function fits(json, body) {
727
774
  function uploadBody(release, filename, debugId, json) {
728
775
  return `{"release":${JSON.stringify(release)},"filename":${JSON.stringify(filename)},${debugId ? `"debugId":${JSON.stringify(debugId)},` : ""}"map":${json}}`;
729
776
  }
730
- async function prepare(bundle, urlPrefix, release, log, compress) {
777
+ async function prepare(bundle, urlPrefix, release, log, compress, sourcesContent) {
731
778
  let map;
732
779
  try {
733
780
  map = JSON.parse(await (0, import_promises3.readFile)(bundle.map, "utf8"));
@@ -742,9 +789,10 @@ async function prepare(bundle, urlPrefix, release, log, compress) {
742
789
  const filename = servedFilename(urlPrefix, bundle.path);
743
790
  const { [SCOPES_KEY]: _stale, ...plain } = map;
744
791
  const scopes = computeScopes(code, map);
745
- let json = storedMapJson(plain);
792
+ const stored = { sourcesContent };
793
+ let json = storedMapJson(plain, stored);
746
794
  if ("scopes" in scopes) {
747
- const scoped = storedMapJson({ ...plain, [SCOPES_KEY]: scopes.scopes });
795
+ const scoped = storedMapJson({ ...plain, [SCOPES_KEY]: scopes.scopes }, stored);
748
796
  if (fits(scoped, uploadBody(release, filename, debugId, scoped))) json = scoped;
749
797
  else if (fits(json, uploadBody(release, filename, debugId, json))) {
750
798
  log(`warning: ${bundle.path}: its map is over 32 MB with function scopes, so it is uploaded without them (frames keep call-site names)`);
@@ -791,7 +839,7 @@ async function uploadDir(dir, options = {}) {
791
839
  };
792
840
  const items = [];
793
841
  for (const bundle of await findBundles(dir, options.files)) {
794
- const prepared = await prepare(bundle, options.urlPrefix, release, log, !options.dryRun);
842
+ const prepared = await prepare(bundle, options.urlPrefix, release, log, !options.dryRun, options.sourcesContent !== false);
795
843
  if ("error" in prepared) {
796
844
  summary.failed.push({ path: bundle.path, filename: servedFilename(options.urlPrefix, bundle.path), error: prepared.error });
797
845
  } else if (prepared.mapChars > MAX_MAP_CHARS || prepared.bytes > MAX_UPLOAD_BYTES) {
@@ -910,6 +958,10 @@ function strip(item) {
910
958
  }
911
959
 
912
960
  // src/build.ts
961
+ function serverUrlPrefix(projectRoot, dir) {
962
+ const rel = (0, import_node_path2.relative)(projectRoot, dir).split(import_node_path2.sep).join("/");
963
+ return !rel || rel.startsWith("..") || (0, import_node_path2.isAbsolute)(rel) ? "/" : `/${rel.replace(/\/+$/, "")}/`;
964
+ }
913
965
  function buildKey(options) {
914
966
  const key = (options.key ?? process.env.AUTTER_RUNTIME_KEY ?? "").trim();
915
967
  return key || null;
@@ -972,12 +1024,13 @@ async function processBuildOutput(input) {
972
1024
  result.upload = await uploadDir(input.dir, {
973
1025
  files: input.files,
974
1026
  release: options.release,
975
- urlPrefix: options.urlPrefix ?? input.urlPrefix,
1027
+ urlPrefix: input.server ? input.urlPrefix : options.urlPrefix ?? input.urlPrefix,
976
1028
  endpoint: options.endpoint,
977
1029
  key: key ?? void 0,
978
1030
  dryRun: options.dryRun,
979
1031
  concurrency: options.concurrency,
980
1032
  deleteAfterUpload: options.deleteAfterUpload ?? input.deleteAfterUpload,
1033
+ ...options.sourcesContent === false ? { sourcesContent: false } : {},
981
1034
  log
982
1035
  });
983
1036
  for (const line of formatUploadSummary(result.upload)) log(line);
@@ -1032,6 +1085,8 @@ function autterSourceMaps(options = {}) {
1032
1085
  let enabledMaps = false;
1033
1086
  let ssr = false;
1034
1087
  let base = "/";
1088
+ let root = process.cwd();
1089
+ const serverBundles = options.serverBundles !== false;
1035
1090
  return {
1036
1091
  name: "autter-runtime-sourcemaps",
1037
1092
  apply: "build",
@@ -1039,7 +1094,7 @@ function autterSourceMaps(options = {}) {
1039
1094
  config(config) {
1040
1095
  isVite = true;
1041
1096
  const current = config.build?.sourcemap;
1042
- if ((current === void 0 || current === false) && !config.build?.ssr) {
1097
+ if ((current === void 0 || current === false) && (serverBundles || !config.build?.ssr)) {
1043
1098
  if (!shouldGenerateMaps(options)) {
1044
1099
  logMapsNotGenerated(options);
1045
1100
  return void 0;
@@ -1051,6 +1106,7 @@ function autterSourceMaps(options = {}) {
1051
1106
  },
1052
1107
  configResolved(config) {
1053
1108
  ssr = Boolean(config.build?.ssr);
1109
+ if (config.root) root = config.root;
1054
1110
  if (config.base && /^(\/|[a-z][\w+.-]*:\/\/)/i.test(config.base)) base = config.base;
1055
1111
  if (config.build?.sourcemap === "inline" && !options.silent) {
1056
1112
  console.warn('[autter-runtime] build.sourcemap is "inline": there are no map files to upload; use "hidden"');
@@ -1069,8 +1125,23 @@ function autterSourceMaps(options = {}) {
1069
1125
  const dir = output.dir ?? (output.file ? (0, import_node_path3.dirname)(output.file) : void 0);
1070
1126
  if (!dir) return;
1071
1127
  const maps = Object.values(bundle).filter((file) => file.fileName.endsWith(".map")).map((file) => (0, import_node_path3.resolve)(dir, file.fileName));
1128
+ const files = Object.values(bundle).filter((file) => file.type === "chunk").map((file) => (0, import_node_path3.resolve)(dir, file.fileName));
1072
1129
  const environment = this?.environment;
1073
- if (ssr || environment?.config?.consumer === "server") {
1130
+ const server = ssr || environment?.config?.consumer === "server";
1131
+ if (server && serverBundles) {
1132
+ await processBuildOutput({
1133
+ dir,
1134
+ files,
1135
+ maps,
1136
+ urlPrefix: serverUrlPrefix(root, dir),
1137
+ options,
1138
+ deleteAfterUpload: enabledMaps,
1139
+ ownMaps: enabledMaps,
1140
+ server: true
1141
+ });
1142
+ return;
1143
+ }
1144
+ if (server) {
1074
1145
  if (enabledMaps && options.deleteAfterUpload !== false) {
1075
1146
  try {
1076
1147
  const removed = await removeSourceMaps(maps);
@@ -1083,7 +1154,6 @@ function autterSourceMaps(options = {}) {
1083
1154
  }
1084
1155
  return;
1085
1156
  }
1086
- const files = Object.values(bundle).filter((file) => file.type === "chunk").map((file) => (0, import_node_path3.resolve)(dir, file.fileName));
1087
1157
  await processBuildOutput({
1088
1158
  dir,
1089
1159
  files,