@interfere/next 0.1.0-alpha.9 → 0.2.0-alpha.4

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 (242) hide show
  1. package/README.md +70 -277
  2. package/dist/_virtual/_rolldown/runtime.mjs +13 -0
  3. package/dist/config.d.mts +11 -0
  4. package/dist/config.d.mts.map +1 -0
  5. package/dist/config.mjs +107 -0
  6. package/dist/config.mjs.map +1 -0
  7. package/dist/instrument-client.d.mts +2 -0
  8. package/dist/instrument-client.mjs +2 -0
  9. package/dist/internal/build/configure-build.d.mts +22 -0
  10. package/dist/internal/build/configure-build.d.mts.map +1 -0
  11. package/dist/internal/build/configure-build.mjs +87 -0
  12. package/dist/internal/build/configure-build.mjs.map +1 -0
  13. package/dist/internal/build/injected.d.mts +12 -0
  14. package/dist/internal/build/injected.d.mts.map +1 -0
  15. package/dist/internal/build/injected.mjs +9 -0
  16. package/dist/internal/build/injected.mjs.map +1 -0
  17. package/dist/internal/build/release/destinations/vercel.d.mts +6 -0
  18. package/dist/internal/build/release/destinations/vercel.d.mts.map +1 -0
  19. package/dist/internal/build/release/destinations/vercel.mjs +25 -0
  20. package/dist/internal/build/release/destinations/vercel.mjs.map +1 -0
  21. package/dist/internal/build/release/git.d.mts +4 -0
  22. package/dist/internal/build/release/git.d.mts.map +1 -0
  23. package/dist/internal/build/release/git.mjs +21 -0
  24. package/dist/internal/build/release/git.mjs.map +1 -0
  25. package/dist/internal/build/release/index.d.mts +7 -0
  26. package/dist/internal/build/release/index.d.mts.map +1 -0
  27. package/dist/internal/build/release/index.mjs +24 -0
  28. package/dist/internal/build/release/index.mjs.map +1 -0
  29. package/dist/internal/build/release/sources/github.d.mts +6 -0
  30. package/dist/internal/build/release/sources/github.d.mts.map +1 -0
  31. package/dist/internal/build/release/sources/github.mjs +15 -0
  32. package/dist/internal/build/release/sources/github.mjs.map +1 -0
  33. package/dist/internal/build/release/types.d.mts +11 -0
  34. package/dist/internal/build/release/types.d.mts.map +1 -0
  35. package/dist/internal/build/release/types.mjs +1 -0
  36. package/dist/internal/build/source-maps/discover.d.mts +14 -0
  37. package/dist/internal/build/source-maps/discover.d.mts.map +1 -0
  38. package/dist/internal/build/source-maps/discover.mjs +61 -0
  39. package/dist/internal/build/source-maps/discover.mjs.map +1 -0
  40. package/dist/internal/build/source-maps/index.d.mts +23 -0
  41. package/dist/internal/build/source-maps/index.d.mts.map +1 -0
  42. package/dist/internal/build/source-maps/index.mjs +33 -0
  43. package/dist/internal/build/source-maps/index.mjs.map +1 -0
  44. package/dist/internal/build/value-injection-loader.d.mts +10 -0
  45. package/dist/internal/build/value-injection-loader.d.mts.map +1 -0
  46. package/dist/internal/build/value-injection-loader.mjs +24 -0
  47. package/dist/internal/build/value-injection-loader.mjs.map +1 -0
  48. package/dist/internal/env.d.mts +16 -0
  49. package/dist/internal/env.d.mts.map +1 -0
  50. package/dist/internal/env.mjs +19 -0
  51. package/dist/internal/env.mjs.map +1 -0
  52. package/dist/internal/logger.d.mts +8 -0
  53. package/dist/internal/logger.d.mts.map +1 -0
  54. package/dist/internal/logger.mjs +44 -0
  55. package/dist/internal/logger.mjs.map +1 -0
  56. package/dist/internal/route/cors.d.mts +4 -0
  57. package/dist/internal/route/cors.d.mts.map +1 -0
  58. package/dist/internal/route/cors.mjs +15 -0
  59. package/dist/internal/route/cors.mjs.map +1 -0
  60. package/dist/internal/route/handle-get.d.mts +4 -0
  61. package/dist/internal/route/handle-get.d.mts.map +1 -0
  62. package/dist/internal/route/handle-get.mjs +15 -0
  63. package/dist/internal/route/handle-get.mjs.map +1 -0
  64. package/dist/internal/route/handle-post.d.mts +4 -0
  65. package/dist/internal/route/handle-post.d.mts.map +1 -0
  66. package/dist/internal/route/handle-post.mjs +105 -0
  67. package/dist/internal/route/handle-post.mjs.map +1 -0
  68. package/dist/internal/route/sw-script.d.mts +4 -0
  69. package/dist/internal/route/sw-script.d.mts.map +1 -0
  70. package/dist/internal/route/sw-script.mjs +32 -0
  71. package/dist/internal/route/sw-script.mjs.map +1 -0
  72. package/dist/internal/server/capture.d.mts +9 -0
  73. package/dist/internal/server/capture.d.mts.map +1 -0
  74. package/dist/internal/server/capture.mjs +46 -0
  75. package/dist/internal/server/capture.mjs.map +1 -0
  76. package/dist/internal/server/dedupe.d.mts +5 -0
  77. package/dist/internal/server/dedupe.d.mts.map +1 -0
  78. package/dist/internal/server/dedupe.mjs +11 -0
  79. package/dist/internal/server/dedupe.mjs.map +1 -0
  80. package/dist/internal/server/envelope.d.mts +14 -0
  81. package/dist/internal/server/envelope.d.mts.map +1 -0
  82. package/dist/internal/server/envelope.mjs +41 -0
  83. package/dist/internal/server/envelope.mjs.map +1 -0
  84. package/dist/internal/server/mechanisms.d.mts +7 -0
  85. package/dist/internal/server/mechanisms.d.mts.map +1 -0
  86. package/dist/internal/server/mechanisms.mjs +12 -0
  87. package/dist/internal/server/mechanisms.mjs.map +1 -0
  88. package/dist/internal/server/normalize-request.d.mts +7 -0
  89. package/dist/internal/server/normalize-request.d.mts.map +1 -0
  90. package/dist/internal/server/normalize-request.mjs +50 -0
  91. package/dist/internal/server/normalize-request.mjs.map +1 -0
  92. package/dist/internal/server/runtime.d.mts +14 -0
  93. package/dist/internal/server/runtime.d.mts.map +1 -0
  94. package/dist/internal/server/runtime.mjs +18 -0
  95. package/dist/internal/server/runtime.mjs.map +1 -0
  96. package/dist/internal/server/session.d.mts +11 -0
  97. package/dist/internal/server/session.d.mts.map +1 -0
  98. package/dist/internal/server/session.mjs +15 -0
  99. package/dist/internal/server/session.mjs.map +1 -0
  100. package/dist/internal/server/transport.d.mts +12 -0
  101. package/dist/internal/server/transport.d.mts.map +1 -0
  102. package/dist/internal/server/transport.mjs +17 -0
  103. package/dist/internal/server/transport.mjs.map +1 -0
  104. package/dist/internal/server/types.d.mts +17 -0
  105. package/dist/internal/server/types.d.mts.map +1 -0
  106. package/dist/internal/server/types.mjs +1 -0
  107. package/dist/provider.d.mts +2 -0
  108. package/dist/provider.mjs +3 -0
  109. package/dist/route-handler.d.mts +7 -0
  110. package/dist/route-handler.d.mts.map +1 -0
  111. package/dist/route-handler.mjs +18 -0
  112. package/dist/route-handler.mjs.map +1 -0
  113. package/dist/server.d.mts +8 -0
  114. package/dist/server.d.mts.map +1 -0
  115. package/dist/server.mjs +6 -0
  116. package/dist/server.mjs.map +1 -0
  117. package/package.json +60 -73
  118. package/LICENSE +0 -21
  119. package/dist/build/env-config.d.mts +0 -7
  120. package/dist/build/env-config.d.mts.map +0 -1
  121. package/dist/build/env-config.mjs +0 -17
  122. package/dist/build/env-config.mjs.map +0 -1
  123. package/dist/build/loaders/value-injection-loader.d.mts +0 -28
  124. package/dist/build/loaders/value-injection-loader.d.mts.map +0 -1
  125. package/dist/build/loaders/value-injection-loader.mjs +0 -44
  126. package/dist/build/loaders/value-injection-loader.mjs.map +0 -1
  127. package/dist/build/logger.d.mts +0 -11
  128. package/dist/build/logger.d.mts.map +0 -1
  129. package/dist/build/logger.mjs +0 -155
  130. package/dist/build/logger.mjs.map +0 -1
  131. package/dist/build/release-program.d.mts +0 -19
  132. package/dist/build/release-program.d.mts.map +0 -1
  133. package/dist/build/release-program.mjs +0 -92
  134. package/dist/build/release-program.mjs.map +0 -1
  135. package/dist/build/secret-key.d.mts +0 -10
  136. package/dist/build/secret-key.d.mts.map +0 -1
  137. package/dist/build/secret-key.mjs +0 -16
  138. package/dist/build/secret-key.mjs.map +0 -1
  139. package/dist/build/services/config.service.d.mts +0 -9
  140. package/dist/build/services/config.service.d.mts.map +0 -1
  141. package/dist/build/services/config.service.mjs +0 -8
  142. package/dist/build/services/config.service.mjs.map +0 -1
  143. package/dist/build/services/instrumentation-detection.service.d.mts +0 -22
  144. package/dist/build/services/instrumentation-detection.service.d.mts.map +0 -1
  145. package/dist/build/services/instrumentation-detection.service.mjs +0 -60
  146. package/dist/build/services/instrumentation-detection.service.mjs.map +0 -1
  147. package/dist/build/services/preflight.service.d.mts +0 -19
  148. package/dist/build/services/preflight.service.d.mts.map +0 -1
  149. package/dist/build/services/preflight.service.mjs +0 -76
  150. package/dist/build/services/preflight.service.mjs.map +0 -1
  151. package/dist/build/services/release-identity.service.d.mts +0 -22
  152. package/dist/build/services/release-identity.service.d.mts.map +0 -1
  153. package/dist/build/services/release-identity.service.mjs +0 -48
  154. package/dist/build/services/release-identity.service.mjs.map +0 -1
  155. package/dist/build/services/source-map.service.d.mts +0 -24
  156. package/dist/build/services/source-map.service.d.mts.map +0 -1
  157. package/dist/build/services/source-map.service.mjs +0 -58
  158. package/dist/build/services/source-map.service.mjs.map +0 -1
  159. package/dist/build/source-maps/api.d.mts +0 -35
  160. package/dist/build/source-maps/api.d.mts.map +0 -1
  161. package/dist/build/source-maps/api.mjs +0 -61
  162. package/dist/build/source-maps/api.mjs.map +0 -1
  163. package/dist/build/source-maps/client.d.mts +0 -73
  164. package/dist/build/source-maps/client.d.mts.map +0 -1
  165. package/dist/build/source-maps/client.mjs +0 -228
  166. package/dist/build/source-maps/client.mjs.map +0 -1
  167. package/dist/build/source-maps/errors.d.mts +0 -109
  168. package/dist/build/source-maps/errors.d.mts.map +0 -1
  169. package/dist/build/source-maps/errors.mjs +0 -22
  170. package/dist/build/source-maps/errors.mjs.map +0 -1
  171. package/dist/build/source-maps/files.d.mts +0 -35
  172. package/dist/build/source-maps/files.d.mts.map +0 -1
  173. package/dist/build/source-maps/files.mjs +0 -222
  174. package/dist/build/source-maps/files.mjs.map +0 -1
  175. package/dist/build/source-maps/providers/deployment/detector.d.mts +0 -26
  176. package/dist/build/source-maps/providers/deployment/detector.d.mts.map +0 -1
  177. package/dist/build/source-maps/providers/deployment/detector.mjs +0 -22
  178. package/dist/build/source-maps/providers/deployment/detector.mjs.map +0 -1
  179. package/dist/build/source-maps/providers/deployment/types.d.mts +0 -12
  180. package/dist/build/source-maps/providers/deployment/types.d.mts.map +0 -1
  181. package/dist/build/source-maps/providers/deployment/types.mjs +0 -3
  182. package/dist/build/source-maps/providers/deployment/vercel.d.mts +0 -6
  183. package/dist/build/source-maps/providers/deployment/vercel.d.mts.map +0 -1
  184. package/dist/build/source-maps/providers/deployment/vercel.mjs +0 -44
  185. package/dist/build/source-maps/providers/deployment/vercel.mjs.map +0 -1
  186. package/dist/build/source-maps/providers/source-control/detector.d.mts +0 -15
  187. package/dist/build/source-maps/providers/source-control/detector.d.mts.map +0 -1
  188. package/dist/build/source-maps/providers/source-control/detector.mjs +0 -22
  189. package/dist/build/source-maps/providers/source-control/detector.mjs.map +0 -1
  190. package/dist/build/source-maps/providers/source-control/git.d.mts +0 -6
  191. package/dist/build/source-maps/providers/source-control/git.d.mts.map +0 -1
  192. package/dist/build/source-maps/providers/source-control/git.mjs +0 -50
  193. package/dist/build/source-maps/providers/source-control/git.mjs.map +0 -1
  194. package/dist/build/source-maps/providers/source-control/types.d.mts +0 -12
  195. package/dist/build/source-maps/providers/source-control/types.d.mts.map +0 -1
  196. package/dist/build/source-maps/providers/source-control/types.mjs +0 -3
  197. package/dist/build/with-interfere.d.mts +0 -70
  198. package/dist/build/with-interfere.d.mts.map +0 -1
  199. package/dist/build/with-interfere.mjs +0 -154
  200. package/dist/build/with-interfere.mjs.map +0 -1
  201. package/dist/client/auto-init.d.mts +0 -92
  202. package/dist/client/auto-init.d.mts.map +0 -1
  203. package/dist/client/auto-init.mjs +0 -121
  204. package/dist/client/auto-init.mjs.map +0 -1
  205. package/dist/client/client.d.mts +0 -3
  206. package/dist/client/client.mjs +0 -5
  207. package/dist/client/provider.d.mts +0 -22
  208. package/dist/client/provider.d.mts.map +0 -1
  209. package/dist/client/provider.mjs +0 -50
  210. package/dist/client/provider.mjs.map +0 -1
  211. package/dist/lib/env.d.mts +0 -12
  212. package/dist/lib/env.d.mts.map +0 -1
  213. package/dist/lib/env.mjs +0 -17
  214. package/dist/lib/env.mjs.map +0 -1
  215. package/dist/lib/test-utils/make-next-request.d.mts +0 -6
  216. package/dist/lib/test-utils/make-next-request.d.mts.map +0 -1
  217. package/dist/lib/test-utils/make-next-request.mjs +0 -12
  218. package/dist/lib/test-utils/make-next-request.mjs.map +0 -1
  219. package/dist/lib/types.d.mts +0 -22
  220. package/dist/lib/types.d.mts.map +0 -1
  221. package/dist/lib/types.mjs +0 -7
  222. package/dist/lib/types.mjs.map +0 -1
  223. package/dist/server/middleware.d.mts +0 -11
  224. package/dist/server/middleware.d.mts.map +0 -1
  225. package/dist/server/middleware.mjs +0 -85
  226. package/dist/server/middleware.mjs.map +0 -1
  227. package/dist/server/proxy.d.mts +0 -6
  228. package/dist/server/proxy.d.mts.map +0 -1
  229. package/dist/server/proxy.mjs +0 -30
  230. package/dist/server/proxy.mjs.map +0 -1
  231. package/dist/server/route-handler.d.mts +0 -9
  232. package/dist/server/route-handler.d.mts.map +0 -1
  233. package/dist/server/route-handler.mjs +0 -172
  234. package/dist/server/route-handler.mjs.map +0 -1
  235. package/dist/server/services/config.service.d.mts +0 -21
  236. package/dist/server/services/config.service.d.mts.map +0 -1
  237. package/dist/server/services/config.service.mjs +0 -43
  238. package/dist/server/services/config.service.mjs.map +0 -1
  239. package/dist/server/services/error-tracking.service.d.mts +0 -19
  240. package/dist/server/services/error-tracking.service.d.mts.map +0 -1
  241. package/dist/server/services/error-tracking.service.mjs +0 -31
  242. package/dist/server/services/error-tracking.service.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"middleware.d.mts","names":[],"sources":["../../src/server/middleware.ts"],"sourcesContent":[],"mappings":";;;iBAiBgB,uBAAA,uBACQ,gBAAgB,QAAQ,gBAAgB,yBAIvC,gBAAW,QAAA;iBA0CpB,qBAAA,gBACC,gBAAgB,QAAQ,kBAIpB,gBAAW,QAAA;AApDhB,iBA8FA,4BA9FuB,CAAA,UAAA,CAAA,GAAA,IAAA,EAAA,OAAA,EAAA,EAAA,GA+FH,OA/FG,CAAA,OAAA,CAAA,CAAA,CAAA,SAAA,EAgG1B,CAhG0B,EAAA,aAAA,CAAA,EAAA,MAAA,CAAA,EAgGE,CAhGF;AACf,iBA8IR,2BAAA,CAAA,CA9IQ,EAAA,CAAA,KAAA,EAiJD,KAjJC,EAAA,SAAA,EAAA;EAAwB,MAAA,CAAA,EAAA,MAAA;CAAR,EAAA,GAiJoB,OAjJpB,CAAA,IAAA,CAAA"}
@@ -1,85 +0,0 @@
1
- import { ConfigServiceLive } from "./services/config.service.mjs";
2
- import { ErrorTrackingService, ErrorTrackingServiceLive } from "./services/error-tracking.service.mjs";
3
- import { withInterfereLogger } from "@interfere/effect-utils/observability";
4
- import { Data, Effect, Layer } from "effect";
5
- import { withSpan } from "@interfere/react/effect/layers/tracer.layer";
6
-
7
- //#region src/server/middleware.ts
8
- var MiddlewareError = class extends Data.TaggedError("MiddlewareError") {};
9
- function withInterfereMiddleware(middleware) {
10
- const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);
11
- return async (request) => {
12
- if (request.nextUrl.pathname.startsWith("/api/interfere")) return middleware(request);
13
- const startTime = Date.now();
14
- const program = Effect.gen(function* () {
15
- const errorTracking = yield* ErrorTrackingService;
16
- return yield* withSpan("middleware.request", Effect.tryPromise({
17
- try: () => Promise.resolve(middleware(request)),
18
- catch: (cause) => new MiddlewareError({ cause })
19
- }), { attributes: { path: request.nextUrl.pathname } }).pipe(Effect.tapError((error) => errorTracking.captureError(error.cause instanceof Error ? error.cause : new Error(String(error.cause)), request, {
20
- pathname: request.nextUrl.pathname,
21
- middleware: true,
22
- duration: Date.now() - startTime
23
- })));
24
- }).pipe(Effect.provide(layer));
25
- return await Effect.runPromise(withInterfereLogger("next", program));
26
- };
27
- }
28
- function withInterfereApiRoute(handler) {
29
- const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);
30
- return async (req) => {
31
- if (req.nextUrl.pathname.startsWith("/api/interfere")) return handler(req);
32
- const startTime = Date.now();
33
- const program = Effect.gen(function* () {
34
- const errorTracking = yield* ErrorTrackingService;
35
- return yield* withSpan("api.request", Effect.tryPromise({
36
- try: () => handler(req),
37
- catch: (cause) => new MiddlewareError({ cause })
38
- }), { attributes: { path: req.nextUrl.pathname } }).pipe(Effect.tapError((error) => errorTracking.captureError(error.cause instanceof Error ? error.cause : new Error(String(error.cause)), req, {
39
- pathname: req.nextUrl.pathname,
40
- type: "api_route",
41
- duration: Date.now() - startTime
42
- })));
43
- }).pipe(Effect.provide(layer));
44
- return await Effect.runPromise(withInterfereLogger("next", program));
45
- };
46
- }
47
- function withInterfereServerComponent(component, componentName) {
48
- const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);
49
- async function wrapped(...args) {
50
- const self = this;
51
- const program = Effect.gen(function* () {
52
- const errorTracking = yield* ErrorTrackingService;
53
- return yield* Effect.tryPromise({
54
- try: () => component.apply(self, args),
55
- catch: (cause) => new MiddlewareError({ cause })
56
- }).pipe(Effect.tapError((error) => errorTracking.captureError(error.cause instanceof Error ? error.cause : new Error(String(error.cause)), void 0, {
57
- type: "server_component",
58
- componentName: componentName || component.name
59
- })));
60
- }).pipe(Effect.provide(layer));
61
- return await Effect.runPromise(withInterfereLogger("next", program));
62
- }
63
- try {
64
- Object.defineProperty(wrapped, "name", {
65
- value: component.name,
66
- configurable: true
67
- });
68
- } catch {}
69
- return wrapped;
70
- }
71
- function createInterfereErrorHandler() {
72
- const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);
73
- return async (error, errorInfo) => {
74
- const program = Effect.gen(function* () {
75
- yield* (yield* ErrorTrackingService).captureError(error, void 0, {
76
- digest: errorInfo.digest,
77
- type: "app_directory_error"
78
- });
79
- }).pipe(Effect.provide(layer), Effect.catchAll(() => Effect.void));
80
- await Effect.runPromise(withInterfereLogger("next", program));
81
- };
82
- }
83
-
84
- //#endregion
85
- export { createInterfereErrorHandler, withInterfereApiRoute, withInterfereMiddleware, withInterfereServerComponent };
@@ -1 +0,0 @@
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 { Data, Effect, Layer } from \"effect\";\nimport type { NextRequest, NextResponse } from \"next/server\";\n\nclass MiddlewareError extends Data.TaggedError(\"MiddlewareError\")<{\n cause: unknown;\n}> {}\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: (cause) => new MiddlewareError({ cause }),\n }),\n { attributes: { path: request.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(\n error.cause instanceof Error\n ? error.cause\n : new Error(String(error.cause)),\n request,\n {\n pathname: request.nextUrl.pathname,\n middleware: true,\n duration: Date.now() - startTime,\n }\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: (cause) => new MiddlewareError({ cause }),\n }),\n { attributes: { path: req.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(\n error.cause instanceof Error\n ? error.cause\n : new Error(String(error.cause)),\n req,\n {\n pathname: req.nextUrl.pathname,\n type: \"api_route\",\n duration: Date.now() - startTime,\n }\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: (cause) => new MiddlewareError({ cause }),\n }).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(\n error.cause instanceof Error\n ? error.cause\n : new Error(String(error.cause)),\n undefined,\n {\n type: \"server_component\",\n componentName: componentName || component.name,\n }\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":"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"}
@@ -1,6 +0,0 @@
1
- import { NextFetchEvent, NextRequest } from "next/server";
2
-
3
- //#region src/server/proxy.d.ts
4
- declare function withInterfereProxy(handler: (req: NextRequest, event: NextFetchEvent) => Promise<Response> | Response): (req: NextRequest, event: NextFetchEvent) => Promise<Response>;
5
- //#endregion
6
- export { withInterfereProxy };
@@ -1 +0,0 @@
1
- {"version":3,"file":"proxy.d.mts","names":[],"sources":["../../src/server/proxy.ts"],"sourcesContent":[],"mappings":";;;iBAiBgB,kBAAA,gBAEP,oBACE,mBACJ,QAAQ,YAAY,iBAIN,oBAAoB,mBAAc,QAAA"}
@@ -1,30 +0,0 @@
1
- import { ConfigServiceLive } from "./services/config.service.mjs";
2
- import { ErrorTrackingService, ErrorTrackingServiceLive } from "./services/error-tracking.service.mjs";
3
- import { withInterfereLogger } from "@interfere/effect-utils/observability";
4
- import { Data, Effect, Layer } from "effect";
5
- import { withSpan } from "@interfere/react/effect/layers/tracer.layer";
6
-
7
- //#region src/server/proxy.ts
8
- var ProxyError = class extends Data.TaggedError("ProxyError") {};
9
- function withInterfereProxy(handler) {
10
- const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);
11
- return async (req, event) => {
12
- if (req.nextUrl.pathname.startsWith("/api/interfere")) return handler(req, event);
13
- const started = Date.now();
14
- const program = Effect.gen(function* () {
15
- const errorTracking = yield* ErrorTrackingService;
16
- return yield* withSpan("proxy.request", Effect.tryPromise({
17
- try: () => Promise.resolve(handler(req, event)),
18
- catch: (cause) => new ProxyError({ cause })
19
- }), { attributes: { path: req.nextUrl.pathname } }).pipe(Effect.tapError((error) => errorTracking.captureError(error.cause instanceof Error ? error.cause : new Error(String(error.cause)), req, {
20
- pathname: req.nextUrl.pathname,
21
- proxy: true,
22
- duration: Date.now() - started
23
- })));
24
- }).pipe(Effect.provide(layer));
25
- return await Effect.runPromise(withInterfereLogger("next", program));
26
- };
27
- }
28
-
29
- //#endregion
30
- export { withInterfereProxy };
@@ -1 +0,0 @@
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 { Data, Effect, Layer } from \"effect\";\nimport type { NextFetchEvent, NextRequest } from \"next/server\";\n\nclass ProxyError extends Data.TaggedError(\"ProxyError\")<{\n cause: unknown;\n}> {}\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: (cause) => new ProxyError({ cause }),\n }),\n { attributes: { path: req.nextUrl.pathname } }\n ).pipe(\n Effect.tapError((error) =>\n errorTracking.captureError(\n error.cause instanceof Error\n ? error.cause\n : new Error(String(error.cause)),\n req,\n {\n pathname: req.nextUrl.pathname,\n proxy: true,\n duration: Date.now() - started,\n }\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":";;;;;;;AAMA,IAAM,aAAN,cAAyB,KAAK,YAAY,aAAa,CAEpD;AASH,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;AAyB7B,UAvBiB,OAAO,SACtB,iBACA,OAAO,WAAW;IAChB,WAAW,QAAQ,QAAQ,QAAQ,KAAK,MAAM,CAAC;IAC/C,QAAQ,UAAU,IAAI,WAAW,EAAE,OAAO,CAAC;IAC5C,CAAC,EACF,EAAE,YAAY,EAAE,MAAM,IAAI,QAAQ,UAAU,EAAE,CAC/C,CAAC,KACA,OAAO,UAAU,UACf,cAAc,aACZ,MAAM,iBAAiB,QACnB,MAAM,QACN,IAAI,MAAM,OAAO,MAAM,MAAM,CAAC,EAClC,KACA;IACE,UAAU,IAAI,QAAQ;IACtB,OAAO;IACP,UAAU,KAAK,KAAK,GAAG;IACxB,CACF,CACF,CACF;IAGD,CAAC,KAAK,OAAO,QAAQ,MAAM,CAAC;AAE9B,SAAO,MAAM,OAAO,WAAW,oBAAoB,QAAQ,QAAQ,CAAC"}
@@ -1,9 +0,0 @@
1
- import { NextRequest } from "next/server";
2
-
3
- //#region src/server/route-handler.d.ts
4
- type RouteHandler = (request: NextRequest) => Promise<Response>;
5
- declare const GET: RouteHandler;
6
- declare const POST: RouteHandler;
7
- declare const OPTIONS: RouteHandler;
8
- //#endregion
9
- export { GET, OPTIONS, POST };
@@ -1 +0,0 @@
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,cAsQjB,OAtQiB,EAsQR,YAtQQ"}
@@ -1,172 +0,0 @@
1
- "use server";
2
-
3
- import { ConfigService, ConfigServiceLive } from "./services/config.service.mjs";
4
- import { ErrorTrackingService, ErrorTrackingServiceLive } from "./services/error-tracking.service.mjs";
5
- import { API_PATHS } from "@interfere/constants/api";
6
- import { withInterfereLogger } from "@interfere/effect-utils/observability";
7
- import { Data, Effect, Layer, Schedule } from "effect";
8
- import { withSpan } from "@interfere/react/effect/layers/tracer.layer";
9
- import { createBackoffSchedule, shouldRetryHttp, withTimeoutFail } from "@interfere/effect-utils/retry";
10
- import { envelopeSchema } from "@interfere/types/sdk/envelope";
11
- import { v7 } from "uuid";
12
- import { z } from "zod";
13
-
14
- //#region src/server/route-handler.ts
15
- /** biome-ignore-all lint/suspicious/useAwait: route handlers must be async */
16
- const layer = Layer.mergeAll(ConfigServiceLive, ErrorTrackingServiceLive);
17
- var ProxyError = class extends Data.TaggedError("ProxyError") {};
18
- const TIMEOUT_MS = 1e4;
19
- const RETRY_COUNT = 2;
20
- const HTTP_BAD_GATEWAY = 502;
21
- const RETRY_INITIAL_MS = 100;
22
- const RETRY_MAX_MS = 2e3;
23
- const envelopesArraySchema = z.array(envelopeSchema);
24
- const GET = async () => {
25
- const program = Effect.gen(function* () {
26
- const configured = yield* (yield* ConfigService).getSecretKey.pipe(Effect.map(() => true), Effect.catchAll(() => Effect.succeed(false)));
27
- return Response.json({
28
- status: "ok",
29
- configured,
30
- timestamp: Date.now()
31
- });
32
- }).pipe(Effect.provide(layer));
33
- return await Effect.runPromise(withInterfereLogger("next", program));
34
- };
35
- const proxyIngestRequest = (request, params) => Effect.gen(function* () {
36
- const traceparent = (request.headers.get("traceparent") || void 0) ?? generateTraceparent();
37
- const body = yield* Effect.tryPromise({
38
- try: () => request.clone().text(),
39
- catch: () => new ProxyError({
40
- status: 400,
41
- message: "Invalid request body"
42
- })
43
- });
44
- let parsed;
45
- try {
46
- parsed = JSON.parse(body);
47
- } catch (error) {
48
- yield* Effect.logWarning("Invalid JSON in request body").pipe(Effect.annotateLogs({ error: String(error) }));
49
- return yield* Effect.fail(new ProxyError({
50
- status: 400,
51
- message: "Invalid JSON in request body",
52
- body: String(error)
53
- }));
54
- }
55
- const validation = envelopesArraySchema.safeParse(parsed);
56
- if (!validation.success) {
57
- const issues = validation.error.issues.map((issue) => ({
58
- path: issue.path.join("."),
59
- message: issue.message,
60
- code: issue.code
61
- }));
62
- yield* Effect.logWarning("Invalid envelope schema").pipe(Effect.annotateLogs({ validationErrors: issues }));
63
- const b = JSON.stringify({
64
- ok: false,
65
- code: "INVALID_ENVELOPE_SCHEMA",
66
- errors: issues
67
- });
68
- return new Response(b, {
69
- status: 422,
70
- headers: { "content-type": "application/json" }
71
- });
72
- }
73
- const seen = /* @__PURE__ */ new Set();
74
- const deduped = validation.data.filter((env) => {
75
- if (seen.has(env.uuid)) return false;
76
- seen.add(env.uuid);
77
- return true;
78
- });
79
- const dropped = validation.data.length - deduped.length;
80
- yield* Effect.logDebug("Envelope validation successful").pipe(Effect.annotateLogs({
81
- envelopeCount: validation.data.length,
82
- dedupedCount: deduped.length,
83
- droppedDuplicates: dropped
84
- }));
85
- const upstream = yield* withTimeoutFail(Effect.tryPromise({
86
- try: () => fetch(`${params.apiUrl}${API_PATHS.INGEST_V0}`, {
87
- method: "POST",
88
- headers: {
89
- "Content-Type": "application/json",
90
- "x-interfere-surface": params.surfaceToken,
91
- traceparent
92
- },
93
- body: JSON.stringify(deduped)
94
- }),
95
- catch: (error) => new ProxyError({
96
- status: 0,
97
- message: error instanceof Error ? error.message : String(error)
98
- })
99
- }), TIMEOUT_MS, () => new ProxyError({
100
- status: 0,
101
- message: "Network timeout"
102
- }));
103
- const responseBody = yield* Effect.tryPromise({
104
- try: () => upstream.text(),
105
- catch: () => ""
106
- });
107
- return new Response(responseBody, {
108
- status: upstream.status,
109
- headers: { "content-type": upstream.headers.get("content-type") || "application/json" }
110
- });
111
- });
112
- const POST = async (request) => {
113
- const program = Effect.gen(function* () {
114
- yield* Effect.logDebug("Handling ingest proxy request").pipe(Effect.annotateLogs({ path: request.nextUrl.pathname }));
115
- const config = yield* ConfigService;
116
- const errorTracking = yield* ErrorTrackingService;
117
- yield* config.getSecretKey.pipe(Effect.tapError(() => Effect.logError("Service not configured - missing INTERFERE_SECRET_KEY")), Effect.catchTag("ConfigError", () => Effect.fail(new ProxyError({
118
- status: 503,
119
- message: "Service not configured. INTERFERE_SECRET_KEY environment variable is required."
120
- }))));
121
- const surfaceToken = yield* config.getPublicToken.pipe(Effect.tapError((error) => Effect.logError("Failed to get public token").pipe(Effect.annotateLogs({ reason: error.message }))), Effect.catchTag("ConfigError", (error) => Effect.fail(new ProxyError({
122
- status: 503,
123
- message: `Auth not available: ${error.message}`
124
- }))));
125
- const apiUrl = yield* config.getApiUrl;
126
- const schedule = createBackoffSchedule(RETRY_INITIAL_MS, RETRY_MAX_MS, RETRY_COUNT).pipe(Schedule.whileInput((e) => e instanceof ProxyError ? shouldRetryHttp(e.status) : false));
127
- const response = yield* withSpan("proxy.forward", proxyIngestRequest(request, {
128
- apiUrl,
129
- surfaceToken
130
- }), { attributes: {} }).pipe(Effect.retry(schedule), Effect.tapError((error) => Effect.gen(function* () {
131
- yield* errorTracking.captureError(error, request, {
132
- pathname: request.nextUrl.pathname,
133
- type: "api_route"
134
- });
135
- yield* Effect.logError("Proxy request failed").pipe(Effect.annotateLogs({
136
- error: String(error),
137
- status: error instanceof ProxyError ? error.status : 0
138
- }));
139
- })));
140
- yield* Effect.logDebug("Proxy request completed").pipe(Effect.annotateLogs({ status: response.status }));
141
- return response;
142
- }).pipe(Effect.provide(layer), Effect.catchTag("ProxyError", (error) => Effect.succeed(Response.json({ error: error.message }, { status: error.status || HTTP_BAD_GATEWAY }))), Effect.catchAll((error) => {
143
- Effect.runFork(Effect.logError("Unexpected error in route handler").pipe(Effect.annotateLogs({ error: String(error) })));
144
- return Effect.succeed(Response.json({ error: "Internal server error" }, { status: 500 }));
145
- }));
146
- return await Effect.runPromise(withInterfereLogger("next", program));
147
- };
148
- const OPTIONS = async () => Effect.runPromise(withInterfereLogger("next", Effect.succeed(new Response(null, {
149
- status: 200,
150
- headers: {
151
- "Access-Control-Allow-Origin": "*",
152
- "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
153
- "Access-Control-Allow-Headers": "Content-Type",
154
- "Access-Control-Max-Age": "86400"
155
- }
156
- }))));
157
- const VERSION = "00";
158
- const TRACE_ID_BYTES = 16;
159
- const SPAN_ID_BYTES = 8;
160
- const FLAGS = "01";
161
- function generateTraceparent() {
162
- return `${VERSION}-${randomHex(TRACE_ID_BYTES)}-${randomHex(SPAN_ID_BYTES)}-${FLAGS}`;
163
- }
164
- function randomHex(bytes) {
165
- const raw = v7().replace(/-/g, "");
166
- const needed = bytes * 2;
167
- if (raw.length >= needed) return raw.substring(0, needed);
168
- return (raw + raw).substring(0, needed);
169
- }
170
-
171
- //#endregion
172
- export { GET, OPTIONS, POST };
@@ -1 +0,0 @@
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((error) =>\n Effect.logError(\"Failed to get public token\").pipe(\n Effect.annotateLogs({ reason: error.message })\n )\n ),\n Effect.catchTag(\"ConfigError\", (error) =>\n Effect.fail(\n new ProxyError({\n status: 503,\n message: `Auth not available: ${error.message}`,\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,21 +0,0 @@
1
- import { NonEmptyString } from "../../lib/types.mjs";
2
- import { Context, Effect, Layer } from "effect";
3
- import * as effect_Types15 from "effect/Types";
4
- import * as effect_Cause15 from "effect/Cause";
5
-
6
- //#region src/server/services/config.service.d.ts
7
- declare const ConfigError_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 & {
8
- readonly _tag: "ConfigError";
9
- } & Readonly<A>;
10
- declare class ConfigError extends ConfigError_base<{
11
- readonly message: string;
12
- }> {}
13
- interface ConfigService {
14
- readonly getApiUrl: Effect.Effect<string>;
15
- readonly getSecretKey: Effect.Effect<NonEmptyString, ConfigError>;
16
- readonly getPublicToken: Effect.Effect<string, ConfigError>;
17
- }
18
- declare const ConfigService: Context.Tag<ConfigService, ConfigService>;
19
- declare const ConfigServiceLive: Layer.Layer<ConfigService, never, never>;
20
- //#endregion
21
- export { ConfigError, ConfigService, ConfigServiceLive };
@@ -1 +0,0 @@
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;cA0Db,mBAAiB,KAAA,CAAA,MAAA"}
@@ -1,43 +0,0 @@
1
- import { normalizeSecretKey, resolveApiUrl } from "../../build/env-config.mjs";
2
- import { Context, Data, Effect, Layer } from "effect";
3
- import { getPublicToken } from "@interfere/react/server/auth";
4
-
5
- //#region src/server/services/config.service.ts
6
- const ONE_HOUR_MS = 36e5;
7
- var ConfigError = class extends Data.TaggedError("ConfigError") {};
8
- const ConfigService = Context.GenericTag("@interfere/next/ConfigService");
9
- let cachedPublicToken = null;
10
- const getSecretKey = () => Effect.gen(function* () {
11
- const normalized = normalizeSecretKey(process.env.INTERFERE_SECRET_KEY);
12
- if (!normalized) return yield* Effect.fail(new ConfigError({ message: "INTERFERE_SECRET_KEY not set or empty" }));
13
- return normalized;
14
- });
15
- const getPublicTokenImpl = () => Effect.gen(function* () {
16
- const override = process.env.INTERFERE_PUBLIC_TOKEN;
17
- if (override) return override;
18
- const secret = yield* getSecretKey();
19
- const apiUrl = resolveApiUrl();
20
- const now = Date.now();
21
- if (cachedPublicToken && cachedPublicToken.expiresAt > now) return cachedPublicToken.token;
22
- const token = yield* Effect.tryPromise({
23
- try: () => getPublicToken({
24
- apiUrl,
25
- secret
26
- }),
27
- catch: (error) => new ConfigError({ message: `Failed to exchange secret for public token at ${apiUrl}/auth/exchange: ${error instanceof Error ? error.message : String(error)}` })
28
- });
29
- if (!token) return yield* Effect.fail(new ConfigError({ message: `Token exchange at ${apiUrl}/auth/exchange returned empty response - check if the API URL is correct and the secret key is valid` }));
30
- cachedPublicToken = {
31
- token,
32
- expiresAt: now + ONE_HOUR_MS
33
- };
34
- return token;
35
- });
36
- const ConfigServiceLive = Layer.succeed(ConfigService, ConfigService.of({
37
- getApiUrl: Effect.succeed(resolveApiUrl()),
38
- getSecretKey: getSecretKey(),
39
- getPublicToken: getPublicTokenImpl()
40
- }));
41
-
42
- //#endregion
43
- export { ConfigError, ConfigService, ConfigServiceLive };
@@ -1 +0,0 @@
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({\n message: `Failed to exchange secret for public token at ${apiUrl}/auth/exchange: ${error instanceof Error ? error.message : String(error)}`,\n }),\n });\n\n if (!token) {\n return yield* Effect.fail(\n new ConfigError({\n message: `Token exchange at ${apiUrl}/auth/exchange returned empty response - check if the API URL is correct and the secret key is valid`,\n })\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,EACd,SAAS,iDAAiD,OAAO,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,IAC1I,CAAC;EACL,CAAC;AAEF,KAAI,CAAC,MACH,QAAO,OAAO,OAAO,KACnB,IAAI,YAAY,EACd,SAAS,qBAAqB,OAAO,uGACtC,CAAC,CACH;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,19 +0,0 @@
1
- import { ConfigService } from "./config.service.mjs";
2
- import { Context, Effect, Layer } from "effect";
3
- import * as effect_Types16 from "effect/Types";
4
- import * as effect_Cause16 from "effect/Cause";
5
-
6
- //#region src/server/services/error-tracking.service.d.ts
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
- readonly _tag: "ErrorTrackingError";
9
- } & Readonly<A>;
10
- declare class ErrorTrackingError extends ErrorTrackingError_base<{
11
- readonly message: string;
12
- }> {}
13
- interface ErrorTrackingService {
14
- readonly captureError: (error: unknown, request?: Request, context?: Record<string, unknown>) => Effect.Effect<void, never, ConfigService>;
15
- }
16
- declare const ErrorTrackingService: Context.Tag<ErrorTrackingService, ErrorTrackingService>;
17
- declare const ErrorTrackingServiceLive: Layer.Layer<ErrorTrackingService, never, never>;
18
- //#endregion
19
- export { ErrorTrackingError, ErrorTrackingService, ErrorTrackingServiceLive };
@@ -1 +0,0 @@
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,31 +0,0 @@
1
- import { ConfigService } from "./config.service.mjs";
2
- import { API_PATHS } from "@interfere/constants/api";
3
- import { Context, Data, Effect, Layer } from "effect";
4
- import { getRuntime } from "@interfere/react/core/runtime/config";
5
- import { buildServerErrorEnvelope, sendEnvelopesToIngest } from "@interfere/react/server/capture";
6
-
7
- //#region src/server/services/error-tracking.service.ts
8
- var ErrorTrackingError = class extends Data.TaggedError("ErrorTrackingError") {};
9
- const ErrorTrackingService = Context.GenericTag("@interfere/next/ErrorTrackingService");
10
- const ErrorTrackingServiceLive = Layer.succeed(ErrorTrackingService, ErrorTrackingService.of({ captureError: (error, request, context) => Effect.gen(function* () {
11
- const config = yield* ConfigService;
12
- const token = yield* config.getPublicToken.pipe(Effect.catchAll(() => Effect.succeed(null)));
13
- if (!token) return;
14
- const apiUrl = yield* config.getApiUrl;
15
- const envelope = buildServerErrorEnvelope({
16
- buildId: process.env.NEXT_PUBLIC_INTERFERE_BUILD_ID ?? null,
17
- releaseId: process.env.NEXT_PUBLIC_INTERFERE_RELEASE_ID ?? null,
18
- environment: process.env.NODE_ENV || null,
19
- runtime: getRuntime(),
20
- error,
21
- request,
22
- context: { ...context }
23
- });
24
- yield* Effect.tryPromise({
25
- try: () => sendEnvelopesToIngest([envelope], `${apiUrl}${API_PATHS.INGEST_V0}`, token),
26
- catch: () => new ErrorTrackingError({ message: "Failed to send error to ingest" })
27
- }).pipe(Effect.catchAll(() => Effect.void));
28
- }) }));
29
-
30
- //#endregion
31
- export { ErrorTrackingError, ErrorTrackingService, ErrorTrackingServiceLive };
@@ -1 +0,0 @@
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"}