@vigilon/nextjs 0.0.0-stage → 0.2.15

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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 Vigilon
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,114 @@
1
- # Temporary Holding Version
1
+ # `@vigilon/nextjs`
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Vigilon for Next.js: server traces and errors from the Node.js runtime, and browser errors from the client, reported under one service. It wraps [`@vigilon/node`](../node#readme) on the server and [`@vigilon/react`](../react#readme) in the browser.
4
+
5
+ > **Early access.** Browser error monitoring is not yet generally available. The ingest endpoint accepts browser events only from projects enabled for early access and answers `403` for the rest, which the SDK does not retry.
6
+
7
+ Requires Next.js 15.3 or later, and Node.js 22.12 or later for the build and the server. Automatic source map upload needs Next.js 15.4 or later.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @vigilon/nextjs
13
+ ```
14
+
15
+ ## Set up
16
+
17
+ ### `next.config.ts`
18
+
19
+ ```ts
20
+ import { withVigilon } from "@vigilon/nextjs/config";
21
+
22
+ export default withVigilon({
23
+ // your Next.js config
24
+ });
25
+ ```
26
+
27
+ `withVigilon()` keeps the SDK and its OpenTelemetry dependencies out of the server bundle, and has Next.js render the request's `traceparent` in a meta tag so browser errors on a server-rendered page link to the server trace that rendered it.
28
+
29
+ ### `instrumentation.ts` (server)
30
+
31
+ ```ts
32
+ export async function register() {
33
+ if (process.env.NEXT_RUNTIME === "nodejs") {
34
+ const { register } = await import("@vigilon/nextjs/server");
35
+ register({ serviceName: "storefront", serviceVersion: process.env.VIGILON_SERVICE_VERSION });
36
+ }
37
+ }
38
+ ```
39
+
40
+ `register()` takes the same options as [`@vigilon/node`](../node#readme) and reads anything you leave out from the environment (`VIGILON_API_KEY`, `VIGILON_ENVIRONMENT`, …). It adds what Next.js needs on top: request spans are labelled with the route Next.js resolved (`/api/orders/[id]`), and on Vercel telemetry is flushed at the end of every request and the real response status is recorded. The SDK cannot run in the Edge runtime, so gate on `NEXT_RUNTIME` and import it dynamically as above.
41
+
42
+ Next.js records errors from Server Components, route handlers, and Server Actions on its own request spans, so no `onRequestError` hook is needed. Everything from `@vigilon/node` (`recordException`, `withJobMonitor`, …) is re-exported from `@vigilon/nextjs/server`.
43
+
44
+ ### `instrumentation-client.ts` (browser)
45
+
46
+ ```ts
47
+ import { init } from "@vigilon/nextjs";
48
+
49
+ init({
50
+ apiKey: process.env.NEXT_PUBLIC_VIGILON_API_KEY!,
51
+ serviceName: "storefront",
52
+ environment: process.env.NEXT_PUBLIC_VIGILON_ENVIRONMENT!,
53
+ serviceVersion: process.env.NEXT_PUBLIC_VIGILON_SERVICE_VERSION,
54
+ });
55
+ ```
56
+
57
+ Use the same `serviceName` as the server: Vigilon keeps server and browser errors apart by origin. `init` takes the options of [`@vigilon/browser`](../browser#readme). Every event captured before the first client-side navigation carries the trace ID of the request that rendered the page.
58
+
59
+ ### Error boundaries
60
+
61
+ Next.js creates the React root itself, so render errors that an `error.tsx` or `global-error.tsx` boundary catches are reported from the boundary:
62
+
63
+ ```tsx
64
+ "use client";
65
+ import { useReportError } from "@vigilon/nextjs";
66
+
67
+ export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
68
+ useReportError(error);
69
+ return (
70
+ <html lang="en">
71
+ <body>
72
+ <h2>Something went wrong.</h2>
73
+ </body>
74
+ </html>
75
+ );
76
+ }
77
+ ```
78
+
79
+ `@vigilon/nextjs` re-exports `@vigilon/react`, including `ErrorBoundary` for your own boundaries inside client components.
80
+
81
+ ## Source maps
82
+
83
+ With a source map upload token, `withVigilon()` builds browser source maps and, once Next.js has compiled, gives every script a debug ID, uploads the scripts and their maps, and deletes every map so none is deployed. Before that it marks, in each map's `ignoreList`, the sources that are not files in your project, such as the precompiled Next.js code a webpack build maps, so Vigilon treats their frames as library code rather than yours. Files outside the project directory that exist on disk, such as a shared package in a monorepo, stay yours. It runs in Next.js's `compiler.runAfterProductionCompile` hook (Next.js 15.4 or later), so it works with both Turbopack and webpack.
84
+
85
+ ```bash
86
+ VIGILON_SOURCE_MAP_TOKEN=vg_sm_... next build
87
+ ```
88
+
89
+ | Option | Default | |
90
+ |---|---|---|
91
+ | `uploadToken` | `VIGILON_SOURCE_MAP_TOKEN` | A source map upload token for the project. Without one, no source maps are built or uploaded. Never use a project API key here: API keys are public in the browser. |
92
+ | `apiUrl` | `VIGILON_API_URL`, then `https://api.vigilon.io` | The Vigilon API. |
93
+ | `onUploadError` | `"error"` | `"warn"` keeps a failed upload from failing the build. The maps are deleted either way. |
94
+
95
+ ```ts
96
+ export default withVigilon(nextConfig, { onUploadError: "warn" });
97
+ ```
98
+
99
+ On Next.js 15.3, run [`@vigilon/cli`](../cli#readme) on `.next/static` after `next build` instead, with `productionBrowserSourceMaps: true`.
100
+
101
+ ## Self-hosted Next.js (optional)
102
+
103
+ With `next start` or the standalone output you can preload the SDK instead of, or as well as, registering it from `instrumentation.ts`, which adds Vigilon's own HTTP server spans:
104
+
105
+ ```bash
106
+ NODE_OPTIONS='--import @vigilon/nextjs/register' next start
107
+ ```
108
+
109
+ The preload reads its settings from the environment. Preload this package's entry, not `@vigilon/node/register`: a plain `@vigilon/node` start has no Next.js route labelling, and `register()` from this package then warns and does nothing. Preloading does not work on Vercel; use `instrumentation.ts` there.
110
+
111
+ ## Support
112
+
113
+ - Bugs and feature requests: [GitHub Issues](https://github.com/vigilonio/js/issues)
114
+ - Security vulnerabilities: report them privately to [security@vigilon.io](mailto:security@vigilon.io)
@@ -0,0 +1,170 @@
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/config/index.ts
21
+ var config_exports = {};
22
+ __export(config_exports, {
23
+ uploadSourceMaps: () => uploadSourceMaps,
24
+ withVigilon: () => withVigilon
25
+ });
26
+ module.exports = __toCommonJS(config_exports);
27
+
28
+ // ../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.31_tsx@4.23.13_typescript@6.0.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
29
+ var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
30
+ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
31
+
32
+ // src/config/index.ts
33
+ var import_node_child_process = require("child_process");
34
+ var import_promises2 = require("fs/promises");
35
+ var import_node_module = require("module");
36
+ var import_node_path2 = require("path");
37
+ var import_node_util = require("util");
38
+
39
+ // src/config/ignore-list.ts
40
+ var import_promises = require("fs/promises");
41
+ var import_node_path = require("path");
42
+ async function ignoreSourcesNotOnDisk(staticDir, projectDir) {
43
+ const files = (await (0, import_promises.readdir)(staticDir, { recursive: true })).filter((file) => file.endsWith(".map"));
44
+ await Promise.all(
45
+ files.map(async (file) => {
46
+ const path = (0, import_node_path.join)(staticDir, file);
47
+ let map;
48
+ try {
49
+ map = JSON.parse(await (0, import_promises.readFile)(path, "utf8"));
50
+ } catch {
51
+ return;
52
+ }
53
+ const maps = map.sections ? map.sections.map((section) => section.map) : [map];
54
+ let changed = false;
55
+ for (const part of maps) {
56
+ changed = await ignoreInMap(part, projectDir) || changed;
57
+ }
58
+ if (changed) {
59
+ await (0, import_promises.writeFile)(path, JSON.stringify(map));
60
+ }
61
+ })
62
+ );
63
+ }
64
+ async function ignoreInMap(map, projectDir) {
65
+ const sources = map.sources ?? [];
66
+ const ignored = /* @__PURE__ */ new Set([...map.ignoreList ?? [], ...map.x_google_ignoreList ?? []]);
67
+ const added = [];
68
+ await Promise.all(
69
+ sources.map(async (source, index) => {
70
+ if (ignored.has(index) || typeof source !== "string") return;
71
+ const path = webpackSourcePath(source, projectDir);
72
+ if (path !== null && !await isFile(path)) added.push(index);
73
+ })
74
+ );
75
+ if (added.length === 0) return false;
76
+ map.ignoreList = [...ignored, ...added].sort((a, b) => a - b);
77
+ return true;
78
+ }
79
+ function webpackSourcePath(source, projectDir) {
80
+ const match = /^webpack:\/\/[^/]*\/(.*)$/.exec(source);
81
+ if (!match) return null;
82
+ const path = (match[1] ?? "").replace(/[?#].*$/, "");
83
+ return (0, import_node_path.isAbsolute)(path) ? path : (0, import_node_path.resolve)(projectDir, path);
84
+ }
85
+ async function isFile(path) {
86
+ try {
87
+ return (await (0, import_promises.stat)(path)).isFile();
88
+ } catch {
89
+ return false;
90
+ }
91
+ }
92
+
93
+ // src/config/index.ts
94
+ var SERVER_PACKAGES = ["@vigilon/nextjs", "@vigilon/node"];
95
+ function withVigilon(config, options = {}) {
96
+ const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;
97
+ const experimental = config.experimental ?? {};
98
+ const wrapped = {
99
+ ...config,
100
+ serverExternalPackages: unique([...config.serverExternalPackages ?? [], ...SERVER_PACKAGES]),
101
+ experimental: {
102
+ ...experimental,
103
+ clientTraceMetadata: unique([...experimental.clientTraceMetadata ?? [], "traceparent"])
104
+ }
105
+ };
106
+ if (uploadToken) {
107
+ const previous = config.compiler?.runAfterProductionCompile;
108
+ wrapped.productionBrowserSourceMaps = true;
109
+ wrapped.compiler = {
110
+ ...config.compiler,
111
+ runAfterProductionCompile: async (metadata) => {
112
+ await previous?.(metadata);
113
+ const staticDir = (0, import_node_path2.join)(metadata.distDir, "static");
114
+ try {
115
+ await ignoreSourcesNotOnDisk(staticDir, metadata.projectDir);
116
+ await uploadSourceMaps(staticDir, uploadToken, options);
117
+ } finally {
118
+ await deleteSourceMaps(staticDir);
119
+ }
120
+ }
121
+ };
122
+ }
123
+ return wrapped;
124
+ }
125
+ var run = (0, import_node_util.promisify)(import_node_child_process.execFile);
126
+ async function uploadSourceMaps(staticDir, uploadToken, options) {
127
+ const cli = cliBinPath();
128
+ const env = {
129
+ ...process.env,
130
+ VIGILON_SOURCE_MAP_TOKEN: uploadToken,
131
+ ...options.apiUrl ? { VIGILON_API_URL: options.apiUrl } : {}
132
+ };
133
+ const warnOnly = options.onUploadError === "warn" ? ["--warn-only"] : [];
134
+ for (const args of [
135
+ ["sourcemaps", "inject", staticDir],
136
+ ["sourcemaps", "upload", staticDir, "--delete-after-upload", ...warnOnly]
137
+ ]) {
138
+ try {
139
+ const { stdout, stderr } = await run(process.execPath, [cli, ...args], { env });
140
+ process.stdout.write(stdout);
141
+ process.stderr.write(stderr);
142
+ } catch (error) {
143
+ const { stdout = "", stderr = "" } = error;
144
+ process.stdout.write(stdout);
145
+ process.stderr.write(stderr);
146
+ throw new Error(`Vigilon source map upload failed: vigilon ${args.join(" ")}`);
147
+ }
148
+ }
149
+ }
150
+ async function deleteSourceMaps(dir) {
151
+ const files = await (0, import_promises2.readdir)(dir, { recursive: true });
152
+ await Promise.all(
153
+ files.filter((file) => file.endsWith(".map")).map((file) => (0, import_promises2.rm)((0, import_node_path2.join)(dir, file), { force: true }))
154
+ );
155
+ }
156
+ function cliBinPath() {
157
+ const require2 = (0, import_node_module.createRequire)(importMetaUrl);
158
+ const manifestPath = require2.resolve("@vigilon/cli/package.json");
159
+ const manifest = require2(manifestPath);
160
+ return (0, import_node_path2.join)((0, import_node_path2.dirname)(manifestPath), manifest.bin.vigilon);
161
+ }
162
+ function unique(values) {
163
+ return [...new Set(values)];
164
+ }
165
+ // Annotate the CommonJS export names for ESM import in node:
166
+ 0 && (module.exports = {
167
+ uploadSourceMaps,
168
+ withVigilon
169
+ });
170
+ //# sourceMappingURL=config.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/index.ts","../../../node_modules/.pnpm/tsup@8.5.1_postcss@8.5.31_tsx@4.23.13_typescript@6.0.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js","../src/config/ignore-list.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { readdir, rm } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { ignoreSourcesNotOnDisk } from \"./ignore-list\";\n\nexport interface VigilonNextConfigOptions {\n /**\n * A source map upload token for the project. Falls back to\n * VIGILON_SOURCE_MAP_TOKEN. Without one, source maps are neither built nor\n * uploaded. Never use a project API key here: API keys are public.\n */\n uploadToken?: string;\n /** The Vigilon API. Falls back to VIGILON_API_URL, then https://api.vigilon.io. */\n apiUrl?: string;\n /** What a failed upload does to the build. Defaults to \"error\". */\n onUploadError?: \"error\" | \"warn\";\n}\n\n/** The parts of a Next.js config this wrapper reads and sets. */\nexport interface NextConfigLike {\n serverExternalPackages?: string[];\n productionBrowserSourceMaps?: boolean;\n experimental?: { clientTraceMetadata?: string[]; [key: string]: unknown };\n compiler?: {\n runAfterProductionCompile?: (metadata: { projectDir: string; distDir: string }) => Promise<void>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nconst SERVER_PACKAGES = [\"@vigilon/nextjs\", \"@vigilon/node\"];\n\n/**\n * Wraps a Next.js config for Vigilon:\n *\n * - keeps the SDK and its require-hook based OpenTelemetry dependencies out\n * of the server bundle;\n * - has Next.js render the request's `traceparent` in a meta tag, so browser\n * errors on a server-rendered page link to its server trace;\n * - with an upload token, builds browser source maps and, once Next.js has\n * compiled (Next.js 15.4 or later, with Turbopack or webpack), marks\n * sources that are not the application's own files as library code, gives\n * every script a debug ID, uploads the scripts and their maps, and deletes\n * every map so none is deployed.\n *\n * ```ts\n * export default withVigilon({ reactStrictMode: true });\n * ```\n */\nexport function withVigilon<T extends NextConfigLike>(\n config: T,\n options: VigilonNextConfigOptions = {},\n): T & NextConfigLike {\n const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;\n const experimental = config.experimental ?? {};\n const wrapped: NextConfigLike = {\n ...config,\n serverExternalPackages: unique([...(config.serverExternalPackages ?? []), ...SERVER_PACKAGES]),\n experimental: {\n ...experimental,\n clientTraceMetadata: unique([...(experimental.clientTraceMetadata ?? []), \"traceparent\"]),\n },\n };\n if (uploadToken) {\n const previous = config.compiler?.runAfterProductionCompile;\n wrapped.productionBrowserSourceMaps = true;\n wrapped.compiler = {\n ...config.compiler,\n runAfterProductionCompile: async (metadata) => {\n await previous?.(metadata);\n const staticDir = join(metadata.distDir, \"static\");\n try {\n // Before inject, so each debug ID covers the final map.\n await ignoreSourcesNotOnDisk(staticDir, metadata.projectDir);\n await uploadSourceMaps(staticDir, uploadToken, options);\n } finally {\n // The maps were turned on only for the upload, so none may be\n // deployed: not after a failed upload, which keeps them for a\n // retry, and not the maps of Next.js's own files, which have no\n // sourceMappingURL to pair them with a script.\n await deleteSourceMaps(staticDir);\n }\n },\n };\n }\n return wrapped as T & NextConfigLike;\n}\n\nconst run = promisify(execFile);\n\n/** Runs @vigilon/cli's inject and upload over the browser build output. */\nexport async function uploadSourceMaps(\n staticDir: string,\n uploadToken: string,\n options: VigilonNextConfigOptions,\n): Promise<void> {\n const cli = cliBinPath();\n const env = {\n ...process.env,\n VIGILON_SOURCE_MAP_TOKEN: uploadToken,\n ...(options.apiUrl ? { VIGILON_API_URL: options.apiUrl } : {}),\n };\n const warnOnly = options.onUploadError === \"warn\" ? [\"--warn-only\"] : [];\n for (const args of [\n [\"sourcemaps\", \"inject\", staticDir],\n [\"sourcemaps\", \"upload\", staticDir, \"--delete-after-upload\", ...warnOnly],\n ]) {\n try {\n const { stdout, stderr } = await run(process.execPath, [cli, ...args], { env });\n process.stdout.write(stdout);\n process.stderr.write(stderr);\n } catch (error) {\n // A failed run rejects with its output attached; show it, then fail the\n // build with it.\n const { stdout = \"\", stderr = \"\" } = error as { stdout?: string; stderr?: string };\n process.stdout.write(stdout);\n process.stderr.write(stderr);\n throw new Error(`Vigilon source map upload failed: vigilon ${args.join(\" \")}`);\n }\n }\n}\n\nasync function deleteSourceMaps(dir: string): Promise<void> {\n const files = await readdir(dir, { recursive: true });\n await Promise.all(\n files.filter((file) => file.endsWith(\".map\")).map((file) => rm(join(dir, file), { force: true })),\n );\n}\n\nfunction cliBinPath(): string {\n const require = createRequire(import.meta.url);\n const manifestPath = require.resolve(\"@vigilon/cli/package.json\");\n const manifest = require(manifestPath) as { bin: { vigilon: string } };\n return join(dirname(manifestPath), manifest.bin.vigilon);\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\n","import { readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { isAbsolute, join, resolve } from \"node:path\";\n\ninterface SourceMapSection {\n map: SourceMapLike;\n}\n\ninterface SourceMapLike {\n sources?: (string | null)[];\n ignoreList?: number[];\n x_google_ignoreList?: number[];\n sections?: SourceMapSection[];\n}\n\n/**\n * Adds to each map's `ignoreList` every webpack source that is not a file on\n * disk under the project, so Vigilon reads it as library code. Next.js's\n * webpack build gives Next's own precompiled client code sources such as\n * `webpack://_N_E/../../src/client/add-base-path.ts`, which no path rule can\n * tell from the application's, and leaves them off the list. The\n * application's own sources, including a monorepo package outside the\n * project, are files on disk while it builds.\n *\n * Turbopack sources are left alone: Turbopack lists its framework and runtime\n * sources itself, and its `[project]` root may be a monorepo root rather than\n * the project directory.\n */\nexport async function ignoreSourcesNotOnDisk(staticDir: string, projectDir: string): Promise<void> {\n const files = (await readdir(staticDir, { recursive: true })).filter((file) => file.endsWith(\".map\"));\n await Promise.all(\n files.map(async (file) => {\n const path = join(staticDir, file);\n let map: SourceMapLike;\n try {\n map = JSON.parse(await readFile(path, \"utf8\")) as SourceMapLike;\n } catch {\n return;\n }\n const maps = map.sections ? map.sections.map((section) => section.map) : [map];\n let changed = false;\n for (const part of maps) {\n changed = (await ignoreInMap(part, projectDir)) || changed;\n }\n if (changed) {\n await writeFile(path, JSON.stringify(map));\n }\n }),\n );\n}\n\nasync function ignoreInMap(map: SourceMapLike, projectDir: string): Promise<boolean> {\n const sources = map.sources ?? [];\n const ignored = new Set([...(map.ignoreList ?? []), ...(map.x_google_ignoreList ?? [])]);\n const added: number[] = [];\n await Promise.all(\n sources.map(async (source, index) => {\n if (ignored.has(index) || typeof source !== \"string\") return;\n const path = webpackSourcePath(source, projectDir);\n if (path !== null && !(await isFile(path))) added.push(index);\n }),\n );\n if (added.length === 0) return false;\n // Readers take ignoreList over x_google_ignoreList, so the old entries are\n // merged into it rather than left beside it.\n map.ignoreList = [...ignored, ...added].sort((a, b) => a - b);\n return true;\n}\n\n/**\n * The file a `webpack://<namespace>/<path>` source names, relative to the\n * project (webpack's context), without a query or fragment; null for any\n * other source.\n */\nexport function webpackSourcePath(source: string, projectDir: string): string | null {\n const match = /^webpack:\\/\\/[^/]*\\/(.*)$/.exec(source);\n if (!match) return null;\n const path = (match[1] ?? \"\").replace(/[?#].*$/, \"\");\n return isAbsolute(path) ? path : resolve(projectDir, path);\n}\n\nasync function isFile(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":["import_promises","import_node_path","require"]}
@@ -0,0 +1,51 @@
1
+ interface VigilonNextConfigOptions {
2
+ /**
3
+ * A source map upload token for the project. Falls back to
4
+ * VIGILON_SOURCE_MAP_TOKEN. Without one, source maps are neither built nor
5
+ * uploaded. Never use a project API key here: API keys are public.
6
+ */
7
+ uploadToken?: string;
8
+ /** The Vigilon API. Falls back to VIGILON_API_URL, then https://api.vigilon.io. */
9
+ apiUrl?: string;
10
+ /** What a failed upload does to the build. Defaults to "error". */
11
+ onUploadError?: "error" | "warn";
12
+ }
13
+ /** The parts of a Next.js config this wrapper reads and sets. */
14
+ interface NextConfigLike {
15
+ serverExternalPackages?: string[];
16
+ productionBrowserSourceMaps?: boolean;
17
+ experimental?: {
18
+ clientTraceMetadata?: string[];
19
+ [key: string]: unknown;
20
+ };
21
+ compiler?: {
22
+ runAfterProductionCompile?: (metadata: {
23
+ projectDir: string;
24
+ distDir: string;
25
+ }) => Promise<void>;
26
+ [key: string]: unknown;
27
+ };
28
+ [key: string]: unknown;
29
+ }
30
+ /**
31
+ * Wraps a Next.js config for Vigilon:
32
+ *
33
+ * - keeps the SDK and its require-hook based OpenTelemetry dependencies out
34
+ * of the server bundle;
35
+ * - has Next.js render the request's `traceparent` in a meta tag, so browser
36
+ * errors on a server-rendered page link to its server trace;
37
+ * - with an upload token, builds browser source maps and, once Next.js has
38
+ * compiled (Next.js 15.4 or later, with Turbopack or webpack), marks
39
+ * sources that are not the application's own files as library code, gives
40
+ * every script a debug ID, uploads the scripts and their maps, and deletes
41
+ * every map so none is deployed.
42
+ *
43
+ * ```ts
44
+ * export default withVigilon({ reactStrictMode: true });
45
+ * ```
46
+ */
47
+ declare function withVigilon<T extends NextConfigLike>(config: T, options?: VigilonNextConfigOptions): T & NextConfigLike;
48
+ /** Runs @vigilon/cli's inject and upload over the browser build output. */
49
+ declare function uploadSourceMaps(staticDir: string, uploadToken: string, options: VigilonNextConfigOptions): Promise<void>;
50
+
51
+ export { type NextConfigLike, type VigilonNextConfigOptions, uploadSourceMaps, withVigilon };
@@ -0,0 +1,51 @@
1
+ interface VigilonNextConfigOptions {
2
+ /**
3
+ * A source map upload token for the project. Falls back to
4
+ * VIGILON_SOURCE_MAP_TOKEN. Without one, source maps are neither built nor
5
+ * uploaded. Never use a project API key here: API keys are public.
6
+ */
7
+ uploadToken?: string;
8
+ /** The Vigilon API. Falls back to VIGILON_API_URL, then https://api.vigilon.io. */
9
+ apiUrl?: string;
10
+ /** What a failed upload does to the build. Defaults to "error". */
11
+ onUploadError?: "error" | "warn";
12
+ }
13
+ /** The parts of a Next.js config this wrapper reads and sets. */
14
+ interface NextConfigLike {
15
+ serverExternalPackages?: string[];
16
+ productionBrowserSourceMaps?: boolean;
17
+ experimental?: {
18
+ clientTraceMetadata?: string[];
19
+ [key: string]: unknown;
20
+ };
21
+ compiler?: {
22
+ runAfterProductionCompile?: (metadata: {
23
+ projectDir: string;
24
+ distDir: string;
25
+ }) => Promise<void>;
26
+ [key: string]: unknown;
27
+ };
28
+ [key: string]: unknown;
29
+ }
30
+ /**
31
+ * Wraps a Next.js config for Vigilon:
32
+ *
33
+ * - keeps the SDK and its require-hook based OpenTelemetry dependencies out
34
+ * of the server bundle;
35
+ * - has Next.js render the request's `traceparent` in a meta tag, so browser
36
+ * errors on a server-rendered page link to its server trace;
37
+ * - with an upload token, builds browser source maps and, once Next.js has
38
+ * compiled (Next.js 15.4 or later, with Turbopack or webpack), marks
39
+ * sources that are not the application's own files as library code, gives
40
+ * every script a debug ID, uploads the scripts and their maps, and deletes
41
+ * every map so none is deployed.
42
+ *
43
+ * ```ts
44
+ * export default withVigilon({ reactStrictMode: true });
45
+ * ```
46
+ */
47
+ declare function withVigilon<T extends NextConfigLike>(config: T, options?: VigilonNextConfigOptions): T & NextConfigLike;
48
+ /** Runs @vigilon/cli's inject and upload over the browser build output. */
49
+ declare function uploadSourceMaps(staticDir: string, uploadToken: string, options: VigilonNextConfigOptions): Promise<void>;
50
+
51
+ export { type NextConfigLike, type VigilonNextConfigOptions, uploadSourceMaps, withVigilon };
@@ -0,0 +1,138 @@
1
+ // src/config/index.ts
2
+ import { execFile } from "child_process";
3
+ import { readdir as readdir2, rm } from "fs/promises";
4
+ import { createRequire } from "module";
5
+ import { dirname, join as join2 } from "path";
6
+ import { promisify } from "util";
7
+
8
+ // src/config/ignore-list.ts
9
+ import { readdir, readFile, stat, writeFile } from "fs/promises";
10
+ import { isAbsolute, join, resolve } from "path";
11
+ async function ignoreSourcesNotOnDisk(staticDir, projectDir) {
12
+ const files = (await readdir(staticDir, { recursive: true })).filter((file) => file.endsWith(".map"));
13
+ await Promise.all(
14
+ files.map(async (file) => {
15
+ const path = join(staticDir, file);
16
+ let map;
17
+ try {
18
+ map = JSON.parse(await readFile(path, "utf8"));
19
+ } catch {
20
+ return;
21
+ }
22
+ const maps = map.sections ? map.sections.map((section) => section.map) : [map];
23
+ let changed = false;
24
+ for (const part of maps) {
25
+ changed = await ignoreInMap(part, projectDir) || changed;
26
+ }
27
+ if (changed) {
28
+ await writeFile(path, JSON.stringify(map));
29
+ }
30
+ })
31
+ );
32
+ }
33
+ async function ignoreInMap(map, projectDir) {
34
+ const sources = map.sources ?? [];
35
+ const ignored = /* @__PURE__ */ new Set([...map.ignoreList ?? [], ...map.x_google_ignoreList ?? []]);
36
+ const added = [];
37
+ await Promise.all(
38
+ sources.map(async (source, index) => {
39
+ if (ignored.has(index) || typeof source !== "string") return;
40
+ const path = webpackSourcePath(source, projectDir);
41
+ if (path !== null && !await isFile(path)) added.push(index);
42
+ })
43
+ );
44
+ if (added.length === 0) return false;
45
+ map.ignoreList = [...ignored, ...added].sort((a, b) => a - b);
46
+ return true;
47
+ }
48
+ function webpackSourcePath(source, projectDir) {
49
+ const match = /^webpack:\/\/[^/]*\/(.*)$/.exec(source);
50
+ if (!match) return null;
51
+ const path = (match[1] ?? "").replace(/[?#].*$/, "");
52
+ return isAbsolute(path) ? path : resolve(projectDir, path);
53
+ }
54
+ async function isFile(path) {
55
+ try {
56
+ return (await stat(path)).isFile();
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ // src/config/index.ts
63
+ var SERVER_PACKAGES = ["@vigilon/nextjs", "@vigilon/node"];
64
+ function withVigilon(config, options = {}) {
65
+ const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;
66
+ const experimental = config.experimental ?? {};
67
+ const wrapped = {
68
+ ...config,
69
+ serverExternalPackages: unique([...config.serverExternalPackages ?? [], ...SERVER_PACKAGES]),
70
+ experimental: {
71
+ ...experimental,
72
+ clientTraceMetadata: unique([...experimental.clientTraceMetadata ?? [], "traceparent"])
73
+ }
74
+ };
75
+ if (uploadToken) {
76
+ const previous = config.compiler?.runAfterProductionCompile;
77
+ wrapped.productionBrowserSourceMaps = true;
78
+ wrapped.compiler = {
79
+ ...config.compiler,
80
+ runAfterProductionCompile: async (metadata) => {
81
+ await previous?.(metadata);
82
+ const staticDir = join2(metadata.distDir, "static");
83
+ try {
84
+ await ignoreSourcesNotOnDisk(staticDir, metadata.projectDir);
85
+ await uploadSourceMaps(staticDir, uploadToken, options);
86
+ } finally {
87
+ await deleteSourceMaps(staticDir);
88
+ }
89
+ }
90
+ };
91
+ }
92
+ return wrapped;
93
+ }
94
+ var run = promisify(execFile);
95
+ async function uploadSourceMaps(staticDir, uploadToken, options) {
96
+ const cli = cliBinPath();
97
+ const env = {
98
+ ...process.env,
99
+ VIGILON_SOURCE_MAP_TOKEN: uploadToken,
100
+ ...options.apiUrl ? { VIGILON_API_URL: options.apiUrl } : {}
101
+ };
102
+ const warnOnly = options.onUploadError === "warn" ? ["--warn-only"] : [];
103
+ for (const args of [
104
+ ["sourcemaps", "inject", staticDir],
105
+ ["sourcemaps", "upload", staticDir, "--delete-after-upload", ...warnOnly]
106
+ ]) {
107
+ try {
108
+ const { stdout, stderr } = await run(process.execPath, [cli, ...args], { env });
109
+ process.stdout.write(stdout);
110
+ process.stderr.write(stderr);
111
+ } catch (error) {
112
+ const { stdout = "", stderr = "" } = error;
113
+ process.stdout.write(stdout);
114
+ process.stderr.write(stderr);
115
+ throw new Error(`Vigilon source map upload failed: vigilon ${args.join(" ")}`);
116
+ }
117
+ }
118
+ }
119
+ async function deleteSourceMaps(dir) {
120
+ const files = await readdir2(dir, { recursive: true });
121
+ await Promise.all(
122
+ files.filter((file) => file.endsWith(".map")).map((file) => rm(join2(dir, file), { force: true }))
123
+ );
124
+ }
125
+ function cliBinPath() {
126
+ const require2 = createRequire(import.meta.url);
127
+ const manifestPath = require2.resolve("@vigilon/cli/package.json");
128
+ const manifest = require2(manifestPath);
129
+ return join2(dirname(manifestPath), manifest.bin.vigilon);
130
+ }
131
+ function unique(values) {
132
+ return [...new Set(values)];
133
+ }
134
+ export {
135
+ uploadSourceMaps,
136
+ withVigilon
137
+ };
138
+ //# sourceMappingURL=config.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config/index.ts","../src/config/ignore-list.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { readdir, rm } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join } from \"node:path\";\nimport { promisify } from \"node:util\";\nimport { ignoreSourcesNotOnDisk } from \"./ignore-list\";\n\nexport interface VigilonNextConfigOptions {\n /**\n * A source map upload token for the project. Falls back to\n * VIGILON_SOURCE_MAP_TOKEN. Without one, source maps are neither built nor\n * uploaded. Never use a project API key here: API keys are public.\n */\n uploadToken?: string;\n /** The Vigilon API. Falls back to VIGILON_API_URL, then https://api.vigilon.io. */\n apiUrl?: string;\n /** What a failed upload does to the build. Defaults to \"error\". */\n onUploadError?: \"error\" | \"warn\";\n}\n\n/** The parts of a Next.js config this wrapper reads and sets. */\nexport interface NextConfigLike {\n serverExternalPackages?: string[];\n productionBrowserSourceMaps?: boolean;\n experimental?: { clientTraceMetadata?: string[]; [key: string]: unknown };\n compiler?: {\n runAfterProductionCompile?: (metadata: { projectDir: string; distDir: string }) => Promise<void>;\n [key: string]: unknown;\n };\n [key: string]: unknown;\n}\n\nconst SERVER_PACKAGES = [\"@vigilon/nextjs\", \"@vigilon/node\"];\n\n/**\n * Wraps a Next.js config for Vigilon:\n *\n * - keeps the SDK and its require-hook based OpenTelemetry dependencies out\n * of the server bundle;\n * - has Next.js render the request's `traceparent` in a meta tag, so browser\n * errors on a server-rendered page link to its server trace;\n * - with an upload token, builds browser source maps and, once Next.js has\n * compiled (Next.js 15.4 or later, with Turbopack or webpack), marks\n * sources that are not the application's own files as library code, gives\n * every script a debug ID, uploads the scripts and their maps, and deletes\n * every map so none is deployed.\n *\n * ```ts\n * export default withVigilon({ reactStrictMode: true });\n * ```\n */\nexport function withVigilon<T extends NextConfigLike>(\n config: T,\n options: VigilonNextConfigOptions = {},\n): T & NextConfigLike {\n const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;\n const experimental = config.experimental ?? {};\n const wrapped: NextConfigLike = {\n ...config,\n serverExternalPackages: unique([...(config.serverExternalPackages ?? []), ...SERVER_PACKAGES]),\n experimental: {\n ...experimental,\n clientTraceMetadata: unique([...(experimental.clientTraceMetadata ?? []), \"traceparent\"]),\n },\n };\n if (uploadToken) {\n const previous = config.compiler?.runAfterProductionCompile;\n wrapped.productionBrowserSourceMaps = true;\n wrapped.compiler = {\n ...config.compiler,\n runAfterProductionCompile: async (metadata) => {\n await previous?.(metadata);\n const staticDir = join(metadata.distDir, \"static\");\n try {\n // Before inject, so each debug ID covers the final map.\n await ignoreSourcesNotOnDisk(staticDir, metadata.projectDir);\n await uploadSourceMaps(staticDir, uploadToken, options);\n } finally {\n // The maps were turned on only for the upload, so none may be\n // deployed: not after a failed upload, which keeps them for a\n // retry, and not the maps of Next.js's own files, which have no\n // sourceMappingURL to pair them with a script.\n await deleteSourceMaps(staticDir);\n }\n },\n };\n }\n return wrapped as T & NextConfigLike;\n}\n\nconst run = promisify(execFile);\n\n/** Runs @vigilon/cli's inject and upload over the browser build output. */\nexport async function uploadSourceMaps(\n staticDir: string,\n uploadToken: string,\n options: VigilonNextConfigOptions,\n): Promise<void> {\n const cli = cliBinPath();\n const env = {\n ...process.env,\n VIGILON_SOURCE_MAP_TOKEN: uploadToken,\n ...(options.apiUrl ? { VIGILON_API_URL: options.apiUrl } : {}),\n };\n const warnOnly = options.onUploadError === \"warn\" ? [\"--warn-only\"] : [];\n for (const args of [\n [\"sourcemaps\", \"inject\", staticDir],\n [\"sourcemaps\", \"upload\", staticDir, \"--delete-after-upload\", ...warnOnly],\n ]) {\n try {\n const { stdout, stderr } = await run(process.execPath, [cli, ...args], { env });\n process.stdout.write(stdout);\n process.stderr.write(stderr);\n } catch (error) {\n // A failed run rejects with its output attached; show it, then fail the\n // build with it.\n const { stdout = \"\", stderr = \"\" } = error as { stdout?: string; stderr?: string };\n process.stdout.write(stdout);\n process.stderr.write(stderr);\n throw new Error(`Vigilon source map upload failed: vigilon ${args.join(\" \")}`);\n }\n }\n}\n\nasync function deleteSourceMaps(dir: string): Promise<void> {\n const files = await readdir(dir, { recursive: true });\n await Promise.all(\n files.filter((file) => file.endsWith(\".map\")).map((file) => rm(join(dir, file), { force: true })),\n );\n}\n\nfunction cliBinPath(): string {\n const require = createRequire(import.meta.url);\n const manifestPath = require.resolve(\"@vigilon/cli/package.json\");\n const manifest = require(manifestPath) as { bin: { vigilon: string } };\n return join(dirname(manifestPath), manifest.bin.vigilon);\n}\n\nfunction unique(values: string[]): string[] {\n return [...new Set(values)];\n}\n","import { readdir, readFile, stat, writeFile } from \"node:fs/promises\";\nimport { isAbsolute, join, resolve } from \"node:path\";\n\ninterface SourceMapSection {\n map: SourceMapLike;\n}\n\ninterface SourceMapLike {\n sources?: (string | null)[];\n ignoreList?: number[];\n x_google_ignoreList?: number[];\n sections?: SourceMapSection[];\n}\n\n/**\n * Adds to each map's `ignoreList` every webpack source that is not a file on\n * disk under the project, so Vigilon reads it as library code. Next.js's\n * webpack build gives Next's own precompiled client code sources such as\n * `webpack://_N_E/../../src/client/add-base-path.ts`, which no path rule can\n * tell from the application's, and leaves them off the list. The\n * application's own sources, including a monorepo package outside the\n * project, are files on disk while it builds.\n *\n * Turbopack sources are left alone: Turbopack lists its framework and runtime\n * sources itself, and its `[project]` root may be a monorepo root rather than\n * the project directory.\n */\nexport async function ignoreSourcesNotOnDisk(staticDir: string, projectDir: string): Promise<void> {\n const files = (await readdir(staticDir, { recursive: true })).filter((file) => file.endsWith(\".map\"));\n await Promise.all(\n files.map(async (file) => {\n const path = join(staticDir, file);\n let map: SourceMapLike;\n try {\n map = JSON.parse(await readFile(path, \"utf8\")) as SourceMapLike;\n } catch {\n return;\n }\n const maps = map.sections ? map.sections.map((section) => section.map) : [map];\n let changed = false;\n for (const part of maps) {\n changed = (await ignoreInMap(part, projectDir)) || changed;\n }\n if (changed) {\n await writeFile(path, JSON.stringify(map));\n }\n }),\n );\n}\n\nasync function ignoreInMap(map: SourceMapLike, projectDir: string): Promise<boolean> {\n const sources = map.sources ?? [];\n const ignored = new Set([...(map.ignoreList ?? []), ...(map.x_google_ignoreList ?? [])]);\n const added: number[] = [];\n await Promise.all(\n sources.map(async (source, index) => {\n if (ignored.has(index) || typeof source !== \"string\") return;\n const path = webpackSourcePath(source, projectDir);\n if (path !== null && !(await isFile(path))) added.push(index);\n }),\n );\n if (added.length === 0) return false;\n // Readers take ignoreList over x_google_ignoreList, so the old entries are\n // merged into it rather than left beside it.\n map.ignoreList = [...ignored, ...added].sort((a, b) => a - b);\n return true;\n}\n\n/**\n * The file a `webpack://<namespace>/<path>` source names, relative to the\n * project (webpack's context), without a query or fragment; null for any\n * other source.\n */\nexport function webpackSourcePath(source: string, projectDir: string): string | null {\n const match = /^webpack:\\/\\/[^/]*\\/(.*)$/.exec(source);\n if (!match) return null;\n const path = (match[1] ?? \"\").replace(/[?#].*$/, \"\");\n return isAbsolute(path) ? path : resolve(projectDir, path);\n}\n\nasync function isFile(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isFile();\n } catch {\n return false;\n }\n}\n"],"mappings":"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","names":["readdir","join","join","readdir","require"]}