@interfere/next 8.0.0 → 8.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,9 +19,11 @@
19
19
  </p>
20
20
 
21
21
  <p align="center">
22
- <a href="https://interfere.com/docs">Documentation</a>
22
+ <a href="https://support.interfere.com/docs">Documentation</a>
23
23
  ·
24
- <a href="https://github.com/interfere-inc/interfere/issues/new">Report a Bug</a>
24
+ <a href="https://support.interfere.com/roadmap">Feature Requests</a>
25
+ ·
26
+ <a href="https://support.interfere.com/requests">Report a Bug</a>
25
27
  ·
26
28
  <a href="mailto:support@interfere.com">Get Help</a>
27
29
  </p>
@@ -104,16 +106,26 @@ Link sessions to your authenticated users with `identity.set()`:
104
106
  ```tsx
105
107
  import { useInterfere } from "@interfere/next/provider";
106
108
 
107
- function OnLogin({ user }: { user: { id: string; name: string; email: string } }) {
109
+ function useInterfereIdentity() {
108
110
  const { identity } = useInterfere();
109
111
 
112
+ // Clerk, Auth0, etc.
113
+ const { user } = useAuthProvider();
114
+
110
115
  useEffect(() => {
111
- identity.set({
112
- identifier: user.id,
113
- name: user.name,
114
- email: user.email,
115
- });
116
- }, [user.id]);
116
+ if (user) {
117
+ identity.set({
118
+ identifier: user.id,
119
+ name: user.name,
120
+ email: user.email,
121
+ source: { type: "clerk", name: "Clerk" },
122
+ });
123
+ } else {
124
+ identity.clear();
125
+ }
126
+ }, [user]);
127
+
128
+ return null;
117
129
  }
118
130
  ```
119
131
 
@@ -122,6 +134,7 @@ function OnLogin({ user }: { user: { id: string; name: string; email: string } }
122
134
  | Field | Required | Description |
123
135
  | --- | --- | --- |
124
136
  | `identifier` | Yes | Unique user ID (your internal ID, not email) |
137
+ | `source` | Yes | Auth source: `{ type: "clerk", name: "Clerk" }`, `{ type: "auth0", name: "Auth0" }`, or `{ type: "custom", name: "Your Provider" }` |
125
138
  | `name` | No | Display name |
126
139
  | `email` | No | Email address |
127
140
  | `avatar` | No | Avatar URL |
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAgBiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,UAEN,uBAAA,SAAgC,UAAA;EAC/C,SAAA,GAAY,eAAA;AAAA;AAAA,UAGG,mBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGK,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA;AAAA,UA2Fc,wBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA;AAAA"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config.ts"],"mappings":";;;;UAgBiB,eAAA,SACP,OAAA,CAAQ,IAAA,CAAK,QAAA;AAAA,UAEN,uBAAA,SAAgC,UAAA;EAC/C,SAAA,GAAY,eAAA;AAAA;AAAA,UAGG,mBAAA;EAAA,SACN,MAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,SAAA;AAAA;AAAA,iBAGK,aAAA,CACd,UAAA,GAAY,uBAAA,GACX,UAAA;AAAA,UA6Fc,wBAAA;EAAA,SACN,OAAA;EAAA,SACA,UAAA;AAAA"}
package/dist/config.mjs CHANGED
@@ -10,13 +10,15 @@ import { omitUndefined } from "@interfere/types/util/omit-undefined";
10
10
  function withInterfere(nextConfig = {}) {
11
11
  const { interfere, env: userEnv, webpack, turbopack, compiler, productionBrowserSourceMaps, ...rest } = nextConfig;
12
12
  const config = resolveBuildConfig(interfere);
13
+ const forceEnable = !!process.env["NEXT_PUBLIC_INTERFERE_FORCE_ENABLE"];
13
14
  const build = configureBuild({
14
15
  existingWebpack: webpack,
15
16
  existingTurbopack: turbopack,
16
17
  projectDir: process.cwd(),
17
18
  values: {
18
19
  __INTERFERE_BUILD_ID__: config.buildId,
19
- __INTERFERE_RELEASE_ID__: config.releaseId
20
+ __INTERFERE_RELEASE_ID__: config.releaseId,
21
+ ...forceEnable && { __INTERFERE_FORCE_ENABLE__: true }
20
22
  }
21
23
  });
22
24
  if (config.apiKey !== null && !build.webpack && !build.turbopack) return log.fatal("Missing instrumentation client", ["INTERFERE_API_KEY is set but no instrumentation-client file was found.", "Create an instrumentation-client.ts file in your project root or src/ directory."]);
@@ -72,7 +74,7 @@ async function runBuildReleasePipeline(context, config) {
72
74
  if (!apiKey) return log.fatal("API key not set", [
73
75
  "withInterfere() requires an API key to upload source maps during production builds.",
74
76
  "Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.",
75
- "See: https://interfere.com/docs/nextjs/setup"
77
+ "See: https://support.interfere.com/docs/guides/next-js"
76
78
  ]);
77
79
  if (!buildId) return log.fatal("Build ID missing", ["Could not resolve a build ID from config, environment variables, or git.", "Set INTERFERE_BUILD_ID, or ensure git is available in your build environment."]);
78
80
  const { runBuildPipeline } = await import("./internal/build/pipeline.mjs");
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport {\n releaseDestinationIdEnvKeys,\n releaseSourceIdEnvKeys,\n} from \"@interfere/types/integrations\";\nimport { parseEnvValue, readFirstEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\nimport { omitUndefined } from \"@interfere/types/util/omit-undefined\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { runGitCommand } from \"./internal/build/release/git.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { log } from \"./internal/logger.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport interface NextConfigWithInterfere extends NextConfig {\n interfere?: InterfereConfig;\n}\n\nexport interface ResolvedBuildConfig {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly buildId: string | null;\n readonly releaseId: string | null;\n}\n\nexport function withInterfere(\n nextConfig: NextConfigWithInterfere = {}\n): NextConfig {\n const {\n interfere,\n env: userEnv,\n webpack,\n turbopack,\n compiler,\n productionBrowserSourceMaps,\n ...rest\n } = nextConfig;\n\n const config = resolveBuildConfig(interfere);\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir: process.cwd(),\n values: {\n __INTERFERE_BUILD_ID__: config.buildId,\n __INTERFERE_RELEASE_ID__: config.releaseId,\n },\n });\n\n if (config.apiKey !== null && !build.webpack && !build.turbopack) {\n return log.fatal(\"Missing instrumentation client\", [\n \"INTERFERE_API_KEY is set but no instrumentation-client file was found.\",\n \"Create an instrumentation-client.ts file in your project root or src/ directory.\",\n ]);\n }\n\n const existingHook = (compiler as NextCompilerWithProductionHook | undefined)\n ?.runAfterProductionCompile;\n\n const browserSourceMaps =\n config.apiKey === null ? productionBrowserSourceMaps : true;\n\n return {\n ...rest,\n env: mergeEnvConfig(userEnv, config),\n\n compiler: {\n ...omitUndefined(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n await runBuildReleasePipeline(context, config);\n },\n },\n\n ...omitUndefined({\n productionBrowserSourceMaps: browserSourceMaps,\n turbopack: build.turbopack,\n webpack: build.webpack,\n }),\n };\n}\n\nfunction resolveBuildConfig(interfere?: InterfereConfig): ResolvedBuildConfig {\n const { apiKey, apiUrl } = readInterfereEnv();\n\n const buildId =\n parseEnvValue(interfere?.buildId) ??\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\");\n\n const releaseId =\n parseEnvValue(interfere?.releaseId) ??\n readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ??\n buildId;\n\n return { apiKey: apiKey ?? null, apiUrl, buildId, releaseId };\n}\n\nfunction mergeEnvConfig(\n userEnv: NextConfig[\"env\"] | undefined,\n config: ResolvedBuildConfig\n): Record<string, string | undefined> {\n const merged: Record<string, string> = {};\n\n if (config.buildId !== null) {\n merged[\"NEXT_PUBLIC_INTERFERE_BUILD_ID\"] = config.buildId;\n }\n\n if (config.releaseId !== null) {\n merged[\"NEXT_PUBLIC_INTERFERE_RELEASE_ID\"] = config.releaseId;\n }\n\n return { ...merged, ...userEnv };\n}\n\nexport interface ProductionCompileContext {\n readonly distDir: string;\n readonly projectDir: string;\n}\n\ntype NextCompilerWithProductionHook = NonNullable<NextConfig[\"compiler\"]> & {\n runAfterProductionCompile?: (\n context: ProductionCompileContext\n ) => void | Promise<void>;\n};\n\nfunction isNetworkError(error: unknown): boolean {\n if (error instanceof TypeError) {\n return true;\n }\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return (\n msg.includes(\"econnrefused\") ||\n msg.includes(\"enotfound\") ||\n msg.includes(\"fetch failed\") ||\n msg.includes(\"network\")\n );\n }\n return false;\n}\n\nasync function runBuildReleasePipeline(\n context: ProductionCompileContext,\n config: ResolvedBuildConfig\n): Promise<void> {\n const { apiKey, apiUrl, buildId } = config;\n\n if (!apiKey) {\n return log.fatal(\"API key not set\", [\n \"withInterfere() requires an API key to upload source maps during production builds.\",\n \"Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.\",\n \"See: https://interfere.com/docs/nextjs/setup\",\n ]);\n }\n\n if (!buildId) {\n return log.fatal(\"Build ID missing\", [\n \"Could not resolve a build ID from config, environment variables, or git.\",\n \"Set INTERFERE_BUILD_ID, or ensure git is available in your build environment.\",\n ]);\n }\n\n const { runBuildPipeline } = await import(\"./internal/build/pipeline.js\");\n\n try {\n const result = await runBuildPipeline(context, {\n ...config,\n apiKey,\n buildId,\n });\n\n if (!result.ready) {\n log.warn(\"Skipping\", [\"No source maps found\"]);\n return;\n }\n\n log.info(\"Completed\", [\n `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,\n `Release: ${result.release?.destination.slug ?? \"Unknown\"}`,\n `Build: ${result.buildId}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (apiUrl !== API_URL) {\n const isNetwork = isNetworkError(error);\n\n log.warn(\"Skipping release pipeline\", [\n message,\n isNetwork\n ? `${apiUrl} is unreachable — this is expected during local development.`\n : `${apiUrl} returned an error. Ensure the collector is running and configured correctly.`,\n ]);\n\n return;\n }\n\n log.error(\"Error\", [message]);\n throw error;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.mjs","names":[],"sources":["../src/config.ts"],"sourcesContent":["import { API_URL } from \"@interfere/constants/api\";\nimport {\n releaseDestinationIdEnvKeys,\n releaseSourceIdEnvKeys,\n} from \"@interfere/types/integrations\";\nimport { parseEnvValue, readFirstEnvValue } from \"@interfere/types/sdk/env\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\nimport { omitUndefined } from \"@interfere/types/util/omit-undefined\";\n\nimport type { NextConfig } from \"next\";\n\nimport { configureBuild } from \"./internal/build/configure-build.js\";\nimport { runGitCommand } from \"./internal/build/release/git.js\";\nimport { readInterfereEnv } from \"./internal/env.js\";\nimport { log } from \"./internal/logger.js\";\n\nexport interface InterfereConfig\n extends Partial<Pick<Envelope, \"buildId\" | \"releaseId\">> {}\n\nexport interface NextConfigWithInterfere extends NextConfig {\n interfere?: InterfereConfig;\n}\n\nexport interface ResolvedBuildConfig {\n readonly apiKey: string | null;\n readonly apiUrl: string;\n readonly buildId: string | null;\n readonly releaseId: string | null;\n}\n\nexport function withInterfere(\n nextConfig: NextConfigWithInterfere = {}\n): NextConfig {\n const {\n interfere,\n env: userEnv,\n webpack,\n turbopack,\n compiler,\n productionBrowserSourceMaps,\n ...rest\n } = nextConfig;\n\n const config = resolveBuildConfig(interfere);\n const forceEnable = !!process.env[\"NEXT_PUBLIC_INTERFERE_FORCE_ENABLE\"];\n const build = configureBuild({\n existingWebpack: webpack,\n existingTurbopack: turbopack,\n projectDir: process.cwd(),\n values: {\n __INTERFERE_BUILD_ID__: config.buildId,\n __INTERFERE_RELEASE_ID__: config.releaseId,\n ...(forceEnable && { __INTERFERE_FORCE_ENABLE__: true }),\n },\n });\n\n if (config.apiKey !== null && !build.webpack && !build.turbopack) {\n return log.fatal(\"Missing instrumentation client\", [\n \"INTERFERE_API_KEY is set but no instrumentation-client file was found.\",\n \"Create an instrumentation-client.ts file in your project root or src/ directory.\",\n ]);\n }\n\n const existingHook = (compiler as NextCompilerWithProductionHook | undefined)\n ?.runAfterProductionCompile;\n\n const browserSourceMaps =\n config.apiKey === null ? productionBrowserSourceMaps : true;\n\n return {\n ...rest,\n env: mergeEnvConfig(userEnv, config),\n\n compiler: {\n ...omitUndefined(compiler ?? {}),\n async runAfterProductionCompile(context: ProductionCompileContext) {\n if (existingHook) {\n await existingHook(context);\n }\n\n await runBuildReleasePipeline(context, config);\n },\n },\n\n ...omitUndefined({\n productionBrowserSourceMaps: browserSourceMaps,\n turbopack: build.turbopack,\n webpack: build.webpack,\n }),\n };\n}\n\nfunction resolveBuildConfig(interfere?: InterfereConfig): ResolvedBuildConfig {\n const { apiKey, apiUrl } = readInterfereEnv();\n\n const buildId =\n parseEnvValue(interfere?.buildId) ??\n readFirstEnvValue(process.env, releaseSourceIdEnvKeys) ??\n runGitCommand(\"git rev-parse HEAD\");\n\n const releaseId =\n parseEnvValue(interfere?.releaseId) ??\n readFirstEnvValue(process.env, releaseDestinationIdEnvKeys) ??\n buildId;\n\n return { apiKey: apiKey ?? null, apiUrl, buildId, releaseId };\n}\n\nfunction mergeEnvConfig(\n userEnv: NextConfig[\"env\"] | undefined,\n config: ResolvedBuildConfig\n): Record<string, string | undefined> {\n const merged: Record<string, string> = {};\n\n if (config.buildId !== null) {\n merged[\"NEXT_PUBLIC_INTERFERE_BUILD_ID\"] = config.buildId;\n }\n\n if (config.releaseId !== null) {\n merged[\"NEXT_PUBLIC_INTERFERE_RELEASE_ID\"] = config.releaseId;\n }\n\n return { ...merged, ...userEnv };\n}\n\nexport interface ProductionCompileContext {\n readonly distDir: string;\n readonly projectDir: string;\n}\n\ntype NextCompilerWithProductionHook = NonNullable<NextConfig[\"compiler\"]> & {\n runAfterProductionCompile?: (\n context: ProductionCompileContext\n ) => void | Promise<void>;\n};\n\nfunction isNetworkError(error: unknown): boolean {\n if (error instanceof TypeError) {\n return true;\n }\n if (error instanceof Error) {\n const msg = error.message.toLowerCase();\n return (\n msg.includes(\"econnrefused\") ||\n msg.includes(\"enotfound\") ||\n msg.includes(\"fetch failed\") ||\n msg.includes(\"network\")\n );\n }\n return false;\n}\n\nasync function runBuildReleasePipeline(\n context: ProductionCompileContext,\n config: ResolvedBuildConfig\n): Promise<void> {\n const { apiKey, apiUrl, buildId } = config;\n\n if (!apiKey) {\n return log.fatal(\"API key not set\", [\n \"withInterfere() requires an API key to upload source maps during production builds.\",\n \"Set the INTERFERE_API_KEY environment variable, or remove withInterfere() from your Next.js config.\",\n \"See: https://support.interfere.com/docs/guides/next-js\",\n ]);\n }\n\n if (!buildId) {\n return log.fatal(\"Build ID missing\", [\n \"Could not resolve a build ID from config, environment variables, or git.\",\n \"Set INTERFERE_BUILD_ID, or ensure git is available in your build environment.\",\n ]);\n }\n\n const { runBuildPipeline } = await import(\"./internal/build/pipeline.js\");\n\n try {\n const result = await runBuildPipeline(context, {\n ...config,\n apiKey,\n buildId,\n });\n\n if (!result.ready) {\n log.warn(\"Skipping\", [\"No source maps found\"]);\n return;\n }\n\n log.info(\"Completed\", [\n `https://interfere.com/~/${result.config?.org.slug}/surfaces/${result.config?.surface.slug}`,\n `Release: ${result.release?.destination.slug ?? \"Unknown\"}`,\n `Build: ${result.buildId}`,\n `Artifacts: ${result.fileCount} source maps`,\n ]);\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n if (apiUrl !== API_URL) {\n const isNetwork = isNetworkError(error);\n\n log.warn(\"Skipping release pipeline\", [\n message,\n isNetwork\n ? `${apiUrl} is unreachable — this is expected during local development.`\n : `${apiUrl} returned an error. Ensure the collector is running and configured correctly.`,\n ]);\n\n return;\n }\n\n log.error(\"Error\", [message]);\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -4,6 +4,7 @@ import { NextConfig } from "next";
4
4
  interface InterfereInjectedValues {
5
5
  readonly __INTERFERE_BUILD_ID__: string | null;
6
6
  readonly __INTERFERE_RELEASE_ID__: string | null;
7
+ readonly __INTERFERE_FORCE_ENABLE__?: boolean;
7
8
  }
8
9
  interface ConfigureBuildInput {
9
10
  readonly existingWebpack: NextConfig["webpack"] | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"configure-build.d.mts","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"mappings":";;;UAKiB,uBAAA;EAAA,SACN,sBAAA;EAAA,SACA,wBAAA;AAAA;AAAA,UAqBD,mBAAA;EAAA,SACC,eAAA,EAAiB,UAAA;EAAA,SACjB,iBAAA,EAAmB,UAAA;EAAA,SACnB,UAAA;EAAA,SACA,MAAA,EAAQ,uBAAA;AAAA;AAAA,UAGT,oBAAA;EAAA,SACC,OAAA,EAAS,UAAA;EAAA,SACT,SAAA,EAAW,UAAA;AAAA;AAAA,iBAGN,cAAA,CAAA;EACd,eAAA;EACA,iBAAA;EACA,UAAA;EACA;AAAA,GACC,mBAAA,GAAsB,oBAAA"}
1
+ {"version":3,"file":"configure-build.d.mts","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"mappings":";;;UAKiB,uBAAA;EAAA,SACN,sBAAA;EAAA,SACA,wBAAA;EAAA,SACA,0BAAA;AAAA;AAAA,UAqBD,mBAAA;EAAA,SACC,eAAA,EAAiB,UAAA;EAAA,SACjB,iBAAA,EAAmB,UAAA;EAAA,SACnB,UAAA;EAAA,SACA,MAAA,EAAQ,uBAAA;AAAA;AAAA,UAGT,oBAAA;EAAA,SACC,OAAA,EAAS,UAAA;EAAA,SACT,SAAA,EAAW,UAAA;AAAA;AAAA,iBAGN,cAAA,CAAA;EACd,eAAA;EACA,iBAAA;EACA,UAAA;EACA;AAAA,GACC,mBAAA,GAAsB,oBAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"configure-build.mjs","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, dirname, join, normalize, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NextConfig } from \"next\";\n\nexport interface InterfereInjectedValues {\n readonly __INTERFERE_BUILD_ID__: string | null;\n readonly __INTERFERE_RELEASE_ID__: string | null;\n}\n\nconst INSTRUMENTATION_CLIENT_FILES = [\n \"instrumentation-client.ts\",\n \"instrumentation-client.tsx\",\n \"instrumentation-client.js\",\n \"instrumentation-client.jsx\",\n \"src/instrumentation-client.ts\",\n \"src/instrumentation-client.tsx\",\n \"src/instrumentation-client.js\",\n \"src/instrumentation-client.jsx\",\n] as const;\n\nconst LOADER_FILE_CANDIDATES = [\n \"value-injection-loader.ts\",\n \"value-injection-loader.js\",\n \"value-injection-loader.mjs\",\n \"value-injection-loader.cjs\",\n] as const;\n\ninterface ConfigureBuildInput {\n readonly existingWebpack: NextConfig[\"webpack\"] | undefined;\n readonly existingTurbopack: NextConfig[\"turbopack\"] | undefined;\n readonly projectDir: string;\n readonly values: InterfereInjectedValues;\n}\n\ninterface ConfigureBuildOutput {\n readonly webpack: NextConfig[\"webpack\"] | undefined;\n readonly turbopack: NextConfig[\"turbopack\"] | undefined;\n}\n\nexport function configureBuild({\n existingWebpack,\n existingTurbopack,\n projectDir,\n values,\n}: ConfigureBuildInput): ConfigureBuildOutput {\n const instrumentationClientPath = resolveInstrumentationClientPath(projectDir);\n\n return {\n webpack: buildWebpackHook(existingWebpack, instrumentationClientPath, values),\n turbopack: buildTurbopackConfig(\n existingTurbopack,\n instrumentationClientPath,\n values\n ),\n };\n}\n\nfunction hasInjectedMetadata(metadata: InterfereInjectedValues): boolean {\n return (\n metadata.__INTERFERE_BUILD_ID__ !== null ||\n metadata.__INTERFERE_RELEASE_ID__ !== null\n );\n}\n\nfunction buildWebpackHook(\n existingWebpack: NextConfig[\"webpack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"webpack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingWebpack;\n }\n\n const normalizedPath = normalize(instrumentationClientPath);\n const loaderPath = resolveLoaderPath();\n\n return (webpackConfig, options) => {\n const outputConfig = existingWebpack\n ? existingWebpack(webpackConfig, options)\n : webpackConfig;\n const mutableConfig = outputConfig as {\n module?: { rules?: unknown[] };\n };\n\n const injectionRule = {\n test: (resource: string): boolean =>\n Boolean(resource) && normalize(resource) === normalizedPath,\n use: [\n {\n loader: loaderPath,\n options: { values },\n },\n ],\n };\n\n mutableConfig.module ??= {};\n mutableConfig.module.rules ??= [];\n mutableConfig.module.rules.push(injectionRule);\n\n return outputConfig;\n };\n}\n\nfunction buildTurbopackConfig(\n existingTurbopack: NextConfig[\"turbopack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"turbopack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingTurbopack;\n }\n\n const baseConfig = (existingTurbopack ?? {}) as {\n rules?: Record<string, unknown>;\n };\n const ruleKey = `**/${basename(instrumentationClientPath)}`;\n const existingRule = (baseConfig.rules?.[ruleKey] ?? {}) as {\n loaders?: unknown[];\n };\n const existingLoaders = Array.isArray(existingRule.loaders)\n ? existingRule.loaders\n : [];\n\n return {\n ...baseConfig,\n rules: {\n ...baseConfig.rules,\n [ruleKey]: {\n ...existingRule,\n loaders: [\n ...existingLoaders,\n {\n loader: resolveLoaderPath(),\n options: {\n serializedValues: JSON.stringify(values),\n },\n },\n ],\n },\n },\n } as NextConfig[\"turbopack\"];\n}\n\nfunction resolveInstrumentationClientPath(projectDir: string): string | null {\n for (const candidate of INSTRUMENTATION_CLIENT_FILES) {\n const filePath = resolve(projectDir, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n}\n\nfunction resolveLoaderPath(): string {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)));\n\n for (const candidate of LOADER_FILE_CANDIDATES) {\n const filePath = join(directory, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return join(directory, \"value-injection-loader.js\");\n}\n"],"mappings":";;;;AAUA,MAAM,+BAA+B;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACD;AAcD,SAAgB,eAAe,EAC7B,iBACA,mBACA,YACA,UAC4C;CAC5C,MAAM,4BAA4B,iCAAiC,WAAW;AAE9E,QAAO;EACL,SAAS,iBAAiB,iBAAiB,2BAA2B,OAAO;EAC7E,WAAW,qBACT,mBACA,2BACA,OACD;EACF;;AAGH,SAAS,oBAAoB,UAA4C;AACvE,QACE,SAAS,2BAA2B,QACpC,SAAS,6BAA6B;;AAI1C,SAAS,iBACP,iBACA,2BACA,QACmC;AACnC,KAAI,EAAE,6BAA6B,oBAAoB,OAAO,EAC5D,QAAO;CAGT,MAAM,iBAAiB,UAAU,0BAA0B;CAC3D,MAAM,aAAa,mBAAmB;AAEtC,SAAQ,eAAe,YAAY;EACjC,MAAM,eAAe,kBACjB,gBAAgB,eAAe,QAAQ,GACvC;EACJ,MAAM,gBAAgB;EAItB,MAAM,gBAAgB;GACpB,OAAO,aACL,QAAQ,SAAS,IAAI,UAAU,SAAS,KAAK;GAC/C,KAAK,CACH;IACE,QAAQ;IACR,SAAS,EAAE,QAAQ;IACpB,CACF;GACF;AAED,gBAAc,WAAW,EAAE;AAC3B,gBAAc,OAAO,UAAU,EAAE;AACjC,gBAAc,OAAO,MAAM,KAAK,cAAc;AAE9C,SAAO;;;AAIX,SAAS,qBACP,mBACA,2BACA,QACqC;AACrC,KAAI,EAAE,6BAA6B,oBAAoB,OAAO,EAC5D,QAAO;CAGT,MAAM,aAAc,qBAAqB,EAAE;CAG3C,MAAM,UAAU,MAAM,SAAS,0BAA0B;CACzD,MAAM,eAAgB,WAAW,QAAQ,YAAY,EAAE;CAGvD,MAAM,kBAAkB,MAAM,QAAQ,aAAa,QAAQ,GACvD,aAAa,UACb,EAAE;AAEN,QAAO;EACL,GAAG;EACH,OAAO;GACL,GAAG,WAAW;IACb,UAAU;IACT,GAAG;IACH,SAAS,CACP,GAAG,iBACH;KACE,QAAQ,mBAAmB;KAC3B,SAAS,EACP,kBAAkB,KAAK,UAAU,OAAO,EACzC;KACF,CACF;IACF;GACF;EACF;;AAGH,SAAS,iCAAiC,YAAmC;AAC3E,MAAK,MAAM,aAAa,8BAA8B;EACpD,MAAM,WAAW,QAAQ,YAAY,UAAU;AAC/C,MAAI,WAAW,SAAS,CACtB,QAAO;;AAIX,QAAO;;AAGT,SAAS,oBAA4B;CACnC,MAAM,YAAY,QAAQ,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,CAAC;AAElE,MAAK,MAAM,aAAa,wBAAwB;EAC9C,MAAM,WAAW,KAAK,WAAW,UAAU;AAC3C,MAAI,WAAW,SAAS,CACtB,QAAO;;AAIX,QAAO,KAAK,WAAW,4BAA4B"}
1
+ {"version":3,"file":"configure-build.mjs","names":[],"sources":["../../../src/internal/build/configure-build.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { basename, dirname, join, normalize, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport type { NextConfig } from \"next\";\n\nexport interface InterfereInjectedValues {\n readonly __INTERFERE_BUILD_ID__: string | null;\n readonly __INTERFERE_RELEASE_ID__: string | null;\n readonly __INTERFERE_FORCE_ENABLE__?: boolean;\n}\n\nconst INSTRUMENTATION_CLIENT_FILES = [\n \"instrumentation-client.ts\",\n \"instrumentation-client.tsx\",\n \"instrumentation-client.js\",\n \"instrumentation-client.jsx\",\n \"src/instrumentation-client.ts\",\n \"src/instrumentation-client.tsx\",\n \"src/instrumentation-client.js\",\n \"src/instrumentation-client.jsx\",\n] as const;\n\nconst LOADER_FILE_CANDIDATES = [\n \"value-injection-loader.ts\",\n \"value-injection-loader.js\",\n \"value-injection-loader.mjs\",\n \"value-injection-loader.cjs\",\n] as const;\n\ninterface ConfigureBuildInput {\n readonly existingWebpack: NextConfig[\"webpack\"] | undefined;\n readonly existingTurbopack: NextConfig[\"turbopack\"] | undefined;\n readonly projectDir: string;\n readonly values: InterfereInjectedValues;\n}\n\ninterface ConfigureBuildOutput {\n readonly webpack: NextConfig[\"webpack\"] | undefined;\n readonly turbopack: NextConfig[\"turbopack\"] | undefined;\n}\n\nexport function configureBuild({\n existingWebpack,\n existingTurbopack,\n projectDir,\n values,\n}: ConfigureBuildInput): ConfigureBuildOutput {\n const instrumentationClientPath = resolveInstrumentationClientPath(projectDir);\n\n return {\n webpack: buildWebpackHook(existingWebpack, instrumentationClientPath, values),\n turbopack: buildTurbopackConfig(\n existingTurbopack,\n instrumentationClientPath,\n values\n ),\n };\n}\n\nfunction hasInjectedMetadata(metadata: InterfereInjectedValues): boolean {\n return (\n metadata.__INTERFERE_BUILD_ID__ !== null ||\n metadata.__INTERFERE_RELEASE_ID__ !== null\n );\n}\n\nfunction buildWebpackHook(\n existingWebpack: NextConfig[\"webpack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"webpack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingWebpack;\n }\n\n const normalizedPath = normalize(instrumentationClientPath);\n const loaderPath = resolveLoaderPath();\n\n return (webpackConfig, options) => {\n const outputConfig = existingWebpack\n ? existingWebpack(webpackConfig, options)\n : webpackConfig;\n const mutableConfig = outputConfig as {\n module?: { rules?: unknown[] };\n };\n\n const injectionRule = {\n test: (resource: string): boolean =>\n Boolean(resource) && normalize(resource) === normalizedPath,\n use: [\n {\n loader: loaderPath,\n options: { values },\n },\n ],\n };\n\n mutableConfig.module ??= {};\n mutableConfig.module.rules ??= [];\n mutableConfig.module.rules.push(injectionRule);\n\n return outputConfig;\n };\n}\n\nfunction buildTurbopackConfig(\n existingTurbopack: NextConfig[\"turbopack\"] | undefined,\n instrumentationClientPath: string | null,\n values: InterfereInjectedValues\n): NextConfig[\"turbopack\"] | undefined {\n if (!(instrumentationClientPath && hasInjectedMetadata(values))) {\n return existingTurbopack;\n }\n\n const baseConfig = (existingTurbopack ?? {}) as {\n rules?: Record<string, unknown>;\n };\n const ruleKey = `**/${basename(instrumentationClientPath)}`;\n const existingRule = (baseConfig.rules?.[ruleKey] ?? {}) as {\n loaders?: unknown[];\n };\n const existingLoaders = Array.isArray(existingRule.loaders)\n ? existingRule.loaders\n : [];\n\n return {\n ...baseConfig,\n rules: {\n ...baseConfig.rules,\n [ruleKey]: {\n ...existingRule,\n loaders: [\n ...existingLoaders,\n {\n loader: resolveLoaderPath(),\n options: {\n serializedValues: JSON.stringify(values),\n },\n },\n ],\n },\n },\n } as NextConfig[\"turbopack\"];\n}\n\nfunction resolveInstrumentationClientPath(projectDir: string): string | null {\n for (const candidate of INSTRUMENTATION_CLIENT_FILES) {\n const filePath = resolve(projectDir, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return null;\n}\n\nfunction resolveLoaderPath(): string {\n const directory = resolve(dirname(fileURLToPath(import.meta.url)));\n\n for (const candidate of LOADER_FILE_CANDIDATES) {\n const filePath = join(directory, candidate);\n if (existsSync(filePath)) {\n return filePath;\n }\n }\n\n return join(directory, \"value-injection-loader.js\");\n}\n"],"mappings":";;;;AAWA,MAAM,+BAA+B;CACnC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,yBAAyB;CAC7B;CACA;CACA;CACA;CACD;AAcD,SAAgB,eAAe,EAC7B,iBACA,mBACA,YACA,UAC4C;CAC5C,MAAM,4BAA4B,iCAAiC,WAAW;AAE9E,QAAO;EACL,SAAS,iBAAiB,iBAAiB,2BAA2B,OAAO;EAC7E,WAAW,qBACT,mBACA,2BACA,OACD;EACF;;AAGH,SAAS,oBAAoB,UAA4C;AACvE,QACE,SAAS,2BAA2B,QACpC,SAAS,6BAA6B;;AAI1C,SAAS,iBACP,iBACA,2BACA,QACmC;AACnC,KAAI,EAAE,6BAA6B,oBAAoB,OAAO,EAC5D,QAAO;CAGT,MAAM,iBAAiB,UAAU,0BAA0B;CAC3D,MAAM,aAAa,mBAAmB;AAEtC,SAAQ,eAAe,YAAY;EACjC,MAAM,eAAe,kBACjB,gBAAgB,eAAe,QAAQ,GACvC;EACJ,MAAM,gBAAgB;EAItB,MAAM,gBAAgB;GACpB,OAAO,aACL,QAAQ,SAAS,IAAI,UAAU,SAAS,KAAK;GAC/C,KAAK,CACH;IACE,QAAQ;IACR,SAAS,EAAE,QAAQ;IACpB,CACF;GACF;AAED,gBAAc,WAAW,EAAE;AAC3B,gBAAc,OAAO,UAAU,EAAE;AACjC,gBAAc,OAAO,MAAM,KAAK,cAAc;AAE9C,SAAO;;;AAIX,SAAS,qBACP,mBACA,2BACA,QACqC;AACrC,KAAI,EAAE,6BAA6B,oBAAoB,OAAO,EAC5D,QAAO;CAGT,MAAM,aAAc,qBAAqB,EAAE;CAG3C,MAAM,UAAU,MAAM,SAAS,0BAA0B;CACzD,MAAM,eAAgB,WAAW,QAAQ,YAAY,EAAE;CAGvD,MAAM,kBAAkB,MAAM,QAAQ,aAAa,QAAQ,GACvD,aAAa,UACb,EAAE;AAEN,QAAO;EACL,GAAG;EACH,OAAO;GACL,GAAG,WAAW;IACb,UAAU;IACT,GAAG;IACH,SAAS,CACP,GAAG,iBACH;KACE,QAAQ,mBAAmB;KAC3B,SAAS,EACP,kBAAkB,KAAK,UAAU,OAAO,EACzC;KACF,CACF;IACF;GACF;EACF;;AAGH,SAAS,iCAAiC,YAAmC;AAC3E,MAAK,MAAM,aAAa,8BAA8B;EACpD,MAAM,WAAW,QAAQ,YAAY,UAAU;AAC/C,MAAI,WAAW,SAAS,CACtB,QAAO;;AAIX,QAAO;;AAGT,SAAS,oBAA4B;CACnC,MAAM,YAAY,QAAQ,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC,CAAC;AAElE,MAAK,MAAM,aAAa,wBAAwB;EAC9C,MAAM,WAAW,KAAK,WAAW,UAAU;AAC3C,MAAI,WAAW,SAAS,CACtB,QAAO;;AAIX,QAAO,KAAK,WAAW,4BAA4B"}
@@ -1,5 +1,5 @@
1
1
  import { ProductionCompileContext, ResolvedBuildConfig } from "../../config.mjs";
2
- import * as _interfere_sdk_models_releases_create_release_response_js0 from "@interfere/sdk/models/releases-create-release-response.js";
2
+ import * as _$_interfere_sdk_models_releases_create_release_response_js0 from "@interfere/sdk/models/releases-create-release-response.js";
3
3
  import { ReleasesConfigResponse } from "@interfere/sdk/models/releases-config-response.js";
4
4
  import { CreateReleaseResponse } from "@interfere/types/releases/definition";
5
5
 
@@ -37,13 +37,13 @@ declare function runBuildPipeline(context: ProductionCompileContext, metadata: R
37
37
  buildId?: never;
38
38
  timing?: never;
39
39
  } | {
40
+ reason?: never;
40
41
  ready: true;
41
42
  fileCount: number;
42
- release: _interfere_sdk_models_releases_create_release_response_js0.ReleasesCreateReleaseResponse;
43
+ release: _$_interfere_sdk_models_releases_create_release_response_js0.ReleasesCreateReleaseResponse;
43
44
  config: ReleasesConfigResponse;
44
45
  buildId: string;
45
46
  timing: BuildTiming;
46
- reason?: never;
47
47
  }>;
48
48
  //#endregion
49
49
  export { BuildTiming, PipelineResult, runBuildPipeline };
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;UAaiB,WAAA;EACf,QAAA;EACA,aAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,KAGU,cAAA;EACN,KAAA;EAAc,MAAA;EAA0B,SAAA;AAAA;EACxC,KAAA;EAAa,SAAA;EAAmB,OAAA,EAAS,qBAAA;EAAuB,MAAA,EAAQ,sBAAA;EAAwB,OAAA;EAAiB,MAAA,EAAQ,WAAA;AAAA;AAAA,iBAYzG,gBAAA,CACpB,OAAA,EAAS,wBAAA,EACT,QAAA,EAAU,mBAAA;EAAwB,MAAA;EAAgB,OAAA;AAAA,IAAiB,OAAA;;;;;;;;;;;WAAtC,0DAAA,CAAA,6BAAA"}
1
+ {"version":3,"file":"pipeline.d.mts","names":[],"sources":["../../../src/internal/build/pipeline.ts"],"mappings":";;;;;;UAaiB,WAAA;EACf,QAAA;EACA,aAAA;EACA,MAAA;EACA,OAAA;EACA,KAAA;EACA,SAAA;EACA,UAAA;AAAA;AAAA,KAGU,cAAA;EACN,KAAA;EAAc,MAAA;EAA0B,SAAA;AAAA;EACxC,KAAA;EAAa,SAAA;EAAmB,OAAA,EAAS,qBAAA;EAAuB,MAAA,EAAQ,sBAAA;EAAwB,OAAA;EAAiB,MAAA,EAAQ,WAAA;AAAA;AAAA,iBAYzG,gBAAA,CACpB,OAAA,EAAS,wBAAA,EACT,QAAA,EAAU,mBAAA;EAAwB,MAAA;EAAgB,OAAA;AAAA,IAAiB,OAAA;;;;;;;;;;;;WAAtC,4DAAA,CAAA,6BAAA"}
@@ -4,7 +4,11 @@ type SourceMapFile = {
4
4
  readonly path: string;
5
5
  readonly content: string;
6
6
  readonly hash: string;
7
+ readonly debugId: string;
7
8
  };
9
+ declare function buildDebugIdSnippet(debugId: string): string;
10
+ declare function injectDebugIdIntoJs(content: string, debugId: string): string;
11
+ declare function injectDebugIdIntoMap(content: string, debugId: string): string;
8
12
  declare function discover(projectDir: string, distDir: string): Promise<{
9
13
  files: SourceMapFile[];
10
14
  mapping: Record<string, string>;
@@ -12,4 +16,4 @@ declare function discover(projectDir: string, distDir: string): Promise<{
12
16
  }>;
13
17
  declare function normalizeDistDir(distDir?: string): string;
14
18
  //#endregion
15
- export { SourceMapFile, discover, normalizeDistDir };
19
+ export { SourceMapFile, buildDebugIdSnippet, discover, injectDebugIdIntoJs, injectDebugIdIntoMap, normalizeDistDir };
@@ -1 +1 @@
1
- {"version":3,"file":"discover.d.mts","names":[],"sources":["../../../../src/internal/build/source-maps/discover.ts"],"mappings":";KAMY,aAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;AAAA;AAAA,iBAgBW,QAAA,CAAS,UAAA,UAAoB,OAAA,WAAe,OAAA;;;;;iBAsDlD,gBAAA,CAAiB,OAAA"}
1
+ {"version":3,"file":"discover.d.mts","names":[],"sources":["../../../../src/internal/build/source-maps/discover.ts"],"mappings":";KAMY,aAAA;EAAA,SACD,QAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA;EAAA,SACA,IAAA;EAAA,SACA,OAAA;AAAA;AAAA,iBAgBK,mBAAA,CAAoB,OAAA;AAAA,iBAIpB,mBAAA,CAAoB,OAAA,UAAiB,OAAA;AAAA,iBAcrC,oBAAA,CAAqB,OAAA,UAAiB,OAAA;AAAA,iBAShC,QAAA,CAAS,UAAA,UAAoB,OAAA,WAAe,OAAA;;;;;iBAqElD,gBAAA,CAAiB,OAAA"}
@@ -1,6 +1,6 @@
1
1
  import { isAbsolute, join, relative, resolve } from "node:path";
2
- import { readFile, readdir } from "node:fs/promises";
3
- import { createHash } from "node:crypto";
2
+ import { readFile, readdir, writeFile } from "node:fs/promises";
3
+ import { createHash, randomUUID } from "node:crypto";
4
4
  //#region src/internal/build/source-maps/discover.ts
5
5
  const SOURCEMAPPING_RE = /\/\/[#@]\s*sourceMappingURL=(\S+)\s*$/;
6
6
  function resolveDistDir(projectDir, distDir) {
@@ -9,6 +9,22 @@ function resolveDistDir(projectDir, distDir) {
9
9
  async function findJsFiles(dir) {
10
10
  return (await readdir(dir, { recursive: true }).catch(() => [])).filter((entry) => entry.endsWith(".js")).map((entry) => join(dir, entry));
11
11
  }
12
+ function buildDebugIdSnippet(debugId) {
13
+ return `!function(){try{var s=(new Error).stack;s&&(globalThis._debugIds=globalThis._debugIds||{},globalThis._debugIds[s]="${debugId}")}catch(e){}}();`;
14
+ }
15
+ function injectDebugIdIntoJs(content, debugId) {
16
+ const snippet = buildDebugIdSnippet(debugId);
17
+ const debugIdComment = `//# debugId=${debugId}`;
18
+ const match = SOURCEMAPPING_RE.exec(content);
19
+ if (match) return `${snippet}\n${content.slice(0, match.index).trimEnd()}\n${debugIdComment}\n${match[0]}`;
20
+ return `${snippet}\n${content}\n${debugIdComment}`;
21
+ }
22
+ function injectDebugIdIntoMap(content, debugId) {
23
+ const json = JSON.parse(content);
24
+ json["debugId"] = debugId;
25
+ if (typeof json["mappings"] === "string") json["mappings"] = `;${json["mappings"]}`;
26
+ return JSON.stringify(json);
27
+ }
12
28
  async function discover(projectDir, distDir) {
13
29
  const absDistDir = resolveDistDir(projectDir, distDir);
14
30
  const relDistDir = relative(projectDir, absDistDir);
@@ -16,6 +32,7 @@ async function discover(projectDir, distDir) {
16
32
  const jsPaths = [...staticFiles, ...serverFiles];
17
33
  const mapping = {};
18
34
  const mapAbsolutes = /* @__PURE__ */ new Map();
35
+ const jsAbsolutes = /* @__PURE__ */ new Map();
19
36
  for (const jsAbs of jsPaths) {
20
37
  const content = await readFile(jsAbs, "utf8");
21
38
  const match = SOURCEMAPPING_RE.exec(content);
@@ -25,15 +42,23 @@ async function discover(projectDir, distDir) {
25
42
  const mapPublic = toPublicPath(relative(projectDir, mapAbs), relDistDir);
26
43
  mapping[mapPublic] = jsPublic;
27
44
  mapAbsolutes.set(mapPublic, mapAbs);
45
+ jsAbsolutes.set(mapPublic, jsAbs);
28
46
  }
29
- const loaded = (await Promise.all([...mapAbsolutes.entries()].map(async ([mapPublic, mapAbs]) => {
30
- const content = await readFile(mapAbs, "utf8").catch(() => null);
31
- if (content === null) return null;
47
+ const loaded = (await Promise.all(mapAbsolutes.entries().map(async ([mapPublic, mapAbs]) => {
48
+ const mapContent = await readFile(mapAbs, "utf8").catch(() => null);
49
+ if (mapContent === null) return null;
50
+ const jsAbs = jsAbsolutes.get(mapPublic);
51
+ if (!jsAbs) return null;
52
+ const debugId = randomUUID();
53
+ await writeFile(jsAbs, injectDebugIdIntoJs(await readFile(jsAbs, "utf8"), debugId), "utf8");
54
+ const injectedMap = injectDebugIdIntoMap(mapContent, debugId);
55
+ await writeFile(mapAbs, injectedMap, "utf8");
32
56
  return {
33
57
  absolute: mapAbs,
34
58
  path: mapPublic,
35
- content,
36
- hash: createHash("sha256").update(content).digest("hex")
59
+ content: injectedMap,
60
+ hash: createHash("sha256").update(injectedMap).digest("hex"),
61
+ debugId
37
62
  };
38
63
  }))).filter((f) => f !== null);
39
64
  const validMapping = {};
@@ -59,4 +84,4 @@ function toPublicPath(rel, distDir) {
59
84
  return p;
60
85
  }
61
86
  //#endregion
62
- export { discover, normalizeDistDir };
87
+ export { buildDebugIdSnippet, discover, injectDebugIdIntoJs, injectDebugIdIntoMap, normalizeDistDir };
@@ -1 +1 @@
1
- {"version":3,"file":"discover.mjs","names":[],"sources":["../../../../src/internal/build/source-maps/discover.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { readFile, readdir } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n\nconst SOURCEMAPPING_RE = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\n\nexport type SourceMapFile = {\n readonly absolute: string;\n readonly path: string;\n readonly content: string;\n readonly hash: string;\n};\n\nfunction resolveDistDir(projectDir: string, distDir: string) {\n return isAbsolute(distDir) ? distDir : resolve(projectDir, distDir);\n}\n\nasync function findJsFiles(dir: string) {\n const entries = await readdir(dir, { recursive: true }).catch(\n () => [] as string[]\n );\n return entries\n .filter((entry) => entry.endsWith(\".js\"))\n .map((entry) => join(dir, entry));\n}\n\nexport async function discover(projectDir: string, distDir: string) {\n const absDistDir = resolveDistDir(projectDir, distDir);\n const relDistDir = relative(projectDir, absDistDir);\n\n const [staticFiles, serverFiles] = await Promise.all([\n findJsFiles(join(absDistDir, \"static\")),\n findJsFiles(join(absDistDir, \"server\")),\n ]);\n\n const jsPaths = [...staticFiles, ...serverFiles];\n\n const mapping: Record<string, string> = {};\n const mapAbsolutes = new Map<string, string>();\n\n for (const jsAbs of jsPaths) {\n const content = await readFile(jsAbs, \"utf8\");\n const match = SOURCEMAPPING_RE.exec(content);\n if (!match?.[1]) continue;\n\n const jsDir = jsAbs.slice(0, jsAbs.lastIndexOf(\"/\") + 1);\n const mapRef = decodeURIComponent(match[1]);\n const mapAbs = `${jsDir}${mapRef}`;\n const jsPublic = toPublicPath(relative(projectDir, jsAbs), relDistDir);\n const mapPublic = toPublicPath(relative(projectDir, mapAbs), relDistDir);\n\n mapping[mapPublic] = jsPublic;\n mapAbsolutes.set(mapPublic, mapAbs);\n }\n\n const files = await Promise.all(\n [...mapAbsolutes.entries()].map(async ([mapPublic, mapAbs]) => {\n const content = await readFile(mapAbs, \"utf8\").catch(() => null);\n if (content === null) return null;\n\n return {\n absolute: mapAbs,\n path: mapPublic,\n content,\n hash: createHash(\"sha256\").update(content).digest(\"hex\"),\n };\n }),\n );\n\n const loaded = files.filter((f): f is SourceMapFile => f !== null);\n\n const validMapping: Record<string, string> = {};\n for (const file of loaded) {\n const js = mapping[file.path];\n if (js) validMapping[file.path] = js;\n }\n\n return { files: loaded, mapping: validMapping, sourceFileCount: mapAbsolutes.size };\n}\n\nexport function normalizeDistDir(distDir = \".next\") {\n let d = distDir.split(\"\\\\\").join(\"/\");\n while (d.startsWith(\"./\")) d = d.slice(2);\n return d;\n}\n\nfunction toPublicPath(rel: string, distDir: string) {\n const p = rel.split(\"\\\\\").join(\"/\");\n if (p.startsWith(`${distDir}/`)) return `_next/${p.slice(distDir.length + 1)}`;\n if (p.startsWith(\".next/\")) return `_next/${p.slice(6)}`;\n return p;\n}\n"],"mappings":";;;;AAIA,MAAM,mBAAmB;AASzB,SAAS,eAAe,YAAoB,SAAiB;AAC3D,QAAO,WAAW,QAAQ,GAAG,UAAU,QAAQ,YAAY,QAAQ;;AAGrE,eAAe,YAAY,KAAa;AAItC,SAHgB,MAAM,QAAQ,KAAK,EAAE,WAAW,MAAM,CAAC,CAAC,YAChD,EAAE,CACT,EAEE,QAAQ,UAAU,MAAM,SAAS,MAAM,CAAC,CACxC,KAAK,UAAU,KAAK,KAAK,MAAM,CAAC;;AAGrC,eAAsB,SAAS,YAAoB,SAAiB;CAClE,MAAM,aAAa,eAAe,YAAY,QAAQ;CACtD,MAAM,aAAa,SAAS,YAAY,WAAW;CAEnD,MAAM,CAAC,aAAa,eAAe,MAAM,QAAQ,IAAI,CACnD,YAAY,KAAK,YAAY,SAAS,CAAC,EACvC,YAAY,KAAK,YAAY,SAAS,CAAC,CACxC,CAAC;CAEF,MAAM,UAAU,CAAC,GAAG,aAAa,GAAG,YAAY;CAEhD,MAAM,UAAkC,EAAE;CAC1C,MAAM,+BAAe,IAAI,KAAqB;AAE9C,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,UAAU,MAAM,SAAS,OAAO,OAAO;EAC7C,MAAM,QAAQ,iBAAiB,KAAK,QAAQ;AAC5C,MAAI,CAAC,QAAQ,GAAI;EAIjB,MAAM,SAAS,GAFD,MAAM,MAAM,GAAG,MAAM,YAAY,IAAI,GAAG,EAAE,GACzC,mBAAmB,MAAM,GAAG;EAE3C,MAAM,WAAW,aAAa,SAAS,YAAY,MAAM,EAAE,WAAW;EACtE,MAAM,YAAY,aAAa,SAAS,YAAY,OAAO,EAAE,WAAW;AAExE,UAAQ,aAAa;AACrB,eAAa,IAAI,WAAW,OAAO;;CAiBrC,MAAM,UAdQ,MAAM,QAAQ,IAC1B,CAAC,GAAG,aAAa,SAAS,CAAC,CAAC,IAAI,OAAO,CAAC,WAAW,YAAY;EAC7D,MAAM,UAAU,MAAM,SAAS,QAAQ,OAAO,CAAC,YAAY,KAAK;AAChE,MAAI,YAAY,KAAM,QAAO;AAE7B,SAAO;GACL,UAAU;GACV,MAAM;GACN;GACA,MAAM,WAAW,SAAS,CAAC,OAAO,QAAQ,CAAC,OAAO,MAAM;GACzD;GACD,CACH,EAEoB,QAAQ,MAA0B,MAAM,KAAK;CAElE,MAAM,eAAuC,EAAE;AAC/C,MAAK,MAAM,QAAQ,QAAQ;EACzB,MAAM,KAAK,QAAQ,KAAK;AACxB,MAAI,GAAI,cAAa,KAAK,QAAQ;;AAGpC,QAAO;EAAE,OAAO;EAAQ,SAAS;EAAc,iBAAiB,aAAa;EAAM;;AAGrF,SAAgB,iBAAiB,UAAU,SAAS;CAClD,IAAI,IAAI,QAAQ,MAAM,KAAK,CAAC,KAAK,IAAI;AACrC,QAAO,EAAE,WAAW,KAAK,CAAE,KAAI,EAAE,MAAM,EAAE;AACzC,QAAO;;AAGT,SAAS,aAAa,KAAa,SAAiB;CAClD,MAAM,IAAI,IAAI,MAAM,KAAK,CAAC,KAAK,IAAI;AACnC,KAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,CAAE,QAAO,SAAS,EAAE,MAAM,QAAQ,SAAS,EAAE;AAC5E,KAAI,EAAE,WAAW,SAAS,CAAE,QAAO,SAAS,EAAE,MAAM,EAAE;AACtD,QAAO"}
1
+ {"version":3,"file":"discover.mjs","names":[],"sources":["../../../../src/internal/build/source-maps/discover.ts"],"sourcesContent":["import { createHash, randomUUID } from \"node:crypto\";\nimport { readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve } from \"node:path\";\n\nconst SOURCEMAPPING_RE = /\\/\\/[#@]\\s*sourceMappingURL=(\\S+)\\s*$/;\n\nexport type SourceMapFile = {\n readonly absolute: string;\n readonly path: string;\n readonly content: string;\n readonly hash: string;\n readonly debugId: string;\n};\n\nfunction resolveDistDir(projectDir: string, distDir: string) {\n return isAbsolute(distDir) ? distDir : resolve(projectDir, distDir);\n}\n\nasync function findJsFiles(dir: string) {\n const entries = await readdir(dir, { recursive: true }).catch(\n () => [] as string[]\n );\n return entries\n .filter((entry) => entry.endsWith(\".js\"))\n .map((entry) => join(dir, entry));\n}\n\nexport function buildDebugIdSnippet(debugId: string) {\n return `!function(){try{var s=(new Error).stack;s&&(globalThis._debugIds=globalThis._debugIds||{},globalThis._debugIds[s]=\"${debugId}\")}catch(e){}}();`;\n}\n\nexport function injectDebugIdIntoJs(content: string, debugId: string) {\n const snippet = buildDebugIdSnippet(debugId);\n const debugIdComment = `//# debugId=${debugId}`;\n\n const match = SOURCEMAPPING_RE.exec(content);\n if (match) {\n const before = content.slice(0, match.index).trimEnd();\n const sourceMappingLine = match[0];\n return `${snippet}\\n${before}\\n${debugIdComment}\\n${sourceMappingLine}`;\n }\n\n return `${snippet}\\n${content}\\n${debugIdComment}`;\n}\n\nexport function injectDebugIdIntoMap(content: string, debugId: string) {\n const json = JSON.parse(content) as Record<string, unknown>;\n json[\"debugId\"] = debugId;\n if (typeof json[\"mappings\"] === \"string\") {\n json[\"mappings\"] = `;${json[\"mappings\"]}`;\n }\n return JSON.stringify(json);\n}\n\nexport async function discover(projectDir: string, distDir: string) {\n const absDistDir = resolveDistDir(projectDir, distDir);\n const relDistDir = relative(projectDir, absDistDir);\n\n const [staticFiles, serverFiles] = await Promise.all([\n findJsFiles(join(absDistDir, \"static\")),\n findJsFiles(join(absDistDir, \"server\")),\n ]);\n\n const jsPaths = [...staticFiles, ...serverFiles];\n\n const mapping: Record<string, string> = {};\n const mapAbsolutes = new Map<string, string>();\n const jsAbsolutes = new Map<string, string>();\n\n for (const jsAbs of jsPaths) {\n const content = await readFile(jsAbs, \"utf8\");\n const match = SOURCEMAPPING_RE.exec(content);\n if (!match?.[1]) continue;\n\n const jsDir = jsAbs.slice(0, jsAbs.lastIndexOf(\"/\") + 1);\n const mapRef = decodeURIComponent(match[1]);\n const mapAbs = `${jsDir}${mapRef}`;\n const jsPublic = toPublicPath(relative(projectDir, jsAbs), relDistDir);\n const mapPublic = toPublicPath(relative(projectDir, mapAbs), relDistDir);\n\n mapping[mapPublic] = jsPublic;\n mapAbsolutes.set(mapPublic, mapAbs);\n jsAbsolutes.set(mapPublic, jsAbs);\n }\n\n const files = await Promise.all(\n mapAbsolutes.entries().map(async ([mapPublic, mapAbs]) => {\n const mapContent = await readFile(mapAbs, \"utf8\").catch(() => null);\n if (mapContent === null) return null;\n\n const jsAbs = jsAbsolutes.get(mapPublic);\n if (!jsAbs) return null;\n\n const debugId: string = randomUUID();\n\n const jsContent = await readFile(jsAbs, \"utf8\");\n const injectedJs = injectDebugIdIntoJs(jsContent, debugId);\n await writeFile(jsAbs, injectedJs, \"utf8\");\n\n const injectedMap = injectDebugIdIntoMap(mapContent, debugId);\n await writeFile(mapAbs, injectedMap, \"utf8\");\n\n return {\n absolute: mapAbs,\n path: mapPublic,\n content: injectedMap,\n hash: createHash(\"sha256\").update(injectedMap).digest(\"hex\"),\n debugId,\n };\n }),\n );\n\n const loaded = files.filter((f): f is SourceMapFile => f !== null);\n\n const validMapping: Record<string, string> = {};\n for (const file of loaded) {\n const js = mapping[file.path];\n if (js) validMapping[file.path] = js;\n }\n\n return { files: loaded, mapping: validMapping, sourceFileCount: mapAbsolutes.size };\n}\n\nexport function normalizeDistDir(distDir = \".next\") {\n let d = distDir.split(\"\\\\\").join(\"/\");\n while (d.startsWith(\"./\")) d = d.slice(2);\n return d;\n}\n\nfunction toPublicPath(rel: string, distDir: string) {\n const p = rel.split(\"\\\\\").join(\"/\");\n if (p.startsWith(`${distDir}/`)) return `_next/${p.slice(distDir.length + 1)}`;\n if (p.startsWith(\".next/\")) return `_next/${p.slice(6)}`;\n return p;\n}\n"],"mappings":"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"}
@@ -16,6 +16,9 @@ declare function buildUploadBody(discovered: {
16
16
  hashes: {
17
17
  [k: string]: string;
18
18
  };
19
+ debugIds: {
20
+ [k: string]: string;
21
+ };
19
22
  sourceFileCount: number;
20
23
  };
21
24
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"mappings":";;;iBAMgB,eAAA,CAAgB,UAAA;EAC9B,KAAA,EAAO,aAAA;EACP,OAAA,EAAS,MAAA;EACT,eAAA;AAAA;;;;;;;;;;;;;;;;iBAqBoB,iBAAA,CAAkB,KAAA,EAAO,aAAA,KAAe,OAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"mappings":";;;iBAMgB,eAAA,CAAgB,UAAA;EAC9B,KAAA,EAAO,aAAA;EACP,OAAA,EAAS,MAAA;EACT,eAAA;AAAA;;;;;;;;;;;;;;;;;;;iBAsBoB,iBAAA,CAAkB,KAAA,EAAO,aAAA,KAAe,OAAA"}
@@ -15,6 +15,7 @@ function buildUploadBody(discovered) {
15
15
  metadata: {
16
16
  sourceMapToGenerated: discovered.mapping,
17
17
  hashes: Object.fromEntries(discovered.files.map((f) => [f.path, f.hash])),
18
+ debugIds: Object.fromEntries(discovered.files.map((f) => [f.path, f.debugId])),
18
19
  sourceFileCount: discovered.sourceFileCount
19
20
  }
20
21
  },
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"sourcesContent":["import { unlink } from \"node:fs/promises\";\n\nimport type { SourceMapFile } from \"./discover.js\";\n\nexport { discover, normalizeDistDir, type SourceMapFile } from \"./discover.js\";\n\nexport function buildUploadBody(discovered: {\n files: SourceMapFile[];\n mapping: Record<string, string>;\n sourceFileCount: number;\n}) {\n let totalBytes = 0;\n\n const files = discovered.files.map((file) => {\n totalBytes += file.content.length;\n return {\n fileName: file.path,\n content: new Blob([file.content], { type: \"application/json\" }),\n };\n });\n\n const metadata = {\n sourceMapToGenerated: discovered.mapping,\n hashes: Object.fromEntries(discovered.files.map((f) => [f.path, f.hash])),\n sourceFileCount: discovered.sourceFileCount,\n };\n\n return { body: { files, metadata }, totalBytes };\n}\n\nexport async function cleanupSourceMaps(files: SourceMapFile[]) {\n await Promise.all(files.map((f) => unlink(f.absolute).catch(() => undefined)));\n}\n"],"mappings":";;;AAMA,SAAgB,gBAAgB,YAI7B;CACD,IAAI,aAAa;AAgBjB,QAAO;EAAE,MAAM;GAAE,OAdH,WAAW,MAAM,KAAK,SAAS;AAC3C,kBAAc,KAAK,QAAQ;AAC3B,WAAO;KACL,UAAU,KAAK;KACf,SAAS,IAAI,KAAK,CAAC,KAAK,QAAQ,EAAE,EAAE,MAAM,oBAAoB,CAAC;KAChE;KACD;GAQsB,UANP;IACf,sBAAsB,WAAW;IACjC,QAAQ,OAAO,YAAY,WAAW,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACzE,iBAAiB,WAAW;IAC7B;GAEiC;EAAE;EAAY;;AAGlD,eAAsB,kBAAkB,OAAwB;AAC9D,OAAM,QAAQ,IAAI,MAAM,KAAK,MAAM,OAAO,EAAE,SAAS,CAAC,YAAY,KAAA,EAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../../../src/internal/build/source-maps/index.ts"],"sourcesContent":["import { unlink } from \"node:fs/promises\";\n\nimport type { SourceMapFile } from \"./discover.js\";\n\nexport { discover, normalizeDistDir, type SourceMapFile } from \"./discover.js\";\n\nexport function buildUploadBody(discovered: {\n files: SourceMapFile[];\n mapping: Record<string, string>;\n sourceFileCount: number;\n}) {\n let totalBytes = 0;\n\n const files = discovered.files.map((file) => {\n totalBytes += file.content.length;\n return {\n fileName: file.path,\n content: new Blob([file.content], { type: \"application/json\" }),\n };\n });\n\n const metadata = {\n sourceMapToGenerated: discovered.mapping,\n hashes: Object.fromEntries(discovered.files.map((f) => [f.path, f.hash])),\n debugIds: Object.fromEntries(discovered.files.map((f) => [f.path, f.debugId])),\n sourceFileCount: discovered.sourceFileCount,\n };\n\n return { body: { files, metadata }, totalBytes };\n}\n\nexport async function cleanupSourceMaps(files: SourceMapFile[]) {\n await Promise.all(files.map((f) => unlink(f.absolute).catch(() => undefined)));\n}\n"],"mappings":";;;AAMA,SAAgB,gBAAgB,YAI7B;CACD,IAAI,aAAa;AAiBjB,QAAO;EAAE,MAAM;GAAE,OAfH,WAAW,MAAM,KAAK,SAAS;AAC3C,kBAAc,KAAK,QAAQ;AAC3B,WAAO;KACL,UAAU,KAAK;KACf,SAAS,IAAI,KAAK,CAAC,KAAK,QAAQ,EAAE,EAAE,MAAM,oBAAoB,CAAC;KAChE;KACD;GASsB,UAPP;IACf,sBAAsB,WAAW;IACjC,QAAQ,OAAO,YAAY,WAAW,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACzE,UAAU,OAAO,YAAY,WAAW,MAAM,KAAK,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC9E,iBAAiB,WAAW;IAC7B;GAEiC;EAAE;EAAY;;AAGlD,eAAsB,kBAAkB,OAAwB;AAC9D,OAAM,QAAQ,IAAI,MAAM,KAAK,MAAM,OAAO,EAAE,SAAS,CAAC,YAAY,KAAA,EAAU,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"handle-post.d.mts","names":[],"sources":["../../../src/internal/route/handle-post.ts"],"mappings":";iBAoCsB,UAAA,CAAW,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA"}
1
+ {"version":3,"file":"handle-post.d.mts","names":[],"sources":["../../../src/internal/route/handle-post.ts"],"mappings":";iBAqCsB,UAAA,CAAW,OAAA,EAAS,OAAA,GAAU,OAAA,CAAQ,QAAA"}
@@ -1,6 +1,7 @@
1
1
  import { log } from "../logger.mjs";
2
2
  import { extractSubPath, formatProxyError, forwardToCollector, notConfiguredResponse, resolveAuthenticatedEnv } from "./proxy.mjs";
3
3
  import { API_PATHS } from "@interfere/constants/api";
4
+ import { extractCountryHeader } from "@interfere/types/sdk/geo";
4
5
  //#region src/internal/route/handle-post.ts
5
6
  function parseEnvelopes(value) {
6
7
  if (!Array.isArray(value)) return null;
@@ -51,7 +52,11 @@ async function handleIngest(request, env) {
51
52
  headers: {
52
53
  "content-type": "application/json",
53
54
  "x-api-key": env.apiKey,
54
- ...traceparent ? { traceparent } : {}
55
+ ...traceparent ? { traceparent } : {},
56
+ ...(() => {
57
+ const country = extractCountryHeader(request);
58
+ return country ? { "x-country-code": country } : {};
59
+ })()
55
60
  },
56
61
  body: JSON.stringify(injectReleaseMetadata(envelopes, env.release)),
57
62
  signal: AbortSignal.timeout(1e4)
@@ -1 +1 @@
1
- {"version":3,"file":"handle-post.mjs","names":[],"sources":["../../../src/internal/route/handle-post.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\n\nimport { log } from \"../logger.js\";\nimport {\n type AuthenticatedEnv,\n extractSubPath,\n formatProxyError,\n forwardToCollector,\n notConfiguredResponse,\n resolveAuthenticatedEnv,\n} from \"./proxy.js\";\n\nfunction parseEnvelopes(value: unknown): Envelope[] | null {\n if (!Array.isArray(value)) {\n return null;\n }\n\n return value as Envelope[];\n}\n\nfunction injectReleaseMetadata(\n envelopes: Envelope[],\n metadata: { sourceId: string | null; destinationId: string | null }\n): Envelope[] {\n if (metadata.sourceId === null && metadata.destinationId === null) {\n return envelopes;\n }\n\n return envelopes.map((envelope) => ({\n ...envelope,\n buildId: metadata.sourceId ?? envelope.buildId,\n releaseId: metadata.destinationId ?? envelope.releaseId,\n }));\n}\n\nexport async function handlePost(request: Request): Promise<Response> {\n const env = resolveAuthenticatedEnv();\n if (!env) {\n return notConfiguredResponse();\n }\n\n const subPath = extractSubPath(request);\n\n try {\n if (subPath === API_PATHS.INGEST) {\n return await handleIngest(request, env);\n }\n\n return await forwardToCollector(request, env, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n log.error(`Proxy ${request.method} ${subPath} failed`, detail.lines);\n return Response.json(\n { code: \"INTERFERE_PROXY_ERROR\", message: detail.message },\n { status: 502 }\n );\n }\n}\n\nasync function handleIngest(\n request: Request,\n env: AuthenticatedEnv\n): Promise<Response> {\n let payload: unknown;\n try {\n payload = await request.json();\n } catch {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_JSON\",\n message: \"Request body must be valid JSON.\",\n },\n { status: 400 }\n );\n }\n\n const envelopes = parseEnvelopes(payload);\n if (envelopes === null) {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_ENVELOPES\",\n message: \"Request body must be an array of envelopes.\",\n },\n { status: 400 }\n );\n }\n\n const traceparent = request.headers.get(\"traceparent\");\n const upstream = await fetch(`${env.apiUrl}${API_PATHS.INGEST}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n },\n body: JSON.stringify(injectReleaseMetadata(envelopes, env.release)),\n signal: AbortSignal.timeout(10_000),\n });\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":";;;;AAaA,SAAS,eAAe,OAAmC;AACzD,KAAI,CAAC,MAAM,QAAQ,MAAM,CACvB,QAAO;AAGT,QAAO;;AAGT,SAAS,sBACP,WACA,UACY;AACZ,KAAI,SAAS,aAAa,QAAQ,SAAS,kBAAkB,KAC3D,QAAO;AAGT,QAAO,UAAU,KAAK,cAAc;EAClC,GAAG;EACH,SAAS,SAAS,YAAY,SAAS;EACvC,WAAW,SAAS,iBAAiB,SAAS;EAC/C,EAAE;;AAGL,eAAsB,WAAW,SAAqC;CACpE,MAAM,MAAM,yBAAyB;AACrC,KAAI,CAAC,IACH,QAAO,uBAAuB;CAGhC,MAAM,UAAU,eAAe,QAAQ;AAEvC,KAAI;AACF,MAAI,YAAY,UAAU,OACxB,QAAO,MAAM,aAAa,SAAS,IAAI;AAGzC,SAAO,MAAM,mBAAmB,SAAS,KAAK,QAAQ;UAC/C,OAAO;EACd,MAAM,SAAS,iBAAiB,MAAM;AACtC,MAAI,MAAM,SAAS,QAAQ,OAAO,GAAG,QAAQ,UAAU,OAAO,MAAM;AACpE,SAAO,SAAS,KACd;GAAE,MAAM;GAAyB,SAAS,OAAO;GAAS,EAC1D,EAAE,QAAQ,KAAK,CAChB;;;AAIL,eAAe,aACb,SACA,KACmB;CACnB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,MAAM;SACxB;AACN,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,YAAY,eAAe,QAAQ;AACzC,KAAI,cAAc,KAChB,QAAO,SAAS,KACd;EACE,MAAM;EACN,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;CAGH,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CACtD,MAAM,WAAW,MAAM,MAAM,GAAG,IAAI,SAAS,UAAU,UAAU;EAC/D,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACvC;EACD,MAAM,KAAK,UAAU,sBAAsB,WAAW,IAAI,QAAQ,CAAC;EACnE,QAAQ,YAAY,QAAQ,IAAO;EACpC,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,SAAS;EACjB,SAAS,EACP,gBACE,SAAS,QAAQ,IAAI,eAAe,IAAI,oBAC3C;EACF,CAAC"}
1
+ {"version":3,"file":"handle-post.mjs","names":[],"sources":["../../../src/internal/route/handle-post.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport type { Envelope } from \"@interfere/types/sdk/envelope\";\nimport { extractCountryHeader } from \"@interfere/types/sdk/geo\";\n\nimport { log } from \"../logger.js\";\nimport {\n type AuthenticatedEnv,\n extractSubPath,\n formatProxyError,\n forwardToCollector,\n notConfiguredResponse,\n resolveAuthenticatedEnv,\n} from \"./proxy.js\";\n\nfunction parseEnvelopes(value: unknown): Envelope[] | null {\n if (!Array.isArray(value)) {\n return null;\n }\n\n return value as Envelope[];\n}\n\nfunction injectReleaseMetadata(\n envelopes: Envelope[],\n metadata: { sourceId: string | null; destinationId: string | null }\n): Envelope[] {\n if (metadata.sourceId === null && metadata.destinationId === null) {\n return envelopes;\n }\n\n return envelopes.map((envelope) => ({\n ...envelope,\n buildId: metadata.sourceId ?? envelope.buildId,\n releaseId: metadata.destinationId ?? envelope.releaseId,\n }));\n}\n\nexport async function handlePost(request: Request): Promise<Response> {\n const env = resolveAuthenticatedEnv();\n if (!env) {\n return notConfiguredResponse();\n }\n\n const subPath = extractSubPath(request);\n\n try {\n if (subPath === API_PATHS.INGEST) {\n return await handleIngest(request, env);\n }\n\n return await forwardToCollector(request, env, subPath);\n } catch (error) {\n const detail = formatProxyError(error);\n log.error(`Proxy ${request.method} ${subPath} failed`, detail.lines);\n return Response.json(\n { code: \"INTERFERE_PROXY_ERROR\", message: detail.message },\n { status: 502 }\n );\n }\n}\n\nasync function handleIngest(\n request: Request,\n env: AuthenticatedEnv\n): Promise<Response> {\n let payload: unknown;\n try {\n payload = await request.json();\n } catch {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_JSON\",\n message: \"Request body must be valid JSON.\",\n },\n { status: 400 }\n );\n }\n\n const envelopes = parseEnvelopes(payload);\n if (envelopes === null) {\n return Response.json(\n {\n code: \"INTERFERE_INVALID_ENVELOPES\",\n message: \"Request body must be an array of envelopes.\",\n },\n { status: 400 }\n );\n }\n\n const traceparent = request.headers.get(\"traceparent\");\n const upstream = await fetch(`${env.apiUrl}${API_PATHS.INGEST}`, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n ...(() => {\n const country = extractCountryHeader(request);\n return country ? { \"x-country-code\": country } : {};\n })(),\n },\n body: JSON.stringify(injectReleaseMetadata(envelopes, env.release)),\n signal: AbortSignal.timeout(10_000),\n });\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":";;;;;AAcA,SAAS,eAAe,OAAmC;AACzD,KAAI,CAAC,MAAM,QAAQ,MAAM,CACvB,QAAO;AAGT,QAAO;;AAGT,SAAS,sBACP,WACA,UACY;AACZ,KAAI,SAAS,aAAa,QAAQ,SAAS,kBAAkB,KAC3D,QAAO;AAGT,QAAO,UAAU,KAAK,cAAc;EAClC,GAAG;EACH,SAAS,SAAS,YAAY,SAAS;EACvC,WAAW,SAAS,iBAAiB,SAAS;EAC/C,EAAE;;AAGL,eAAsB,WAAW,SAAqC;CACpE,MAAM,MAAM,yBAAyB;AACrC,KAAI,CAAC,IACH,QAAO,uBAAuB;CAGhC,MAAM,UAAU,eAAe,QAAQ;AAEvC,KAAI;AACF,MAAI,YAAY,UAAU,OACxB,QAAO,MAAM,aAAa,SAAS,IAAI;AAGzC,SAAO,MAAM,mBAAmB,SAAS,KAAK,QAAQ;UAC/C,OAAO;EACd,MAAM,SAAS,iBAAiB,MAAM;AACtC,MAAI,MAAM,SAAS,QAAQ,OAAO,GAAG,QAAQ,UAAU,OAAO,MAAM;AACpE,SAAO,SAAS,KACd;GAAE,MAAM;GAAyB,SAAS,OAAO;GAAS,EAC1D,EAAE,QAAQ,KAAK,CAChB;;;AAIL,eAAe,aACb,SACA,KACmB;CACnB,IAAI;AACJ,KAAI;AACF,YAAU,MAAM,QAAQ,MAAM;SACxB;AACN,SAAO,SAAS,KACd;GACE,MAAM;GACN,SAAS;GACV,EACD,EAAE,QAAQ,KAAK,CAChB;;CAGH,MAAM,YAAY,eAAe,QAAQ;AACzC,KAAI,cAAc,KAChB,QAAO,SAAS,KACd;EACE,MAAM;EACN,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;CAGH,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CACtD,MAAM,WAAW,MAAM,MAAM,GAAG,IAAI,SAAS,UAAU,UAAU;EAC/D,QAAQ;EACR,SAAS;GACP,gBAAgB;GAChB,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACtC,UAAU;IACR,MAAM,UAAU,qBAAqB,QAAQ;AAC7C,WAAO,UAAU,EAAE,kBAAkB,SAAS,GAAG,EAAE;OACjD;GACL;EACD,MAAM,KAAK,UAAU,sBAAsB,WAAW,IAAI,QAAQ,CAAC;EACnE,QAAQ,YAAY,QAAQ,IAAO;EACpC,CAAC;AAEF,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,SAAS;EACjB,SAAS,EACP,gBACE,SAAS,QAAQ,IAAI,eAAe,IAAI,oBAC3C;EACF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.mts","names":[],"sources":["../../../src/internal/route/proxy.ts"],"mappings":";;;UAOiB,gBAAA;EACf,MAAA;EACA,MAAA;EACA,OAAA,EAAS,YAAA;AAAA;AAAA,iBAGK,uBAAA,CAAA,GAA2B,gBAAA;AAAA,iBAQ3B,cAAA,CAAe,OAAA,EAAS,OAAA;AAAA,iBAMxB,qBAAA,CAAA,GAAyB,QAAA;AAAA,iBAazB,gBAAA,CAAiB,KAAA;EAC/B,OAAA;EACA,KAAA;AAAA;AAAA,iBAwBoB,kBAAA,CACpB,OAAA,EAAS,OAAA,EACT,GAAA,EAAK,gBAAA,EACL,OAAA,WACC,OAAA,CAAQ,QAAA"}
1
+ {"version":3,"file":"proxy.d.mts","names":[],"sources":["../../../src/internal/route/proxy.ts"],"mappings":";;;UAaiB,gBAAA;EACf,MAAA;EACA,MAAA;EACA,OAAA,EAAS,YAAA;AAAA;AAAA,iBAGK,uBAAA,CAAA,GAA2B,gBAAA;AAAA,iBAQ3B,cAAA,CAAe,OAAA,EAAS,OAAA;AAAA,iBAMxB,qBAAA,CAAA,GAAyB,QAAA;AAAA,iBAazB,gBAAA,CAAiB,KAAA;EAC/B,OAAA;EACA,KAAA;AAAA;AAAA,iBAwBoB,kBAAA,CACpB,OAAA,EAAS,OAAA,EACT,GAAA,EAAK,gBAAA,EACL,OAAA,WACC,OAAA,CAAQ,QAAA"}
@@ -1,8 +1,13 @@
1
1
  import { log } from "../logger.mjs";
2
2
  import { readInterfereEnv } from "../env.mjs";
3
3
  import { omitUndefined } from "@interfere/types/util/omit-undefined";
4
+ import { extractCountryHeader } from "@interfere/types/sdk/geo";
4
5
  //#region src/internal/route/proxy.ts
5
6
  const PROXY_PATH_PATTERN = /\/api\/interfere(\/.*)/;
7
+ function geoHeaders(request) {
8
+ const country = extractCountryHeader(request);
9
+ return country ? { "x-country-code": country } : {};
10
+ }
6
11
  function resolveAuthenticatedEnv() {
7
12
  const env = readInterfereEnv();
8
13
  if (env.apiKey === null) return null;
@@ -48,7 +53,8 @@ async function forwardToCollector(request, env, subPath) {
48
53
  headers: {
49
54
  "content-type": request.headers.get("content-type") ?? "application/json",
50
55
  "x-api-key": env.apiKey,
51
- ...traceparent ? { traceparent } : {}
56
+ ...traceparent ? { traceparent } : {},
57
+ ...geoHeaders(request)
52
58
  },
53
59
  signal: AbortSignal.timeout(1e4)
54
60
  });
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.mjs","names":[],"sources":["../../../src/internal/route/proxy.ts"],"sourcesContent":["import { omitUndefined } from \"@interfere/types/util/omit-undefined\";\n\nimport { type InterfereEnv, readInterfereEnv } from \"../env.js\";\nimport { log } from \"../logger.js\";\n\nconst PROXY_PATH_PATTERN = /\\/api\\/interfere(\\/.*)/;\n\nexport interface AuthenticatedEnv {\n apiKey: string;\n apiUrl: string;\n release: InterfereEnv[\"release\"];\n}\n\nexport function resolveAuthenticatedEnv(): AuthenticatedEnv | null {\n const env = readInterfereEnv();\n if (env.apiKey === null) {\n return null;\n }\n return { apiKey: env.apiKey, apiUrl: env.apiUrl, release: env.release };\n}\n\nexport function extractSubPath(request: Request): string {\n const url = new URL(request.url);\n const match = url.pathname.match(PROXY_PATH_PATTERN);\n return match?.[1] ?? \"/\";\n}\n\nexport function notConfiguredResponse(): Response {\n log.warn(\"Not configured\", [\n \"INTERFERE_API_KEY is not set. The proxy route will return 503.\",\n ]);\n return Response.json(\n {\n code: \"INTERFERE_NOT_CONFIGURED\",\n message: \"INTERFERE_API_KEY is required.\",\n },\n { status: 503 }\n );\n}\n\nexport function formatProxyError(error: unknown): {\n message: string;\n lines: string[];\n} {\n if (!(error instanceof Error)) {\n return { message: String(error), lines: [String(error)] };\n }\n\n const lines = [`${error.name}: ${error.message}`];\n\n if (\"cause\" in error && error.cause) {\n const cause =\n error.cause instanceof Error ? error.cause.message : String(error.cause);\n lines.push(`cause: ${cause}`);\n }\n\n if (\n \"code\" in error &&\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ) {\n lines.push(`code: ${(error as NodeJS.ErrnoException).code}`);\n }\n\n return { message: `${error.name}: ${error.message}`, lines };\n}\n\nexport async function forwardToCollector(\n request: Request,\n env: AuthenticatedEnv,\n subPath: string\n): Promise<Response> {\n const url = `${env.apiUrl}${subPath}`;\n const traceparent = request.headers.get(\"traceparent\");\n const hasBody = request.method !== \"GET\" && request.method !== \"HEAD\";\n const body = hasBody ? await request.text() : undefined;\n\n const upstream = await fetch(url, {\n ...omitUndefined({ body }),\n method: request.method,\n headers: {\n \"content-type\": request.headers.get(\"content-type\") ?? \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n },\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => \"\");\n\n if (upstream.status >= 500) {\n log.error(\n `Upstream ${upstream.status} for ${request.method} ${subPath}`,\n [text]\n );\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: text },\n { status: upstream.status }\n );\n }\n if (upstream.status >= 400) {\n log.warn(`Upstream ${upstream.status} for ${request.method} ${subPath}`, [\n text,\n ]);\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_WARNING\", message: text },\n { status: upstream.status }\n );\n }\n\n log.error(`Upstream ${upstream.status} for ${request.method} ${subPath}`, [\n text,\n ]);\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: text },\n { status: upstream.status }\n );\n }\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":";;;;AAKA,MAAM,qBAAqB;AAQ3B,SAAgB,0BAAmD;CACjE,MAAM,MAAM,kBAAkB;AAC9B,KAAI,IAAI,WAAW,KACjB,QAAO;AAET,QAAO;EAAE,QAAQ,IAAI;EAAQ,QAAQ,IAAI;EAAQ,SAAS,IAAI;EAAS;;AAGzE,SAAgB,eAAe,SAA0B;AAGvD,QAFY,IAAI,IAAI,QAAQ,IAAI,CACd,SAAS,MAAM,mBAAmB,GACrC,MAAM;;AAGvB,SAAgB,wBAAkC;AAChD,KAAI,KAAK,kBAAkB,CACzB,iEACD,CAAC;AACF,QAAO,SAAS,KACd;EACE,MAAM;EACN,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;;AAGH,SAAgB,iBAAiB,OAG/B;AACA,KAAI,EAAE,iBAAiB,OACrB,QAAO;EAAE,SAAS,OAAO,MAAM;EAAE,OAAO,CAAC,OAAO,MAAM,CAAC;EAAE;CAG3D,MAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU;AAEjD,KAAI,WAAW,SAAS,MAAM,OAAO;EACnC,MAAM,QACJ,MAAM,iBAAiB,QAAQ,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM;AAC1E,QAAM,KAAK,UAAU,QAAQ;;AAG/B,KACE,UAAU,SACV,OAAQ,MAAgC,SAAS,SAEjD,OAAM,KAAK,SAAU,MAAgC,OAAO;AAG9D,QAAO;EAAE,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM;EAAW;EAAO;;AAG9D,eAAsB,mBACpB,SACA,KACA,SACmB;CACnB,MAAM,MAAM,GAAG,IAAI,SAAS;CAC5B,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CAEtD,MAAM,OADU,QAAQ,WAAW,SAAS,QAAQ,WAAW,SACxC,MAAM,QAAQ,MAAM,GAAG,KAAA;CAE9C,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,GAAG,cAAc,EAAE,MAAM,CAAC;EAC1B,QAAQ,QAAQ;EAChB,SAAS;GACP,gBAAgB,QAAQ,QAAQ,IAAI,eAAe,IAAI;GACvD,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACvC;EACD,QAAQ,YAAY,QAAQ,IAAO;EACpC,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,GAAG;AAElD,MAAI,SAAS,UAAU,KAAK;AAC1B,OAAI,MACF,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WACrD,CAAC,KAAK,CACP;AACD,UAAO,SAAS,KACd;IAAE,MAAM;IAA4B,SAAS;IAAM,EACnD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAEH,MAAI,SAAS,UAAU,KAAK;AAC1B,OAAI,KAAK,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WAAW,CACvE,KACD,CAAC;AACF,UAAO,SAAS,KACd;IAAE,MAAM;IAA8B,SAAS;IAAM,EACrD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAGH,MAAI,MAAM,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WAAW,CACxE,KACD,CAAC;AACF,SAAO,SAAS,KACd;GAAE,MAAM;GAA4B,SAAS;GAAM,EACnD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAGH,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,SAAS;EACjB,SAAS,EACP,gBACE,SAAS,QAAQ,IAAI,eAAe,IAAI,oBAC3C;EACF,CAAC"}
1
+ {"version":3,"file":"proxy.mjs","names":[],"sources":["../../../src/internal/route/proxy.ts"],"sourcesContent":["import { extractCountryHeader } from \"@interfere/types/sdk/geo\";\nimport { omitUndefined } from \"@interfere/types/util/omit-undefined\";\n\nimport { type InterfereEnv, readInterfereEnv } from \"../env.js\";\nimport { log } from \"../logger.js\";\n\nconst PROXY_PATH_PATTERN = /\\/api\\/interfere(\\/.*)/;\n\nfunction geoHeaders(request: Request): Record<string, string> {\n const country = extractCountryHeader(request);\n return country ? { \"x-country-code\": country } : {};\n}\n\nexport interface AuthenticatedEnv {\n apiKey: string;\n apiUrl: string;\n release: InterfereEnv[\"release\"];\n}\n\nexport function resolveAuthenticatedEnv(): AuthenticatedEnv | null {\n const env = readInterfereEnv();\n if (env.apiKey === null) {\n return null;\n }\n return { apiKey: env.apiKey, apiUrl: env.apiUrl, release: env.release };\n}\n\nexport function extractSubPath(request: Request): string {\n const url = new URL(request.url);\n const match = url.pathname.match(PROXY_PATH_PATTERN);\n return match?.[1] ?? \"/\";\n}\n\nexport function notConfiguredResponse(): Response {\n log.warn(\"Not configured\", [\n \"INTERFERE_API_KEY is not set. The proxy route will return 503.\",\n ]);\n return Response.json(\n {\n code: \"INTERFERE_NOT_CONFIGURED\",\n message: \"INTERFERE_API_KEY is required.\",\n },\n { status: 503 }\n );\n}\n\nexport function formatProxyError(error: unknown): {\n message: string;\n lines: string[];\n} {\n if (!(error instanceof Error)) {\n return { message: String(error), lines: [String(error)] };\n }\n\n const lines = [`${error.name}: ${error.message}`];\n\n if (\"cause\" in error && error.cause) {\n const cause =\n error.cause instanceof Error ? error.cause.message : String(error.cause);\n lines.push(`cause: ${cause}`);\n }\n\n if (\n \"code\" in error &&\n typeof (error as NodeJS.ErrnoException).code === \"string\"\n ) {\n lines.push(`code: ${(error as NodeJS.ErrnoException).code}`);\n }\n\n return { message: `${error.name}: ${error.message}`, lines };\n}\n\nexport async function forwardToCollector(\n request: Request,\n env: AuthenticatedEnv,\n subPath: string\n): Promise<Response> {\n const url = `${env.apiUrl}${subPath}`;\n const traceparent = request.headers.get(\"traceparent\");\n const hasBody = request.method !== \"GET\" && request.method !== \"HEAD\";\n const body = hasBody ? await request.text() : undefined;\n\n const upstream = await fetch(url, {\n ...omitUndefined({ body }),\n method: request.method,\n headers: {\n \"content-type\": request.headers.get(\"content-type\") ?? \"application/json\",\n \"x-api-key\": env.apiKey,\n ...(traceparent ? { traceparent } : {}),\n ...geoHeaders(request),\n },\n signal: AbortSignal.timeout(10_000),\n });\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => \"\");\n\n if (upstream.status >= 500) {\n log.error(\n `Upstream ${upstream.status} for ${request.method} ${subPath}`,\n [text]\n );\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: text },\n { status: upstream.status }\n );\n }\n if (upstream.status >= 400) {\n log.warn(`Upstream ${upstream.status} for ${request.method} ${subPath}`, [\n text,\n ]);\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_WARNING\", message: text },\n { status: upstream.status }\n );\n }\n\n log.error(`Upstream ${upstream.status} for ${request.method} ${subPath}`, [\n text,\n ]);\n return Response.json(\n { code: \"INTERFERE_UPSTREAM_ERROR\", message: text },\n { status: upstream.status }\n );\n }\n\n return new Response(upstream.body, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") ?? \"application/json\",\n },\n });\n}\n"],"mappings":";;;;;AAMA,MAAM,qBAAqB;AAE3B,SAAS,WAAW,SAA0C;CAC5D,MAAM,UAAU,qBAAqB,QAAQ;AAC7C,QAAO,UAAU,EAAE,kBAAkB,SAAS,GAAG,EAAE;;AASrD,SAAgB,0BAAmD;CACjE,MAAM,MAAM,kBAAkB;AAC9B,KAAI,IAAI,WAAW,KACjB,QAAO;AAET,QAAO;EAAE,QAAQ,IAAI;EAAQ,QAAQ,IAAI;EAAQ,SAAS,IAAI;EAAS;;AAGzE,SAAgB,eAAe,SAA0B;AAGvD,QAFY,IAAI,IAAI,QAAQ,IAAI,CACd,SAAS,MAAM,mBAAmB,GACrC,MAAM;;AAGvB,SAAgB,wBAAkC;AAChD,KAAI,KAAK,kBAAkB,CACzB,iEACD,CAAC;AACF,QAAO,SAAS,KACd;EACE,MAAM;EACN,SAAS;EACV,EACD,EAAE,QAAQ,KAAK,CAChB;;AAGH,SAAgB,iBAAiB,OAG/B;AACA,KAAI,EAAE,iBAAiB,OACrB,QAAO;EAAE,SAAS,OAAO,MAAM;EAAE,OAAO,CAAC,OAAO,MAAM,CAAC;EAAE;CAG3D,MAAM,QAAQ,CAAC,GAAG,MAAM,KAAK,IAAI,MAAM,UAAU;AAEjD,KAAI,WAAW,SAAS,MAAM,OAAO;EACnC,MAAM,QACJ,MAAM,iBAAiB,QAAQ,MAAM,MAAM,UAAU,OAAO,MAAM,MAAM;AAC1E,QAAM,KAAK,UAAU,QAAQ;;AAG/B,KACE,UAAU,SACV,OAAQ,MAAgC,SAAS,SAEjD,OAAM,KAAK,SAAU,MAAgC,OAAO;AAG9D,QAAO;EAAE,SAAS,GAAG,MAAM,KAAK,IAAI,MAAM;EAAW;EAAO;;AAG9D,eAAsB,mBACpB,SACA,KACA,SACmB;CACnB,MAAM,MAAM,GAAG,IAAI,SAAS;CAC5B,MAAM,cAAc,QAAQ,QAAQ,IAAI,cAAc;CAEtD,MAAM,OADU,QAAQ,WAAW,SAAS,QAAQ,WAAW,SACxC,MAAM,QAAQ,MAAM,GAAG,KAAA;CAE9C,MAAM,WAAW,MAAM,MAAM,KAAK;EAChC,GAAG,cAAc,EAAE,MAAM,CAAC;EAC1B,QAAQ,QAAQ;EAChB,SAAS;GACP,gBAAgB,QAAQ,QAAQ,IAAI,eAAe,IAAI;GACvD,aAAa,IAAI;GACjB,GAAI,cAAc,EAAE,aAAa,GAAG,EAAE;GACtC,GAAG,WAAW,QAAQ;GACvB;EACD,QAAQ,YAAY,QAAQ,IAAO;EACpC,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,OAAO,MAAM,SAAS,MAAM,CAAC,YAAY,GAAG;AAElD,MAAI,SAAS,UAAU,KAAK;AAC1B,OAAI,MACF,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WACrD,CAAC,KAAK,CACP;AACD,UAAO,SAAS,KACd;IAAE,MAAM;IAA4B,SAAS;IAAM,EACnD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAEH,MAAI,SAAS,UAAU,KAAK;AAC1B,OAAI,KAAK,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WAAW,CACvE,KACD,CAAC;AACF,UAAO,SAAS,KACd;IAAE,MAAM;IAA8B,SAAS;IAAM,EACrD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAGH,MAAI,MAAM,YAAY,SAAS,OAAO,OAAO,QAAQ,OAAO,GAAG,WAAW,CACxE,KACD,CAAC;AACF,SAAO,SAAS,KACd;GAAE,MAAM;GAA4B,SAAS;GAAM,EACnD,EAAE,QAAQ,SAAS,QAAQ,CAC5B;;AAGH,QAAO,IAAI,SAAS,SAAS,MAAM;EACjC,QAAQ,SAAS;EACjB,SAAS,EACP,gBACE,SAAS,QAAQ,IAAI,eAAe,IAAI,oBAC3C;EACF,CAAC"}
package/dist/package.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
2
  var name = "@interfere/next";
3
- var version = "8.0.0";
3
+ var version = "8.1.0";
4
4
  //#endregion
5
5
  export { name, version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/next",
3
- "version": "8.0.0",
3
+ "version": "8.1.0",
4
4
  "license": "MIT",
5
5
  "description": "Build software that never breaks.",
6
6
  "keywords": [
@@ -58,44 +58,40 @@
58
58
  "scripts": {
59
59
  "build": "tsdown",
60
60
  "dev": "tsdown --watch",
61
- "test:e2e": "vitest run --project browser",
62
- "test:unit": "vitest run --project unit --coverage",
63
- "typecheck": "tsc --noEmit --incremental",
64
- "test": "bun run test:unit"
61
+ "test": "vitest run --coverage",
62
+ "typecheck": "tsc --noEmit --incremental"
65
63
  },
66
64
  "dependencies": {
67
- "@interfere/constants": "^8.0.0",
68
- "@interfere/react": "^8.0.0",
69
- "@interfere/sdk": "^8.0.0",
70
- "@interfere/types": "^8.0.0",
65
+ "@interfere/constants": "^8.1.0",
66
+ "@interfere/react": "^8.1.0",
67
+ "@interfere/sdk": "^8.1.0",
68
+ "@interfere/types": "^8.1.0",
71
69
  "chalk": "^5.6.2",
72
70
  "uuid": "^13.0.0"
73
71
  },
74
72
  "peerDependencies": {
75
- "@vercel/blob": "^2",
76
- "next": ">=16",
73
+ "next": ">=16.2.2",
77
74
  "react": ">=19",
78
75
  "react-dom": ">=19"
79
76
  },
80
77
  "devDependencies": {
81
- "@interfere/typescript-config": "^8.0.0",
82
- "@interfere/vitest-config": "^8.0.0",
83
- "@testing-library/react": "^16.3.2",
78
+ "@interfere/typescript-config": "^8.1.0",
79
+ "@interfere/test-utils": "^1.0.0",
84
80
  "@types/node": "^24.12.0",
85
81
  "@types/react": "19.2.14",
86
82
  "@types/react-dom": "19.2.3",
87
83
  "@vitejs/plugin-react": "^6.0.1",
88
- "@vitest/browser": "4.1.0",
89
- "@vitest/browser-playwright": "4.1.0",
90
- "@vitest/coverage-v8": "^4.0.18",
91
- "jsdom": "^29.0.1",
92
- "next": "^16.2.1",
93
- "playwright": "^1.56.1",
84
+ "@vitest/browser": "4.1.2",
85
+ "@vitest/browser-playwright": "4.1.2",
86
+ "@vitest/coverage-v8": "^4.1.2",
87
+ "next": "^16.2.2",
88
+ "playwright": "^1.59.0",
94
89
  "react": "^19.2.4",
95
90
  "react-dom": "^19.2.4",
96
- "tsdown": "^0.21.4",
97
- "typescript": "5.9.3",
98
- "vitest": "^4.0.18",
91
+ "tsdown": "^0.21.6",
92
+ "typescript": "6.0.2",
93
+ "vitest": "^4.1.2",
94
+ "vitest-browser-react": "2.1.0",
99
95
  "webpack": "^5.105.1"
100
96
  }
101
97
  }