@interfere/next 0.0.7-32ca917f3c6af1d90d7b0a54eb0b5dfa3b9d2305 → 0.0.9

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 (41) hide show
  1. package/dist/core/client.d.ts +22 -0
  2. package/dist/core/client.d.ts.map +1 -0
  3. package/dist/core/client.js +115 -0
  4. package/dist/core/client.js.map +1 -0
  5. package/dist/core/client.test.d.ts +2 -0
  6. package/dist/core/client.test.d.ts.map +1 -0
  7. package/dist/core/client.test.js +227 -0
  8. package/dist/core/client.test.js.map +1 -0
  9. package/dist/core/encoders.d.ts +3 -0
  10. package/dist/core/encoders.d.ts.map +1 -0
  11. package/dist/core/encoders.js +5 -0
  12. package/dist/core/encoders.js.map +1 -0
  13. package/dist/core/encoders.test.d.ts +2 -0
  14. package/dist/core/encoders.test.d.ts.map +1 -0
  15. package/dist/core/encoders.test.js +55 -0
  16. package/dist/core/encoders.test.js.map +1 -0
  17. package/dist/edge/edge.d.ts +11 -0
  18. package/dist/edge/edge.d.ts.map +1 -0
  19. package/dist/edge/edge.js +41 -0
  20. package/dist/edge/edge.js.map +1 -0
  21. package/dist/edge/edge.test.d.ts +2 -0
  22. package/dist/edge/edge.test.d.ts.map +1 -0
  23. package/dist/edge/edge.test.js +109 -0
  24. package/dist/edge/edge.test.js.map +1 -0
  25. package/dist/index.d.ts +6 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +6 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/react/provider.d.ts +15 -0
  30. package/dist/react/provider.d.ts.map +1 -0
  31. package/dist/react/provider.jsx +21 -0
  32. package/dist/react/provider.jsx.map +1 -0
  33. package/dist/server/server.d.ts +6 -0
  34. package/dist/server/server.d.ts.map +1 -0
  35. package/dist/server/server.js +35 -0
  36. package/dist/server/server.js.map +1 -0
  37. package/dist/server/server.test.d.ts +2 -0
  38. package/dist/server/server.test.d.ts.map +1 -0
  39. package/dist/server/server.test.js +88 -0
  40. package/dist/server/server.test.js.map +1 -0
  41. package/package.json +8 -11
@@ -0,0 +1,22 @@
1
+ import type { Config, EventType } from '@interfere/types';
2
+ declare class InterfereClient {
3
+ private config;
4
+ private queue;
5
+ private seq;
6
+ private sessionId;
7
+ private runtime;
8
+ private flushTimer?;
9
+ constructor(config: Partial<Config>);
10
+ private detectRuntime;
11
+ private generateSessionId;
12
+ private startFlushTimer;
13
+ capture(type: EventType, payload: unknown): void;
14
+ flush(): void;
15
+ getSessionId(): string;
16
+ }
17
+ export declare const init: (config: Partial<Config>) => InterfereClient;
18
+ export declare const capture: (type: EventType, payload: unknown) => void;
19
+ export declare const flush: () => void;
20
+ export declare const getSessionId: () => string;
21
+ export {};
22
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAY,SAAS,EAAW,MAAM,kBAAkB,CAAC;AAG7E,cAAM,eAAe;IACnB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAkB;IAC/B,OAAO,CAAC,GAAG,CAAK;IAChB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAAU;IACzB,OAAO,CAAC,UAAU,CAAC,CAAiB;gBAExB,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC;IAyBnC,OAAO,CAAC,aAAa;IAUrB,OAAO,CAAC,iBAAiB;IAIzB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAoBhD,KAAK,IAAI,IAAI;IA8Bb,YAAY,IAAI,MAAM;CAGvB;AAID,eAAO,MAAM,IAAI,GAAI,QAAQ,OAAO,CAAC,MAAM,CAAC,KAAG,eAM9C,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,MAAM,SAAS,EAAE,SAAS,OAAO,KAAG,IAK3D,CAAC;AAEF,eAAO,MAAM,KAAK,QAAO,IAExB,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,MAK/B,CAAC"}
@@ -0,0 +1,115 @@
1
+ import { encode } from './encoders.js';
2
+ class InterfereClient {
3
+ config;
4
+ queue = [];
5
+ seq = 0;
6
+ sessionId;
7
+ runtime;
8
+ flushTimer;
9
+ constructor(config) {
10
+ if (!config.projectId) {
11
+ throw new Error('[interfere] projectId required');
12
+ }
13
+ this.runtime = this.detectRuntime();
14
+ this.sessionId = config.sessionId || this.generateSessionId();
15
+ this.config = {
16
+ projectId: config.projectId,
17
+ endpoint: config.endpoint || 'https://ingest.interfere.com/v0',
18
+ env: config.env || 'development',
19
+ flushInterval: config.flushInterval || 5000,
20
+ debug: config.debug,
21
+ runtime: this.runtime,
22
+ sessionId: this.sessionId,
23
+ };
24
+ if (this.runtime === 'client') {
25
+ this.startFlushTimer();
26
+ if (typeof window !== 'undefined') {
27
+ window.addEventListener('beforeunload', () => this.flush());
28
+ }
29
+ }
30
+ }
31
+ detectRuntime() {
32
+ if (typeof window !== 'undefined') {
33
+ return 'client';
34
+ }
35
+ if (typeof globalThis !== 'undefined' && 'EdgeRuntime' in globalThis) {
36
+ return 'edge';
37
+ }
38
+ return 'server';
39
+ }
40
+ generateSessionId() {
41
+ return crypto.randomUUID();
42
+ }
43
+ startFlushTimer() {
44
+ this.flushTimer = setInterval(() => this.flush(), this.config.flushInterval);
45
+ }
46
+ capture(type, payload) {
47
+ const envelope = {
48
+ v: '0',
49
+ runtime: this.runtime,
50
+ project: this.config.projectId,
51
+ env: this.config.env,
52
+ client_ts: Date.now(),
53
+ session_id: this.sessionId,
54
+ seq: ++this.seq,
55
+ type,
56
+ payload: encode(payload),
57
+ };
58
+ this.queue.push(envelope);
59
+ if (this.runtime !== 'client' || this.queue.length >= 10) {
60
+ this.flush();
61
+ }
62
+ }
63
+ flush() {
64
+ if (this.queue.length === 0) {
65
+ return;
66
+ }
67
+ const batch = [...this.queue];
68
+ this.queue = [];
69
+ const body = JSON.stringify(batch);
70
+ if (this.runtime === 'client' &&
71
+ typeof window !== 'undefined' &&
72
+ typeof window.navigator?.sendBeacon === 'function') {
73
+ window.navigator.sendBeacon(this.config.endpoint, body);
74
+ }
75
+ else {
76
+ fetch(this.config.endpoint, {
77
+ method: 'POST',
78
+ headers: { 'Content-Type': 'application/json' },
79
+ body,
80
+ }).catch((_err) => {
81
+ if (this.config.debug) {
82
+ // In production, this would be sent to a logging service
83
+ // For now, we'll silently fail in non-debug mode
84
+ }
85
+ });
86
+ }
87
+ }
88
+ getSessionId() {
89
+ return this.sessionId;
90
+ }
91
+ }
92
+ let instance = null;
93
+ export const init = (config) => {
94
+ if (!config.projectId) {
95
+ throw new Error('[interfere] projectId required');
96
+ }
97
+ instance = new InterfereClient(config);
98
+ return instance;
99
+ };
100
+ export const capture = (type, payload) => {
101
+ if (!instance) {
102
+ throw new Error('[interfere] not initialized');
103
+ }
104
+ instance.capture(type, payload);
105
+ };
106
+ export const flush = () => {
107
+ instance?.flush();
108
+ };
109
+ export const getSessionId = () => {
110
+ if (!instance) {
111
+ throw new Error('[interfere] not initialized');
112
+ }
113
+ return instance.getSessionId();
114
+ };
115
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/core/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=client.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.d.ts","sourceRoot":"","sources":["../../src/core/client.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
+ import { capture, flush, getSessionId, init } from './client.js';
3
+ // Top level regex for UUID validation
4
+ const UUID_REGEX = /^[0-9a-f-]{36}$/;
5
+ describe('client', () => {
6
+ beforeEach(() => {
7
+ vi.resetModules();
8
+ vi.clearAllMocks();
9
+ vi.clearAllTimers();
10
+ vi.useFakeTimers();
11
+ });
12
+ afterEach(() => {
13
+ vi.useRealTimers();
14
+ });
15
+ describe('init', () => {
16
+ it('throws without projectId', () => {
17
+ expect(() => init({})).toThrow('[interfere] projectId required');
18
+ });
19
+ it('initializes with required config', () => {
20
+ const client = init({ projectId: 'if_p_test' });
21
+ expect(client).toBeDefined();
22
+ });
23
+ it('uses default endpoint', () => {
24
+ const fetchSpy = vi
25
+ .spyOn(global, 'fetch')
26
+ .mockResolvedValue(new Response());
27
+ init({ projectId: 'if_p_test' });
28
+ capture('error', { test: true });
29
+ flush();
30
+ expect(fetchSpy).toHaveBeenCalledWith('https://ingest.interfere.com/v0', expect.any(Object));
31
+ });
32
+ it('uses custom endpoint', () => {
33
+ const fetchSpy = vi
34
+ .spyOn(global, 'fetch')
35
+ .mockResolvedValue(new Response());
36
+ init({ projectId: 'if_p_test', endpoint: 'https://custom.example.com' });
37
+ capture('error', { test: true });
38
+ flush();
39
+ expect(fetchSpy).toHaveBeenCalledWith('https://custom.example.com', expect.any(Object));
40
+ });
41
+ });
42
+ describe('capture', () => {
43
+ it('throws if not initialized', async () => {
44
+ vi.resetModules();
45
+ const { capture: freshCapture } = await import('./client.js');
46
+ expect(() => freshCapture('error', {})).toThrow('[interfere] not initialized');
47
+ });
48
+ it('queues events', () => {
49
+ const fetchSpy = vi
50
+ .spyOn(global, 'fetch')
51
+ .mockResolvedValue(new Response());
52
+ init({ projectId: 'if_p_test' });
53
+ capture('ui_event', { action: 'click' });
54
+ capture('error', { message: 'test error' });
55
+ // In server mode, each capture auto-flushes
56
+ // So we expect 2 fetch calls
57
+ expect(fetchSpy).toHaveBeenCalledTimes(2);
58
+ const call1 = fetchSpy.mock.calls[0];
59
+ const call2 = fetchSpy.mock.calls[1];
60
+ if (!(call1?.[1] && call2?.[1])) {
61
+ throw new Error('Expected 2 fetch calls');
62
+ }
63
+ const body1 = JSON.parse(call1[1].body);
64
+ const body2 = JSON.parse(call2[1].body);
65
+ expect(body1).toHaveLength(1);
66
+ expect(body1[0].type).toBe('ui_event');
67
+ expect(body2).toHaveLength(1);
68
+ expect(body2[0].type).toBe('error');
69
+ });
70
+ it('auto-flushes after 10 events', () => {
71
+ const fetchSpy = vi
72
+ .spyOn(global, 'fetch')
73
+ .mockResolvedValue(new Response());
74
+ init({ projectId: 'if_p_test' });
75
+ // In server mode, each capture triggers a flush
76
+ for (let i = 0; i < 10; i++) {
77
+ capture('ui_event', { index: i });
78
+ }
79
+ // Each capture causes a flush in server mode
80
+ expect(fetchSpy).toHaveBeenCalledTimes(10);
81
+ });
82
+ it('includes correct envelope structure', () => {
83
+ const fetchSpy = vi
84
+ .spyOn(global, 'fetch')
85
+ .mockResolvedValue(new Response());
86
+ init({ projectId: 'if_p_test', env: 'production' });
87
+ capture('network', { url: '/api/test' });
88
+ flush();
89
+ const call = fetchSpy.mock.calls[0];
90
+ if (!call?.[1]) {
91
+ throw new Error('Expected fetch call');
92
+ }
93
+ const body = JSON.parse(call[1].body);
94
+ const envelope = body[0];
95
+ expect(envelope.v).toBe('0');
96
+ expect(envelope.runtime).toBe('server'); // Default in test environment
97
+ expect(envelope.project).toBe('if_p_test');
98
+ expect(envelope.env).toBe('production');
99
+ expect(envelope.client_ts).toBeGreaterThan(0);
100
+ expect(envelope.session_id).toMatch(UUID_REGEX);
101
+ expect(envelope.seq).toBe(1);
102
+ expect(envelope.type).toBe('network');
103
+ expect(envelope.payload).toBeDefined();
104
+ });
105
+ });
106
+ describe('flush', () => {
107
+ it('does nothing with empty queue', () => {
108
+ const fetchSpy = vi
109
+ .spyOn(global, 'fetch')
110
+ .mockResolvedValue(new Response());
111
+ init({ projectId: 'if_p_test' });
112
+ flush();
113
+ expect(fetchSpy).not.toHaveBeenCalled();
114
+ });
115
+ it('clears queue after flush', () => {
116
+ const fetchSpy = vi
117
+ .spyOn(global, 'fetch')
118
+ .mockResolvedValue(new Response());
119
+ init({ projectId: 'if_p_test' });
120
+ capture('error', { test: true });
121
+ flush();
122
+ expect(fetchSpy).toHaveBeenCalledTimes(1);
123
+ flush(); // Second flush should do nothing
124
+ expect(fetchSpy).toHaveBeenCalledTimes(1);
125
+ });
126
+ it('handles fetch errors in debug mode', async () => {
127
+ const fetchSpy = vi
128
+ .spyOn(global, 'fetch')
129
+ .mockRejectedValue(new Error('Network error'));
130
+ init({ projectId: 'if_p_test', debug: true });
131
+ capture('error', { test: true });
132
+ // Should not throw
133
+ expect(() => flush()).not.toThrow();
134
+ await vi.waitFor(() => {
135
+ expect(fetchSpy).toHaveBeenCalled();
136
+ });
137
+ });
138
+ });
139
+ describe('getSessionId', () => {
140
+ it('throws if not initialized', async () => {
141
+ vi.resetModules();
142
+ const { getSessionId: freshGetSessionId } = await import('./client.js');
143
+ expect(() => freshGetSessionId()).toThrow('[interfere] not initialized');
144
+ });
145
+ it('returns consistent session ID', () => {
146
+ init({ projectId: 'if_p_test' });
147
+ const id1 = getSessionId();
148
+ const id2 = getSessionId();
149
+ expect(id1).toBe(id2);
150
+ expect(id1).toMatch(UUID_REGEX);
151
+ });
152
+ it('uses provided session ID', () => {
153
+ const customId = 'custom-session-id';
154
+ init({ projectId: 'if_p_test', sessionId: customId });
155
+ expect(getSessionId()).toBe(customId);
156
+ });
157
+ });
158
+ describe('runtime detection', () => {
159
+ it('detects server runtime by default', () => {
160
+ const fetchSpy = vi
161
+ .spyOn(global, 'fetch')
162
+ .mockResolvedValue(new Response());
163
+ init({ projectId: 'if_p_test' });
164
+ capture('server_req', {});
165
+ flush();
166
+ const call = fetchSpy.mock.calls[0];
167
+ if (!call?.[1]) {
168
+ throw new Error('Expected fetch call');
169
+ }
170
+ const body = JSON.parse(call[1].body);
171
+ expect(body[0].runtime).toBe('server');
172
+ });
173
+ it('detects client runtime with window', async () => {
174
+ const originalWindow = global.window;
175
+ global.window = {
176
+ addEventListener: vi.fn(),
177
+ };
178
+ vi.resetModules();
179
+ const { init: freshInit, capture: freshCapture, flush: freshFlush, } = await import('./client.js');
180
+ const fetchSpy = vi
181
+ .spyOn(global, 'fetch')
182
+ .mockResolvedValue(new Response());
183
+ freshInit({ projectId: 'if_p_test' });
184
+ freshCapture('ui_event', {});
185
+ // Client mode doesn't auto-flush
186
+ expect(fetchSpy).not.toHaveBeenCalled();
187
+ freshFlush();
188
+ const call = fetchSpy.mock.calls[0];
189
+ if (!call?.[1]) {
190
+ throw new Error('Expected fetch call');
191
+ }
192
+ const body = JSON.parse(call[1].body);
193
+ expect(body[0].runtime).toBe('client');
194
+ global.window = originalWindow;
195
+ });
196
+ });
197
+ describe('client mode features', () => {
198
+ it('uses sendBeacon when available', async () => {
199
+ const originalWindow = global.window;
200
+ const sendBeaconSpy = vi.fn().mockReturnValue(true);
201
+ // Create a proper mock window with sendBeacon on it
202
+ global.window = {
203
+ addEventListener: vi.fn(),
204
+ navigator: {
205
+ sendBeacon: sendBeaconSpy,
206
+ },
207
+ };
208
+ vi.resetModules();
209
+ const { init: freshInit, capture: freshCapture, flush: freshFlush, } = await import('./client.js');
210
+ freshInit({ projectId: 'if_p_test' });
211
+ freshCapture('ui_event', {});
212
+ freshFlush();
213
+ expect(sendBeaconSpy).toHaveBeenCalledWith('https://ingest.interfere.com/v0', expect.any(String));
214
+ global.window = originalWindow;
215
+ });
216
+ it('sets up auto-flush timer in client mode', async () => {
217
+ const originalWindow = global.window;
218
+ global.window = { addEventListener: vi.fn() };
219
+ vi.resetModules();
220
+ const { init: freshInit } = await import('./client.js');
221
+ freshInit({ projectId: 'if_p_test', flushInterval: 1000 });
222
+ expect(global.window.addEventListener).toHaveBeenCalledWith('beforeunload', expect.any(Function));
223
+ global.window = originalWindow;
224
+ });
225
+ });
226
+ });
227
+ //# sourceMappingURL=client.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.test.js","sourceRoot":"","sources":["../../src/core/client.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AACzE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAEjE,sCAAsC;AACtC,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAErC,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE;IACtB,UAAU,CAAC,GAAG,EAAE;QACd,EAAE,CAAC,YAAY,EAAE,CAAC;QAClB,EAAE,CAAC,aAAa,EAAE,CAAC;QACnB,EAAE,CAAC,cAAc,EAAE,CAAC;QACpB,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,GAAG,EAAE;QACb,EAAE,CAAC,aAAa,EAAE,CAAC;IACrB,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE;QACpB,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;QACnE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;YAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YAChD,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,KAAK,EAAE,CAAC;YAER,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CACnC,iCAAiC,EACjC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;YAC9B,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,EAAE,4BAA4B,EAAE,CAAC,CAAC;YACzE,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,KAAK,EAAE,CAAC;YAER,MAAM,CAAC,QAAQ,CAAC,CAAC,oBAAoB,CACnC,4BAA4B,EAC5B,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE;QACvB,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,EAAE,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAC9D,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAC7C,6BAA6B,CAC9B,CAAC;QACJ,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,eAAe,EAAE,GAAG,EAAE;YACvB,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;YACzC,OAAO,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;YAE5C,4CAA4C;YAC5C,6BAA6B;YAC7B,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAE1C,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACrC,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACrC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBAChC,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;YAC5C,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAE,KAAK,CAAC,CAAC,CAAiB,CAAC,IAAc,CAAC,CAAC;YACnE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAE,KAAK,CAAC,CAAC,CAAiB,CAAC,IAAc,CAAC,CAAC;YAEnE,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAEvC,MAAM,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YAEjC,gDAAgD;YAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC5B,OAAO,CAAC,UAAU,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;YACpC,CAAC;YAED,6CAA6C;YAC7C,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC7C,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;YACpD,OAAO,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;YACzC,KAAK,EAAE,CAAC;YAER,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACzC,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,CAAC,CAAiB,CAAC,IAAc,CAAC,CAAC;YACjE,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;YAEzB,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC7B,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,8BAA8B;YACvE,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;YAC3C,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACxC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;YAChD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC7B,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,OAAO,EAAE,GAAG,EAAE;QACrB,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACjC,KAAK,EAAE,CAAC;YAER,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACjC,KAAK,EAAE,CAAC;YAER,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;YAE1C,KAAK,EAAE,CAAC,CAAC,iCAAiC;YAC1C,MAAM,CAAC,QAAQ,CAAC,CAAC,qBAAqB,CAAC,CAAC,CAAC,CAAC;QAC5C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC,CAAC;YAEjD,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YAEjC,mBAAmB;YACnB,MAAM,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;YAEpC,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBACpB,MAAM,CAAC,QAAQ,CAAC,CAAC,gBAAgB,EAAE,CAAC;YACtC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,EAAE,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YACxE,MAAM,CAAC,GAAG,EAAE,CAAC,iBAAiB,EAAE,CAAC,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;YACvC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACjC,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;YAC3B,MAAM,GAAG,GAAG,YAAY,EAAE,CAAC;YAE3B,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACtB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;YAClC,MAAM,QAAQ,GAAG,mBAAmB,CAAC;YACrC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;YAEtD,MAAM,CAAC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;YAC3C,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,IAAI,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACjC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;YAC1B,KAAK,EAAE,CAAC;YAER,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACzC,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,CAAC,CAAiB,CAAC,IAAc,CAAC,CAAC;YACjE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAClD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;YACrC,MAAM,CAAC,MAAM,GAAG;gBACd,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE;aACe,CAAC;YAE3C,EAAE,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,EACJ,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,UAAU,GAClB,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAEhC,MAAM,QAAQ,GAAG,EAAE;iBAChB,KAAK,CAAC,MAAM,EAAE,OAAO,CAAC;iBACtB,iBAAiB,CAAC,IAAI,QAAQ,EAAE,CAAC,CAAC;YAErC,SAAS,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACtC,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YAE7B,iCAAiC;YACjC,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC;YAExC,UAAU,EAAE,CAAC;YAEb,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YACpC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACf,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACzC,CAAC;YACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,CAAC,CAAiB,CAAC,IAAc,CAAC,CAAC;YACjE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAEvC,MAAM,CAAC,MAAM,GAAG,cAAc,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;QACpC,EAAE,CAAC,gCAAgC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;YACrC,MAAM,aAAa,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;YAEpD,oDAAoD;YACpD,MAAM,CAAC,MAAM,GAAG;gBACd,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE;gBACzB,SAAS,EAAE;oBACT,UAAU,EAAE,aAAa;iBAC1B;aACuC,CAAC;YAE3C,EAAE,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,EACJ,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,UAAU,GAClB,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAEhC,SAAS,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC,CAAC;YACtC,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;YAC7B,UAAU,EAAE,CAAC;YAEb,MAAM,CAAC,aAAa,CAAC,CAAC,oBAAoB,CACxC,iCAAiC,EACjC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CACnB,CAAC;YAEF,MAAM,CAAC,MAAM,GAAG,cAAc,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACvD,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;YACrC,MAAM,CAAC,MAAM,GAAG,EAAE,gBAAgB,EAAE,EAAE,CAAC,EAAE,EAAE,EACxB,CAAC;YAEpB,EAAE,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;YAExD,SAAS,CAAC,EAAE,SAAS,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;YAE3D,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,oBAAoB,CACzD,cAAc,EACd,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CACrB,CAAC;YAEF,MAAM,CAAC,MAAM,GAAG,cAAc,CAAC;QACjC,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const encode: (data: unknown) => Uint8Array;
2
+ export declare const decode: (data: Uint8Array) => unknown;
3
+ //# sourceMappingURL=encoders.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoders.d.ts","sourceRoot":"","sources":["../../src/core/encoders.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,MAAM,GAAI,MAAM,OAAO,KAAG,UACD,CAAC;AACvC,eAAO,MAAM,MAAM,GAAI,MAAM,UAAU,KAAG,OACR,CAAC"}
@@ -0,0 +1,5 @@
1
+ const encoder = new TextEncoder();
2
+ const decoder = new TextDecoder();
3
+ export const encode = (data) => encoder.encode(JSON.stringify(data));
4
+ export const decode = (data) => JSON.parse(decoder.decode(data));
5
+ //# sourceMappingURL=encoders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoders.js","sourceRoot":"","sources":["../../src/core/encoders.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAClC,MAAM,OAAO,GAAG,IAAI,WAAW,EAAE,CAAC;AAElC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAa,EAAc,EAAE,CAClD,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,IAAgB,EAAW,EAAE,CAClD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=encoders.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoders.test.d.ts","sourceRoot":"","sources":["../../src/core/encoders.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,55 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { decode, encode } from './encoders.js';
3
+ describe('encoders', () => {
4
+ describe('encode', () => {
5
+ it('encodes strings to Uint8Array', () => {
6
+ const result = encode('hello');
7
+ expect(result).toBeInstanceOf(Uint8Array);
8
+ expect(new TextDecoder().decode(result)).toBe('"hello"');
9
+ });
10
+ it('encodes objects to Uint8Array', () => {
11
+ const obj = { foo: 'bar', num: 123 };
12
+ const result = encode(obj);
13
+ expect(result).toBeInstanceOf(Uint8Array);
14
+ expect(new TextDecoder().decode(result)).toBe('{"foo":"bar","num":123}');
15
+ });
16
+ it('encodes arrays to Uint8Array', () => {
17
+ const arr = [1, 2, 3];
18
+ const result = encode(arr);
19
+ expect(result).toBeInstanceOf(Uint8Array);
20
+ expect(new TextDecoder().decode(result)).toBe('[1,2,3]');
21
+ });
22
+ it('encodes null', () => {
23
+ expect(new TextDecoder().decode(encode(null))).toBe('null');
24
+ });
25
+ it('handles undefined by encoding as null', () => {
26
+ // JSON.stringify(undefined) returns undefined, which becomes empty string
27
+ // This is expected behavior for JSON
28
+ const result = encode(undefined);
29
+ expect(result).toBeInstanceOf(Uint8Array);
30
+ });
31
+ });
32
+ describe('decode', () => {
33
+ it('decodes Uint8Array back to original values', () => {
34
+ const testCases = [
35
+ 'hello',
36
+ { foo: 'bar', num: 123 },
37
+ [1, 2, 3],
38
+ null,
39
+ true,
40
+ false,
41
+ 42,
42
+ ];
43
+ for (const original of testCases) {
44
+ const encoded = encode(original);
45
+ const decoded = decode(encoded);
46
+ expect(decoded).toEqual(original);
47
+ }
48
+ });
49
+ it('throws on invalid JSON', () => {
50
+ const invalidJson = new TextEncoder().encode('not valid json');
51
+ expect(() => decode(invalidJson)).toThrow();
52
+ });
53
+ });
54
+ });
55
+ //# sourceMappingURL=encoders.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"encoders.test.js","sourceRoot":"","sources":["../../src/core/encoders.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Config } from '@interfere/types';
2
+ import type { NextRequest } from 'next/server';
3
+ import { NextResponse } from 'next/server';
4
+ type EdgeHandler = (req: NextRequest) => Promise<NextResponse | Response>;
5
+ export declare function withInterfereEdge(handler: EdgeHandler, edgeConfig?: Partial<Config>): EdgeHandler;
6
+ export declare function interfereMiddleware(req: NextRequest): Promise<NextResponse>;
7
+ export declare const config: {
8
+ matcher: string[];
9
+ };
10
+ export {};
11
+ //# sourceMappingURL=edge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge.d.ts","sourceRoot":"","sources":["../../src/edge/edge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,KAAK,WAAW,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,GAAG,QAAQ,CAAC,CAAC;AAE1E,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAC3B,WAAW,CAmCb;AAED,wBAAsB,mBAAmB,CACvC,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,CAGvB;AAED,eAAO,MAAM,MAAM;;CAElB,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { capture, init } from '../core/client.js';
3
+ export function withInterfereEdge(handler, edgeConfig) {
4
+ return async (req) => {
5
+ const start = Date.now();
6
+ const sessionId = req.headers.get('x-interfere-session') || undefined;
7
+ if (edgeConfig || sessionId) {
8
+ init({ ...edgeConfig, sessionId });
9
+ }
10
+ try {
11
+ const response = await handler(req);
12
+ const latency = Date.now() - start;
13
+ capture('edge_req', {
14
+ method: req.method,
15
+ url: req.url,
16
+ latency,
17
+ status: response.status,
18
+ });
19
+ return response;
20
+ }
21
+ catch (error) {
22
+ const latency = Date.now() - start;
23
+ capture('edge_error', {
24
+ method: req.method,
25
+ url: req.url,
26
+ latency,
27
+ error: error instanceof Error ? error.message : String(error),
28
+ stack: error instanceof Error ? error.stack : undefined,
29
+ });
30
+ throw error;
31
+ }
32
+ };
33
+ }
34
+ export async function interfereMiddleware(req) {
35
+ const wrapped = withInterfereEdge(async () => NextResponse.next());
36
+ return (await wrapped(req));
37
+ }
38
+ export const config = {
39
+ matcher: ['/(?!_next/static|_next/image|favicon.ico).*'],
40
+ };
41
+ //# sourceMappingURL=edge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge.js","sourceRoot":"","sources":["../../src/edge/edge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAIlD,MAAM,UAAU,iBAAiB,CAC/B,OAAoB,EACpB,UAA4B;IAE5B,OAAO,KAAK,EAAE,GAAgB,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,SAAS,CAAC;QAEtE,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;YAC5B,IAAI,CAAC,EAAE,GAAG,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAEnC,OAAO,CAAC,UAAU,EAAE;gBAClB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO;gBACP,MAAM,EAAE,QAAQ,CAAC,MAAM;aACxB,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAEnC,OAAO,CAAC,YAAY,EAAE;gBACpB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO;gBACP,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC7D,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aACxD,CAAC,CAAC;YAEH,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,GAAgB;IAEhB,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,IAAI,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IACnE,OAAO,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,CAAiB,CAAC;AAC9C,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,OAAO,EAAE,CAAC,6CAA6C,CAAC;CACzD,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=edge.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge.test.d.ts","sourceRoot":"","sources":["../../src/edge/edge.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,109 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { capture, init } from '../core/client.js';
4
+ import { config, interfereMiddleware, withInterfereEdge } from './edge.js';
5
+ vi.mock('../core/client.js', () => ({
6
+ init: vi.fn(),
7
+ capture: vi.fn(),
8
+ }));
9
+ // Top level regex for static asset matching
10
+ const STATIC_ASSET_REGEX = /^\/(?!_next\/static|_next\/image|favicon\.ico).*/;
11
+ describe('withInterfereEdge', () => {
12
+ beforeEach(() => {
13
+ vi.clearAllMocks();
14
+ });
15
+ it('wraps handler and captures successful requests', async () => {
16
+ const mockResponse = NextResponse.json({ success: true });
17
+ const handler = vi.fn().mockResolvedValue(mockResponse);
18
+ const wrapped = withInterfereEdge(handler);
19
+ const req = new NextRequest('http://localhost/api/edge', {
20
+ method: 'POST',
21
+ });
22
+ const response = await wrapped(req);
23
+ expect(handler).toHaveBeenCalledWith(req);
24
+ expect(response).toBe(mockResponse);
25
+ expect(capture).toHaveBeenCalledWith('edge_req', {
26
+ method: 'POST',
27
+ url: 'http://localhost/api/edge',
28
+ latency: expect.any(Number),
29
+ status: 200,
30
+ });
31
+ });
32
+ it('captures errors and rethrows them', async () => {
33
+ const testError = new Error('Edge error');
34
+ const handler = vi.fn().mockRejectedValue(testError);
35
+ const wrapped = withInterfereEdge(handler);
36
+ const req = new NextRequest('http://localhost/api/edge');
37
+ await expect(wrapped(req)).rejects.toThrow('Edge error');
38
+ expect(capture).toHaveBeenCalledWith('edge_error', {
39
+ method: 'GET',
40
+ url: 'http://localhost/api/edge',
41
+ latency: expect.any(Number),
42
+ error: 'Edge error',
43
+ stack: expect.stringContaining('Error: Edge error'),
44
+ });
45
+ });
46
+ it('uses session ID from headers', async () => {
47
+ const handler = vi.fn().mockResolvedValue(NextResponse.json({}));
48
+ const wrapped = withInterfereEdge(handler);
49
+ const req = new NextRequest('http://localhost/api/edge', {
50
+ headers: {
51
+ 'x-interfere-session': 'edge-session-456',
52
+ },
53
+ });
54
+ await wrapped(req);
55
+ expect(init).toHaveBeenCalledWith({
56
+ sessionId: 'edge-session-456',
57
+ });
58
+ });
59
+ it('initializes with edge config if provided', async () => {
60
+ const edgeConfig = { projectId: 'if_p_edge', env: 'production' };
61
+ const handler = vi.fn().mockResolvedValue(NextResponse.json({}));
62
+ const wrapped = withInterfereEdge(handler, edgeConfig);
63
+ await wrapped(new NextRequest('http://localhost/api/edge'));
64
+ expect(init).toHaveBeenCalledWith(edgeConfig);
65
+ });
66
+ });
67
+ describe('interfereMiddleware', () => {
68
+ beforeEach(() => {
69
+ vi.clearAllMocks();
70
+ });
71
+ it('returns NextResponse.next() for requests', async () => {
72
+ const req = new NextRequest('http://localhost/some-page');
73
+ const response = await interfereMiddleware(req);
74
+ expect(response).toBeInstanceOf(NextResponse);
75
+ expect(response.headers.get('x-middleware-next')).toBe('1');
76
+ });
77
+ it('captures edge requests', async () => {
78
+ const req = new NextRequest('http://localhost/some-page');
79
+ await interfereMiddleware(req);
80
+ expect(capture).toHaveBeenCalledWith('edge_req', {
81
+ method: 'GET',
82
+ url: 'http://localhost/some-page',
83
+ latency: expect.any(Number),
84
+ status: 200,
85
+ });
86
+ });
87
+ });
88
+ describe('config export', () => {
89
+ it('has correct matcher pattern', () => {
90
+ expect(config).toEqual({
91
+ matcher: ['/(?!_next/static|_next/image|favicon.ico).*'],
92
+ });
93
+ });
94
+ it('excludes static assets', () => {
95
+ const matcher = config.matcher?.[0];
96
+ if (!matcher) {
97
+ throw new Error('Matcher not found');
98
+ }
99
+ // Should match regular routes
100
+ expect('/api/users'.match(STATIC_ASSET_REGEX)).toBeTruthy();
101
+ expect('/dashboard'.match(STATIC_ASSET_REGEX)).toBeTruthy();
102
+ expect('/'.match(STATIC_ASSET_REGEX)).toBeTruthy();
103
+ // Should not match static assets
104
+ expect('/_next/static/chunk.js'.match(STATIC_ASSET_REGEX)).toBeFalsy();
105
+ expect('/_next/image'.match(STATIC_ASSET_REGEX)).toBeFalsy();
106
+ expect('/favicon.ico'.match(STATIC_ASSET_REGEX)).toBeFalsy();
107
+ });
108
+ });
109
+ //# sourceMappingURL=edge.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edge.test.js","sourceRoot":"","sources":["../../src/edge/edge.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export { capture, flush, getSessionId, init } from './core/client.js';
2
+ export { decode, encode } from './core/encoders.js';
3
+ export { config, interfereMiddleware, withInterfereEdge, } from './edge/edge.js';
4
+ export { InterfereProvider, useInterfere } from './react/provider.js';
5
+ export { withInterfereApi } from './server/server.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,MAAM,EACN,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { capture, flush, getSessionId, init } from './core/client.js';
2
+ export { decode, encode } from './core/encoders.js';
3
+ export { config, interfereMiddleware, withInterfereEdge, } from './edge/edge.js';
4
+ export { InterfereProvider, useInterfere } from './react/provider.js';
5
+ export { withInterfereApi } from './server/server.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,MAAM,EACN,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { Config } from '@interfere/types';
2
+ import { type ReactNode } from 'react';
3
+ import { capture, flush, getSessionId } from '../core/client.js';
4
+ interface InterfereProviderProps {
5
+ cfg: Partial<Config>;
6
+ children: ReactNode;
7
+ }
8
+ export declare function InterfereProvider({ cfg, children }: InterfereProviderProps): import("react").JSX.Element;
9
+ export declare function useInterfere(): {
10
+ capture: typeof capture;
11
+ flush: typeof flush;
12
+ getSessionId: typeof getSessionId;
13
+ };
14
+ export {};
15
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAiB,KAAK,SAAS,EAAyB,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAQ,MAAM,mBAAmB,CAAC;AAQvE,UAAU,sBAAsB;IAC9B,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,iBAAiB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,sBAAsB,+BAW1E;AAED,wBAAgB,YAAY;aAvBjB,OAAO,OAAO;WAChB,OAAO,KAAK;kBACL,OAAO,YAAY;EA2BlC"}
@@ -0,0 +1,21 @@
1
+ 'use client';
2
+ import { createContext, useContext, useEffect } from 'react';
3
+ import { capture, flush, getSessionId, init } from '../core/client.js';
4
+ const InterfereContext = createContext(null);
5
+ export function InterfereProvider({ cfg, children }) {
6
+ useEffect(() => {
7
+ init(cfg);
8
+ return () => flush();
9
+ }, [cfg]);
10
+ return (<InterfereContext.Provider value={{ capture, flush, getSessionId }}>
11
+ {children}
12
+ </InterfereContext.Provider>);
13
+ }
14
+ export function useInterfere() {
15
+ const context = useContext(InterfereContext);
16
+ if (!context) {
17
+ throw new Error('useInterfere() must be used within InterfereProvider');
18
+ }
19
+ return context;
20
+ }
21
+ //# sourceMappingURL=provider.jsx.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.jsx","sourceRoot":"","sources":["../../src/react/provider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAGb,OAAO,EAAE,aAAa,EAAkB,UAAU,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAEvE,MAAM,gBAAgB,GAAG,aAAa,CAI5B,IAAI,CAAC,CAAC;AAOhB,MAAM,UAAU,iBAAiB,CAAC,EAAE,GAAG,EAAE,QAAQ,EAA0B;IACzE,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACV,OAAO,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAEV,OAAO,CACL,CAAC,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CACjE;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAC7B,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAC7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { Config } from '@interfere/types';
2
+ import type { NextRequest, NextResponse } from 'next/server';
3
+ type Handler = (req: NextRequest) => Promise<NextResponse | Response>;
4
+ export declare function withInterfereApi(handler: Handler, config?: Partial<Config>): Handler;
5
+ export {};
6
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG7D,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,GAAG,QAAQ,CAAC,CAAC;AAEtE,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,OAAO,EAChB,MAAM,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GACvB,OAAO,CAoCT"}
@@ -0,0 +1,35 @@
1
+ import { headers } from 'next/headers';
2
+ import { capture, init } from '../core/client.js';
3
+ export function withInterfereApi(handler, config) {
4
+ return async (req) => {
5
+ const start = Date.now();
6
+ const headersList = await headers();
7
+ const sessionId = headersList.get('x-interfere-session') || undefined;
8
+ if (config || sessionId) {
9
+ init({ ...config, sessionId });
10
+ }
11
+ try {
12
+ const response = await handler(req);
13
+ const latency = Date.now() - start;
14
+ capture('server_req', {
15
+ method: req.method,
16
+ url: req.url,
17
+ latency,
18
+ status: response.status,
19
+ });
20
+ return response;
21
+ }
22
+ catch (error) {
23
+ const latency = Date.now() - start;
24
+ capture('server_error', {
25
+ method: req.method,
26
+ url: req.url,
27
+ latency,
28
+ error: error instanceof Error ? error.message : String(error),
29
+ stack: error instanceof Error ? error.stack : undefined,
30
+ });
31
+ throw error;
32
+ }
33
+ };
34
+ }
35
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AAIlD,MAAM,UAAU,gBAAgB,CAC9B,OAAgB,EAChB,MAAwB;IAExB,OAAO,KAAK,EAAE,GAAgB,EAAE,EAAE;QAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,MAAM,OAAO,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,SAAS,CAAC;QAEtE,IAAI,MAAM,IAAI,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,EAAE,GAAG,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;QACjC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;YACpC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAEnC,OAAO,CAAC,YAAY,EAAE;gBACpB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO;gBACP,MAAM,EAAE,QAAQ,CAAC,MAAM;aACxB,CAAC,CAAC;YAEH,OAAO,QAAQ,CAAC;QAClB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;YAEnC,OAAO,CAAC,cAAc,EAAE;gBACtB,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,GAAG,EAAE,GAAG,CAAC,GAAG;gBACZ,OAAO;gBACP,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;gBAC7D,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;aACxD,CAAC,CAAC;YAEH,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.test.d.ts","sourceRoot":"","sources":["../../src/server/server.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,88 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { capture, init } from '../core/client.js';
4
+ import { withInterfereApi } from './server.js';
5
+ vi.mock('../core/client.js', () => ({
6
+ init: vi.fn(),
7
+ capture: vi.fn(),
8
+ }));
9
+ vi.mock('next/headers', () => ({
10
+ headers: vi.fn().mockResolvedValue({
11
+ get: vi.fn(() => null),
12
+ }),
13
+ }));
14
+ describe('withInterfereApi', () => {
15
+ beforeEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+ it('wraps handler and captures successful requests', async () => {
19
+ const mockResponse = new NextResponse('Success', { status: 200 });
20
+ const handler = vi.fn().mockResolvedValue(mockResponse);
21
+ const wrapped = withInterfereApi(handler);
22
+ const req = new NextRequest('http://localhost/api/test', {
23
+ method: 'POST',
24
+ });
25
+ const response = await wrapped(req);
26
+ expect(handler).toHaveBeenCalledWith(req);
27
+ expect(response).toBe(mockResponse);
28
+ expect(capture).toHaveBeenCalledWith('server_req', {
29
+ method: 'POST',
30
+ url: 'http://localhost/api/test',
31
+ latency: expect.any(Number),
32
+ status: 200,
33
+ });
34
+ });
35
+ it('captures errors and rethrows them', async () => {
36
+ const testError = new Error('Test error');
37
+ const handler = vi.fn().mockRejectedValue(testError);
38
+ const wrapped = withInterfereApi(handler);
39
+ const req = new NextRequest('http://localhost/api/test');
40
+ await expect(wrapped(req)).rejects.toThrow('Test error');
41
+ expect(capture).toHaveBeenCalledWith('server_error', {
42
+ method: 'GET',
43
+ url: 'http://localhost/api/test',
44
+ latency: expect.any(Number),
45
+ error: 'Test error',
46
+ stack: expect.stringContaining('Error: Test error'),
47
+ });
48
+ });
49
+ it('uses session ID from headers', async () => {
50
+ const { headers } = await import('next/headers');
51
+ vi.mocked(headers).mockResolvedValue({
52
+ get: vi.fn((key) => key === 'x-interfere-session' ? 'session-123' : null),
53
+ });
54
+ const handler = vi.fn().mockResolvedValue(new NextResponse());
55
+ const wrapped = withInterfereApi(handler);
56
+ await wrapped(new NextRequest('http://localhost/api/test'));
57
+ expect(init).toHaveBeenCalledWith({
58
+ sessionId: 'session-123',
59
+ });
60
+ });
61
+ it('initializes with config if provided', async () => {
62
+ // Reset headers mock to return null for session ID
63
+ const { headers } = await import('next/headers');
64
+ vi.mocked(headers).mockResolvedValue({
65
+ get: vi.fn(() => null),
66
+ });
67
+ const config = { projectId: 'if_p_test', env: 'production' };
68
+ const handler = vi.fn().mockResolvedValue(new NextResponse());
69
+ const wrapped = withInterfereApi(handler, config);
70
+ await wrapped(new NextRequest('http://localhost/api/test'));
71
+ expect(init).toHaveBeenCalledWith(config);
72
+ });
73
+ it('measures latency accurately', async () => {
74
+ let capturedLatency = 0;
75
+ vi.mocked(capture).mockImplementation((_type, payload) => {
76
+ capturedLatency = payload.latency;
77
+ });
78
+ const handler = vi.fn().mockImplementation(async () => {
79
+ await new Promise((resolve) => setTimeout(resolve, 50));
80
+ return new NextResponse();
81
+ });
82
+ const wrapped = withInterfereApi(handler);
83
+ await wrapped(new NextRequest('http://localhost/api/test'));
84
+ expect(capturedLatency).toBeGreaterThanOrEqual(50);
85
+ expect(capturedLatency).toBeLessThan(100);
86
+ });
87
+ });
88
+ //# sourceMappingURL=server.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.test.js","sourceRoot":"","sources":["../../src/server/server.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@interfere/next",
3
- "version": "0.0.7-32ca917f3c6af1d90d7b0a54eb0b5dfa3b9d2305",
3
+ "version": "0.0.9",
4
4
  "license": "MIT",
5
5
  "description": "Build apps that never break.",
6
6
  "keywords": [
@@ -18,14 +18,8 @@
18
18
  "dist"
19
19
  ],
20
20
  "type": "module",
21
- "exports": {
22
- ".": "./dist/client.js",
23
- "./react": "./dist/provider.js",
24
- "./server": "./dist/server.js",
25
- "./edge": "./dist/edge.js"
26
- },
27
- "main": "./dist/client.js",
28
- "types": "./dist/client.d.ts",
21
+ "main": "./dist/index.js",
22
+ "types": "./dist/index.d.ts",
29
23
  "publishConfig": {
30
24
  "access": "public"
31
25
  },
@@ -33,14 +27,17 @@
33
27
  "@interfere/types": "0.0.3"
34
28
  },
35
29
  "peerDependencies": {
36
- "next": ">=14",
37
- "react": ">=18"
30
+ "next": ">=15",
31
+ "react": ">=19",
32
+ "react-dom": ">=19"
38
33
  },
39
34
  "devDependencies": {
40
35
  "@types/node": "22.15.29",
41
36
  "@types/react": "19.1.8",
37
+ "@types/react-dom": "19.1.6",
42
38
  "next": "^15.3.5",
43
39
  "react": "^19.1.0",
40
+ "react-dom": "^19.1.0",
44
41
  "typescript": "5.8.3",
45
42
  "vitest": "^3.2.4",
46
43
  "@interfere/typescript-config": "1.0.1"