@interfere/next 0.0.15-alpha.0 → 0.0.15-alpha.2

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.
Files changed (32) hide show
  1. package/dist/build/logger.d.mts.map +1 -1
  2. package/dist/build/services/preflight.service.mjs +2 -2
  3. package/dist/build/services/preflight.service.mjs.map +1 -1
  4. package/dist/build/source-maps/api.d.mts +1 -1
  5. package/dist/build/source-maps/api.d.mts.map +1 -1
  6. package/dist/build/source-maps/client.d.mts +1 -1
  7. package/dist/build/source-maps/files.mjs +1 -1
  8. package/dist/build/source-maps/files.mjs.map +1 -1
  9. package/dist/build/with-interfere.d.mts +2 -3
  10. package/dist/build/with-interfere.d.mts.map +1 -1
  11. package/dist/build/with-interfere.mjs +4 -4
  12. package/dist/build/with-interfere.mjs.map +1 -1
  13. package/dist/client/provider.d.mts +2 -2
  14. package/dist/client/provider.d.mts.map +1 -1
  15. package/dist/client/provider.mjs +2 -0
  16. package/dist/client/provider.mjs.map +1 -1
  17. package/dist/lib/types.d.mts +4 -4
  18. package/dist/lib/types.d.mts.map +1 -1
  19. package/dist/lib/types.mjs.map +1 -1
  20. package/dist/server/middleware.d.mts.map +1 -1
  21. package/dist/server/middleware.mjs.map +1 -1
  22. package/dist/server/proxy.d.mts.map +1 -1
  23. package/dist/server/proxy.mjs.map +1 -1
  24. package/dist/server/route-handler.d.mts.map +1 -1
  25. package/dist/server/route-handler.mjs.map +1 -1
  26. package/dist/server/services/config.service.d.mts +5 -5
  27. package/dist/server/services/config.service.d.mts.map +1 -1
  28. package/dist/server/services/config.service.mjs.map +1 -1
  29. package/dist/server/services/error-tracking.service.d.mts +5 -5
  30. package/dist/server/services/error-tracking.service.d.mts.map +1 -1
  31. package/dist/server/services/error-tracking.service.mjs.map +1 -1
  32. package/package.json +8 -2
@@ -1 +1 @@
1
- {"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/build/logger.ts"],"sourcesContent":[],"mappings":";;;cA+CM,iBAAe,MAAA,CAAA;AAAf,iBA0HU,cAAA,CA1HK,KAAA,EA0HiB,QAAA,CAAS,OA1H1B,EAAA,KAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,CAAA,EA0HiE,MAAA,CAAA,MA1HjE,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AA0HL,iBAyCA,gBAAA,CAzCsB,KAAS,EA0CtC,QAAA,CAAS,OA1CoE,EAAA,KAAA,EAAA,MAAA,CAAA,EA2CvE,MAAA,CAAA,MA3CuE,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAyCtE,iBAUA,kBAAA,CATP,IAAS,EAAA,MACH,CAAA,EAQgC,MAAA,CAAA,MARhC,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAQC,iBAWA,aAAA,CAAA,CAX+B,EAWlB,MAAA,CAAA,MAXkB,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAW/B,iBAmBA,oBAAA,CAnBa,KAAA,EAoBpB,QAAA,CAAS,OApBW,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,EAAA,CAAA,GAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAuBF,UAvBE,CAAA,OAuBgB,kBAvBhB,CAAA,EAAA,GAwBtB,MAAA,CAAO,MAxBe,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA,CAAA,EAwBkB,MAAA,CAAA,MAxBlB,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA"}
1
+ {"version":3,"file":"logger.d.mts","names":[],"sources":["../../src/build/logger.ts"],"sourcesContent":[],"mappings":";;;cA+CM,iBAAe,MAAA,CAAA;AAAf,iBA0HU,cAAA,CA1HK,KAAA,EA0HiB,QAAA,CAAS,OA1H1B,EAAA,KAAA,EAAA,MAAA,EAAA,KAAA,EAAA,MAAA,EAAA,CAAA,EA0HiE,MAAA,CAAA,MA1HjE,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AA0HL,iBAyCA,gBAAA,CAzC+B,KAAA,EA0CtC,QAAA,CAAS,OA1CoE,EAAA,KAAA,EAAA,MAAA,CAAA,EA2CvE,MAAA,CAAA,MA3CuE,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAyCtE,iBAUA,kBAAA,CATE,IAAA,EAAA,MACH,CAAA,EAQgC,MAAA,CAAA,MARhC,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAQC,iBAWA,aAAA,CAAA,CAX+B,EAWlB,MAAA,CAAA,MAXkB,CAAA,IAAA,EAAA,KAAA,EAAA,KAAA,CAAA;AAW/B,iBAmBA,oBAAA,CAnBa,KAAA,EAoBpB,QAAA,CAAS,OApBW,EAAA,KAAA,EAAA,MAAA,EAAA,GAAA,EAAA,CAAA,GAAA,EAAA,CAAA,IAAA,EAAA,MAAA,EAAA,GAuBF,UAvBE,CAAA,OAuBgB,kBAvBhB,CAAA,EAAA,GAwBtB,MAAA,CAAO,MAxBe,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA,CAAA,EAwBkB,MAAA,CAAA,MAxBlB,CAAA,OAAA,EAAA,OAAA,EAAA,OAAA,CAAA"}
@@ -20,7 +20,7 @@ const validateSecretKey = (raw) => Effect.gen(function* () {
20
20
  const extractSurfaceSlug = (secretKey) => Effect.gen(function* () {
21
21
  const parsed = parseSurfaceSlugFromSecretKey(secretKey);
22
22
  const result = parsed ? toNonEmptyString(parsed) : void 0;
23
- if (!result) return yield* Effect.fail(new InvalidSecretKeyError({ message: "Invalid secret key format. Expected format: int_sk_{surfaceSlug}_{random}. Set the INTERFERE_SECRET_KEY environment variable." }));
23
+ if (!result) return yield* Effect.fail(new InvalidSecretKeyError({ message: "Invalid secret key format. Please use the secret key provided in your Interfere dashboard." }));
24
24
  return result;
25
25
  });
26
26
  const PreflightServiceLive = Layer.succeed(PreflightService, {
@@ -52,7 +52,7 @@ const PreflightServiceLive = Layer.succeed(PreflightService, {
52
52
  yield* logBuildResult("Warning", "Interfere disabled (invalid secret key format)", [
53
53
  message,
54
54
  "Source maps will not be uploaded for this build.",
55
- "Ensure INTERFERE_SECRET_KEY matches the format int_sk_{surfaceSlug}_{random}."
55
+ "Please use the secret key provided in your Interfere dashboard."
56
56
  ]);
57
57
  return {
58
58
  enabled: false,
@@ -1 +1 @@
1
- {"version":3,"file":"preflight.service.mjs","names":[],"sources":["../../../src/build/services/preflight.service.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\nimport {\n type NonEmptyString,\n type PreflightConfig,\n toNonEmptyString,\n} from \"../../lib/types.js\";\nimport { logBuildResult } from \"../logger.js\";\nimport { parseSurfaceSlugFromSecretKey } from \"../secret-key.js\";\nimport {\n InvalidSecretKeyError,\n WithInterfereUsageError,\n} from \"../source-maps/errors.js\";\n\nexport class PreflightService extends Context.Tag(\"PreflightService\")<\n PreflightService,\n {\n readonly validateEnvironment: () => Effect.Effect<void, WithInterfereUsageError>;\n readonly validateSecretKey: (key: string | null) => Effect.Effect<NonEmptyString, InvalidSecretKeyError>;\n readonly extractSurfaceSlug: (key: NonEmptyString) => Effect.Effect<NonEmptyString, InvalidSecretKeyError>;\n readonly buildConfig: (options: {\n environment?: string;\n debug?: boolean;\n cleanupSourceMaps?: boolean;\n }) => Effect.Effect<PreflightConfig, WithInterfereUsageError>;\n }\n>() {}\n\nconst validateEnvironment = () =>\n Effect.gen(function* () {\n if (typeof window !== \"undefined\") {\n return yield* Effect.fail(\n new WithInterfereUsageError({\n message: \"Security Error: withInterfere must only be used in next.config.js (server-side). It should never be imported in client-side code.\"\n })\n );\n }\n\n if (typeof process === \"undefined\" || !process.versions?.node) {\n return yield* Effect.fail(\n new WithInterfereUsageError({\n message: \"Security Error: withInterfere requires Node.js environment. It should only run during build time, not in the browser.\"\n })\n );\n }\n\n if (\n typeof process.env.INTERFERE_SECRET_KEY === \"string\" &&\n process.env.INTERFERE_SECRET_KEY.startsWith(\"NEXT_PUBLIC_\")\n ) {\n return yield* Effect.fail(\n new WithInterfereUsageError({\n message: \"Security Error: Secret key should NOT use NEXT_PUBLIC_ prefix. Use INTERFERE_SECRET_KEY instead to keep it server-side only.\"\n })\n );\n }\n });\n\nconst validateSecretKey = (raw: string | null) =>\n Effect.gen(function* () {\n if (typeof raw !== \"string\") {\n return yield* Effect.fail(\n new InvalidSecretKeyError(\n { message: \"Missing secret key. Set the INTERFERE_SECRET_KEY environment variable\" }\n )\n );\n }\n\n const trimmed = raw.trim();\n const cleaned = trimmed.replace(/^['\"]|['\"]$/g, \"\");\n const result = toNonEmptyString(cleaned);\n\n if (!result) {\n return yield* Effect.fail(\n new InvalidSecretKeyError(\n { message: \"Invalid secret key. Set the INTERFERE_SECRET_KEY environment variable\" }\n )\n );\n }\n\n return result;\n });\n\nconst extractSurfaceSlug = (secretKey: NonEmptyString) =>\n Effect.gen(function* () {\n const parsed = parseSurfaceSlugFromSecretKey(secretKey);\n const result = parsed ? (toNonEmptyString(parsed) as NonEmptyString) : undefined;\n\n if (!result) {\n return yield* Effect.fail(\n new InvalidSecretKeyError(\n { message: \"Invalid secret key format. Expected format: int_sk_{surfaceSlug}_{random}. Set the INTERFERE_SECRET_KEY environment variable.\" }\n )\n );\n }\n\n return result;\n });\n\nexport const PreflightServiceLive = Layer.succeed(\n PreflightService,\n {\n validateEnvironment,\n validateSecretKey,\n extractSurfaceSlug,\n buildConfig: (options) =>\n Effect.gen(function* () {\n yield* validateEnvironment();\n \n const secretKeyRaw = process.env.INTERFERE_SECRET_KEY;\n \n // Try to get secret key and surface slug\n const secretKeyResult = yield* validateSecretKey(\n secretKeyRaw ?? null\n ).pipe(Effect.either);\n\n if (secretKeyResult._tag === \"Left\") {\n const message = secretKeyResult.left.message;\n\n yield* logBuildResult(\n \"Warning\",\n \"Interfere disabled (invalid secret key)\",\n [\n message,\n \"Source maps will not be uploaded for this build.\",\n \"Set a valid INTERFERE_SECRET_KEY in your environment to enable Interfere.\",\n ]\n );\n\n // Return disabled config if no valid secret key\n return {\n enabled: false as const,\n environment: options.environment || process.env.NODE_ENV,\n debug: options.debug ?? false,\n cleanupSourceMaps: options.cleanupSourceMaps ?? true,\n };\n }\n \n const secretKey = secretKeyResult.right;\n const surfaceSlugResult = yield* extractSurfaceSlug(secretKey).pipe(\n Effect.either\n );\n\n if (surfaceSlugResult._tag === \"Left\") {\n const message = surfaceSlugResult.left.message;\n\n yield* logBuildResult(\n \"Warning\",\n \"Interfere disabled (invalid secret key format)\",\n [\n message,\n \"Source maps will not be uploaded for this build.\",\n \"Ensure INTERFERE_SECRET_KEY matches the format int_sk_{surfaceSlug}_{random}.\",\n ]\n );\n\n // Return disabled config if no valid surface slug\n return {\n enabled: false as const,\n environment: options.environment || process.env.NODE_ENV,\n debug: options.debug ?? false,\n cleanupSourceMaps: options.cleanupSourceMaps ?? true,\n };\n }\n\n return {\n enabled: true as const,\n surface: surfaceSlugResult.right,\n secretKey,\n environment: options.environment || process.env.NODE_ENV,\n debug: options.debug ?? false,\n cleanupSourceMaps: options.cleanupSourceMaps ?? true,\n };\n }),\n }\n);\n"],"mappings":";;;;;;;AAaA,IAAa,mBAAb,cAAsC,QAAQ,IAAI,mBAAmB,EAYlE,CAAC;AAEJ,MAAM,4BACJ,OAAO,IAAI,aAAa;AACtB,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,OAAO,KACnB,IAAI,wBAAwB,EAC1B,SAAS,qIACV,CAAC,CACH;AAGH,KAAI,OAAO,YAAY,eAAe,CAAC,QAAQ,UAAU,KACvD,QAAO,OAAO,OAAO,KACnB,IAAI,wBAAwB,EAC1B,SAAS,yHACV,CAAC,CACH;AAGH,KACE,OAAO,QAAQ,IAAI,yBAAyB,YAC5C,QAAQ,IAAI,qBAAqB,WAAW,eAAe,CAE3D,QAAO,OAAO,OAAO,KACnB,IAAI,wBAAwB,EAC1B,SAAS,gIACV,CAAC,CACH;EAEH;AAEJ,MAAM,qBAAqB,QACzB,OAAO,IAAI,aAAa;AACtB,KAAI,OAAO,QAAQ,SACjB,QAAO,OAAO,OAAO,KACnB,IAAI,sBACF,EAAE,SAAS,yEAAyE,CACrF,CACF;CAKH,MAAM,SAAS,iBAFC,IAAI,MAAM,CACF,QAAQ,gBAAgB,GAAG,CACX;AAExC,KAAI,CAAC,OACH,QAAO,OAAO,OAAO,KACnB,IAAI,sBACF,EAAE,SAAS,yEAAyE,CACrF,CACF;AAGH,QAAO;EACP;AAEJ,MAAM,sBAAsB,cAC1B,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,8BAA8B,UAAU;CACvD,MAAM,SAAS,SAAU,iBAAiB,OAAO,GAAsB;AAEvE,KAAI,CAAC,OACH,QAAO,OAAO,OAAO,KACnB,IAAI,sBACF,EAAE,SAAS,iIAAiI,CAC7I,CACF;AAGH,QAAO;EACP;AAEJ,MAAa,uBAAuB,MAAM,QACxC,kBACA;CACE;CACA;CACA;CACA,cAAc,YACZ,OAAO,IAAI,aAAa;AACtB,SAAO,qBAAqB;EAE5B,MAAM,eAAe,QAAQ,IAAI;EAGjC,MAAM,kBAAkB,OAAO,kBAC7B,gBAAgB,KACjB,CAAC,KAAK,OAAO,OAAO;AAErB,MAAI,gBAAgB,SAAS,QAAQ;GACnC,MAAM,UAAU,gBAAgB,KAAK;AAErC,UAAO,eACL,WACA,2CACA;IACE;IACA;IACA;IACD,CACF;AAGD,UAAO;IACL,SAAS;IACT,aAAa,QAAQ,eAAe,QAAQ,IAAI;IAChD,OAAO,QAAQ,SAAS;IACxB,mBAAmB,QAAQ,qBAAqB;IACjD;;EAGH,MAAM,YAAY,gBAAgB;EAClC,MAAM,oBAAoB,OAAO,mBAAmB,UAAU,CAAC,KAC7D,OAAO,OACR;AAED,MAAI,kBAAkB,SAAS,QAAQ;GACrC,MAAM,UAAU,kBAAkB,KAAK;AAEvC,UAAO,eACL,WACA,kDACA;IACE;IACA;IACA;IACD,CACF;AAGD,UAAO;IACL,SAAS;IACT,aAAa,QAAQ,eAAe,QAAQ,IAAI;IAChD,OAAO,QAAQ,SAAS;IACxB,mBAAmB,QAAQ,qBAAqB;IACjD;;AAGH,SAAO;GACL,SAAS;GACT,SAAS,kBAAkB;GAC3B;GACA,aAAa,QAAQ,eAAe,QAAQ,IAAI;GAChD,OAAO,QAAQ,SAAS;GACxB,mBAAmB,QAAQ,qBAAqB;GACjD;GACD;CACL,CACF"}
1
+ {"version":3,"file":"preflight.service.mjs","names":[],"sources":["../../../src/build/services/preflight.service.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\nimport {\n type NonEmptyString,\n type PreflightConfig,\n toNonEmptyString,\n} from \"../../lib/types.js\";\nimport { logBuildResult } from \"../logger.js\";\nimport { parseSurfaceSlugFromSecretKey } from \"../secret-key.js\";\nimport {\n InvalidSecretKeyError,\n WithInterfereUsageError,\n} from \"../source-maps/errors.js\";\n\nexport class PreflightService extends Context.Tag(\"PreflightService\")<\n PreflightService,\n {\n readonly validateEnvironment: () => Effect.Effect<void, WithInterfereUsageError>;\n readonly validateSecretKey: (key: string | null) => Effect.Effect<NonEmptyString, InvalidSecretKeyError>;\n readonly extractSurfaceSlug: (key: NonEmptyString) => Effect.Effect<NonEmptyString, InvalidSecretKeyError>;\n readonly buildConfig: (options: {\n environment?: string;\n debug?: boolean;\n cleanupSourceMaps?: boolean;\n }) => Effect.Effect<PreflightConfig, WithInterfereUsageError>;\n }\n>() {}\n\nconst validateEnvironment = () =>\n Effect.gen(function* () {\n if (typeof window !== \"undefined\") {\n return yield* Effect.fail(\n new WithInterfereUsageError({\n message: \"Security Error: withInterfere must only be used in next.config.js (server-side). It should never be imported in client-side code.\"\n })\n );\n }\n\n if (typeof process === \"undefined\" || !process.versions?.node) {\n return yield* Effect.fail(\n new WithInterfereUsageError({\n message: \"Security Error: withInterfere requires Node.js environment. It should only run during build time, not in the browser.\"\n })\n );\n }\n\n if (\n typeof process.env.INTERFERE_SECRET_KEY === \"string\" &&\n process.env.INTERFERE_SECRET_KEY.startsWith(\"NEXT_PUBLIC_\")\n ) {\n return yield* Effect.fail(\n new WithInterfereUsageError({\n message: \"Security Error: Secret key should NOT use NEXT_PUBLIC_ prefix. Use INTERFERE_SECRET_KEY instead to keep it server-side only.\"\n })\n );\n }\n });\n\nconst validateSecretKey = (raw: string | null) =>\n Effect.gen(function* () {\n if (typeof raw !== \"string\") {\n return yield* Effect.fail(\n new InvalidSecretKeyError(\n { message: \"Missing secret key. Set the INTERFERE_SECRET_KEY environment variable\" }\n )\n );\n }\n\n const trimmed = raw.trim();\n const cleaned = trimmed.replace(/^['\"]|['\"]$/g, \"\");\n const result = toNonEmptyString(cleaned);\n\n if (!result) {\n return yield* Effect.fail(\n new InvalidSecretKeyError(\n { message: \"Invalid secret key. Set the INTERFERE_SECRET_KEY environment variable\" }\n )\n );\n }\n\n return result;\n });\n\nconst extractSurfaceSlug = (secretKey: NonEmptyString) =>\n Effect.gen(function* () {\n const parsed = parseSurfaceSlugFromSecretKey(secretKey);\n const result = parsed ? (toNonEmptyString(parsed) as NonEmptyString) : undefined;\n\n if (!result) {\n return yield* Effect.fail(\n new InvalidSecretKeyError(\n { message: \"Invalid secret key format. Please use the secret key provided in your Interfere dashboard.\" }\n )\n );\n }\n\n return result;\n });\n\nexport const PreflightServiceLive = Layer.succeed(\n PreflightService,\n {\n validateEnvironment,\n validateSecretKey,\n extractSurfaceSlug,\n buildConfig: (options) =>\n Effect.gen(function* () {\n yield* validateEnvironment();\n \n const secretKeyRaw = process.env.INTERFERE_SECRET_KEY;\n \n // Try to get secret key and surface slug\n const secretKeyResult = yield* validateSecretKey(\n secretKeyRaw ?? null\n ).pipe(Effect.either);\n\n if (secretKeyResult._tag === \"Left\") {\n const message = secretKeyResult.left.message;\n\n yield* logBuildResult(\n \"Warning\",\n \"Interfere disabled (invalid secret key)\",\n [\n message,\n \"Source maps will not be uploaded for this build.\",\n \"Set a valid INTERFERE_SECRET_KEY in your environment to enable Interfere.\",\n ]\n );\n\n // Return disabled config if no valid secret key\n return {\n enabled: false as const,\n environment: options.environment || process.env.NODE_ENV,\n debug: options.debug ?? false,\n cleanupSourceMaps: options.cleanupSourceMaps ?? true,\n };\n }\n \n const secretKey = secretKeyResult.right;\n const surfaceSlugResult = yield* extractSurfaceSlug(secretKey).pipe(\n Effect.either\n );\n\n if (surfaceSlugResult._tag === \"Left\") {\n const message = surfaceSlugResult.left.message;\n\n yield* logBuildResult(\n \"Warning\",\n \"Interfere disabled (invalid secret key format)\",\n [\n message,\n \"Source maps will not be uploaded for this build.\",\n \"Please use the secret key provided in your Interfere dashboard.\",\n ]\n );\n\n // Return disabled config if no valid surface slug\n return {\n enabled: false as const,\n environment: options.environment || process.env.NODE_ENV,\n debug: options.debug ?? false,\n cleanupSourceMaps: options.cleanupSourceMaps ?? true,\n };\n }\n\n return {\n enabled: true as const,\n surface: surfaceSlugResult.right,\n secretKey,\n environment: options.environment || process.env.NODE_ENV,\n debug: options.debug ?? false,\n cleanupSourceMaps: options.cleanupSourceMaps ?? true,\n };\n }),\n }\n);\n"],"mappings":";;;;;;;AAaA,IAAa,mBAAb,cAAsC,QAAQ,IAAI,mBAAmB,EAYlE,CAAC;AAEJ,MAAM,4BACJ,OAAO,IAAI,aAAa;AACtB,KAAI,OAAO,WAAW,YACpB,QAAO,OAAO,OAAO,KACnB,IAAI,wBAAwB,EAC1B,SAAS,qIACV,CAAC,CACH;AAGH,KAAI,OAAO,YAAY,eAAe,CAAC,QAAQ,UAAU,KACvD,QAAO,OAAO,OAAO,KACnB,IAAI,wBAAwB,EAC1B,SAAS,yHACV,CAAC,CACH;AAGH,KACE,OAAO,QAAQ,IAAI,yBAAyB,YAC5C,QAAQ,IAAI,qBAAqB,WAAW,eAAe,CAE3D,QAAO,OAAO,OAAO,KACnB,IAAI,wBAAwB,EAC1B,SAAS,gIACV,CAAC,CACH;EAEH;AAEJ,MAAM,qBAAqB,QACzB,OAAO,IAAI,aAAa;AACtB,KAAI,OAAO,QAAQ,SACjB,QAAO,OAAO,OAAO,KACnB,IAAI,sBACF,EAAE,SAAS,yEAAyE,CACrF,CACF;CAKH,MAAM,SAAS,iBAFC,IAAI,MAAM,CACF,QAAQ,gBAAgB,GAAG,CACX;AAExC,KAAI,CAAC,OACH,QAAO,OAAO,OAAO,KACnB,IAAI,sBACF,EAAE,SAAS,yEAAyE,CACrF,CACF;AAGH,QAAO;EACP;AAEJ,MAAM,sBAAsB,cAC1B,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,8BAA8B,UAAU;CACvD,MAAM,SAAS,SAAU,iBAAiB,OAAO,GAAsB;AAEvE,KAAI,CAAC,OACH,QAAO,OAAO,OAAO,KACnB,IAAI,sBACF,EAAE,SAAS,8FAA8F,CAC1G,CACF;AAGH,QAAO;EACP;AAEJ,MAAa,uBAAuB,MAAM,QACxC,kBACA;CACE;CACA;CACA;CACA,cAAc,YACZ,OAAO,IAAI,aAAa;AACtB,SAAO,qBAAqB;EAE5B,MAAM,eAAe,QAAQ,IAAI;EAGjC,MAAM,kBAAkB,OAAO,kBAC7B,gBAAgB,KACjB,CAAC,KAAK,OAAO,OAAO;AAErB,MAAI,gBAAgB,SAAS,QAAQ;GACnC,MAAM,UAAU,gBAAgB,KAAK;AAErC,UAAO,eACL,WACA,2CACA;IACE;IACA;IACA;IACD,CACF;AAGD,UAAO;IACL,SAAS;IACT,aAAa,QAAQ,eAAe,QAAQ,IAAI;IAChD,OAAO,QAAQ,SAAS;IACxB,mBAAmB,QAAQ,qBAAqB;IACjD;;EAGH,MAAM,YAAY,gBAAgB;EAClC,MAAM,oBAAoB,OAAO,mBAAmB,UAAU,CAAC,KAC7D,OAAO,OACR;AAED,MAAI,kBAAkB,SAAS,QAAQ;GACrC,MAAM,UAAU,kBAAkB,KAAK;AAEvC,UAAO,eACL,WACA,kDACA;IACE;IACA;IACA;IACD,CACF;AAGD,UAAO;IACL,SAAS;IACT,aAAa,QAAQ,eAAe,QAAQ,IAAI;IAChD,OAAO,QAAQ,SAAS;IACxB,mBAAmB,QAAQ,qBAAqB;IACjD;;AAGH,SAAO;GACL,SAAS;GACT,SAAS,kBAAkB;GAC3B;GACA,aAAa,QAAQ,eAAe,QAAQ,IAAI;GAChD,OAAO,QAAQ,SAAS;GACxB,mBAAmB,QAAQ,qBAAqB;GACjD;GACD;CACL,CACF"}
@@ -30,6 +30,6 @@ declare function createRelease(config: PreflightConfig, releaseInfo: ReleaseInfo
30
30
  declare function uploadSourceMaps(sourceMaps: UploadedSourceMap[], sourceMapToGenerated: Record<string, string>, config: PreflightConfig, meta: UploadMeta): Effect.Effect<{
31
31
  uploaded: number;
32
32
  processed: any;
33
- }, UploadError | TokenRequestError | NotificationError, never>;
33
+ }, TokenRequestError | UploadError | NotificationError, never>;
34
34
  //#endregion
35
35
  export { createRelease, uploadSourceMaps };
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.mts","names":[],"sources":["../../../src/build/source-maps/api.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAyBK,WAAA;;EAAA,QAAA,EAAA,MAAW;EAGF,UAAA,EAAA,iBAAA;EACI,cAAA,EAAA,qBAAA;EACC,eAAA,EAAA,sBAAA;EACI,mBAAA,EAAA,0BAAA;CAA0B;AA4FjC,iBAAA,aAAA,CAAa,MAAA,EACnB,eADmB,EAAA,WAAA,EAEd,WAFc,CAAA,EAEH,MAAA,CAAA,MAFG,CAAA;EACnB,KAAA,EAAA,MAAA;EACK,SAAA,EAAA,MAAA;;;;EAAW,SAAA,EAAA,MAAA;EAAA,WAAA,EAAA,MAAA;AAmB1B,CAAA,aAAgB,qBAAgB,wBAAA,EAAA,KAAA,CAAA;;;;;iBAAhB,gBAAA,aACF,2CACU,gCACd,uBACF,aAAU,MAAA,CAAA;;;CAAA,aAAA,wCAAA,EAAA,KAAA,CAAA"}
1
+ {"version":3,"file":"api.d.mts","names":[],"sources":["../../../src/build/source-maps/api.ts"],"sourcesContent":[],"mappings":";;;;;;;;KAyBK,WAAA;;EAAA,QAAA,EAAA,MAAW;EAGF,UAAA,EAAA,iBAAA;EACI,cAAA,EAAA,qBAAA;EACC,eAAA,EAAA,sBAAA;EACI,mBAAA,EAAA,0BAAA;CAA0B;AA4FjC,iBAAA,aAAA,CAAa,MAAA,EACnB,eADmB,EAAA,WAAA,EAEd,WAFc,CAAA,EAEH,MAAA,CAAA,MAFG,CAAA;EACnB,KAAA,EAAA,MAAA;EACK,SAAA,EAAA,MAAA;;;;EAAW,SAAA,EAAA,MAAA;EAAA,WAAA,EAAA,MAAA;AAmB1B,CAAA,aAAgB,qBAAgB,wBAAA,EAAA,KAAA,CAAA;;;;;AAId,iBAJF,gBAAA,CAIE,UAAA,EAHJ,iBAGI,EAAA,EAAA,oBAAA,EAFM,MAEN,CAAA,MAAA,EAAA,MAAA,CAAA,EAAA,MAAA,EADR,eACQ,EAAA,IAAA,EAAV,UAAU,CAAA,EAAA,MAAA,CAAA,MAAA,CAAA;;;CAAA,EAAA,iBAAA,cAAA,oBAAA,EAAA,KAAA,CAAA"}
@@ -67,7 +67,7 @@ declare class SourceMapClient {
67
67
  uploadSourceMaps(releaseSlug: string, sourceMapFiles: SourceMapFileWithContent[], sourceMapToGenerated: Record<string, string>): Effect.Effect<{
68
68
  uploaded: number;
69
69
  processed: any;
70
- }, UploadError | TokenRequestError | NotificationError, never>;
70
+ }, TokenRequestError | UploadError | NotificationError, never>;
71
71
  }
72
72
  //#endregion
73
73
  export { SourceMapClient };
@@ -105,7 +105,7 @@ function findGeneratedJsFiles() {
105
105
  }
106
106
  /**
107
107
  * Regex to extract sourceMappingURL from JS files
108
- * Matches: //# sourceMappingURL=filename.js.map or //@ sourceMappingURL=filename.js.map
108
+ * Matches: //# sourceMappingURL = filename.js.map or //@ sourceMappingURL = filename.js.map
109
109
  */
110
110
  const SOURCE_MAPPING_URL_REGEX = /\/\/[#@] ?sourceMappingURL=([^\s'"]+)\s*$/gm;
111
111
  const HTTP_PREFIX_REGEX = /^https?:\/\//i;
@@ -1 +1 @@
1
- {"version":3,"file":"files.mjs","names":["mapping: Record<string, string>"],"sources":["../../../src/build/source-maps/files.ts"],"sourcesContent":["import { readFile, unlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Effect } from \"effect\";\nimport { glob } from \"glob\";\nimport { appendBuildLogLine } from \"../logger.js\";\nimport {\n FileDeleteError,\n FileGlobError,\n FileHashError,\n FileReadError,\n} from \"./errors.js\";\n\nconst SOURCE_MAP_GLOB = \".next/**/*.js.map\";\nconst JS_GLOB = \".next/**/*.js\";\n\nasync function hashString(content: string) {\n const crypto = await import(\"crypto\");\n\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function findSourceMapFiles() {\n return Effect.tryPromise({\n try: () =>\n glob(SOURCE_MAP_GLOB, {\n cwd: process.cwd(),\n absolute: true,\n }),\n catch: (error) => new FileGlobError({\n message: `Failed to find source map files: ${String(error)}`,\n pattern: SOURCE_MAP_GLOB,\n }),\n });\n}\n\nexport function readSourceMapsFromFiles(paths: string[]) {\n return Effect.forEach(\n paths,\n (filePath) =>\n Effect.gen(function* () {\n const content = yield* Effect.tryPromise({\n try: () => readFile(filePath, \"utf8\"),\n catch: (error) => new FileReadError({\n message: `Failed to read file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const hash = yield* Effect.tryPromise({\n try: () => hashString(content),\n catch: (error) => new FileHashError({\n message: `Failed to hash file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const relativePath = path.relative(process.cwd(), filePath).replace(\n /\\\\/g,\n \"/\"\n );\n\n return {\n relativePath: toPublicUrlPath(relativePath),\n content,\n hash,\n };\n }),\n { concurrency: \"unbounded\" }\n );\n}\n\nexport function cleanupSourceMaps(paths: string[], debug: boolean) {\n if (paths.length === 0) {\n return Effect.void;\n }\n\n return Effect.gen(function* () {\n const results = yield* Effect.forEach(\n paths,\n (filePath) =>\n Effect.tryPromise({\n try: () => unlink(filePath),\n catch: (error) => new FileDeleteError({\n message: `Failed to delete file: ${String(error)}`,\n path: filePath,\n }),\n }).pipe(\n Effect.map(() => ({ file: filePath, success: true })),\n Effect.catchAll((error) =>\n debug\n ? Effect.gen(function* () {\n yield* appendBuildLogLine(\n `Failed to delete source map file ${JSON.stringify({\n file: filePath,\n error: error.message,\n })}`\n );\n\n return { file: filePath, success: false };\n })\n : Effect.succeed({ file: filePath, success: false })\n )\n ),\n { concurrency: \"unbounded\" }\n );\n\n const successful = results.filter((result) => result.success).length;\n const failed = results.length - successful;\n\n if (successful > 0) {\n yield* appendBuildLogLine(\n `Cleaned ${successful}/${paths.length} source map files`\n );\n }\n\n if (failed > 0 && debug) {\n return yield* Effect.fail(new FileDeleteError({\n message: `Failed to clean up ${failed} source map files - Failing the build to avoid leaking source maps to the public`,\n path: \"multiple files\",\n }));\n }\n });\n}\n\nexport function maybeCleanupAfterFailure(debug: boolean) {\n return Effect.gen(function* () {\n const files = yield* findSourceMapFiles();\n\n if (files.length === 0) {\n return;\n }\n\n yield* cleanupSourceMaps(files, debug);\n });\n}\n\n/**\n * Find all generated JavaScript files (excluding source maps)\n */\nexport function findGeneratedJsFiles() {\n return Effect.tryPromise({\n try: () =>\n glob(JS_GLOB, {\n cwd: process.cwd(),\n absolute: true,\n ignore: [\"**/*.map\"], // Exclude source map files\n }),\n catch: (error) => new FileGlobError({\n message: `Failed to find generated JS files: ${String(error)}`,\n pattern: JS_GLOB,\n }),\n });\n}\n\n/**\n * Regex to extract sourceMappingURL from JS files\n * Matches: //# sourceMappingURL=filename.js.map or //@ sourceMappingURL=filename.js.map\n */\nconst SOURCE_MAPPING_URL_REGEX = /\\/\\/[#@] ?sourceMappingURL=([^\\s'\"]+)\\s*$/gm;\n\nconst HTTP_PREFIX_REGEX = /^https?:\\/\\//i;\n\nfunction removeQueryString(value: string): string {\n const queryIndex = value.indexOf(\"?\");\n return queryIndex === -1 ? value : value.slice(0, queryIndex);\n}\n\nfunction normalizeReferenceSlashes(value: string): string {\n return value.replace(/\\\\/g, \"/\");\n}\n\n/**\n * Normalize an absolute reference to the public URL path format.\n * Next.js serves .next/ directory as _next/ in URLs, so we store paths\n * in the _next/ format to match what appears in error stack traces.\n */\nfunction normalizeAbsoluteReference(value: string): string {\n const normalized = normalizeReferenceSlashes(value);\n const trimmed = normalized.replace(/^\\/+/, \"\");\n\n // If it already has _next/, extract from there (handles CDN prefixes like /prod/_next/)\n const publicIndex = trimmed.indexOf(\"_next/\");\n if (publicIndex !== -1) {\n return trimmed.slice(publicIndex);\n }\n\n // Convert .next/ build path to _next/ public URL path\n const buildIndex = trimmed.indexOf(\".next/\");\n if (buildIndex !== -1) {\n return `_next/${trimmed.slice(buildIndex + \".next/\".length)}`;\n }\n\n return trimmed;\n}\n\n/**\n * Extract sourceMappingURL reference from JS file content\n */\nfunction extractSourceMappingReference(content: string): string | null {\n SOURCE_MAPPING_URL_REGEX.lastIndex = 0;\n const match = SOURCE_MAPPING_URL_REGEX.exec(content);\n if (match && match[1]) {\n return match[1].trim();\n }\n return null;\n}\n\nfunction resolveSourceMapRelativePath(\n jsRelativePath: string,\n reference: string\n): string | null {\n if (!reference) {\n return null;\n }\n\n const withoutQuery = removeQueryString(reference);\n if (!withoutQuery) {\n return null;\n }\n\n const normalizedReference = normalizeReferenceSlashes(withoutQuery);\n\n if (HTTP_PREFIX_REGEX.test(normalizedReference)) {\n try {\n const url = new URL(normalizedReference);\n return normalizeAbsoluteReference(url.pathname);\n } catch {\n return normalizeAbsoluteReference(normalizedReference);\n }\n }\n\n if (normalizedReference.startsWith(\"/\")) {\n return normalizeAbsoluteReference(normalizedReference);\n }\n\n const jsDirectory = path.posix.dirname(jsRelativePath);\n const resolved = path.posix.normalize(\n path.posix.join(jsDirectory, normalizedReference)\n );\n\n return toPublicUrlPath(normalizeReferenceSlashes(resolved));\n}\n\n// Regex to convert .next/ build paths to _next/ public URL paths\nconst NEXT_BUILD_TO_PUBLIC_REGEX = /^\\.next\\//;\n\n/**\n * Convert a build path to a public URL path.\n * Next.js serves .next/ directory as _next/ in URLs.\n * So on our backend we store it as the public URL path since that's what appears in error stack traces.\n */\nfunction toPublicUrlPath(buildPath: string): string {\n return buildPath.replace(NEXT_BUILD_TO_PUBLIC_REGEX, \"_next/\");\n}\n\n/**\n * Read generated JS files and extract sourceMappingURL to build a mapping.\n * Returns a map: sourceMapFilename -> generatedJsFilePath\n * \n * Both keys and values are in public URL format (_next/...) to match\n * what appears in error stack traces, making the backend framework-agnostic.\n */\nexport function buildSourceMapToGeneratedMapping(paths: string[]) {\n return Effect.forEach(\n paths,\n (filePath) =>\n Effect.gen(function* () {\n const content = yield* Effect.tryPromise({\n try: () => readFile(filePath, \"utf8\"),\n catch: (error) => new FileReadError({\n message: `Failed to read file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const relativePath = path\n .relative(process.cwd(), filePath)\n .replace(/\\\\/g, \"/\");\n\n const sourceMapReference = extractSourceMappingReference(content);\n const sourceMapRelativePath = sourceMapReference\n ? resolveSourceMapRelativePath(relativePath, sourceMapReference)\n : null;\n\n return {\n // Convert .next/ to _next/ for public URL format\n generatedFilePath: toPublicUrlPath(relativePath),\n sourceMapRelativePath,\n };\n }),\n { concurrency: \"unbounded\" }\n ).pipe(\n Effect.map((results) => {\n // Build reverse mapping: sourceMapRelativePath -> generatedFilePath\n const mapping: Record<string, string> = {};\n for (const result of results) {\n if (result.sourceMapRelativePath) {\n mapping[result.sourceMapRelativePath] = result.generatedFilePath;\n }\n }\n return mapping;\n })\n );\n}\n\n/**\n * Read generated JS files from disk\n * @deprecated Use buildSourceMapToGeneratedMapping instead - we no longer upload JS files\n */\nexport function readGeneratedJsFiles(paths: string[]) {\n return Effect.forEach(\n paths,\n (filePath) =>\n Effect.gen(function* () {\n const content = yield* Effect.tryPromise({\n try: () => readFile(filePath, \"utf8\"),\n catch: (error) => new FileReadError({\n message: `Failed to read file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const hash = yield* Effect.tryPromise({\n try: () => hashString(content),\n catch: (error) => new FileHashError({\n message: `Failed to hash file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const relativePath = path\n .relative(process.cwd(), filePath)\n .replace(/\\\\/g, \"/\");\n\n return {\n relativePath,\n content,\n hash,\n };\n }),\n { concurrency: \"unbounded\" }\n );\n}\n\n\n\n\n"],"mappings":"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"}
1
+ {"version":3,"file":"files.mjs","names":["mapping: Record<string, string>"],"sources":["../../../src/build/source-maps/files.ts"],"sourcesContent":["import { readFile, unlink } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { Effect } from \"effect\";\nimport { glob } from \"glob\";\nimport { appendBuildLogLine } from \"../logger.js\";\nimport {\n FileDeleteError,\n FileGlobError,\n FileHashError,\n FileReadError,\n} from \"./errors.js\";\n\nconst SOURCE_MAP_GLOB = \".next/**/*.js.map\";\nconst JS_GLOB = \".next/**/*.js\";\n\nasync function hashString(content: string) {\n const crypto = await import(\"crypto\");\n\n return crypto.createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nexport function findSourceMapFiles() {\n return Effect.tryPromise({\n try: () =>\n glob(SOURCE_MAP_GLOB, {\n cwd: process.cwd(),\n absolute: true,\n }),\n catch: (error) => new FileGlobError({\n message: `Failed to find source map files: ${String(error)}`,\n pattern: SOURCE_MAP_GLOB,\n }),\n });\n}\n\nexport function readSourceMapsFromFiles(paths: string[]) {\n return Effect.forEach(\n paths,\n (filePath) =>\n Effect.gen(function* () {\n const content = yield* Effect.tryPromise({\n try: () => readFile(filePath, \"utf8\"),\n catch: (error) => new FileReadError({\n message: `Failed to read file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const hash = yield* Effect.tryPromise({\n try: () => hashString(content),\n catch: (error) => new FileHashError({\n message: `Failed to hash file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const relativePath = path.relative(process.cwd(), filePath).replace(\n /\\\\/g,\n \"/\"\n );\n\n return {\n relativePath: toPublicUrlPath(relativePath),\n content,\n hash,\n };\n }),\n { concurrency: \"unbounded\" }\n );\n}\n\nexport function cleanupSourceMaps(paths: string[], debug: boolean) {\n if (paths.length === 0) {\n return Effect.void;\n }\n\n return Effect.gen(function* () {\n const results = yield* Effect.forEach(\n paths,\n (filePath) =>\n Effect.tryPromise({\n try: () => unlink(filePath),\n catch: (error) => new FileDeleteError({\n message: `Failed to delete file: ${String(error)}`,\n path: filePath,\n }),\n }).pipe(\n Effect.map(() => ({ file: filePath, success: true })),\n Effect.catchAll((error) =>\n debug\n ? Effect.gen(function* () {\n yield* appendBuildLogLine(\n `Failed to delete source map file ${JSON.stringify({\n file: filePath,\n error: error.message,\n })}`\n );\n\n return { file: filePath, success: false };\n })\n : Effect.succeed({ file: filePath, success: false })\n )\n ),\n { concurrency: \"unbounded\" }\n );\n\n const successful = results.filter((result) => result.success).length;\n const failed = results.length - successful;\n\n if (successful > 0) {\n yield* appendBuildLogLine(\n `Cleaned ${successful}/${paths.length} source map files`\n );\n }\n\n if (failed > 0 && debug) {\n return yield* Effect.fail(new FileDeleteError({\n message: `Failed to clean up ${failed} source map files - Failing the build to avoid leaking source maps to the public`,\n path: \"multiple files\",\n }));\n }\n });\n}\n\nexport function maybeCleanupAfterFailure(debug: boolean) {\n return Effect.gen(function* () {\n const files = yield* findSourceMapFiles();\n\n if (files.length === 0) {\n return;\n }\n\n yield* cleanupSourceMaps(files, debug);\n });\n}\n\n/**\n * Find all generated JavaScript files (excluding source maps)\n */\nexport function findGeneratedJsFiles() {\n return Effect.tryPromise({\n try: () =>\n glob(JS_GLOB, {\n cwd: process.cwd(),\n absolute: true,\n ignore: [\"**/*.map\"], // Exclude source map files\n }),\n catch: (error) => new FileGlobError({\n message: `Failed to find generated JS files: ${String(error)}`,\n pattern: JS_GLOB,\n }),\n });\n}\n\n/**\n * Regex to extract sourceMappingURL from JS files\n * Matches: //# sourceMappingURL = filename.js.map or //@ sourceMappingURL = filename.js.map\n */\nconst SOURCE_MAPPING_URL_REGEX = /\\/\\/[#@] ?sourceMappingURL=([^\\s'\"]+)\\s*$/gm;\n\nconst HTTP_PREFIX_REGEX = /^https?:\\/\\//i;\n\nfunction removeQueryString(value: string): string {\n const queryIndex = value.indexOf(\"?\");\n return queryIndex === -1 ? value : value.slice(0, queryIndex);\n}\n\nfunction normalizeReferenceSlashes(value: string): string {\n return value.replace(/\\\\/g, \"/\");\n}\n\n/**\n * Normalize an absolute reference to the public URL path format.\n * Next.js serves .next/ directory as _next/ in URLs, so we store paths\n * in the _next/ format to match what appears in error stack traces.\n */\nfunction normalizeAbsoluteReference(value: string): string {\n const normalized = normalizeReferenceSlashes(value);\n const trimmed = normalized.replace(/^\\/+/, \"\");\n\n // If it already has _next/, extract from there (handles CDN prefixes like /prod/_next/)\n const publicIndex = trimmed.indexOf(\"_next/\");\n if (publicIndex !== -1) {\n return trimmed.slice(publicIndex);\n }\n\n // Convert .next/ build path to _next/ public URL path\n const buildIndex = trimmed.indexOf(\".next/\");\n if (buildIndex !== -1) {\n return `_next/${trimmed.slice(buildIndex + \".next/\".length)}`;\n }\n\n return trimmed;\n}\n\n/**\n * Extract sourceMappingURL reference from JS file content\n */\nfunction extractSourceMappingReference(content: string): string | null {\n SOURCE_MAPPING_URL_REGEX.lastIndex = 0;\n const match = SOURCE_MAPPING_URL_REGEX.exec(content);\n if (match && match[1]) {\n return match[1].trim();\n }\n return null;\n}\n\nfunction resolveSourceMapRelativePath(\n jsRelativePath: string,\n reference: string\n): string | null {\n if (!reference) {\n return null;\n }\n\n const withoutQuery = removeQueryString(reference);\n if (!withoutQuery) {\n return null;\n }\n\n const normalizedReference = normalizeReferenceSlashes(withoutQuery);\n\n if (HTTP_PREFIX_REGEX.test(normalizedReference)) {\n try {\n const url = new URL(normalizedReference);\n return normalizeAbsoluteReference(url.pathname);\n } catch {\n return normalizeAbsoluteReference(normalizedReference);\n }\n }\n\n if (normalizedReference.startsWith(\"/\")) {\n return normalizeAbsoluteReference(normalizedReference);\n }\n\n const jsDirectory = path.posix.dirname(jsRelativePath);\n const resolved = path.posix.normalize(\n path.posix.join(jsDirectory, normalizedReference)\n );\n\n return toPublicUrlPath(normalizeReferenceSlashes(resolved));\n}\n\n// Regex to convert .next/ build paths to _next/ public URL paths\nconst NEXT_BUILD_TO_PUBLIC_REGEX = /^\\.next\\//;\n\n/**\n * Convert a build path to a public URL path.\n * Next.js serves .next/ directory as _next/ in URLs.\n * So on our backend we store it as the public URL path since that's what appears in error stack traces.\n */\nfunction toPublicUrlPath(buildPath: string): string {\n return buildPath.replace(NEXT_BUILD_TO_PUBLIC_REGEX, \"_next/\");\n}\n\n/**\n * Read generated JS files and extract sourceMappingURL to build a mapping.\n * Returns a map: sourceMapFilename -> generatedJsFilePath\n * \n * Both keys and values are in public URL format (_next/...) to match\n * what appears in error stack traces, making the backend framework-agnostic.\n */\nexport function buildSourceMapToGeneratedMapping(paths: string[]) {\n return Effect.forEach(\n paths,\n (filePath) =>\n Effect.gen(function* () {\n const content = yield* Effect.tryPromise({\n try: () => readFile(filePath, \"utf8\"),\n catch: (error) => new FileReadError({\n message: `Failed to read file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const relativePath = path\n .relative(process.cwd(), filePath)\n .replace(/\\\\/g, \"/\");\n\n const sourceMapReference = extractSourceMappingReference(content);\n const sourceMapRelativePath = sourceMapReference\n ? resolveSourceMapRelativePath(relativePath, sourceMapReference)\n : null;\n\n return {\n // Convert .next/ to _next/ for public URL format\n generatedFilePath: toPublicUrlPath(relativePath),\n sourceMapRelativePath,\n };\n }),\n { concurrency: \"unbounded\" }\n ).pipe(\n Effect.map((results) => {\n // Build reverse mapping: sourceMapRelativePath -> generatedFilePath\n const mapping: Record<string, string> = {};\n for (const result of results) {\n if (result.sourceMapRelativePath) {\n mapping[result.sourceMapRelativePath] = result.generatedFilePath;\n }\n }\n return mapping;\n })\n );\n}\n\n/**\n * Read generated JS files from disk\n * @deprecated Use buildSourceMapToGeneratedMapping instead - we no longer upload JS files\n */\nexport function readGeneratedJsFiles(paths: string[]) {\n return Effect.forEach(\n paths,\n (filePath) =>\n Effect.gen(function* () {\n const content = yield* Effect.tryPromise({\n try: () => readFile(filePath, \"utf8\"),\n catch: (error) => new FileReadError({\n message: `Failed to read file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const hash = yield* Effect.tryPromise({\n try: () => hashString(content),\n catch: (error) => new FileHashError({\n message: `Failed to hash file: ${String(error)}`,\n path: filePath,\n }),\n });\n\n const relativePath = path\n .relative(process.cwd(), filePath)\n .replace(/\\\\/g, \"/\");\n\n return {\n relativePath,\n content,\n hash,\n };\n }),\n { concurrency: \"unbounded\" }\n );\n}\n\n\n\n\n"],"mappings":"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"}
@@ -25,14 +25,13 @@ type NextConfigWithInterfere = NextConfig & {
25
25
  * Next.js configuration wrapper that automatically uploads source maps in production builds
26
26
  *
27
27
  * SECURITY: Secret key must be set via INTERFERE_SECRET_KEY env var (without NEXT_PUBLIC_ prefix)
28
- * Format: int_sk_{surfaceId}_{random}
29
28
  *
30
29
  * @example
31
30
  * ```js
32
31
  * // next.config.js
33
- * const { withInterfere } = require('@interfere/next/build');
32
+ * import { withInterfere } from '@interfere/next/config';
34
33
  *
35
- * module.exports = withInterfere({
34
+ * export default withInterfere({
36
35
  * environment: 'staging',
37
36
  * debug: true,
38
37
  * cleanupSourceMaps: true
@@ -1 +1 @@
1
- {"version":3,"file":"with-interfere.d.mts","names":[],"sources":["../../src/build/with-interfere.ts"],"sourcesContent":[],"mappings":";;;KAQY,gBAAA;;AAAZ;AAkBE;AA0BF;EACE,WAAA,CAAA,EAAA,MAAA;EAEC;;;;;;;;;;;KA3BE,uBAAA,GAA0B;cACjB;;;;;;;;;;;;;;;;;;;;;;iBAuBE,aAAA;;;IAGb,gCAAqC"}
1
+ {"version":3,"file":"with-interfere.d.mts","names":[],"sources":["../../src/build/with-interfere.ts"],"sourcesContent":[],"mappings":";;;KAQY,gBAAA;;AAAZ;AAkBE;AAyBF;EACE,WAAA,CAAA,EAAA,MAAA;EAEC;;;;;;;;;;;KA1BE,uBAAA,GAA0B;cACjB;;;;;;;;;;;;;;;;;;;;;iBAsBE,aAAA;;;IAGb,gCAAqC"}
@@ -10,14 +10,13 @@ import { Effect, Layer, LogLevel, Logger, Option } from "effect";
10
10
  * Next.js configuration wrapper that automatically uploads source maps in production builds
11
11
  *
12
12
  * SECURITY: Secret key must be set via INTERFERE_SECRET_KEY env var (without NEXT_PUBLIC_ prefix)
13
- * Format: int_sk_{surfaceId}_{random}
14
13
  *
15
14
  * @example
16
15
  * ```js
17
16
  * // next.config.js
18
- * const { withInterfere } = require('@interfere/next/build');
17
+ * import { withInterfere } from '@interfere/next/config';
19
18
  *
20
- * module.exports = withInterfere({
19
+ * export default withInterfere({
21
20
  * environment: 'staging',
22
21
  * debug: true,
23
22
  * cleanupSourceMaps: true
@@ -66,7 +65,8 @@ function withInterfere({ interfere = {}, ...nextConfig } = {}) {
66
65
  ...nextConfig,
67
66
  compiler,
68
67
  env,
69
- productionBrowserSourceMaps: interfereConfig.enabled ? true : nextConfig.productionBrowserSourceMaps
68
+ productionBrowserSourceMaps: interfereConfig.enabled ? true : nextConfig.productionBrowserSourceMaps,
69
+ turbopack: nextConfig.turbopack ?? {}
70
70
  };
71
71
  };
72
72
  }
@@ -1 +1 @@
1
- {"version":3,"file":"with-interfere.mjs","names":[],"sources":["../../src/build/with-interfere.ts"],"sourcesContent":["import { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport { Effect, Layer, Logger, LogLevel, Option } from \"effect\";\nimport type { NextConfig } from \"next\";\nimport { nextBuildLogger } from \"./logger.js\";\nimport { createReleaseLayers, releaseProgram } from \"./release-program.js\";\nimport { PreflightService, PreflightServiceLive } from \"./services/preflight.service.js\";\nimport { ReleaseIdentityService, ReleaseIdentityServiceLive } from \"./services/release-identity.service.js\";\n\nexport type InterfereOptions = {\n /**\n * Environment name\n * @default \"production\"\n */\n environment?: string;\n\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Whether to delete source maps after upload to prevent leakage\n * @default true\n */\n cleanupSourceMaps?: boolean;\n};\n\ntype NextConfigWithInterfere = NextConfig & {\n interfere?: InterfereOptions;\n};\n\n/**\n * Next.js configuration wrapper that automatically uploads source maps in production builds\n *\n * SECURITY: Secret key must be set via INTERFERE_SECRET_KEY env var (without NEXT_PUBLIC_ prefix)\n * Format: int_sk_{surfaceId}_{random}\n *\n * @example\n * ```js\n * // next.config.js\n * const { withInterfere } = require('@interfere/next/build');\n *\n * module.exports = withInterfere({\n * environment: 'staging',\n * debug: true,\n * cleanupSourceMaps: true\n * })({\n * // Your Next.js config\n * });\n * ```\n */\nexport function withInterfere({\n interfere = {},\n ...nextConfig\n}: NextConfigWithInterfere = {}): () => NextConfig {\n // Build the preflight config using the service\n const configProgram = Effect.gen(function* () {\n const preflight = yield* PreflightService;\n return yield* preflight.buildConfig(interfere);\n }).pipe(\n Effect.provide(PreflightServiceLive),\n Effect.runSync\n );\n\n const interfereConfig = configProgram;\n \n // Use the ReleaseIdentityService to infer build/release IDs\n // This runs the same logic that the release program uses\n const identityProgram = Effect.gen(function* () {\n const identityEffect = yield* ReleaseIdentityService;\n return yield* identityEffect.pipe(Effect.option);\n }).pipe(\n Effect.provide(ReleaseIdentityServiceLive),\n Effect.runSync\n );\n \n const identity = Option.getOrUndefined(identityProgram);\n\n return function buildConfig() {\n // Use the same release identity logic that the release program uses\n // This ensures consistency between what gets uploaded and what the client SDK sends\n const env = {\n ...nextConfig.env,\n // Pass the deduced/configured environment to the client SDK\n // (it defaults to NODE_ENV in preflight service)\n NEXT_PUBLIC_INTERFERE_ENVIRONMENT: interfereConfig.environment,\n // Pass the inferred build/release IDs to the client SDK\n // These come from the same ReleaseIdentityService that the release program uses\n ...(identity?.buildId\n ? { NEXT_PUBLIC_INTERFERE_BUILD_ID: identity.buildId }\n : {}),\n ...(identity?.releaseId\n ? { NEXT_PUBLIC_INTERFERE_RELEASE_ID: identity.releaseId }\n : {}),\n };\n\n // Set up compiler hook if enabled\n const compiler = !interfereConfig.enabled\n ? nextConfig.compiler\n : {\n ...nextConfig.compiler,\n runAfterProductionCompile: async (ctx: {\n projectDir: string;\n distDir: string;\n }) => {\n const debugEnabled = process.env.INTERFERE_PLUGIN_DEBUG === \"1\";\n const startTime = Date.now();\n\n if (debugEnabled) {\n console.log(\"[Interfere Plugin] Starting runAfterProductionCompile\");\n }\n\n // Run existing hook first\n const existingHook = nextConfig.compiler?.runAfterProductionCompile;\n if (existingHook) {\n const hookStart = Date.now();\n await existingHook(ctx);\n if (debugEnabled) {\n console.log(`[Interfere Plugin] Existing hook completed in ${Date.now() - hookStart}ms`);\n }\n }\n\n // Run the unified release program with all layers\n const scopedProgram = releaseProgram.pipe(\n Effect.provide(createReleaseLayers(interfereConfig)),\n Effect.scoped,\n debugEnabled\n ? Logger.withMinimumLogLevel(LogLevel.Debug)\n : (x) => x\n ) as Effect.Effect<unknown, unknown, never>;\n\n const programStart = Date.now();\n await Effect.runPromise(\n withInterfereLogger(\"next\", scopedProgram, { logger: nextBuildLogger })\n );\n if (debugEnabled) {\n console.log(`[Interfere Plugin] Release program completed in ${Date.now() - programStart}ms`);\n console.log(`[Interfere Plugin] Total runAfterProductionCompile time: ${Date.now() - startTime}ms`);\n }\n },\n };\n\n return {\n ...nextConfig,\n compiler,\n env,\n // Automatically enable browser source maps when Interfere is enabled\n productionBrowserSourceMaps: interfereConfig.enabled\n ? true\n : nextConfig.productionBrowserSourceMaps,\n };\n };\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,SAAgB,cAAc,EAC5B,YAAY,EAAE,EACd,GAAG,eACwB,EAAE,EAAoB;CAUjD,MAAM,kBARgB,OAAO,IAAI,aAAa;AAE5C,SAAO,QADW,OAAO,kBACD,YAAY,UAAU;GAC9C,CAAC,KACD,OAAO,QAAQ,qBAAqB,EACpC,OAAO,QACR;CAMD,MAAM,kBAAkB,OAAO,IAAI,aAAa;AAE9C,SAAO,QADgB,OAAO,wBACD,KAAK,OAAO,OAAO;GAChD,CAAC,KACD,OAAO,QAAQ,2BAA2B,EAC1C,OAAO,QACR;CAED,MAAM,WAAW,OAAO,eAAe,gBAAgB;AAEvD,QAAO,SAAS,cAAc;EAG5B,MAAM,MAAM;GACV,GAAG,WAAW;GAGd,mCAAmC,gBAAgB;GAGnD,GAAI,UAAU,UACV,EAAE,gCAAgC,SAAS,SAAS,GACpD,EAAE;GACN,GAAI,UAAU,YACV,EAAE,kCAAkC,SAAS,WAAW,GACxD,EAAE;GACP;EAGD,MAAM,WAAW,CAAC,gBAAgB,UAC9B,WAAW,WACX;GACE,GAAG,WAAW;GACd,2BAA2B,OAAO,QAG5B;IACJ,MAAM,eAAe,QAAQ,IAAI,2BAA2B;IAC5D,MAAM,YAAY,KAAK,KAAK;AAE5B,QAAI,aACF,SAAQ,IAAI,wDAAwD;IAItE,MAAM,eAAe,WAAW,UAAU;AAC1C,QAAI,cAAc;KAChB,MAAM,YAAY,KAAK,KAAK;AAC5B,WAAM,aAAa,IAAI;AACvB,SAAI,aACF,SAAQ,IAAI,iDAAiD,KAAK,KAAK,GAAG,UAAU,IAAI;;IAK5F,MAAM,gBAAgB,eAAe,KACnC,OAAO,QAAQ,oBAAoB,gBAAgB,CAAC,EACpD,OAAO,QACP,eACI,OAAO,oBAAoB,SAAS,MAAM,IACzC,MAAM,EACZ;IAED,MAAM,eAAe,KAAK,KAAK;AAC/B,UAAM,OAAO,WACX,oBAAoB,QAAQ,eAAe,EAAE,QAAQ,iBAAiB,CAAC,CACxE;AACD,QAAI,cAAc;AAChB,aAAQ,IAAI,mDAAmD,KAAK,KAAK,GAAG,aAAa,IAAI;AAC7F,aAAQ,IAAI,4DAA4D,KAAK,KAAK,GAAG,UAAU,IAAI;;;GAGxG;AAEL,SAAO;GACL,GAAG;GACH;GACA;GAEA,6BAA6B,gBAAgB,UACzC,OACA,WAAW;GAChB"}
1
+ {"version":3,"file":"with-interfere.mjs","names":[],"sources":["../../src/build/with-interfere.ts"],"sourcesContent":["import { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport { Effect, Layer, Logger, LogLevel, Option } from \"effect\";\nimport type { NextConfig } from \"next\";\nimport { nextBuildLogger } from \"./logger.js\";\nimport { createReleaseLayers, releaseProgram } from \"./release-program.js\";\nimport { PreflightService, PreflightServiceLive } from \"./services/preflight.service.js\";\nimport { ReleaseIdentityService, ReleaseIdentityServiceLive } from \"./services/release-identity.service.js\";\n\nexport type InterfereOptions = {\n /**\n * Environment name\n * @default \"production\"\n */\n environment?: string;\n\n /**\n * Enable debug logging\n * @default false\n */\n debug?: boolean;\n\n /**\n * Whether to delete source maps after upload to prevent leakage\n * @default true\n */\n cleanupSourceMaps?: boolean;\n};\n\ntype NextConfigWithInterfere = NextConfig & {\n interfere?: InterfereOptions;\n};\n\n/**\n * Next.js configuration wrapper that automatically uploads source maps in production builds\n *\n * SECURITY: Secret key must be set via INTERFERE_SECRET_KEY env var (without NEXT_PUBLIC_ prefix)\n *\n * @example\n * ```js\n * // next.config.js\n * import { withInterfere } from '@interfere/next/config';\n *\n * export default withInterfere({\n * environment: 'staging',\n * debug: true,\n * cleanupSourceMaps: true\n * })({\n * // Your Next.js config\n * });\n * ```\n */\nexport function withInterfere({\n interfere = {},\n ...nextConfig\n}: NextConfigWithInterfere = {}): () => NextConfig {\n // Build the preflight config using the service\n const configProgram = Effect.gen(function* () {\n const preflight = yield* PreflightService;\n return yield* preflight.buildConfig(interfere);\n }).pipe(\n Effect.provide(PreflightServiceLive),\n Effect.runSync\n );\n\n const interfereConfig = configProgram;\n \n // Use the ReleaseIdentityService to infer build/release IDs\n // This runs the same logic that the release program uses\n const identityProgram = Effect.gen(function* () {\n const identityEffect = yield* ReleaseIdentityService;\n return yield* identityEffect.pipe(Effect.option);\n }).pipe(\n Effect.provide(ReleaseIdentityServiceLive),\n Effect.runSync\n );\n \n const identity = Option.getOrUndefined(identityProgram);\n\n return function buildConfig() {\n // Use the same release identity logic that the release program uses\n // This ensures consistency between what gets uploaded and what the client SDK sends\n const env = {\n ...nextConfig.env,\n // Pass the deduced/configured environment to the client SDK\n // (it defaults to NODE_ENV in preflight service)\n NEXT_PUBLIC_INTERFERE_ENVIRONMENT: interfereConfig.environment,\n // Pass the inferred build/release IDs to the client SDK\n // These come from the same ReleaseIdentityService that the release program uses\n ...(identity?.buildId\n ? { NEXT_PUBLIC_INTERFERE_BUILD_ID: identity.buildId }\n : {}),\n ...(identity?.releaseId\n ? { NEXT_PUBLIC_INTERFERE_RELEASE_ID: identity.releaseId }\n : {}),\n };\n\n // Set up compiler hook if enabled\n const compiler = !interfereConfig.enabled\n ? nextConfig.compiler\n : {\n ...nextConfig.compiler,\n runAfterProductionCompile: async (ctx: {\n projectDir: string;\n distDir: string;\n }) => {\n const debugEnabled = process.env.INTERFERE_PLUGIN_DEBUG === \"1\";\n const startTime = Date.now();\n\n if (debugEnabled) {\n console.log(\"[Interfere Plugin] Starting runAfterProductionCompile\");\n }\n\n // Run existing hook first\n const existingHook = nextConfig.compiler?.runAfterProductionCompile;\n if (existingHook) {\n const hookStart = Date.now();\n await existingHook(ctx);\n if (debugEnabled) {\n console.log(`[Interfere Plugin] Existing hook completed in ${Date.now() - hookStart}ms`);\n }\n }\n\n // Run the unified release program with all layers\n const scopedProgram = releaseProgram.pipe(\n Effect.provide(createReleaseLayers(interfereConfig)),\n Effect.scoped,\n debugEnabled\n ? Logger.withMinimumLogLevel(LogLevel.Debug)\n : (x) => x\n ) as Effect.Effect<unknown, unknown, never>;\n\n const programStart = Date.now();\n await Effect.runPromise(\n withInterfereLogger(\"next\", scopedProgram, { logger: nextBuildLogger })\n );\n if (debugEnabled) {\n console.log(`[Interfere Plugin] Release program completed in ${Date.now() - programStart}ms`);\n console.log(`[Interfere Plugin] Total runAfterProductionCompile time: ${Date.now() - startTime}ms`);\n }\n },\n };\n\n return {\n ...nextConfig,\n compiler,\n env,\n // Automatically enable browser source maps when Interfere is enabled\n productionBrowserSourceMaps: interfereConfig.enabled\n ? true\n : nextConfig.productionBrowserSourceMaps,\n // Silence Next.js 16+ Turbopack warning when using compiler hooks\n // The runAfterProductionCompile hook is webpack-specific, but works fine\n // during production builds which still use webpack\n turbopack: nextConfig.turbopack ?? {},\n };\n };\n}"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,SAAgB,cAAc,EAC5B,YAAY,EAAE,EACd,GAAG,eACwB,EAAE,EAAoB;CAUjD,MAAM,kBARgB,OAAO,IAAI,aAAa;AAE5C,SAAO,QADW,OAAO,kBACD,YAAY,UAAU;GAC9C,CAAC,KACD,OAAO,QAAQ,qBAAqB,EACpC,OAAO,QACR;CAMD,MAAM,kBAAkB,OAAO,IAAI,aAAa;AAE9C,SAAO,QADgB,OAAO,wBACD,KAAK,OAAO,OAAO;GAChD,CAAC,KACD,OAAO,QAAQ,2BAA2B,EAC1C,OAAO,QACR;CAED,MAAM,WAAW,OAAO,eAAe,gBAAgB;AAEvD,QAAO,SAAS,cAAc;EAG5B,MAAM,MAAM;GACV,GAAG,WAAW;GAGd,mCAAmC,gBAAgB;GAGnD,GAAI,UAAU,UACV,EAAE,gCAAgC,SAAS,SAAS,GACpD,EAAE;GACN,GAAI,UAAU,YACV,EAAE,kCAAkC,SAAS,WAAW,GACxD,EAAE;GACP;EAGD,MAAM,WAAW,CAAC,gBAAgB,UAC9B,WAAW,WACX;GACE,GAAG,WAAW;GACd,2BAA2B,OAAO,QAG5B;IACJ,MAAM,eAAe,QAAQ,IAAI,2BAA2B;IAC5D,MAAM,YAAY,KAAK,KAAK;AAE5B,QAAI,aACF,SAAQ,IAAI,wDAAwD;IAItE,MAAM,eAAe,WAAW,UAAU;AAC1C,QAAI,cAAc;KAChB,MAAM,YAAY,KAAK,KAAK;AAC5B,WAAM,aAAa,IAAI;AACvB,SAAI,aACF,SAAQ,IAAI,iDAAiD,KAAK,KAAK,GAAG,UAAU,IAAI;;IAK5F,MAAM,gBAAgB,eAAe,KACnC,OAAO,QAAQ,oBAAoB,gBAAgB,CAAC,EACpD,OAAO,QACP,eACI,OAAO,oBAAoB,SAAS,MAAM,IACzC,MAAM,EACZ;IAED,MAAM,eAAe,KAAK,KAAK;AAC/B,UAAM,OAAO,WACX,oBAAoB,QAAQ,eAAe,EAAE,QAAQ,iBAAiB,CAAC,CACxE;AACD,QAAI,cAAc;AAChB,aAAQ,IAAI,mDAAmD,KAAK,KAAK,GAAG,aAAa,IAAI;AAC7F,aAAQ,IAAI,4DAA4D,KAAK,KAAK,GAAG,UAAU,IAAI;;;GAGxG;AAEL,SAAO;GACL,GAAG;GACH;GACA;GAEA,6BAA6B,gBAAgB,UACzC,OACA,WAAW;GAIf,WAAW,WAAW,aAAa,EAAE;GACtC"}
@@ -3,14 +3,14 @@ import { ConfigInput } from "@interfere/types/sdk/config";
3
3
  import * as react0 from "react";
4
4
 
5
5
  //#region src/client/provider.d.ts
6
- type NextConfigInput = {
6
+ interface NextConfigInput {
7
7
  features?: ConfigInput["features"];
8
8
  metadata?: ConfigInput["metadata"];
9
9
  batch?: ConfigInput["batch"];
10
10
  proxyUrl?: string;
11
11
  ingestUrl?: string;
12
12
  surfaceToken?: string;
13
- };
13
+ }
14
14
  declare function InterfereProvider({
15
15
  children,
16
16
  config,
@@ -1 +1 @@
1
- {"version":3,"file":"provider.d.mts","names":[],"sources":["../../src/client/provider.tsx"],"sourcesContent":[],"mappings":";;;;;KAyBK,eAAA;aACQ;aACA;EAFR,KAAA,CAAA,EAGK,WAHU,CAAA,OAAA,CAAA;EACP,QAAA,CAAA,EAAA,MAAA;EACA,SAAA,CAAA,EAAA,MAAA;EACH,YAAA,CAAA,EAAA,MAAA;CAAW;AAgCL,iBAAA,iBAAA,CAAiB;EAAA,QAAA;EAAA,MAAA;EAAA,GAAA;CAAA,EAI9B,IAJ8B,CAIzB,sBAJyB,EAAA,QAAA,CAAA,GAAA;EAC/B,MAAA,CAAA,EAGqD,eAHrD;CACA,CAAA,EAEsE,MAAA,CAAA,GAAA,CAAA,OAFtE"}
1
+ {"version":3,"file":"provider.d.mts","names":[],"sources":["../../src/client/provider.tsx"],"sourcesContent":[],"mappings":";;;;;UAyBU,eAAA;aACG;aACA;EAFH,KAAA,CAAA,EAGA,WAHe,CAAA,OAAA,CAAA;EACZ,QAAA,CAAA,EAAA,MAAA;EACA,SAAA,CAAA,EAAA,MAAA;EACH,YAAA,CAAA,EAAA,MAAA;;AAgCM,iBAAA,iBAAA,CAAiB;EAAA,QAAA;EAAA,MAAA;EAAA,GAAA;CAAA,EAI9B,IAJ8B,CAIzB,sBAJyB,EAAA,QAAA,CAAA,GAAA;EAC/B,MAAA,CAAA,EAGqD,eAHrD;CACA,CAAA,EAEsE,MAAA,CAAA,GAAA,CAAA,OAFtE"}
@@ -1,3 +1,5 @@
1
+ "use client";
2
+
1
3
  import { InterfereProvider as InterfereProvider$1 } from "@interfere/react/provider";
2
4
  import { getRuntime } from "@interfere/react/core/runtime/config";
3
5
  import { configSchema } from "@interfere/types/sdk/config";
@@ -1 +1 @@
1
- {"version":3,"file":"provider.mjs","names":["defaults: ConfigInput[\"metadata\"]","InterfereProviderReact"],"sources":["../../src/client/provider.tsx"],"sourcesContent":["import { getRuntime } from \"@interfere/react/core/runtime/config\";\n\nimport {\n type InterfereProviderProps,\n InterfereProvider as InterfereProviderReact,\n} from \"@interfere/react/provider\";\n\nimport {\n type Config,\n type ConfigInput,\n configSchema,\n} from \"@interfere/types/sdk/config\";\nimport { envSchema } from \"@interfere/types/sdk/runtime\";\n\nconst defaults: ConfigInput[\"metadata\"] = {\n buildId: process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID ?? null,\n releaseId: process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID ?? null,\n environment: process.env.NEXT_PUBLIC_INTERFERE_ENVIRONMENT\n ? envSchema.parse(process.env.NEXT_PUBLIC_INTERFERE_ENVIRONMENT)\n : \"production\",\n runtime: getRuntime(),\n};\n\n// Next.js-specific config type that allows omitting transport\n// because Next.js can provide its own proxy endpoint\ntype NextConfigInput = {\n features?: ConfigInput[\"features\"];\n metadata?: ConfigInput[\"metadata\"];\n batch?: ConfigInput[\"batch\"];\n proxyUrl?: string;\n ingestUrl?: string;\n surfaceToken?: string;\n};\n\nfunction mergeConfig(config: NextConfigInput): Config {\n const incomingMeta = config.metadata ?? {};\n\n // Determine transport config:\n // - If they explicitly set proxyUrl, use proxy mode\n // - If they set ingestUrl or surfaceToken, use direct mode (let schema validate)\n // - Otherwise, default to Next.js proxy\n const hasTransportConfig =\n typeof config.proxyUrl !== \"undefined\" ||\n typeof config.ingestUrl !== \"undefined\" ||\n typeof config.surfaceToken !== \"undefined\";\n\n const transportConfig = hasTransportConfig\n ? config\n : { proxyUrl: \"/api/interfere\" }; // Default Next.js proxy endpoint\n\n return configSchema.parse({\n ...transportConfig,\n ...config,\n metadata: {\n ...defaults,\n ...incomingMeta,\n },\n });\n}\n\nexport function InterfereProvider({\n children,\n config = {},\n ...rest\n}: Omit<InterfereProviderProps, \"config\"> & { config?: NextConfigInput }) {\n const mergedConfig = mergeConfig(config);\n\n return (\n <InterfereProviderReact config={mergedConfig} {...rest}>\n {children}\n </InterfereProviderReact>\n );\n}\n"],"mappings":";;;;;;AAcA,MAAMA,WAAoC;CACxC,SAAS,QAAQ,IAAI,kCAAkC;CACvD,WAAW,QAAQ,IAAI,oCAAoC;CAC3D,aAAa,QAAQ,IAAI,oCACrB,UAAU,MAAM,QAAQ,IAAI,kCAAkC,GAC9D;CACJ,SAAS,YAAY;CACtB;AAaD,SAAS,YAAY,QAAiC;CACpD,MAAM,eAAe,OAAO,YAAY,EAAE;CAW1C,MAAM,kBAJJ,OAAO,OAAO,aAAa,eAC3B,OAAO,OAAO,cAAc,eAC5B,OAAO,OAAO,iBAAiB,cAG7B,SACA,EAAE,UAAU,kBAAkB;AAElC,QAAO,aAAa,MAAM;EACxB,GAAG;EACH,GAAG;EACH,UAAU;GACR,GAAG;GACH,GAAG;GACJ;EACF,CAAC;;AAGJ,SAAgB,kBAAkB,EAChC,UACA,SAAS,EAAE,EACX,GAAG,QACqE;CACxE,MAAM,eAAe,YAAY,OAAO;AAExC,QACE,CAACC,oBAAuB,QAAQ,kBAAkB,MAAM;OACrD,SAAS;IACZ,EAAEA"}
1
+ {"version":3,"file":"provider.mjs","names":["defaults: ConfigInput[\"metadata\"]","InterfereProviderReact"],"sources":["../../src/client/provider.tsx"],"sourcesContent":["\"use client\";\n\nimport { getRuntime } from \"@interfere/react/core/runtime/config\";\nimport {\n type InterfereProviderProps,\n InterfereProvider as InterfereProviderReact,\n} from \"@interfere/react/provider\";\nimport {\n type Config,\n type ConfigInput,\n configSchema,\n} from \"@interfere/types/sdk/config\";\nimport { envSchema } from \"@interfere/types/sdk/runtime\";\n\nconst defaults: ConfigInput[\"metadata\"] = {\n buildId: process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID ?? null,\n releaseId: process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID ?? null,\n environment: process.env.NEXT_PUBLIC_INTERFERE_ENVIRONMENT\n ? envSchema.parse(process.env.NEXT_PUBLIC_INTERFERE_ENVIRONMENT)\n : \"production\",\n runtime: getRuntime(),\n};\n\n// Next.js-specific config type that allows omitting transport\n// because Next.js can provide its own proxy endpoint\ninterface NextConfigInput {\n features?: ConfigInput[\"features\"];\n metadata?: ConfigInput[\"metadata\"];\n batch?: ConfigInput[\"batch\"];\n proxyUrl?: string;\n ingestUrl?: string;\n surfaceToken?: string;\n}\n\nfunction mergeConfig(config: NextConfigInput): Config {\n const incomingMeta = config.metadata ?? {};\n\n // Determine transport config:\n // - If they explicitly set proxyUrl, use proxy mode\n // - If they set ingestUrl or surfaceToken, use direct mode (let schema validate)\n // - Otherwise, default to Next.js proxy\n const hasTransportConfig =\n typeof config.proxyUrl !== \"undefined\" ||\n typeof config.ingestUrl !== \"undefined\" ||\n typeof config.surfaceToken !== \"undefined\";\n\n const transportConfig = hasTransportConfig\n ? config\n : { proxyUrl: \"/api/interfere\" }; // Default Next.js proxy endpoint\n\n return configSchema.parse({\n ...transportConfig,\n ...config,\n metadata: {\n ...defaults,\n ...incomingMeta,\n },\n });\n}\n\nexport function InterfereProvider({\n children,\n config = {},\n ...rest\n}: Omit<InterfereProviderProps, \"config\"> & { config?: NextConfigInput }) {\n const mergedConfig = mergeConfig(config);\n\n return (\n <InterfereProviderReact config={mergedConfig} {...rest}>\n {children}\n </InterfereProviderReact>\n );\n}\n"],"mappings":";;;;;;;;AAcA,MAAMA,WAAoC;CACxC,SAAS,QAAQ,IAAI,kCAAkC;CACvD,WAAW,QAAQ,IAAI,oCAAoC;CAC3D,aAAa,QAAQ,IAAI,oCACrB,UAAU,MAAM,QAAQ,IAAI,kCAAkC,GAC9D;CACJ,SAAS,YAAY;CACtB;AAaD,SAAS,YAAY,QAAiC;CACpD,MAAM,eAAe,OAAO,YAAY,EAAE;CAW1C,MAAM,kBAJJ,OAAO,OAAO,aAAa,eAC3B,OAAO,OAAO,cAAc,eAC5B,OAAO,OAAO,iBAAiB,cAG7B,SACA,EAAE,UAAU,kBAAkB;AAElC,QAAO,aAAa,MAAM;EACxB,GAAG;EACH,GAAG;EACH,UAAU;GACR,GAAG;GACH,GAAG;GACJ;EACF,CAAC;;AAGJ,SAAgB,kBAAkB,EAChC,UACA,SAAS,EAAE,EACX,GAAG,QACqE;CACxE,MAAM,eAAe,YAAY,OAAO;AAExC,QACE,CAACC,oBAAuB,QAAQ,kBAAkB,MAAM;OACrD,SAAS;IACZ,EAAEA"}
@@ -3,20 +3,20 @@ type NonEmptyString = string & {
3
3
  readonly __brand: unique symbol;
4
4
  };
5
5
  declare function toNonEmptyString(value: string): NonEmptyString | null;
6
- type PreflightEnabled = {
6
+ interface PreflightEnabled {
7
7
  enabled: true;
8
8
  surface: NonEmptyString;
9
9
  secretKey: NonEmptyString;
10
10
  environment: string;
11
11
  debug: boolean;
12
12
  cleanupSourceMaps: boolean;
13
- };
14
- type PreflightDisabled = {
13
+ }
14
+ interface PreflightDisabled {
15
15
  enabled: false;
16
16
  environment: string | undefined;
17
17
  debug: boolean;
18
18
  cleanupSourceMaps: boolean;
19
- };
19
+ }
20
20
  type PreflightConfig = PreflightEnabled | PreflightDisabled;
21
21
  //#endregion
22
22
  export { NonEmptyString, PreflightConfig, PreflightDisabled, PreflightEnabled, toNonEmptyString };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":[],"mappings":";KACY,cAAA;EAAA,SAAA,OAAA,EAAc,OAAA,MAAA;AAE1B,CAAA;AAIY,iBAJI,gBAAA,CAML,KAAA,EAAA,MACE,CAAA,EAPoC,cAOtB,GAAA,IAAA;AAMf,KATA,gBAAA,GASiB;EAOjB,OAAA,EAAA,IAAA;WAdD;aACE;;;;;KAMD,iBAAA;;;;;;KAOA,eAAA,GAAkB,mBAAmB"}
1
+ {"version":3,"file":"types.d.mts","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":[],"mappings":";KACY,cAAA;EAAA,SAAA,OAAA,EAAc,OAAA,MAAA;AAE1B,CAAA;AAIiB,iBAJD,gBAAA,CAML,KAAA,EAAA,MACE,CAAA,EAPoC,cAOtB,GAAA,IAAA;AAMV,UATA,gBAAA,CASiB;EAOtB,OAAA,EAAA,IAAA;WAdD;aACE;;;;;UAMI,iBAAA;;;;;;KAOL,eAAA,GAAkB,mBAAmB"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":["// Branded non-empty string type to prevent passing empty strings accidentally\nexport type NonEmptyString = string & { readonly __brand: unique symbol };\n\nexport function toNonEmptyString(value: string): NonEmptyString | null {\n return value.length > 0 ? (value as NonEmptyString) : null;\n}\n\nexport type PreflightEnabled = {\n enabled: true;\n surface: NonEmptyString;\n secretKey: NonEmptyString;\n environment: string;\n debug: boolean;\n cleanupSourceMaps: boolean;\n};\n\nexport type PreflightDisabled = {\n enabled: false;\n environment: string | undefined;\n debug: boolean;\n cleanupSourceMaps: boolean;\n};\n\nexport type PreflightConfig = PreflightEnabled | PreflightDisabled;\n"],"mappings":";AAGA,SAAgB,iBAAiB,OAAsC;AACrE,QAAO,MAAM,SAAS,IAAK,QAA2B"}
1
+ {"version":3,"file":"types.mjs","names":[],"sources":["../../src/lib/types.ts"],"sourcesContent":["// Branded non-empty string type to prevent passing empty strings accidentally\nexport type NonEmptyString = string & { readonly __brand: unique symbol };\n\nexport function toNonEmptyString(value: string): NonEmptyString | null {\n return value.length > 0 ? (value as NonEmptyString) : null;\n}\n\nexport interface PreflightEnabled {\n enabled: true;\n surface: NonEmptyString;\n secretKey: NonEmptyString;\n environment: string;\n debug: boolean;\n cleanupSourceMaps: boolean;\n}\n\nexport interface PreflightDisabled {\n enabled: false;\n environment: string | undefined;\n debug: boolean;\n cleanupSourceMaps: boolean;\n}\n\nexport type PreflightConfig = PreflightEnabled | PreflightDisabled;\n"],"mappings":";AAGA,SAAgB,iBAAiB,OAAsC;AACrE,QAAO,MAAM,SAAS,IAAK,QAA2B"}
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.mts","names":[],"sources":["../../src/server/middleware.ts"],"sourcesContent":[],"mappings":";;;iBAWgB,uBAAA,uBACQ,gBAAgB,QAAQ,gBAAgB,yBAIvC,gBAAW,QAAA;iBAoCpB,qBAAA,gBACC,gBAAgB,QAAQ,kBAIpB,gBAAW,QAAA;AA9ChB,iBAkFA,4BAlFuB,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAmFH,OAnFG,CAAA,OAAA,CAAA,CAAA,CAAA,SAAA,EAoF1B,CApF0B,EAAA,aAAA,CAAA,EAAA,MAAA,CAAA,EAoFE,CApFF;AACf,iBA4HR,2BAAA,CAAA,CA5HQ,EAAA,CAAA,KAAA,EA+HD,KA/HC,EAAA,SAAA,EAAA;EAAwB,MAAA,CAAA,EAAA,MAAA;CAAR,EAAA,GA+HoB,OA/HpB,CAAA,IAAA,CAAA"}
1
+ {"version":3,"file":"middleware.d.mts","names":[],"sources":["../../src/server/middleware.ts"],"sourcesContent":[],"mappings":";;;iBAagB,uBAAA,uBACQ,gBAAgB,QAAQ,gBAAgB,yBAIvC,gBAAW,QAAA;iBAoCpB,qBAAA,gBACC,gBAAgB,QAAQ,kBAIpB,gBAAW,QAAA;AA9ChB,iBAkFA,4BAlFuB,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GAmFH,OAnFG,CAAA,OAAA,CAAA,CAAA,CAAA,SAAA,EAoF1B,CApF0B,EAAA,aAAA,CAAA,EAAA,MAAA,CAAA,EAoFE,CApFF;AACf,iBA4HR,2BAAA,CAAA,CA5HQ,EAAA,CAAA,KAAA,EA+HD,KA/HC,EAAA,SAAA,EAAA;EAAwB,MAAA,CAAA,EAAA,MAAA;CAAR,EAAA,GA+HoB,OA/HpB,CAAA,IAAA,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.mjs","names":[],"sources":["../../src/server/middleware.ts"],"sourcesContent":["import { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport { withSpan } from \"@interfere/react/effect/layers/tracer.layer\";\nimport { Effect, Layer } from \"effect\";\nimport type { NextRequest, NextResponse } from \"next/server\";\nimport { ConfigServiceLive } from \"./services/config.service\";\nimport {\n ErrorTrackingService,\n ErrorTrackingServiceLive,\n} from \"./services/error-tracking.service\";\n\n// Middleware wrapper to capture errors with proper Effect handling\nexport function withInterfereMiddleware(\n middleware: (request: NextRequest) => Promise<NextResponse> | NextResponse\n) {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (request: NextRequest) => {\n // Skip capturing for Interfere's own endpoint to avoid recursion\n if (request.nextUrl.pathname.startsWith(\"/api/interfere\")) {\n return middleware(request);\n }\n\n const startTime = Date.now();\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const response = yield* withSpan(\n \"middleware.request\",\n Effect.tryPromise({\n try: () => Promise.resolve(middleware(request)),\n catch: (error) => error as Error,\n }),\n { attributes: { path: request.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, request, {\n pathname: request.nextUrl.pathname,\n middleware: true,\n duration: Date.now() - startTime,\n })\n )\n );\n\n return response;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n\n// Helper for API route error handling with Effect\nexport function withInterfereApiRoute(\n handler: (req: NextRequest) => Promise<Response>\n) {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (req: NextRequest) => {\n // Skip capturing for Interfere's own endpoint to avoid recursion\n if (req.nextUrl.pathname.startsWith(\"/api/interfere\")) {\n return handler(req);\n }\n\n const startTime = Date.now();\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const response = yield* withSpan(\n \"api.request\",\n Effect.tryPromise({\n try: () => handler(req),\n catch: (error) => error as Error,\n }),\n { attributes: { path: req.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, req, {\n pathname: req.nextUrl.pathname,\n type: \"api_route\",\n duration: Date.now() - startTime,\n })\n )\n );\n\n return response;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n\n// Helper for server component error handling with Effect\nexport function withInterfereServerComponent<\n T extends (...args: unknown[]) => Promise<unknown>,\n>(component: T, componentName?: string): T {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n async function wrapped(this: unknown, ...args: Parameters<T>) {\n const self = this;\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const result = yield* Effect.tryPromise({\n try: () => component.apply(self as never, args as never),\n catch: (error) => error as Error,\n }).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, undefined, {\n type: \"server_component\",\n componentName: componentName || component.name,\n })\n )\n );\n\n return result;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n }\n\n // Preserve the original function name for diagnostics and tests\n try {\n Object.defineProperty(wrapped, \"name\", {\n value: component.name,\n configurable: true,\n });\n } catch {\n // Non-critical if we cannot redefine the name\n }\n\n return wrapped as unknown as T;\n}\n\n// App directory error handling with Effect\nexport function createInterfereErrorHandler() {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (error: Error, errorInfo: { digest?: string }) => {\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n yield* errorTracking.captureError(error, undefined, {\n digest: errorInfo.digest,\n type: \"app_directory_error\",\n });\n }).pipe(\n Effect.provide(layer),\n Effect.catchAll(() => Effect.void) // Best-effort\n );\n\n await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n"],"mappings":";;;;;;;AAWA,SAAgB,wBACd,YACA;CACA,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,YAAyB;AAErC,MAAI,QAAQ,QAAQ,SAAS,WAAW,iBAAiB,CACvD,QAAO,WAAW,QAAQ;EAG5B,MAAM,YAAY,KAAK,KAAK;EAE5B,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAmB7B,UAjBiB,OAAO,SACtB,sBACA,OAAO,WAAW;IAChB,WAAW,QAAQ,QAAQ,WAAW,QAAQ,CAAC;IAC/C,QAAQ,UAAU;IACnB,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,QAAQ,QAAQ,UAAU,EAAE,CACnD,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,SAAS;IACzC,UAAU,QAAQ,QAAQ;IAC1B,YAAY;IACZ,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC;;;AAKxE,SAAgB,sBACd,SACA;CACA,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,QAAqB;AAEjC,MAAI,IAAI,QAAQ,SAAS,WAAW,iBAAiB,CACnD,QAAO,QAAQ,IAAI;EAGrB,MAAM,YAAY,KAAK,KAAK;EAE5B,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAmB7B,UAjBiB,OAAO,SACtB,eACA,OAAO,WAAW;IAChB,WAAW,QAAQ,IAAI;IACvB,QAAQ,UAAU;IACnB,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,IAAI,QAAQ,UAAU,EAAE,CAC/C,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,KAAK;IACrC,UAAU,IAAI,QAAQ;IACtB,MAAM;IACN,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC;;;AAKxE,SAAgB,6BAEd,WAAc,eAA2B;CACzC,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;CAEzE,eAAe,QAAuB,GAAG,MAAqB;EAC5D,MAAM,OAAO;EAEb,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAc7B,UAZe,OAAO,OAAO,WAAW;IACtC,WAAW,UAAU,MAAM,MAAe,KAAc;IACxD,QAAQ,UAAU;IACnB,CAAC,CAAC,KACD,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,QAAW;IAC3C,MAAM;IACN,eAAe,iBAAiB,UAAU;IAC3C,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC;;AAItE,KAAI;AACF,SAAO,eAAe,SAAS,QAAQ;GACrC,OAAO,UAAU;GACjB,cAAc;GACf,CAAC;SACI;AAIR,QAAO;;AAIT,SAAgB,8BAA8B;CAC5C,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,OAAc,cAAmC;EAC7D,MAAM,UAAU,OAAO,IAAI,aAAa;AAGtC,WAFsB,OAAO,sBAER,aAAa,OAAO,QAAW;IAClD,QAAQ,UAAU;IAClB,MAAM;IACP,CAAC;IACF,CAAC,KACD,OAAO,QAAQ,MAAM,EACrB,OAAO,eAAe,OAAO,KAAK,CACnC;AAED,QAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC"}
1
+ {"version":3,"file":"middleware.mjs","names":[],"sources":["../../src/server/middleware.ts"],"sourcesContent":["import { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport { withSpan } from \"@interfere/react/effect/layers/tracer.layer\";\n\nimport { Effect, Layer } from \"effect\";\nimport type { NextRequest, NextResponse } from \"next/server\";\n\nimport { ConfigServiceLive } from \"./services/config.service\";\nimport {\n ErrorTrackingService,\n ErrorTrackingServiceLive,\n} from \"./services/error-tracking.service\";\n\n// Middleware wrapper to capture errors with proper Effect handling\nexport function withInterfereMiddleware(\n middleware: (request: NextRequest) => Promise<NextResponse> | NextResponse\n) {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (request: NextRequest) => {\n // Skip capturing for Interfere's own endpoint to avoid recursion\n if (request.nextUrl.pathname.startsWith(\"/api/interfere\")) {\n return middleware(request);\n }\n\n const startTime = Date.now();\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const response = yield* withSpan(\n \"middleware.request\",\n Effect.tryPromise({\n try: () => Promise.resolve(middleware(request)),\n catch: (error) => error as Error,\n }),\n { attributes: { path: request.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, request, {\n pathname: request.nextUrl.pathname,\n middleware: true,\n duration: Date.now() - startTime,\n })\n )\n );\n\n return response;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n\n// Helper for API route error handling with Effect\nexport function withInterfereApiRoute(\n handler: (req: NextRequest) => Promise<Response>\n) {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (req: NextRequest) => {\n // Skip capturing for Interfere's own endpoint to avoid recursion\n if (req.nextUrl.pathname.startsWith(\"/api/interfere\")) {\n return handler(req);\n }\n\n const startTime = Date.now();\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const response = yield* withSpan(\n \"api.request\",\n Effect.tryPromise({\n try: () => handler(req),\n catch: (error) => error as Error,\n }),\n { attributes: { path: req.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, req, {\n pathname: req.nextUrl.pathname,\n type: \"api_route\",\n duration: Date.now() - startTime,\n })\n )\n );\n\n return response;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n\n// Helper for server component error handling with Effect\nexport function withInterfereServerComponent<\n T extends (...args: unknown[]) => Promise<unknown>,\n>(component: T, componentName?: string): T {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n async function wrapped(this: unknown, ...args: Parameters<T>) {\n const self = this;\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const result = yield* Effect.tryPromise({\n try: () => component.apply(self as never, args as never),\n catch: (error) => error as Error,\n }).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, undefined, {\n type: \"server_component\",\n componentName: componentName || component.name,\n })\n )\n );\n\n return result;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n }\n\n // Preserve the original function name for diagnostics and tests\n try {\n Object.defineProperty(wrapped, \"name\", {\n value: component.name,\n configurable: true,\n });\n } catch {\n // Non-critical if we cannot redefine the name\n }\n\n return wrapped as unknown as T;\n}\n\n// App directory error handling with Effect\nexport function createInterfereErrorHandler() {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (error: Error, errorInfo: { digest?: string }) => {\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n yield* errorTracking.captureError(error, undefined, {\n digest: errorInfo.digest,\n type: \"app_directory_error\",\n });\n }).pipe(\n Effect.provide(layer),\n Effect.catchAll(() => Effect.void) // Best-effort\n );\n\n await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,wBACd,YACA;CACA,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,YAAyB;AAErC,MAAI,QAAQ,QAAQ,SAAS,WAAW,iBAAiB,CACvD,QAAO,WAAW,QAAQ;EAG5B,MAAM,YAAY,KAAK,KAAK;EAE5B,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAmB7B,UAjBiB,OAAO,SACtB,sBACA,OAAO,WAAW;IAChB,WAAW,QAAQ,QAAQ,WAAW,QAAQ,CAAC;IAC/C,QAAQ,UAAU;IACnB,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,QAAQ,QAAQ,UAAU,EAAE,CACnD,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,SAAS;IACzC,UAAU,QAAQ,QAAQ;IAC1B,YAAY;IACZ,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC;;;AAKxE,SAAgB,sBACd,SACA;CACA,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,QAAqB;AAEjC,MAAI,IAAI,QAAQ,SAAS,WAAW,iBAAiB,CACnD,QAAO,QAAQ,IAAI;EAGrB,MAAM,YAAY,KAAK,KAAK;EAE5B,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAmB7B,UAjBiB,OAAO,SACtB,eACA,OAAO,WAAW;IAChB,WAAW,QAAQ,IAAI;IACvB,QAAQ,UAAU;IACnB,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,IAAI,QAAQ,UAAU,EAAE,CAC/C,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,KAAK;IACrC,UAAU,IAAI,QAAQ;IACtB,MAAM;IACN,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC;;;AAKxE,SAAgB,6BAEd,WAAc,eAA2B;CACzC,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;CAEzE,eAAe,QAAuB,GAAG,MAAqB;EAC5D,MAAM,OAAO;EAEb,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAc7B,UAZe,OAAO,OAAO,WAAW;IACtC,WAAW,UAAU,MAAM,MAAe,KAAc;IACxD,QAAQ,UAAU;IACnB,CAAC,CAAC,KACD,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,QAAW;IAC3C,MAAM;IACN,eAAe,iBAAiB,UAAU;IAC3C,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC;;AAItE,KAAI;AACF,SAAO,eAAe,SAAS,QAAQ;GACrC,OAAO,UAAU;GACjB,cAAc;GACf,CAAC;SACI;AAIR,QAAO;;AAIT,SAAgB,8BAA8B;CAC5C,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,OAAc,cAAmC;EAC7D,MAAM,UAAU,OAAO,IAAI,aAAa;AAGtC,WAFsB,OAAO,sBAER,aAAa,OAAO,QAAW;IAClD,QAAQ,UAAU;IAClB,MAAM;IACP,CAAC;IACF,CAAC,KACD,OAAO,QAAQ,MAAM,EACrB,OAAO,eAAe,OAAO,KAAK,CACnC;AAED,QAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.mts","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":[],"mappings":";;;iBAWgB,kBAAA,gBAEP,oBACE,mBACJ,QAAQ,YAAY,iBAIN,oBAAoB,mBAAc,QAAA"}
1
+ {"version":3,"file":"proxy.d.mts","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":[],"mappings":";;;iBAagB,kBAAA,gBAEP,oBACE,mBACJ,QAAQ,YAAY,iBAIN,oBAAoB,mBAAc,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.mjs","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":["import { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport { withSpan } from \"@interfere/react/effect/layers/tracer.layer\";\nimport { Effect, Layer } from \"effect\";\nimport type { NextFetchEvent, NextRequest } from \"next/server\";\nimport { ConfigServiceLive } from \"./services/config.service\";\nimport {\n ErrorTrackingService,\n ErrorTrackingServiceLive,\n} from \"./services/error-tracking.service\";\n\n// Proxy wrapper compatible with Next 16 `proxy.ts` with Effect\nexport function withInterfereProxy(\n handler: (\n req: NextRequest,\n event: NextFetchEvent\n ) => Promise<Response> | Response\n) {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (req: NextRequest, event: NextFetchEvent) => {\n if (req.nextUrl.pathname.startsWith(\"/api/interfere\")) {\n return handler(req, event);\n }\n\n const started = Date.now();\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const response = yield* withSpan(\n \"proxy.request\",\n Effect.tryPromise({\n try: () => Promise.resolve(handler(req, event)),\n catch: (error) => error as Error,\n }),\n { attributes: { path: req.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, req, {\n pathname: req.nextUrl.pathname,\n proxy: true,\n duration: Date.now() - started,\n })\n )\n );\n\n return response;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n"],"mappings":";;;;;;;AAWA,SAAgB,mBACd,SAIA;CACA,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,KAAkB,UAA0B;AACxD,MAAI,IAAI,QAAQ,SAAS,WAAW,iBAAiB,CACnD,QAAO,QAAQ,KAAK,MAAM;EAG5B,MAAM,UAAU,KAAK,KAAK;EAE1B,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAmB7B,UAjBiB,OAAO,SACtB,iBACA,OAAO,WAAW;IAChB,WAAW,QAAQ,QAAQ,QAAQ,KAAK,MAAM,CAAC;IAC/C,QAAQ,UAAU;IACnB,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,IAAI,QAAQ,UAAU,EAAE,CAC/C,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,KAAK;IACrC,UAAU,IAAI,QAAQ;IACtB,OAAO;IACP,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC"}
1
+ {"version":3,"file":"proxy.mjs","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":["import { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport { withSpan } from \"@interfere/react/effect/layers/tracer.layer\";\n\nimport { Effect, Layer } from \"effect\";\nimport type { NextFetchEvent, NextRequest } from \"next/server\";\n\nimport { ConfigServiceLive } from \"./services/config.service\";\nimport {\n ErrorTrackingService,\n ErrorTrackingServiceLive,\n} from \"./services/error-tracking.service\";\n\n// Proxy wrapper compatible with Next 16 `proxy.ts` with Effect\nexport function withInterfereProxy(\n handler: (\n req: NextRequest,\n event: NextFetchEvent\n ) => Promise<Response> | Response\n) {\n const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n return async (req: NextRequest, event: NextFetchEvent) => {\n if (req.nextUrl.pathname.startsWith(\"/api/interfere\")) {\n return handler(req, event);\n }\n\n const started = Date.now();\n\n const program = Effect.gen(function* () {\n const errorTracking = yield* ErrorTrackingService;\n\n const response = yield* withSpan(\n \"proxy.request\",\n Effect.tryPromise({\n try: () => Promise.resolve(handler(req, event)),\n catch: (error) => error as Error,\n }),\n { attributes: { path: req.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(error, req, {\n pathname: req.nextUrl.pathname,\n proxy: true,\n duration: Date.now() - started,\n })\n )\n );\n\n return response;\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n };\n}\n"],"mappings":";;;;;;;AAaA,SAAgB,mBACd,SAIA;CACA,MAAM,QAAQ,MAAM,SAAS,mBAAmB,yBAAyB;AAEzE,QAAO,OAAO,KAAkB,UAA0B;AACxD,MAAI,IAAI,QAAQ,SAAS,WAAW,iBAAiB,CACnD,QAAO,QAAQ,KAAK,MAAM;EAG5B,MAAM,UAAU,KAAK,KAAK;EAE1B,MAAM,UAAU,OAAO,IAAI,aAAa;GACtC,MAAM,gBAAgB,OAAO;AAmB7B,UAjBiB,OAAO,SACtB,iBACA,OAAO,WAAW;IAChB,WAAW,QAAQ,QAAQ,QAAQ,KAAK,MAAM,CAAC;IAC/C,QAAQ,UAAU;IACnB,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,IAAI,QAAQ,UAAU,EAAE,CAC/C,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aAAa,OAAO,KAAK;IACrC,UAAU,IAAI,QAAQ;IACtB,OAAO;IACP,UAAU,KAAK,KAAK,GAAG;IACxB,CAAC,CACH,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"route-handler.d.mts","names":[],"sources":["../../src/server/route-handler.ts"],"sourcesContent":[],"mappings":";;;KAsBK,YAAA,aAAyB,gBAAgB,QAAQ;cAmBzC,KAAK;AAnBb,cA2JQ,IA3JI,EA2JE,YA3JF;AAAa,cAoQjB,OApQiB,EAoQR,YApQQ"}
1
+ {"version":3,"file":"route-handler.d.mts","names":[],"sources":["../../src/server/route-handler.ts"],"sourcesContent":[],"mappings":";;;KAwBK,YAAA,aAAyB,gBAAgB,QAAQ;cAmBzC,KAAK;AAnBb,cA2JQ,IA3JI,EA2JE,YA3JF;AAAa,cAoQjB,OApQiB,EAoQR,YApQQ"}
@@ -1 +1 @@
1
- {"version":3,"file":"route-handler.mjs","names":["GET: RouteHandler","parsed: unknown","POST: RouteHandler","OPTIONS: RouteHandler","uuidv7"],"sources":["../../src/server/route-handler.ts"],"sourcesContent":["/** biome-ignore-all lint/suspicious/useAwait: route handlers must be async */\n\"use server\";\n\nimport { API_PATHS } from \"@interfere/constants/api\";\nimport { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport {\n createBackoffSchedule,\n shouldRetryHttp,\n withTimeoutFail,\n} from \"@interfere/effect-utils/retry\";\nimport { withSpan } from \"@interfere/react/effect/layers/tracer.layer\";\nimport { envelopeSchema } from \"@interfere/types/sdk/envelope\";\nimport { Data, Effect, Layer, Schedule } from \"effect\";\nimport type { NextRequest } from \"next/server\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport { z } from \"zod\";\nimport { ConfigService, ConfigServiceLive } from \"./services/config.service\";\nimport {\n ErrorTrackingService,\n ErrorTrackingServiceLive,\n} from \"./services/error-tracking.service\";\n\ntype RouteHandler = (request: NextRequest) => Promise<Response>;\n\nconst layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n// Error types for the proxy\nclass ProxyError extends Data.TaggedError(\"ProxyError\")<{\n readonly status: number;\n readonly message: string;\n readonly body?: string;\n}> {}\n\nconst TIMEOUT_MS = 10_000;\nconst RETRY_COUNT = 2;\nconst HTTP_BAD_GATEWAY = 502;\nconst RETRY_INITIAL_MS = 100;\nconst RETRY_MAX_MS = 2000;\n\nconst envelopesArraySchema = z.array(envelopeSchema);\n\nexport const GET: RouteHandler = async () => {\n const program = Effect.gen(function* () {\n const config = yield* ConfigService;\n const configured = yield* config.getSecretKey.pipe(\n Effect.map(() => true),\n Effect.catchAll(() => Effect.succeed(false))\n );\n\n return Response.json({ status: \"ok\", configured, timestamp: Date.now() });\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n};\n\nconst proxyIngestRequest = (\n request: Request,\n params: { apiUrl: string; surfaceToken: string }\n) =>\n Effect.gen(function* () {\n const incomingTrace = request.headers.get(\"traceparent\") || undefined;\n const traceparent = incomingTrace ?? generateTraceparent();\n\n // Read request body once\n const body = yield* Effect.tryPromise({\n try: () => request.clone().text(),\n catch: () =>\n new ProxyError({ status: 400, message: \"Invalid request body\" }),\n });\n\n // Validate the envelopes before proxying\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(body);\n } catch (error) {\n yield* Effect.logWarning(\"Invalid JSON in request body\").pipe(\n Effect.annotateLogs({ error: String(error) })\n );\n\n return yield* Effect.fail(\n new ProxyError({\n status: 400,\n message: \"Invalid JSON in request body\",\n body: String(error),\n })\n );\n }\n\n const validation = envelopesArraySchema.safeParse(parsed);\n\n if (!validation.success) {\n const issues = validation.error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n code: issue.code,\n }));\n\n yield* Effect.logWarning(\"Invalid envelope schema\").pipe(\n Effect.annotateLogs({ validationErrors: issues })\n );\n\n // For malformed envelopes, short‑circuit and return a 422 directly.\n // This lets SDKs drop bad envelopes instead of retrying or feeding them\n // back into the error tracking pipeline.\n const b = JSON.stringify({\n ok: false,\n code: \"INVALID_ENVELOPE_SCHEMA\",\n errors: issues,\n });\n\n return new Response(b, {\n status: 422,\n headers: {\n \"content-type\": \"application/json\",\n },\n });\n }\n\n // De-duplicate by envelope.uuid to avoid reprocessing on client retries\n const seen = new Set<string>();\n\n const deduped = validation.data.filter((env) => {\n if (seen.has(env.uuid)) {\n return false;\n }\n\n seen.add(env.uuid);\n return true;\n });\n\n const dropped = validation.data.length - deduped.length;\n\n yield* Effect.logDebug(\"Envelope validation successful\").pipe(\n Effect.annotateLogs({\n envelopeCount: validation.data.length,\n dedupedCount: deduped.length,\n droppedDuplicates: dropped,\n })\n );\n\n const upstream = yield* withTimeoutFail(\n Effect.tryPromise({\n try: () =>\n fetch(`${params.apiUrl}${API_PATHS.INGEST_V0}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-interfere-surface\": params.surfaceToken,\n traceparent,\n },\n body: JSON.stringify(deduped),\n }),\n catch: (error) =>\n new ProxyError({\n status: 0,\n message: error instanceof Error ? error.message : String(error),\n }),\n }),\n TIMEOUT_MS,\n () => new ProxyError({ status: 0, message: \"Network timeout\" })\n );\n\n const responseBody = yield* Effect.tryPromise({\n try: () => upstream.text(),\n catch: () => \"\",\n });\n\n return new Response(responseBody, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") || \"application/json\",\n },\n });\n });\n\nexport const POST: RouteHandler = async (request): Promise<Response> => {\n const program = Effect.gen(function* () {\n yield* Effect.logDebug(\"Handling ingest proxy request\").pipe(\n Effect.annotateLogs({ path: request.nextUrl.pathname })\n );\n\n const config = yield* ConfigService;\n const errorTracking = yield* ErrorTrackingService;\n\n // Check secret key\n yield* config.getSecretKey.pipe(\n Effect.tapError(() =>\n Effect.logError(\"Service not configured - missing INTERFERE_SECRET_KEY\")\n ),\n Effect.catchTag(\"ConfigError\", () =>\n Effect.fail(\n new ProxyError({\n status: 503,\n message:\n \"Service not configured. INTERFERE_SECRET_KEY environment variable is required.\",\n })\n )\n )\n );\n\n // Get public token\n const surfaceToken = yield* config.getPublicToken.pipe(\n Effect.tapError(() =>\n Effect.logError(\"Auth not available - missing public token\")\n ),\n Effect.catchTag(\"ConfigError\", () =>\n Effect.fail(\n new ProxyError({\n status: 503,\n message: \"Auth not available\",\n })\n )\n )\n );\n\n const apiUrl = yield* config.getApiUrl;\n\n // Proxy the request with retry logic\n const schedule = createBackoffSchedule(\n RETRY_INITIAL_MS,\n RETRY_MAX_MS,\n RETRY_COUNT\n ).pipe(\n Schedule.whileInput((e: unknown) =>\n e instanceof ProxyError ? shouldRetryHttp(e.status) : false\n )\n );\n\n const response = yield* withSpan(\n \"proxy.forward\",\n proxyIngestRequest(request, { apiUrl, surfaceToken }),\n { attributes: {} }\n ).pipe(\n Effect.retry(schedule),\n Effect.tapError((error) =>\n Effect.gen(function* () {\n yield* errorTracking.captureError(error, request, {\n pathname: request.nextUrl.pathname,\n type: \"api_route\",\n });\n yield* Effect.logError(\"Proxy request failed\").pipe(\n Effect.annotateLogs({\n error: String(error),\n status: error instanceof ProxyError ? error.status : 0,\n })\n );\n })\n )\n );\n\n yield* Effect.logDebug(\"Proxy request completed\").pipe(\n Effect.annotateLogs({ status: response.status })\n );\n\n return response;\n }).pipe(\n Effect.provide(layer),\n Effect.catchTag(\"ProxyError\", (error) =>\n Effect.succeed(\n Response.json(\n { error: error.message },\n { status: error.status || HTTP_BAD_GATEWAY }\n )\n )\n ),\n Effect.catchAll((error) => {\n Effect.runFork(\n Effect.logError(\"Unexpected error in route handler\").pipe(\n Effect.annotateLogs({ error: String(error) })\n )\n );\n return Effect.succeed(\n Response.json({ error: \"Internal server error\" }, { status: 500 })\n );\n })\n );\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n};\n\nexport const OPTIONS: RouteHandler = async () =>\n Effect.runPromise(\n withInterfereLogger(\n \"next\",\n Effect.succeed(\n new Response(null, {\n status: 200,\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Access-Control-Max-Age\": \"86400\",\n },\n })\n )\n )\n );\n\n// Helper functions\nconst VERSION = \"00\";\nconst TRACE_ID_BYTES = 16;\nconst SPAN_ID_BYTES = 8;\nconst FLAGS = \"01\";\n\nfunction generateTraceparent() {\n const traceId = randomHex(TRACE_ID_BYTES);\n const spanId = randomHex(SPAN_ID_BYTES);\n return `${VERSION}-${traceId}-${spanId}-${FLAGS}`;\n}\n\nfunction randomHex(bytes: number): string {\n const raw = uuidv7().replace(/-/g, \"\");\n const needed = bytes * 2;\n if (raw.length >= needed) {\n return raw.substring(0, needed);\n }\n return (raw + raw).substring(0, needed);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"route-handler.mjs","names":["GET: RouteHandler","parsed: unknown","POST: RouteHandler","OPTIONS: RouteHandler","uuidv7"],"sources":["../../src/server/route-handler.ts"],"sourcesContent":["/** biome-ignore-all lint/suspicious/useAwait: route handlers must be async */\n\"use server\";\n\nimport { API_PATHS } from \"@interfere/constants/api\";\nimport { withInterfereLogger } from \"@interfere/effect-utils/observability\";\nimport {\n createBackoffSchedule,\n shouldRetryHttp,\n withTimeoutFail,\n} from \"@interfere/effect-utils/retry\";\nimport { withSpan } from \"@interfere/react/effect/layers/tracer.layer\";\nimport { envelopeSchema } from \"@interfere/types/sdk/envelope\";\n\nimport { Data, Effect, Layer, Schedule } from \"effect\";\nimport type { NextRequest } from \"next/server\";\nimport { v7 as uuidv7 } from \"uuid\";\nimport { z } from \"zod\";\n\nimport { ConfigService, ConfigServiceLive } from \"./services/config.service\";\nimport {\n ErrorTrackingService,\n ErrorTrackingServiceLive,\n} from \"./services/error-tracking.service\";\n\ntype RouteHandler = (request: NextRequest) => Promise<Response>;\n\nconst layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);\n\n// Error types for the proxy\nclass ProxyError extends Data.TaggedError(\"ProxyError\")<{\n readonly status: number;\n readonly message: string;\n readonly body?: string;\n}> {}\n\nconst TIMEOUT_MS = 10_000;\nconst RETRY_COUNT = 2;\nconst HTTP_BAD_GATEWAY = 502;\nconst RETRY_INITIAL_MS = 100;\nconst RETRY_MAX_MS = 2000;\n\nconst envelopesArraySchema = z.array(envelopeSchema);\n\nexport const GET: RouteHandler = async () => {\n const program = Effect.gen(function* () {\n const config = yield* ConfigService;\n const configured = yield* config.getSecretKey.pipe(\n Effect.map(() => true),\n Effect.catchAll(() => Effect.succeed(false))\n );\n\n return Response.json({ status: \"ok\", configured, timestamp: Date.now() });\n }).pipe(Effect.provide(layer));\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n};\n\nconst proxyIngestRequest = (\n request: Request,\n params: { apiUrl: string; surfaceToken: string }\n) =>\n Effect.gen(function* () {\n const incomingTrace = request.headers.get(\"traceparent\") || undefined;\n const traceparent = incomingTrace ?? generateTraceparent();\n\n // Read request body once\n const body = yield* Effect.tryPromise({\n try: () => request.clone().text(),\n catch: () =>\n new ProxyError({ status: 400, message: \"Invalid request body\" }),\n });\n\n // Validate the envelopes before proxying\n let parsed: unknown;\n\n try {\n parsed = JSON.parse(body);\n } catch (error) {\n yield* Effect.logWarning(\"Invalid JSON in request body\").pipe(\n Effect.annotateLogs({ error: String(error) })\n );\n\n return yield* Effect.fail(\n new ProxyError({\n status: 400,\n message: \"Invalid JSON in request body\",\n body: String(error),\n })\n );\n }\n\n const validation = envelopesArraySchema.safeParse(parsed);\n\n if (!validation.success) {\n const issues = validation.error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n code: issue.code,\n }));\n\n yield* Effect.logWarning(\"Invalid envelope schema\").pipe(\n Effect.annotateLogs({ validationErrors: issues })\n );\n\n // For malformed envelopes, short‑circuit and return a 422 directly.\n // This lets SDKs drop bad envelopes instead of retrying or feeding them\n // back into the error tracking pipeline.\n const b = JSON.stringify({\n ok: false,\n code: \"INVALID_ENVELOPE_SCHEMA\",\n errors: issues,\n });\n\n return new Response(b, {\n status: 422,\n headers: {\n \"content-type\": \"application/json\",\n },\n });\n }\n\n // De-duplicate by envelope.uuid to avoid reprocessing on client retries\n const seen = new Set<string>();\n\n const deduped = validation.data.filter((env) => {\n if (seen.has(env.uuid)) {\n return false;\n }\n\n seen.add(env.uuid);\n return true;\n });\n\n const dropped = validation.data.length - deduped.length;\n\n yield* Effect.logDebug(\"Envelope validation successful\").pipe(\n Effect.annotateLogs({\n envelopeCount: validation.data.length,\n dedupedCount: deduped.length,\n droppedDuplicates: dropped,\n })\n );\n\n const upstream = yield* withTimeoutFail(\n Effect.tryPromise({\n try: () =>\n fetch(`${params.apiUrl}${API_PATHS.INGEST_V0}`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"x-interfere-surface\": params.surfaceToken,\n traceparent,\n },\n body: JSON.stringify(deduped),\n }),\n catch: (error) =>\n new ProxyError({\n status: 0,\n message: error instanceof Error ? error.message : String(error),\n }),\n }),\n TIMEOUT_MS,\n () => new ProxyError({ status: 0, message: \"Network timeout\" })\n );\n\n const responseBody = yield* Effect.tryPromise({\n try: () => upstream.text(),\n catch: () => \"\",\n });\n\n return new Response(responseBody, {\n status: upstream.status,\n headers: {\n \"content-type\":\n upstream.headers.get(\"content-type\") || \"application/json\",\n },\n });\n });\n\nexport const POST: RouteHandler = async (request): Promise<Response> => {\n const program = Effect.gen(function* () {\n yield* Effect.logDebug(\"Handling ingest proxy request\").pipe(\n Effect.annotateLogs({ path: request.nextUrl.pathname })\n );\n\n const config = yield* ConfigService;\n const errorTracking = yield* ErrorTrackingService;\n\n // Check secret key\n yield* config.getSecretKey.pipe(\n Effect.tapError(() =>\n Effect.logError(\"Service not configured - missing INTERFERE_SECRET_KEY\")\n ),\n Effect.catchTag(\"ConfigError\", () =>\n Effect.fail(\n new ProxyError({\n status: 503,\n message:\n \"Service not configured. INTERFERE_SECRET_KEY environment variable is required.\",\n })\n )\n )\n );\n\n // Get public token\n const surfaceToken = yield* config.getPublicToken.pipe(\n Effect.tapError(() =>\n Effect.logError(\"Auth not available - missing public token\")\n ),\n Effect.catchTag(\"ConfigError\", () =>\n Effect.fail(\n new ProxyError({\n status: 503,\n message: \"Auth not available\",\n })\n )\n )\n );\n\n const apiUrl = yield* config.getApiUrl;\n\n // Proxy the request with retry logic\n const schedule = createBackoffSchedule(\n RETRY_INITIAL_MS,\n RETRY_MAX_MS,\n RETRY_COUNT\n ).pipe(\n Schedule.whileInput((e: unknown) =>\n e instanceof ProxyError ? shouldRetryHttp(e.status) : false\n )\n );\n\n const response = yield* withSpan(\n \"proxy.forward\",\n proxyIngestRequest(request, { apiUrl, surfaceToken }),\n { attributes: {} }\n ).pipe(\n Effect.retry(schedule),\n Effect.tapError((error) =>\n Effect.gen(function* () {\n yield* errorTracking.captureError(error, request, {\n pathname: request.nextUrl.pathname,\n type: \"api_route\",\n });\n yield* Effect.logError(\"Proxy request failed\").pipe(\n Effect.annotateLogs({\n error: String(error),\n status: error instanceof ProxyError ? error.status : 0,\n })\n );\n })\n )\n );\n\n yield* Effect.logDebug(\"Proxy request completed\").pipe(\n Effect.annotateLogs({ status: response.status })\n );\n\n return response;\n }).pipe(\n Effect.provide(layer),\n Effect.catchTag(\"ProxyError\", (error) =>\n Effect.succeed(\n Response.json(\n { error: error.message },\n { status: error.status || HTTP_BAD_GATEWAY }\n )\n )\n ),\n Effect.catchAll((error) => {\n Effect.runFork(\n Effect.logError(\"Unexpected error in route handler\").pipe(\n Effect.annotateLogs({ error: String(error) })\n )\n );\n return Effect.succeed(\n Response.json({ error: \"Internal server error\" }, { status: 500 })\n );\n })\n );\n\n return await Effect.runPromise(withInterfereLogger(\"next\", program));\n};\n\nexport const OPTIONS: RouteHandler = async () =>\n Effect.runPromise(\n withInterfereLogger(\n \"next\",\n Effect.succeed(\n new Response(null, {\n status: 200,\n headers: {\n \"Access-Control-Allow-Origin\": \"*\",\n \"Access-Control-Allow-Methods\": \"GET, POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type\",\n \"Access-Control-Max-Age\": \"86400\",\n },\n })\n )\n )\n );\n\n// Helper functions\nconst VERSION = \"00\";\nconst TRACE_ID_BYTES = 16;\nconst SPAN_ID_BYTES = 8;\nconst FLAGS = \"01\";\n\nfunction generateTraceparent() {\n const traceId = randomHex(TRACE_ID_BYTES);\n const spanId = randomHex(SPAN_ID_BYTES);\n return `${VERSION}-${traceId}-${spanId}-${FLAGS}`;\n}\n\nfunction randomHex(bytes: number): string {\n const raw = uuidv7().replace(/-/g, \"\");\n const needed = bytes * 2;\n if (raw.length >= needed) {\n return raw.substring(0, needed);\n }\n return (raw + raw).substring(0, needed);\n}\n"],"mappings":"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"}
@@ -1,20 +1,20 @@
1
1
  import { NonEmptyString } from "../../lib/types.mjs";
2
2
  import { Context, Effect, Layer } from "effect";
3
- import * as effect_Types16 from "effect/Types";
4
- import * as effect_Cause16 from "effect/Cause";
3
+ import * as effect_Types0 from "effect/Types";
4
+ import * as effect_Cause0 from "effect/Cause";
5
5
 
6
6
  //#region src/server/services/config.service.d.ts
7
- declare const ConfigError_base: new <A extends Record<string, any> = {}>(args: effect_Types16.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause16.YieldableError & {
7
+ declare const ConfigError_base: new <A extends Record<string, any> = {}>(args: effect_Types0.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause0.YieldableError & {
8
8
  readonly _tag: "ConfigError";
9
9
  } & Readonly<A>;
10
10
  declare class ConfigError extends ConfigError_base<{
11
11
  readonly message: string;
12
12
  }> {}
13
- type ConfigService = {
13
+ interface ConfigService {
14
14
  readonly getApiUrl: Effect.Effect<string>;
15
15
  readonly getSecretKey: Effect.Effect<NonEmptyString, ConfigError>;
16
16
  readonly getPublicToken: Effect.Effect<string, ConfigError>;
17
- };
17
+ }
18
18
  declare const ConfigService: Context.Tag<ConfigService, ConfigService>;
19
19
  declare const ConfigServiceLive: Layer.Layer<ConfigService, never, never>;
20
20
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"config.service.d.mts","names":[],"sources":["../../../src/server/services/config.service.ts"],"sourcesContent":[],"mappings":";;;;;;cAIyD;;;cAI5C,WAAA,SAAoB;EAJwB,SAAA,OAAA,EAAA,MAAA;;KAQ7C,aAAA;sBACU,MAAA,CAAO;yBACJ,MAAA,CAAO,OAAO,gBAAgB;2BAC5B,MAAA,CAAO,eAAe;;cAGpC,eAAa,OAAA,CAAA,IAAA,eAAA;cAsDb,mBAAiB,KAAA,CAAA,MAAA"}
1
+ {"version":3,"file":"config.service.d.mts","names":[],"sources":["../../../src/server/services/config.service.ts"],"sourcesContent":[],"mappings":";;;;;;cAKyD;;;cAI5C,WAAA,SAAoB;EAJwB,SAAA,OAAA,EAAA,MAAA;;UAQxC,aAAA;sBACK,MAAA,CAAO;yBACJ,MAAA,CAAO,OAAO,gBAAgB;2BAC5B,MAAA,CAAO,eAAe;;cAGpC,eAAa,OAAA,CAAA,IAAA,eAAA;cAsDb,mBAAiB,KAAA,CAAA,MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.service.mjs","names":["cachedPublicToken: { token: string; expiresAt: number } | null","getPublicTokenShared"],"sources":["../../../src/server/services/config.service.ts"],"sourcesContent":["import { getPublicToken as getPublicTokenShared } from \"@interfere/react/server/auth\";\nimport { Context, Data, Effect, Layer } from \"effect\";\n\nimport { normalizeSecretKey, resolveApiUrl } from \"../../build/env-config.js\";\nimport type { NonEmptyString } from \"../../lib/types.js\";\n\nconst ONE_HOUR_MS = 3_600_000;\n\nexport class ConfigError extends Data.TaggedError(\"ConfigError\")<{\n readonly message: string;\n}> {}\n\nexport type ConfigService = {\n readonly getApiUrl: Effect.Effect<string>;\n readonly getSecretKey: Effect.Effect<NonEmptyString, ConfigError>;\n readonly getPublicToken: Effect.Effect<string, ConfigError>;\n};\n\nexport const ConfigService = Context.GenericTag<ConfigService>(\n \"@interfere/next/ConfigService\"\n);\n\nlet cachedPublicToken: { token: string; expiresAt: number } | null = null;\n\nconst getSecretKey = (): Effect.Effect<NonEmptyString, ConfigError> =>\n Effect.gen(function* () {\n const normalized = normalizeSecretKey(process.env.INTERFERE_SECRET_KEY);\n\n if (!normalized) {\n return yield* Effect.fail(\n new ConfigError({ message: \"INTERFERE_SECRET_KEY not set or empty\" })\n );\n }\n\n return normalized;\n });\n\nconst getPublicTokenImpl = (): Effect.Effect<string, ConfigError> =>\n Effect.gen(function* () {\n const override = process.env.INTERFERE_PUBLIC_TOKEN;\n if (override) {\n return override;\n }\n\n const secret = yield* getSecretKey();\n const apiUrl = resolveApiUrl();\n\n const now = Date.now();\n if (cachedPublicToken && cachedPublicToken.expiresAt > now) {\n return cachedPublicToken.token;\n }\n\n const token = yield* Effect.tryPromise({\n try: () => getPublicTokenShared({ apiUrl, secret }),\n catch: (error) =>\n new ConfigError({ message: `Failed to get public token: ${error}` }),\n });\n\n if (!token) {\n return yield* Effect.fail(\n new ConfigError({ message: \"No token returned\" })\n );\n }\n\n cachedPublicToken = {\n token,\n expiresAt: now + ONE_HOUR_MS,\n };\n\n return token;\n });\n\nexport const ConfigServiceLive = Layer.succeed(\n ConfigService,\n ConfigService.of({\n getApiUrl: Effect.succeed(resolveApiUrl()),\n getSecretKey: getSecretKey(),\n getPublicToken: getPublicTokenImpl(),\n })\n);\n"],"mappings":";;;;;AAMA,MAAM,cAAc;AAEpB,IAAa,cAAb,cAAiC,KAAK,YAAY,cAAc,CAE7D;AAQH,MAAa,gBAAgB,QAAQ,WACnC,gCACD;AAED,IAAIA,oBAAiE;AAErE,MAAM,qBACJ,OAAO,IAAI,aAAa;CACtB,MAAM,aAAa,mBAAmB,QAAQ,IAAI,qBAAqB;AAEvE,KAAI,CAAC,WACH,QAAO,OAAO,OAAO,KACnB,IAAI,YAAY,EAAE,SAAS,yCAAyC,CAAC,CACtE;AAGH,QAAO;EACP;AAEJ,MAAM,2BACJ,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,QAAQ,IAAI;AAC7B,KAAI,SACF,QAAO;CAGT,MAAM,SAAS,OAAO,cAAc;CACpC,MAAM,SAAS,eAAe;CAE9B,MAAM,MAAM,KAAK,KAAK;AACtB,KAAI,qBAAqB,kBAAkB,YAAY,IACrD,QAAO,kBAAkB;CAG3B,MAAM,QAAQ,OAAO,OAAO,WAAW;EACrC,WAAWC,eAAqB;GAAE;GAAQ;GAAQ,CAAC;EACnD,QAAQ,UACN,IAAI,YAAY,EAAE,SAAS,+BAA+B,SAAS,CAAC;EACvE,CAAC;AAEF,KAAI,CAAC,MACH,QAAO,OAAO,OAAO,KACnB,IAAI,YAAY,EAAE,SAAS,qBAAqB,CAAC,CAClD;AAGH,qBAAoB;EAClB;EACA,WAAW,MAAM;EAClB;AAED,QAAO;EACP;AAEJ,MAAa,oBAAoB,MAAM,QACrC,eACA,cAAc,GAAG;CACf,WAAW,OAAO,QAAQ,eAAe,CAAC;CAC1C,cAAc,cAAc;CAC5B,gBAAgB,oBAAoB;CACrC,CAAC,CACH"}
1
+ {"version":3,"file":"config.service.mjs","names":["cachedPublicToken: { token: string; expiresAt: number } | null","getPublicTokenShared"],"sources":["../../../src/server/services/config.service.ts"],"sourcesContent":["import { getPublicToken as getPublicTokenShared } from \"@interfere/react/server/auth\";\n\nimport { Context, Data, Effect, Layer } from \"effect\";\n\nimport { normalizeSecretKey, resolveApiUrl } from \"../../build/env-config.js\";\nimport type { NonEmptyString } from \"../../lib/types.js\";\n\nconst ONE_HOUR_MS = 3_600_000;\n\nexport class ConfigError extends Data.TaggedError(\"ConfigError\")<{\n readonly message: string;\n}> {}\n\nexport interface ConfigService {\n readonly getApiUrl: Effect.Effect<string>;\n readonly getSecretKey: Effect.Effect<NonEmptyString, ConfigError>;\n readonly getPublicToken: Effect.Effect<string, ConfigError>;\n}\n\nexport const ConfigService = Context.GenericTag<ConfigService>(\n \"@interfere/next/ConfigService\"\n);\n\nlet cachedPublicToken: { token: string; expiresAt: number } | null = null;\n\nconst getSecretKey = (): Effect.Effect<NonEmptyString, ConfigError> =>\n Effect.gen(function* () {\n const normalized = normalizeSecretKey(process.env.INTERFERE_SECRET_KEY);\n\n if (!normalized) {\n return yield* Effect.fail(\n new ConfigError({ message: \"INTERFERE_SECRET_KEY not set or empty\" })\n );\n }\n\n return normalized;\n });\n\nconst getPublicTokenImpl = (): Effect.Effect<string, ConfigError> =>\n Effect.gen(function* () {\n const override = process.env.INTERFERE_PUBLIC_TOKEN;\n if (override) {\n return override;\n }\n\n const secret = yield* getSecretKey();\n const apiUrl = resolveApiUrl();\n\n const now = Date.now();\n if (cachedPublicToken && cachedPublicToken.expiresAt > now) {\n return cachedPublicToken.token;\n }\n\n const token = yield* Effect.tryPromise({\n try: () => getPublicTokenShared({ apiUrl, secret }),\n catch: (error) =>\n new ConfigError({ message: `Failed to get public token: ${error}` }),\n });\n\n if (!token) {\n return yield* Effect.fail(\n new ConfigError({ message: \"No token returned\" })\n );\n }\n\n cachedPublicToken = {\n token,\n expiresAt: now + ONE_HOUR_MS,\n };\n\n return token;\n });\n\nexport const ConfigServiceLive = Layer.succeed(\n ConfigService,\n ConfigService.of({\n getApiUrl: Effect.succeed(resolveApiUrl()),\n getSecretKey: getSecretKey(),\n getPublicToken: getPublicTokenImpl(),\n })\n);\n"],"mappings":";;;;;AAOA,MAAM,cAAc;AAEpB,IAAa,cAAb,cAAiC,KAAK,YAAY,cAAc,CAE7D;AAQH,MAAa,gBAAgB,QAAQ,WACnC,gCACD;AAED,IAAIA,oBAAiE;AAErE,MAAM,qBACJ,OAAO,IAAI,aAAa;CACtB,MAAM,aAAa,mBAAmB,QAAQ,IAAI,qBAAqB;AAEvE,KAAI,CAAC,WACH,QAAO,OAAO,OAAO,KACnB,IAAI,YAAY,EAAE,SAAS,yCAAyC,CAAC,CACtE;AAGH,QAAO;EACP;AAEJ,MAAM,2BACJ,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,QAAQ,IAAI;AAC7B,KAAI,SACF,QAAO;CAGT,MAAM,SAAS,OAAO,cAAc;CACpC,MAAM,SAAS,eAAe;CAE9B,MAAM,MAAM,KAAK,KAAK;AACtB,KAAI,qBAAqB,kBAAkB,YAAY,IACrD,QAAO,kBAAkB;CAG3B,MAAM,QAAQ,OAAO,OAAO,WAAW;EACrC,WAAWC,eAAqB;GAAE;GAAQ;GAAQ,CAAC;EACnD,QAAQ,UACN,IAAI,YAAY,EAAE,SAAS,+BAA+B,SAAS,CAAC;EACvE,CAAC;AAEF,KAAI,CAAC,MACH,QAAO,OAAO,OAAO,KACnB,IAAI,YAAY,EAAE,SAAS,qBAAqB,CAAC,CAClD;AAGH,qBAAoB;EAClB;EACA,WAAW,MAAM;EAClB;AAED,QAAO;EACP;AAEJ,MAAa,oBAAoB,MAAM,QACrC,eACA,cAAc,GAAG;CACf,WAAW,OAAO,QAAQ,eAAe,CAAC;CAC1C,cAAc,cAAc;CAC5B,gBAAgB,oBAAoB;CACrC,CAAC,CACH"}
@@ -1,18 +1,18 @@
1
1
  import { ConfigService } from "./config.service.mjs";
2
2
  import { Context, Effect, Layer } from "effect";
3
- import * as effect_Types15 from "effect/Types";
4
- import * as effect_Cause15 from "effect/Cause";
3
+ import * as effect_Types16 from "effect/Types";
4
+ import * as effect_Cause16 from "effect/Cause";
5
5
 
6
6
  //#region src/server/services/error-tracking.service.d.ts
7
- declare const ErrorTrackingError_base: new <A extends Record<string, any> = {}>(args: effect_Types15.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause15.YieldableError & {
7
+ declare const ErrorTrackingError_base: new <A extends Record<string, any> = {}>(args: effect_Types16.Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P] }) => effect_Cause16.YieldableError & {
8
8
  readonly _tag: "ErrorTrackingError";
9
9
  } & Readonly<A>;
10
10
  declare class ErrorTrackingError extends ErrorTrackingError_base<{
11
11
  readonly message: string;
12
12
  }> {}
13
- type ErrorTrackingService = {
13
+ interface ErrorTrackingService {
14
14
  readonly captureError: (error: unknown, request?: Request, context?: Record<string, unknown>) => Effect.Effect<void, never, ConfigService>;
15
- };
15
+ }
16
16
  declare const ErrorTrackingService: Context.Tag<ErrorTrackingService, ErrorTrackingService>;
17
17
  declare const ErrorTrackingServiceLive: Layer.Layer<ErrorTrackingService, never, never>;
18
18
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"error-tracking.service.d.mts","names":[],"sources":["../../../src/server/services/error-tracking.service.ts"],"sourcesContent":[],"mappings":";;;;;;cAOiD;;;cAEpC,kBAAA,SAA2B;EAFS,SAAA,OAAA,EAAA,MAAA;;KAMrC,oBAAA;oDAGE,mBACA,4BACP,MAAA,CAAO,oBAAoB;;cAGrB,sBAAoB,OAAA,CAAA,IAAA,sBAAA;cAIpB,0BAAwB,KAAA,CAAA,MAAA"}
1
+ {"version":3,"file":"error-tracking.service.d.mts","names":[],"sources":["../../../src/server/services/error-tracking.service.ts"],"sourcesContent":[],"mappings":";;;;;;cASiD;;;cAEpC,kBAAA,SAA2B;EAFS,SAAA,OAAA,EAAA,MAAA;;UAMhC,oBAAA;oDAGH,mBACA,4BACP,MAAA,CAAO,oBAAoB;;cAGrB,sBAAoB,OAAA,CAAA,IAAA,sBAAA;cAIpB,0BAAwB,KAAA,CAAA,MAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"error-tracking.service.mjs","names":[],"sources":["../../../src/server/services/error-tracking.service.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport { getRuntime } from \"@interfere/react/core/runtime/config\";\nimport {\n buildServerErrorEnvelope,\n sendEnvelopesToIngest,\n} from \"@interfere/react/server/capture\";\nimport { Context, Data, Effect, Layer } from \"effect\";\nimport { ConfigService } from \"./config.service\";\n\nexport class ErrorTrackingError extends Data.TaggedError(\"ErrorTrackingError\")<{\n readonly message: string;\n}> {}\n\nexport type ErrorTrackingService = {\n readonly captureError: (\n error: unknown,\n request?: Request,\n context?: Record<string, unknown>\n ) => Effect.Effect<void, never, ConfigService>;\n};\n\nexport const ErrorTrackingService = Context.GenericTag<ErrorTrackingService>(\n \"@interfere/next/ErrorTrackingService\"\n);\n\nexport const ErrorTrackingServiceLive = Layer.succeed(\n ErrorTrackingService,\n ErrorTrackingService.of({\n captureError: (error, request, context) =>\n Effect.gen(function* () {\n const config = yield* ConfigService;\n const token = yield* config.getPublicToken.pipe(\n Effect.catchAll(() => Effect.succeed(null))\n );\n\n if (!token) {\n return;\n }\n\n const apiUrl = yield* config.getApiUrl;\n const inferredValues = {\n buildId: process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID ?? null,\n releaseId: process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID ?? null,\n environment: process.env.NODE_ENV || null,\n runtime: getRuntime(),\n };\n\n const envelope = buildServerErrorEnvelope({\n ...inferredValues,\n error,\n request,\n context: {\n ...context,\n },\n });\n\n yield* Effect.tryPromise({\n try: () =>\n sendEnvelopesToIngest(\n [envelope],\n `${apiUrl}${API_PATHS.INGEST_V0}`,\n token\n ),\n catch: () =>\n new ErrorTrackingError({\n message: \"Failed to send error to ingest\",\n }),\n }).pipe(\n Effect.catchAll(() => Effect.void) // Best-effort\n );\n }),\n })\n);\n"],"mappings":";;;;;;;AASA,IAAa,qBAAb,cAAwC,KAAK,YAAY,qBAAqB,CAE3E;AAUH,MAAa,uBAAuB,QAAQ,WAC1C,uCACD;AAED,MAAa,2BAA2B,MAAM,QAC5C,sBACA,qBAAqB,GAAG,EACtB,eAAe,OAAO,SAAS,YAC7B,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO,OAAO,eAAe,KACzC,OAAO,eAAe,OAAO,QAAQ,KAAK,CAAC,CAC5C;AAED,KAAI,CAAC,MACH;CAGF,MAAM,SAAS,OAAO,OAAO;CAQ7B,MAAM,WAAW,yBAAyB;EANxC,SAAS,QAAQ,IAAI,kCAAkC;EACvD,WAAW,QAAQ,IAAI,oCAAoC;EAC3D,aAAa,QAAQ,IAAI,YAAY;EACrC,SAAS,YAAY;EAKrB;EACA;EACA,SAAS,EACP,GAAG,SACJ;EACF,CAAC;AAEF,QAAO,OAAO,WAAW;EACvB,WACE,sBACE,CAAC,SAAS,EACV,GAAG,SAAS,UAAU,aACtB,MACD;EACH,aACE,IAAI,mBAAmB,EACrB,SAAS,kCACV,CAAC;EACL,CAAC,CAAC,KACD,OAAO,eAAe,OAAO,KAAK,CACnC;EACD,EACL,CAAC,CACH"}
1
+ {"version":3,"file":"error-tracking.service.mjs","names":[],"sources":["../../../src/server/services/error-tracking.service.ts"],"sourcesContent":["import { API_PATHS } from \"@interfere/constants/api\";\nimport { getRuntime } from \"@interfere/react/core/runtime/config\";\nimport {\n buildServerErrorEnvelope,\n sendEnvelopesToIngest,\n} from \"@interfere/react/server/capture\";\n\nimport { Context, Data, Effect, Layer } from \"effect\";\n\nimport { ConfigService } from \"./config.service\";\n\nexport class ErrorTrackingError extends Data.TaggedError(\"ErrorTrackingError\")<{\n readonly message: string;\n}> {}\n\nexport interface ErrorTrackingService {\n readonly captureError: (\n error: unknown,\n request?: Request,\n context?: Record<string, unknown>\n ) => Effect.Effect<void, never, ConfigService>;\n}\n\nexport const ErrorTrackingService = Context.GenericTag<ErrorTrackingService>(\n \"@interfere/next/ErrorTrackingService\"\n);\n\nexport const ErrorTrackingServiceLive = Layer.succeed(\n ErrorTrackingService,\n ErrorTrackingService.of({\n captureError: (error, request, context) =>\n Effect.gen(function* () {\n const config = yield* ConfigService;\n const token = yield* config.getPublicToken.pipe(\n Effect.catchAll(() => Effect.succeed(null))\n );\n\n if (!token) {\n return;\n }\n\n const apiUrl = yield* config.getApiUrl;\n const inferredValues = {\n buildId: process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID ?? null,\n releaseId: process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID ?? null,\n environment: process.env.NODE_ENV || null,\n runtime: getRuntime(),\n };\n\n const envelope = buildServerErrorEnvelope({\n ...inferredValues,\n error,\n request,\n context: {\n ...context,\n },\n });\n\n yield* Effect.tryPromise({\n try: () =>\n sendEnvelopesToIngest(\n [envelope],\n `${apiUrl}${API_PATHS.INGEST_V0}`,\n token\n ),\n catch: () =>\n new ErrorTrackingError({\n message: \"Failed to send error to ingest\",\n }),\n }).pipe(\n Effect.catchAll(() => Effect.void) // Best-effort\n );\n }),\n })\n);\n"],"mappings":";;;;;;;AAWA,IAAa,qBAAb,cAAwC,KAAK,YAAY,qBAAqB,CAE3E;AAUH,MAAa,uBAAuB,QAAQ,WAC1C,uCACD;AAED,MAAa,2BAA2B,MAAM,QAC5C,sBACA,qBAAqB,GAAG,EACtB,eAAe,OAAO,SAAS,YAC7B,OAAO,IAAI,aAAa;CACtB,MAAM,SAAS,OAAO;CACtB,MAAM,QAAQ,OAAO,OAAO,eAAe,KACzC,OAAO,eAAe,OAAO,QAAQ,KAAK,CAAC,CAC5C;AAED,KAAI,CAAC,MACH;CAGF,MAAM,SAAS,OAAO,OAAO;CAQ7B,MAAM,WAAW,yBAAyB;EANxC,SAAS,QAAQ,IAAI,kCAAkC;EACvD,WAAW,QAAQ,IAAI,oCAAoC;EAC3D,aAAa,QAAQ,IAAI,YAAY;EACrC,SAAS,YAAY;EAKrB;EACA;EACA,SAAS,EACP,GAAG,SACJ;EACF,CAAC;AAEF,QAAO,OAAO,WAAW;EACvB,WACE,sBACE,CAAC,SAAS,EACV,GAAG,SAAS,UAAU,aACtB,MACD;EACH,aACE,IAAI,mBAAmB,EACrB,SAAS,kCACV,CAAC;EACL,CAAC,CAAC,KACD,OAAO,eAAe,OAAO,KAAK,CACnC;EACD,EACL,CAAC,CACH"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/next",
3
- "version": "0.0.15-alpha.0",
3
+ "version": "0.0.15-alpha.2",
4
4
  "license": "MIT",
5
5
  "description": "Build apps that never break.",
6
6
  "keywords": [
@@ -21,6 +21,11 @@
21
21
  ],
22
22
  "type": "module",
23
23
  "exports": {
24
+ "./config": {
25
+ "@source": "./src/build/with-interfere.ts",
26
+ "types": "./dist/build/with-interfere.d.mts",
27
+ "default": "./dist/build/with-interfere.mjs"
28
+ },
24
29
  "./build": {
25
30
  "@source": "./src/build/with-interfere.ts",
26
31
  "types": "./dist/build/with-interfere.d.mts",
@@ -85,9 +90,10 @@
85
90
  "@vitest/coverage-v8": "^4.0.16",
86
91
  "jsdom": "^27.3.0",
87
92
  "msw": "^2.12.4",
88
- "next": "^16.1.0",
93
+ "next": "^16.1.1",
89
94
  "react": "^19.2.3",
90
95
  "react-dom": "^19.2.3",
96
+ "tsdown": "^0.18.3",
91
97
  "typescript": "5.9.3",
92
98
  "vitest": "^4.0.16",
93
99
  "webpack": "^5.104.1",