@vigilon/nextjs 0.2.16 → 0.2.17-beta.pr-9.11
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 +2 -0
- package/dist/config.cjs +5 -4
- package/dist/config.cjs.map +1 -1
- package/dist/config.d.mts +6 -5
- package/dist/config.d.ts +6 -5
- package/dist/config.mjs +5 -4
- package/dist/config.mjs.map +1 -1
- package/dist/index.cjs +6 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.mjs +6 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -76,6 +76,8 @@ export default function GlobalError({ error }: { error: Error & { digest?: strin
|
|
|
76
76
|
}
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
+
Errors thrown on the server, in a Server Component or a Server Action, reach these boundaries with their message redacted and a `digest`. Next.js already records them on the server, so `useReportError` skips any error that has a `digest` rather than reporting the redacted copy again.
|
|
80
|
+
|
|
79
81
|
`@vigilon/nextjs` re-exports `@vigilon/react`, including `ErrorBoundary` for your own boundaries inside client components.
|
|
80
82
|
|
|
81
83
|
## Source maps
|
package/dist/config.cjs
CHANGED
|
@@ -93,21 +93,22 @@ async function isFile(path) {
|
|
|
93
93
|
// src/config/index.ts
|
|
94
94
|
var SERVER_PACKAGES = ["@vigilon/nextjs", "@vigilon/node"];
|
|
95
95
|
function withVigilon(config, options = {}) {
|
|
96
|
+
const base = config;
|
|
96
97
|
const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;
|
|
97
|
-
const experimental =
|
|
98
|
+
const experimental = base.experimental ?? {};
|
|
98
99
|
const wrapped = {
|
|
99
100
|
...config,
|
|
100
|
-
serverExternalPackages: unique([...
|
|
101
|
+
serverExternalPackages: unique([...base.serverExternalPackages ?? [], ...SERVER_PACKAGES]),
|
|
101
102
|
experimental: {
|
|
102
103
|
...experimental,
|
|
103
104
|
clientTraceMetadata: unique([...experimental.clientTraceMetadata ?? [], "traceparent"])
|
|
104
105
|
}
|
|
105
106
|
};
|
|
106
107
|
if (uploadToken) {
|
|
107
|
-
const previous =
|
|
108
|
+
const previous = base.compiler?.runAfterProductionCompile;
|
|
108
109
|
wrapped.productionBrowserSourceMaps = true;
|
|
109
110
|
wrapped.compiler = {
|
|
110
|
-
...
|
|
111
|
+
...base.compiler,
|
|
111
112
|
runAfterProductionCompile: async (metadata) => {
|
|
112
113
|
await previous?.(metadata);
|
|
113
114
|
const staticDir = (0, import_node_path2.join)(metadata.distDir, "static");
|
package/dist/config.cjs.map
CHANGED
|
@@ -1 +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"]}
|
|
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/**\n * The parts of a Next.js config this wrapper reads and sets. It has no index\n * signatures, so a config typed with Next.js's own `NextConfig` interface\n * stays assignable to it.\n */\nexport interface NextConfigLike {\n serverExternalPackages?: string[];\n productionBrowserSourceMaps?: boolean;\n experimental?: { clientTraceMetadata?: string[] };\n compiler?: {\n runAfterProductionCompile?: (metadata: { projectDir: string; distDir: string }) => Promise<void>;\n };\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 object>(\n config: T,\n options: VigilonNextConfigOptions = {},\n): T & NextConfigLike {\n // T is the app's own config type (Next.js's NextConfig, or a literal),\n // which this package does not import; read the parts it changes.\n const base = config as NextConfigLike;\n const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;\n const experimental = base.experimental ?? {};\n const wrapped: NextConfigLike = {\n ...config,\n serverExternalPackages: unique([...(base.serverExternalPackages ?? []), ...SERVER_PACKAGES]),\n experimental: {\n ...experimental,\n clientTraceMetadata: unique([...(experimental.clientTraceMetadata ?? []), \"traceparent\"]),\n },\n };\n if (uploadToken) {\n const previous = base.compiler?.runAfterProductionCompile;\n wrapped.productionBrowserSourceMaps = true;\n wrapped.compiler = {\n ...base.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"]}
|
package/dist/config.d.mts
CHANGED
|
@@ -10,22 +10,23 @@ interface VigilonNextConfigOptions {
|
|
|
10
10
|
/** What a failed upload does to the build. Defaults to "error". */
|
|
11
11
|
onUploadError?: "error" | "warn";
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The parts of a Next.js config this wrapper reads and sets. It has no index
|
|
15
|
+
* signatures, so a config typed with Next.js's own `NextConfig` interface
|
|
16
|
+
* stays assignable to it.
|
|
17
|
+
*/
|
|
14
18
|
interface NextConfigLike {
|
|
15
19
|
serverExternalPackages?: string[];
|
|
16
20
|
productionBrowserSourceMaps?: boolean;
|
|
17
21
|
experimental?: {
|
|
18
22
|
clientTraceMetadata?: string[];
|
|
19
|
-
[key: string]: unknown;
|
|
20
23
|
};
|
|
21
24
|
compiler?: {
|
|
22
25
|
runAfterProductionCompile?: (metadata: {
|
|
23
26
|
projectDir: string;
|
|
24
27
|
distDir: string;
|
|
25
28
|
}) => Promise<void>;
|
|
26
|
-
[key: string]: unknown;
|
|
27
29
|
};
|
|
28
|
-
[key: string]: unknown;
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* Wraps a Next.js config for Vigilon:
|
|
@@ -44,7 +45,7 @@ interface NextConfigLike {
|
|
|
44
45
|
* export default withVigilon({ reactStrictMode: true });
|
|
45
46
|
* ```
|
|
46
47
|
*/
|
|
47
|
-
declare function withVigilon<T extends
|
|
48
|
+
declare function withVigilon<T extends object>(config: T, options?: VigilonNextConfigOptions): T & NextConfigLike;
|
|
48
49
|
/** Runs @vigilon/cli's inject and upload over the browser build output. */
|
|
49
50
|
declare function uploadSourceMaps(staticDir: string, uploadToken: string, options: VigilonNextConfigOptions): Promise<void>;
|
|
50
51
|
|
package/dist/config.d.ts
CHANGED
|
@@ -10,22 +10,23 @@ interface VigilonNextConfigOptions {
|
|
|
10
10
|
/** What a failed upload does to the build. Defaults to "error". */
|
|
11
11
|
onUploadError?: "error" | "warn";
|
|
12
12
|
}
|
|
13
|
-
/**
|
|
13
|
+
/**
|
|
14
|
+
* The parts of a Next.js config this wrapper reads and sets. It has no index
|
|
15
|
+
* signatures, so a config typed with Next.js's own `NextConfig` interface
|
|
16
|
+
* stays assignable to it.
|
|
17
|
+
*/
|
|
14
18
|
interface NextConfigLike {
|
|
15
19
|
serverExternalPackages?: string[];
|
|
16
20
|
productionBrowserSourceMaps?: boolean;
|
|
17
21
|
experimental?: {
|
|
18
22
|
clientTraceMetadata?: string[];
|
|
19
|
-
[key: string]: unknown;
|
|
20
23
|
};
|
|
21
24
|
compiler?: {
|
|
22
25
|
runAfterProductionCompile?: (metadata: {
|
|
23
26
|
projectDir: string;
|
|
24
27
|
distDir: string;
|
|
25
28
|
}) => Promise<void>;
|
|
26
|
-
[key: string]: unknown;
|
|
27
29
|
};
|
|
28
|
-
[key: string]: unknown;
|
|
29
30
|
}
|
|
30
31
|
/**
|
|
31
32
|
* Wraps a Next.js config for Vigilon:
|
|
@@ -44,7 +45,7 @@ interface NextConfigLike {
|
|
|
44
45
|
* export default withVigilon({ reactStrictMode: true });
|
|
45
46
|
* ```
|
|
46
47
|
*/
|
|
47
|
-
declare function withVigilon<T extends
|
|
48
|
+
declare function withVigilon<T extends object>(config: T, options?: VigilonNextConfigOptions): T & NextConfigLike;
|
|
48
49
|
/** Runs @vigilon/cli's inject and upload over the browser build output. */
|
|
49
50
|
declare function uploadSourceMaps(staticDir: string, uploadToken: string, options: VigilonNextConfigOptions): Promise<void>;
|
|
50
51
|
|
package/dist/config.mjs
CHANGED
|
@@ -62,21 +62,22 @@ async function isFile(path) {
|
|
|
62
62
|
// src/config/index.ts
|
|
63
63
|
var SERVER_PACKAGES = ["@vigilon/nextjs", "@vigilon/node"];
|
|
64
64
|
function withVigilon(config, options = {}) {
|
|
65
|
+
const base = config;
|
|
65
66
|
const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;
|
|
66
|
-
const experimental =
|
|
67
|
+
const experimental = base.experimental ?? {};
|
|
67
68
|
const wrapped = {
|
|
68
69
|
...config,
|
|
69
|
-
serverExternalPackages: unique([...
|
|
70
|
+
serverExternalPackages: unique([...base.serverExternalPackages ?? [], ...SERVER_PACKAGES]),
|
|
70
71
|
experimental: {
|
|
71
72
|
...experimental,
|
|
72
73
|
clientTraceMetadata: unique([...experimental.clientTraceMetadata ?? [], "traceparent"])
|
|
73
74
|
}
|
|
74
75
|
};
|
|
75
76
|
if (uploadToken) {
|
|
76
|
-
const previous =
|
|
77
|
+
const previous = base.compiler?.runAfterProductionCompile;
|
|
77
78
|
wrapped.productionBrowserSourceMaps = true;
|
|
78
79
|
wrapped.compiler = {
|
|
79
|
-
...
|
|
80
|
+
...base.compiler,
|
|
80
81
|
runAfterProductionCompile: async (metadata) => {
|
|
81
82
|
await previous?.(metadata);
|
|
82
83
|
const staticDir = join2(metadata.distDir, "static");
|
package/dist/config.mjs.map
CHANGED
|
@@ -1 +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"]}
|
|
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/**\n * The parts of a Next.js config this wrapper reads and sets. It has no index\n * signatures, so a config typed with Next.js's own `NextConfig` interface\n * stays assignable to it.\n */\nexport interface NextConfigLike {\n serverExternalPackages?: string[];\n productionBrowserSourceMaps?: boolean;\n experimental?: { clientTraceMetadata?: string[] };\n compiler?: {\n runAfterProductionCompile?: (metadata: { projectDir: string; distDir: string }) => Promise<void>;\n };\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 object>(\n config: T,\n options: VigilonNextConfigOptions = {},\n): T & NextConfigLike {\n // T is the app's own config type (Next.js's NextConfig, or a literal),\n // which this package does not import; read the parts it changes.\n const base = config as NextConfigLike;\n const uploadToken = options.uploadToken ?? process.env.VIGILON_SOURCE_MAP_TOKEN;\n const experimental = base.experimental ?? {};\n const wrapped: NextConfigLike = {\n ...config,\n serverExternalPackages: unique([...(base.serverExternalPackages ?? []), ...SERVER_PACKAGES]),\n experimental: {\n ...experimental,\n clientTraceMetadata: unique([...(experimental.clientTraceMetadata ?? []), \"traceparent\"]),\n },\n };\n if (uploadToken) {\n const previous = base.compiler?.runAfterProductionCompile;\n wrapped.productionBrowserSourceMaps = true;\n wrapped.compiler = {\n ...base.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"]}
|
package/dist/index.cjs
CHANGED
|
@@ -73,9 +73,15 @@ var import_react2 = require("@vigilon/react");
|
|
|
73
73
|
var import_react3 = require("react");
|
|
74
74
|
function useReportError(error) {
|
|
75
75
|
(0, import_react3.useEffect)(() => {
|
|
76
|
+
if (isServerError(error)) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
76
79
|
(0, import_react2.captureException)(error, { mechanism: "react_error_boundary", handled: true });
|
|
77
80
|
}, [error]);
|
|
78
81
|
}
|
|
82
|
+
function isServerError(error) {
|
|
83
|
+
return typeof error === "object" && error !== null && typeof error.digest === "string";
|
|
84
|
+
}
|
|
79
85
|
// Annotate the CommonJS export names for ESM import in node:
|
|
80
86
|
0 && (module.exports = {
|
|
81
87
|
init,
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/index.ts","../src/client/init.ts","../src/client/use-report-error.ts"],"sourcesContent":["/**\n * @vigilon/nextjs: the browser half, for instrumentation-client.ts and client\n * components. Re-exports @vigilon/react, with an init() that links events to\n * the server request that rendered the page.\n */\nexport * from \"@vigilon/react\";\nexport { init, linkServerTrace } from \"./init\";\nexport { useReportError } from \"./use-report-error\";\n","import { type BrowserEvent, init as initBrowser, type VigilonBrowserOptions } from \"@vigilon/react\";\n\n/**\n * Starts error monitoring in the browser, as @vigilon/browser's init() does.\n * With `withVigilon()` in next.config, Next.js renders the trace ID of the\n * request that rendered the page in a `traceparent` meta tag; every event\n * captured before the first client-side navigation carries it, so a hydration\n * or early render error links to its server trace.\n */\nexport function init(options: VigilonBrowserOptions): boolean {\n const serverTrace = readServerTrace();\n if (serverTrace === null) {\n return initBrowser(options);\n }\n const { beforeSend } = options;\n return initBrowser({\n ...options,\n beforeSend: (event) => {\n const linked = linkServerTrace(event, serverTrace);\n return beforeSend ? beforeSend(linked) : linked;\n },\n });\n}\n\ninterface ServerTrace {\n traceId: string;\n /** The page URL the server rendered, without its fragment. */\n url: string;\n}\n\nfunction readServerTrace(): ServerTrace | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const content = document.querySelector('meta[name=\"traceparent\"]')?.getAttribute(\"content\");\n // W3C traceparent: version-traceid-parentid-flags.\n const traceId = content?.split(\"-\")[1];\n if (!traceId || !/^[0-9a-f]{32}$/.test(traceId) || /^0+$/.test(traceId)) {\n return null;\n }\n return { traceId, url: withoutFragment(window.location.href) };\n}\n\n/**\n * The trace belongs to the request that rendered the page, so it applies only\n * while the browser is still on that page's URL.\n */\nexport function linkServerTrace(event: BrowserEvent, serverTrace: ServerTrace): BrowserEvent {\n if (event.traceId || withoutFragment(String(event.page.url)) !== serverTrace.url) {\n return event;\n }\n return { ...event, traceId: serverTrace.traceId };\n}\n\nfunction withoutFragment(url: string): string {\n const hash = url.indexOf(\"#\");\n return hash === -1 ? url : url.slice(0, hash);\n}\n","import { captureException } from \"@vigilon/react\";\nimport { useEffect } from \"react\";\n\n/**\n * Reports the error an `error.tsx` or `global-error.tsx` boundary received.\n * Next.js creates the React root itself, so @vigilon/react's\n * rootErrorHandlers cannot be passed to it; this hook reports what those\n * boundaries catch instead.\n *\n * ```tsx\n * \"use client\";\n * export default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n * useReportError(error);\n * return <html><body><h2>Something went wrong.</h2></body></html>;\n * }\n * ```\n */\nexport function useReportError(error: unknown): void {\n useEffect(() => {\n captureException(error, { mechanism: \"react_error_boundary\", handled: true });\n }, [error]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,2BAAc,2BALd;;;ACAA,mBAAmF;AAS5E,SAAS,KAAK,SAAyC;AAC5D,QAAM,cAAc,gBAAgB;AACpC,MAAI,gBAAgB,MAAM;AACxB,eAAO,aAAAA,MAAY,OAAO;AAAA,EAC5B;AACA,QAAM,EAAE,WAAW,IAAI;AACvB,aAAO,aAAAA,MAAY;AAAA,IACjB,GAAG;AAAA,IACH,YAAY,CAAC,UAAU;AACrB,YAAM,SAAS,gBAAgB,OAAO,WAAW;AACjD,aAAO,aAAa,WAAW,MAAM,IAAI;AAAA,IAC3C;AAAA,EACF,CAAC;AACH;AAQA,SAAS,kBAAsC;AA9B/C;AA+BE,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AACA,QAAM,WAAU,cAAS,cAAc,0BAA0B,MAAjD,mBAAoD,aAAa;AAEjF,QAAM,UAAU,mCAAS,MAAM,KAAK;AACpC,MAAI,CAAC,WAAW,CAAC,iBAAiB,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO,EAAE,SAAS,KAAK,gBAAgB,OAAO,SAAS,IAAI,EAAE;AAC/D;AAMO,SAAS,gBAAgB,OAAqB,aAAwC;AAC3F,MAAI,MAAM,WAAW,gBAAgB,OAAO,MAAM,KAAK,GAAG,CAAC,MAAM,YAAY,KAAK;AAChF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,OAAO,SAAS,YAAY,QAAQ;AAClD;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,OAAO,IAAI,QAAQ,GAAG;AAC5B,SAAO,SAAS,KAAK,MAAM,IAAI,MAAM,GAAG,IAAI;AAC9C;;;ACzDA,IAAAC,gBAAiC;AACjC,IAAAA,gBAA0B;
|
|
1
|
+
{"version":3,"sources":["../src/client/index.ts","../src/client/init.ts","../src/client/use-report-error.ts"],"sourcesContent":["/**\n * @vigilon/nextjs: the browser half, for instrumentation-client.ts and client\n * components. Re-exports @vigilon/react, with an init() that links events to\n * the server request that rendered the page.\n */\nexport * from \"@vigilon/react\";\nexport { init, linkServerTrace } from \"./init\";\nexport { useReportError } from \"./use-report-error\";\n","import { type BrowserEvent, init as initBrowser, type VigilonBrowserOptions } from \"@vigilon/react\";\n\n/**\n * Starts error monitoring in the browser, as @vigilon/browser's init() does.\n * With `withVigilon()` in next.config, Next.js renders the trace ID of the\n * request that rendered the page in a `traceparent` meta tag; every event\n * captured before the first client-side navigation carries it, so a hydration\n * or early render error links to its server trace.\n */\nexport function init(options: VigilonBrowserOptions): boolean {\n const serverTrace = readServerTrace();\n if (serverTrace === null) {\n return initBrowser(options);\n }\n const { beforeSend } = options;\n return initBrowser({\n ...options,\n beforeSend: (event) => {\n const linked = linkServerTrace(event, serverTrace);\n return beforeSend ? beforeSend(linked) : linked;\n },\n });\n}\n\ninterface ServerTrace {\n traceId: string;\n /** The page URL the server rendered, without its fragment. */\n url: string;\n}\n\nfunction readServerTrace(): ServerTrace | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const content = document.querySelector('meta[name=\"traceparent\"]')?.getAttribute(\"content\");\n // W3C traceparent: version-traceid-parentid-flags.\n const traceId = content?.split(\"-\")[1];\n if (!traceId || !/^[0-9a-f]{32}$/.test(traceId) || /^0+$/.test(traceId)) {\n return null;\n }\n return { traceId, url: withoutFragment(window.location.href) };\n}\n\n/**\n * The trace belongs to the request that rendered the page, so it applies only\n * while the browser is still on that page's URL.\n */\nexport function linkServerTrace(event: BrowserEvent, serverTrace: ServerTrace): BrowserEvent {\n if (event.traceId || withoutFragment(String(event.page.url)) !== serverTrace.url) {\n return event;\n }\n return { ...event, traceId: serverTrace.traceId };\n}\n\nfunction withoutFragment(url: string): string {\n const hash = url.indexOf(\"#\");\n return hash === -1 ? url : url.slice(0, hash);\n}\n","import { captureException } from \"@vigilon/react\";\nimport { useEffect } from \"react\";\n\n/**\n * Reports the error an `error.tsx` or `global-error.tsx` boundary received.\n * Next.js creates the React root itself, so @vigilon/react's\n * rootErrorHandlers cannot be passed to it; this hook reports what those\n * boundaries catch instead.\n *\n * An error with a `digest` was thrown on the server (a Server Component or\n * Server Action). Next.js records it on the server's request span and hands\n * the browser only a redacted copy, so it is not reported again here.\n *\n * ```tsx\n * \"use client\";\n * export default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n * useReportError(error);\n * return <html><body><h2>Something went wrong.</h2></body></html>;\n * }\n * ```\n */\nexport function useReportError(error: unknown): void {\n useEffect(() => {\n if (isServerError(error)) {\n return;\n }\n captureException(error, { mechanism: \"react_error_boundary\", handled: true });\n }, [error]);\n}\n\nfunction isServerError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n typeof (error as { digest?: unknown }).digest === \"string\"\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,2BAAc,2BALd;;;ACAA,mBAAmF;AAS5E,SAAS,KAAK,SAAyC;AAC5D,QAAM,cAAc,gBAAgB;AACpC,MAAI,gBAAgB,MAAM;AACxB,eAAO,aAAAA,MAAY,OAAO;AAAA,EAC5B;AACA,QAAM,EAAE,WAAW,IAAI;AACvB,aAAO,aAAAA,MAAY;AAAA,IACjB,GAAG;AAAA,IACH,YAAY,CAAC,UAAU;AACrB,YAAM,SAAS,gBAAgB,OAAO,WAAW;AACjD,aAAO,aAAa,WAAW,MAAM,IAAI;AAAA,IAC3C;AAAA,EACF,CAAC;AACH;AAQA,SAAS,kBAAsC;AA9B/C;AA+BE,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AACA,QAAM,WAAU,cAAS,cAAc,0BAA0B,MAAjD,mBAAoD,aAAa;AAEjF,QAAM,UAAU,mCAAS,MAAM,KAAK;AACpC,MAAI,CAAC,WAAW,CAAC,iBAAiB,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO,EAAE,SAAS,KAAK,gBAAgB,OAAO,SAAS,IAAI,EAAE;AAC/D;AAMO,SAAS,gBAAgB,OAAqB,aAAwC;AAC3F,MAAI,MAAM,WAAW,gBAAgB,OAAO,MAAM,KAAK,GAAG,CAAC,MAAM,YAAY,KAAK;AAChF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,OAAO,SAAS,YAAY,QAAQ;AAClD;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,OAAO,IAAI,QAAQ,GAAG;AAC5B,SAAO,SAAS,KAAK,MAAM,IAAI,MAAM,GAAG,IAAI;AAC9C;;;ACzDA,IAAAC,gBAAiC;AACjC,IAAAA,gBAA0B;AAoBnB,SAAS,eAAe,OAAsB;AACnD,+BAAU,MAAM;AACd,QAAI,cAAc,KAAK,GAAG;AACxB;AAAA,IACF;AACA,wCAAiB,OAAO,EAAE,WAAW,wBAAwB,SAAS,KAAK,CAAC;AAAA,EAC9E,GAAG,CAAC,KAAK,CAAC;AACZ;AAEA,SAAS,cAAc,OAAyB;AAC9C,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA+B,WAAW;AAEtD;","names":["initBrowser","import_react"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -26,6 +26,10 @@ declare function linkServerTrace(event: BrowserEvent, serverTrace: ServerTrace):
|
|
|
26
26
|
* rootErrorHandlers cannot be passed to it; this hook reports what those
|
|
27
27
|
* boundaries catch instead.
|
|
28
28
|
*
|
|
29
|
+
* An error with a `digest` was thrown on the server (a Server Component or
|
|
30
|
+
* Server Action). Next.js records it on the server's request span and hands
|
|
31
|
+
* the browser only a redacted copy, so it is not reported again here.
|
|
32
|
+
*
|
|
29
33
|
* ```tsx
|
|
30
34
|
* "use client";
|
|
31
35
|
* export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
|
package/dist/index.d.ts
CHANGED
|
@@ -26,6 +26,10 @@ declare function linkServerTrace(event: BrowserEvent, serverTrace: ServerTrace):
|
|
|
26
26
|
* rootErrorHandlers cannot be passed to it; this hook reports what those
|
|
27
27
|
* boundaries catch instead.
|
|
28
28
|
*
|
|
29
|
+
* An error with a `digest` was thrown on the server (a Server Component or
|
|
30
|
+
* Server Action). Next.js records it on the server's request span and hands
|
|
31
|
+
* the browser only a redacted copy, so it is not reported again here.
|
|
32
|
+
*
|
|
29
33
|
* ```tsx
|
|
30
34
|
* "use client";
|
|
31
35
|
* export default function GlobalError({ error }: { error: Error & { digest?: string } }) {
|
package/dist/index.mjs
CHANGED
|
@@ -47,9 +47,15 @@ import { captureException } from "@vigilon/react";
|
|
|
47
47
|
import { useEffect } from "react";
|
|
48
48
|
function useReportError(error) {
|
|
49
49
|
useEffect(() => {
|
|
50
|
+
if (isServerError(error)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
50
53
|
captureException(error, { mechanism: "react_error_boundary", handled: true });
|
|
51
54
|
}, [error]);
|
|
52
55
|
}
|
|
56
|
+
function isServerError(error) {
|
|
57
|
+
return typeof error === "object" && error !== null && typeof error.digest === "string";
|
|
58
|
+
}
|
|
53
59
|
export {
|
|
54
60
|
init,
|
|
55
61
|
linkServerTrace,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/index.ts","../src/client/init.ts","../src/client/use-report-error.ts"],"sourcesContent":["/**\n * @vigilon/nextjs: the browser half, for instrumentation-client.ts and client\n * components. Re-exports @vigilon/react, with an init() that links events to\n * the server request that rendered the page.\n */\nexport * from \"@vigilon/react\";\nexport { init, linkServerTrace } from \"./init\";\nexport { useReportError } from \"./use-report-error\";\n","import { type BrowserEvent, init as initBrowser, type VigilonBrowserOptions } from \"@vigilon/react\";\n\n/**\n * Starts error monitoring in the browser, as @vigilon/browser's init() does.\n * With `withVigilon()` in next.config, Next.js renders the trace ID of the\n * request that rendered the page in a `traceparent` meta tag; every event\n * captured before the first client-side navigation carries it, so a hydration\n * or early render error links to its server trace.\n */\nexport function init(options: VigilonBrowserOptions): boolean {\n const serverTrace = readServerTrace();\n if (serverTrace === null) {\n return initBrowser(options);\n }\n const { beforeSend } = options;\n return initBrowser({\n ...options,\n beforeSend: (event) => {\n const linked = linkServerTrace(event, serverTrace);\n return beforeSend ? beforeSend(linked) : linked;\n },\n });\n}\n\ninterface ServerTrace {\n traceId: string;\n /** The page URL the server rendered, without its fragment. */\n url: string;\n}\n\nfunction readServerTrace(): ServerTrace | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const content = document.querySelector('meta[name=\"traceparent\"]')?.getAttribute(\"content\");\n // W3C traceparent: version-traceid-parentid-flags.\n const traceId = content?.split(\"-\")[1];\n if (!traceId || !/^[0-9a-f]{32}$/.test(traceId) || /^0+$/.test(traceId)) {\n return null;\n }\n return { traceId, url: withoutFragment(window.location.href) };\n}\n\n/**\n * The trace belongs to the request that rendered the page, so it applies only\n * while the browser is still on that page's URL.\n */\nexport function linkServerTrace(event: BrowserEvent, serverTrace: ServerTrace): BrowserEvent {\n if (event.traceId || withoutFragment(String(event.page.url)) !== serverTrace.url) {\n return event;\n }\n return { ...event, traceId: serverTrace.traceId };\n}\n\nfunction withoutFragment(url: string): string {\n const hash = url.indexOf(\"#\");\n return hash === -1 ? url : url.slice(0, hash);\n}\n","import { captureException } from \"@vigilon/react\";\nimport { useEffect } from \"react\";\n\n/**\n * Reports the error an `error.tsx` or `global-error.tsx` boundary received.\n * Next.js creates the React root itself, so @vigilon/react's\n * rootErrorHandlers cannot be passed to it; this hook reports what those\n * boundaries catch instead.\n *\n * ```tsx\n * \"use client\";\n * export default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n * useReportError(error);\n * return <html><body><h2>Something went wrong.</h2></body></html>;\n * }\n * ```\n */\nexport function useReportError(error: unknown): void {\n useEffect(() => {\n captureException(error, { mechanism: \"react_error_boundary\", handled: true });\n }, [error]);\n}\n"],"mappings":";;;AAKA,cAAc;;;ACLd,SAA4B,QAAQ,mBAA+C;AAS5E,SAAS,KAAK,SAAyC;AAC5D,QAAM,cAAc,gBAAgB;AACpC,MAAI,gBAAgB,MAAM;AACxB,WAAO,YAAY,OAAO;AAAA,EAC5B;AACA,QAAM,EAAE,WAAW,IAAI;AACvB,SAAO,YAAY;AAAA,IACjB,GAAG;AAAA,IACH,YAAY,CAAC,UAAU;AACrB,YAAM,SAAS,gBAAgB,OAAO,WAAW;AACjD,aAAO,aAAa,WAAW,MAAM,IAAI;AAAA,IAC3C;AAAA,EACF,CAAC;AACH;AAQA,SAAS,kBAAsC;AA9B/C;AA+BE,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AACA,QAAM,WAAU,cAAS,cAAc,0BAA0B,MAAjD,mBAAoD,aAAa;AAEjF,QAAM,UAAU,mCAAS,MAAM,KAAK;AACpC,MAAI,CAAC,WAAW,CAAC,iBAAiB,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO,EAAE,SAAS,KAAK,gBAAgB,OAAO,SAAS,IAAI,EAAE;AAC/D;AAMO,SAAS,gBAAgB,OAAqB,aAAwC;AAC3F,MAAI,MAAM,WAAW,gBAAgB,OAAO,MAAM,KAAK,GAAG,CAAC,MAAM,YAAY,KAAK;AAChF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,OAAO,SAAS,YAAY,QAAQ;AAClD;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,OAAO,IAAI,QAAQ,GAAG;AAC5B,SAAO,SAAS,KAAK,MAAM,IAAI,MAAM,GAAG,IAAI;AAC9C;;;ACzDA,SAAS,wBAAwB;AACjC,SAAS,iBAAiB;
|
|
1
|
+
{"version":3,"sources":["../src/client/index.ts","../src/client/init.ts","../src/client/use-report-error.ts"],"sourcesContent":["/**\n * @vigilon/nextjs: the browser half, for instrumentation-client.ts and client\n * components. Re-exports @vigilon/react, with an init() that links events to\n * the server request that rendered the page.\n */\nexport * from \"@vigilon/react\";\nexport { init, linkServerTrace } from \"./init\";\nexport { useReportError } from \"./use-report-error\";\n","import { type BrowserEvent, init as initBrowser, type VigilonBrowserOptions } from \"@vigilon/react\";\n\n/**\n * Starts error monitoring in the browser, as @vigilon/browser's init() does.\n * With `withVigilon()` in next.config, Next.js renders the trace ID of the\n * request that rendered the page in a `traceparent` meta tag; every event\n * captured before the first client-side navigation carries it, so a hydration\n * or early render error links to its server trace.\n */\nexport function init(options: VigilonBrowserOptions): boolean {\n const serverTrace = readServerTrace();\n if (serverTrace === null) {\n return initBrowser(options);\n }\n const { beforeSend } = options;\n return initBrowser({\n ...options,\n beforeSend: (event) => {\n const linked = linkServerTrace(event, serverTrace);\n return beforeSend ? beforeSend(linked) : linked;\n },\n });\n}\n\ninterface ServerTrace {\n traceId: string;\n /** The page URL the server rendered, without its fragment. */\n url: string;\n}\n\nfunction readServerTrace(): ServerTrace | null {\n if (typeof document === \"undefined\") {\n return null;\n }\n const content = document.querySelector('meta[name=\"traceparent\"]')?.getAttribute(\"content\");\n // W3C traceparent: version-traceid-parentid-flags.\n const traceId = content?.split(\"-\")[1];\n if (!traceId || !/^[0-9a-f]{32}$/.test(traceId) || /^0+$/.test(traceId)) {\n return null;\n }\n return { traceId, url: withoutFragment(window.location.href) };\n}\n\n/**\n * The trace belongs to the request that rendered the page, so it applies only\n * while the browser is still on that page's URL.\n */\nexport function linkServerTrace(event: BrowserEvent, serverTrace: ServerTrace): BrowserEvent {\n if (event.traceId || withoutFragment(String(event.page.url)) !== serverTrace.url) {\n return event;\n }\n return { ...event, traceId: serverTrace.traceId };\n}\n\nfunction withoutFragment(url: string): string {\n const hash = url.indexOf(\"#\");\n return hash === -1 ? url : url.slice(0, hash);\n}\n","import { captureException } from \"@vigilon/react\";\nimport { useEffect } from \"react\";\n\n/**\n * Reports the error an `error.tsx` or `global-error.tsx` boundary received.\n * Next.js creates the React root itself, so @vigilon/react's\n * rootErrorHandlers cannot be passed to it; this hook reports what those\n * boundaries catch instead.\n *\n * An error with a `digest` was thrown on the server (a Server Component or\n * Server Action). Next.js records it on the server's request span and hands\n * the browser only a redacted copy, so it is not reported again here.\n *\n * ```tsx\n * \"use client\";\n * export default function GlobalError({ error }: { error: Error & { digest?: string } }) {\n * useReportError(error);\n * return <html><body><h2>Something went wrong.</h2></body></html>;\n * }\n * ```\n */\nexport function useReportError(error: unknown): void {\n useEffect(() => {\n if (isServerError(error)) {\n return;\n }\n captureException(error, { mechanism: \"react_error_boundary\", handled: true });\n }, [error]);\n}\n\nfunction isServerError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n typeof (error as { digest?: unknown }).digest === \"string\"\n );\n}\n"],"mappings":";;;AAKA,cAAc;;;ACLd,SAA4B,QAAQ,mBAA+C;AAS5E,SAAS,KAAK,SAAyC;AAC5D,QAAM,cAAc,gBAAgB;AACpC,MAAI,gBAAgB,MAAM;AACxB,WAAO,YAAY,OAAO;AAAA,EAC5B;AACA,QAAM,EAAE,WAAW,IAAI;AACvB,SAAO,YAAY;AAAA,IACjB,GAAG;AAAA,IACH,YAAY,CAAC,UAAU;AACrB,YAAM,SAAS,gBAAgB,OAAO,WAAW;AACjD,aAAO,aAAa,WAAW,MAAM,IAAI;AAAA,IAC3C;AAAA,EACF,CAAC;AACH;AAQA,SAAS,kBAAsC;AA9B/C;AA+BE,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO;AAAA,EACT;AACA,QAAM,WAAU,cAAS,cAAc,0BAA0B,MAAjD,mBAAoD,aAAa;AAEjF,QAAM,UAAU,mCAAS,MAAM,KAAK;AACpC,MAAI,CAAC,WAAW,CAAC,iBAAiB,KAAK,OAAO,KAAK,OAAO,KAAK,OAAO,GAAG;AACvE,WAAO;AAAA,EACT;AACA,SAAO,EAAE,SAAS,KAAK,gBAAgB,OAAO,SAAS,IAAI,EAAE;AAC/D;AAMO,SAAS,gBAAgB,OAAqB,aAAwC;AAC3F,MAAI,MAAM,WAAW,gBAAgB,OAAO,MAAM,KAAK,GAAG,CAAC,MAAM,YAAY,KAAK;AAChF,WAAO;AAAA,EACT;AACA,SAAO,EAAE,GAAG,OAAO,SAAS,YAAY,QAAQ;AAClD;AAEA,SAAS,gBAAgB,KAAqB;AAC5C,QAAM,OAAO,IAAI,QAAQ,GAAG;AAC5B,SAAO,SAAS,KAAK,MAAM,IAAI,MAAM,GAAG,IAAI;AAC9C;;;ACzDA,SAAS,wBAAwB;AACjC,SAAS,iBAAiB;AAoBnB,SAAS,eAAe,OAAsB;AACnD,YAAU,MAAM;AACd,QAAI,cAAc,KAAK,GAAG;AACxB;AAAA,IACF;AACA,qBAAiB,OAAO,EAAE,WAAW,wBAAwB,SAAS,KAAK,CAAC;AAAA,EAC9E,GAAG,CAAC,KAAK,CAAC;AACZ;AAEA,SAAS,cAAc,OAAyB;AAC9C,SACE,OAAO,UAAU,YACjB,UAAU,QACV,OAAQ,MAA+B,WAAW;AAEtD;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vigilon/nextjs",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.17-beta.pr-9.11",
|
|
4
4
|
"description": "Vigilon monitoring for Next.js applications: server traces and browser errors",
|
|
5
5
|
"license": "ISC",
|
|
6
6
|
"author": "Vigilon",
|
|
@@ -76,9 +76,9 @@
|
|
|
76
76
|
"@opentelemetry/api": "^1.9.1",
|
|
77
77
|
"@opentelemetry/core": "^2.11.0",
|
|
78
78
|
"@opentelemetry/sdk-trace-node": "^2.11.0",
|
|
79
|
-
"@vigilon/
|
|
80
|
-
"@vigilon/
|
|
81
|
-
"@vigilon/
|
|
79
|
+
"@vigilon/cli": "0.2.17-beta.pr-9.11",
|
|
80
|
+
"@vigilon/react": "0.2.17-beta.pr-9.11",
|
|
81
|
+
"@vigilon/node": "0.2.17-beta.pr-9.11"
|
|
82
82
|
},
|
|
83
83
|
"peerDependencies": {
|
|
84
84
|
"react": ">=18.0.0"
|