@egdesk/next-api-plugin 1.2.3 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -50,7 +50,7 @@ function generateHelpers(projectPath) {
50
50
  const helperContent = `/**
51
51
  * EGDesk Helper Functions for Next.js
52
52
  *
53
- * Type-safe helpers for accessing EGDesk user data and FinanceHub.
53
+ * Type-safe helpers for EGDesk user data, FinanceHub, and browser recorder replay.
54
54
  * Works in both client and server components.
55
55
  *
56
56
  * Generated by @egdesk/next-api-plugin
@@ -439,6 +439,92 @@ export async function getOverallStats() {
439
439
  export async function getSyncHistory(limit: number = 50) {
440
440
  return callFinanceHubTool('financehub_get_sync_history', { limit });
441
441
  }
442
+
443
+ // ==========================================
444
+ // BROWSER RECORDING HELPERS
445
+ // ==========================================
446
+
447
+ /**
448
+ * Call EGDesk Browser Recording MCP tool (saved recorder tests, replay with optional dates).
449
+ *
450
+ * - Server: \`POST {apiUrl}/browser-recording/tools/call\`
451
+ * - Client: \`POST /__browser_recording_proxy\` (see proxy.ts / middleware)
452
+ */
453
+ export async function callBrowserRecordingTool(
454
+ toolName: string,
455
+ args: Record<string, any> = {}
456
+ ): Promise<any> {
457
+ const body = JSON.stringify({ tool: toolName, arguments: args });
458
+ const headers: Record<string, string> = {
459
+ 'Content-Type': 'application/json'
460
+ };
461
+
462
+ const isServer = typeof window === 'undefined';
463
+
464
+ let response: Response;
465
+ if (isServer) {
466
+ const apiUrl =
467
+ (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_EGDESK_API_URL) ||
468
+ EGDESK_CONFIG.apiUrl;
469
+ const apiKey =
470
+ (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_EGDESK_API_KEY) ||
471
+ EGDESK_CONFIG.apiKey;
472
+ if (apiKey) {
473
+ headers['X-Api-Key'] = apiKey;
474
+ }
475
+ response = await fetch(\`\${apiUrl}/browser-recording/tools/call\`, {
476
+ method: 'POST',
477
+ headers,
478
+ body
479
+ });
480
+ } else {
481
+ response = await fetch('/__browser_recording_proxy', {
482
+ method: 'POST',
483
+ headers,
484
+ body
485
+ });
486
+ }
487
+
488
+ if (!response.ok) {
489
+ throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
490
+ }
491
+
492
+ const result = await response.json();
493
+
494
+ if (!result.success) {
495
+ throw new Error(result.error || 'Tool call failed');
496
+ }
497
+
498
+ const content = result.result?.content?.[0]?.text;
499
+ return content ? JSON.parse(content) : null;
500
+ }
501
+
502
+ /** List saved *.spec.js files in the EGDesk browser-recorder-tests output folder */
503
+ export async function listBrowserRecordingTests() {
504
+ return callBrowserRecordingTool('browser_recording_list_saved_tests', {});
505
+ }
506
+
507
+ /** Inspect a spec for date-picker replay options */
508
+ export async function getBrowserRecordingReplayOptions(testFile: string) {
509
+ return callBrowserRecordingTool('browser_recording_get_replay_options', { testFile });
510
+ }
511
+
512
+ export type BrowserRecordingRunOptions = {
513
+ startDate?: string;
514
+ endDate?: string;
515
+ datePickersByIndex?: string[];
516
+ };
517
+
518
+ /** Replay a saved recording in Chrome */
519
+ export async function runBrowserRecording(
520
+ testFile: string,
521
+ options: BrowserRecordingRunOptions = {}
522
+ ) {
523
+ return callBrowserRecordingTool('browser_recording_run', {
524
+ testFile,
525
+ ...options
526
+ });
527
+ }
442
528
  `;
443
529
  fs.writeFileSync(helperPath, helperContent.replace(/\r?\n/g, os.EOL), 'utf-8');
444
530
  console.log(`✅ Generated ${helperPath}`);
@@ -73,7 +73,8 @@ import type { NextRequest } from 'next/server';
73
73
  /**
74
74
  * EGDesk Database Proxy Middleware
75
75
  *
76
- * Intercepts __user_data_proxy requests and forwards them to the EGDesk MCP server.
76
+ * Intercepts __user_data_proxy and __browser_recording_proxy requests and forwards them
77
+ * to the EGDesk MCP HTTP server.
77
78
  * This allows CORS-free database access in both local and tunneled environments.
78
79
  *
79
80
  * Generated by @egdesk/next-api-plugin
@@ -116,6 +117,38 @@ export async function middleware(request: NextRequest) {
116
117
  }
117
118
  }
118
119
 
120
+ if (pathname.includes('__browser_recording_proxy')) {
121
+ try {
122
+ const body = await request.text();
123
+
124
+ const apiKey = process.env.NEXT_PUBLIC_EGDESK_API_KEY;
125
+ const apiUrl = process.env.NEXT_PUBLIC_EGDESK_API_URL || 'http://localhost:8080';
126
+
127
+ const headers: HeadersInit = {
128
+ 'Content-Type': 'application/json',
129
+ };
130
+
131
+ if (apiKey) {
132
+ headers['X-Api-Key'] = apiKey;
133
+ }
134
+
135
+ const response = await fetch(\`\${apiUrl}/browser-recording/tools/call\`, {
136
+ method: 'POST',
137
+ headers,
138
+ body,
139
+ });
140
+
141
+ const result = await response.json();
142
+
143
+ return NextResponse.json(result, { status: response.status });
144
+ } catch (error: any) {
145
+ return NextResponse.json(
146
+ { error: 'Proxy error', message: error.message },
147
+ { status: 500 }
148
+ );
149
+ }
150
+ }
151
+
119
152
  // Continue to next middleware or route
120
153
  return NextResponse.next();
121
154
  }
@@ -75,8 +75,8 @@ import type { NextRequest } from 'next/server';
75
75
  /**
76
76
  * EGDesk Database Proxy (Next.js 16+)
77
77
  *
78
- * Intercepts __user_data_proxy requests and forwards them to the EGDesk MCP server.
79
- * This allows CORS-free database access in both local and tunneled environments.
78
+ * Intercepts __user_data_proxy and __browser_recording_proxy requests and forwards them
79
+ * to the EGDesk MCP HTTP server. This avoids CORS in local and tunneled environments.
80
80
  *
81
81
  * Generated by @egdesk/next-api-plugin
82
82
  */
@@ -118,6 +118,38 @@ export async function proxy(request: NextRequest) {
118
118
  }
119
119
  }
120
120
 
121
+ if (pathname.includes('__browser_recording_proxy')) {
122
+ try {
123
+ const body = await request.text();
124
+
125
+ const apiKey = process.env.NEXT_PUBLIC_EGDESK_API_KEY;
126
+ const apiUrl = process.env.NEXT_PUBLIC_EGDESK_API_URL || 'http://localhost:8080';
127
+
128
+ const headers: HeadersInit = {
129
+ 'Content-Type': 'application/json',
130
+ };
131
+
132
+ if (apiKey) {
133
+ headers['X-Api-Key'] = apiKey;
134
+ }
135
+
136
+ const response = await fetch(\`\${apiUrl}/browser-recording/tools/call\`, {
137
+ method: 'POST',
138
+ headers,
139
+ body,
140
+ });
141
+
142
+ const result = await response.json();
143
+
144
+ return NextResponse.json(result, { status: response.status });
145
+ } catch (error: any) {
146
+ return NextResponse.json(
147
+ { error: 'Proxy error', message: error.message },
148
+ { status: 500 }
149
+ );
150
+ }
151
+ }
152
+
121
153
  // Continue to next proxy or route
122
154
  return NextResponse.next();
123
155
  }
@@ -126,7 +158,7 @@ export const config = {
126
158
  matcher: [
127
159
  /*
128
160
  * Match all paths except static assets
129
- * The proxy function itself filters for __user_data_proxy
161
+ * The proxy function filters for __user_data_proxy / __browser_recording_proxy
130
162
  */
131
163
  '/:path*',
132
164
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@egdesk/next-api-plugin",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "Next.js plugin for EGDesk database proxy integration",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -17,7 +17,7 @@ export function generateHelpers(projectPath: string): void {
17
17
  const helperContent = `/**
18
18
  * EGDesk Helper Functions for Next.js
19
19
  *
20
- * Type-safe helpers for accessing EGDesk user data and FinanceHub.
20
+ * Type-safe helpers for EGDesk user data, FinanceHub, and browser recorder replay.
21
21
  * Works in both client and server components.
22
22
  *
23
23
  * Generated by @egdesk/next-api-plugin
@@ -406,6 +406,92 @@ export async function getOverallStats() {
406
406
  export async function getSyncHistory(limit: number = 50) {
407
407
  return callFinanceHubTool('financehub_get_sync_history', { limit });
408
408
  }
409
+
410
+ // ==========================================
411
+ // BROWSER RECORDING HELPERS
412
+ // ==========================================
413
+
414
+ /**
415
+ * Call EGDesk Browser Recording MCP tool (saved recorder tests, replay with optional dates).
416
+ *
417
+ * - Server: \`POST {apiUrl}/browser-recording/tools/call\`
418
+ * - Client: \`POST /__browser_recording_proxy\` (see proxy.ts / middleware)
419
+ */
420
+ export async function callBrowserRecordingTool(
421
+ toolName: string,
422
+ args: Record<string, any> = {}
423
+ ): Promise<any> {
424
+ const body = JSON.stringify({ tool: toolName, arguments: args });
425
+ const headers: Record<string, string> = {
426
+ 'Content-Type': 'application/json'
427
+ };
428
+
429
+ const isServer = typeof window === 'undefined';
430
+
431
+ let response: Response;
432
+ if (isServer) {
433
+ const apiUrl =
434
+ (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_EGDESK_API_URL) ||
435
+ EGDESK_CONFIG.apiUrl;
436
+ const apiKey =
437
+ (typeof process !== 'undefined' && process.env?.NEXT_PUBLIC_EGDESK_API_KEY) ||
438
+ EGDESK_CONFIG.apiKey;
439
+ if (apiKey) {
440
+ headers['X-Api-Key'] = apiKey;
441
+ }
442
+ response = await fetch(\`\${apiUrl}/browser-recording/tools/call\`, {
443
+ method: 'POST',
444
+ headers,
445
+ body
446
+ });
447
+ } else {
448
+ response = await fetch('/__browser_recording_proxy', {
449
+ method: 'POST',
450
+ headers,
451
+ body
452
+ });
453
+ }
454
+
455
+ if (!response.ok) {
456
+ throw new Error(\`HTTP \${response.status}: \${response.statusText}\`);
457
+ }
458
+
459
+ const result = await response.json();
460
+
461
+ if (!result.success) {
462
+ throw new Error(result.error || 'Tool call failed');
463
+ }
464
+
465
+ const content = result.result?.content?.[0]?.text;
466
+ return content ? JSON.parse(content) : null;
467
+ }
468
+
469
+ /** List saved *.spec.js files in the EGDesk browser-recorder-tests output folder */
470
+ export async function listBrowserRecordingTests() {
471
+ return callBrowserRecordingTool('browser_recording_list_saved_tests', {});
472
+ }
473
+
474
+ /** Inspect a spec for date-picker replay options */
475
+ export async function getBrowserRecordingReplayOptions(testFile: string) {
476
+ return callBrowserRecordingTool('browser_recording_get_replay_options', { testFile });
477
+ }
478
+
479
+ export type BrowserRecordingRunOptions = {
480
+ startDate?: string;
481
+ endDate?: string;
482
+ datePickersByIndex?: string[];
483
+ };
484
+
485
+ /** Replay a saved recording in Chrome */
486
+ export async function runBrowserRecording(
487
+ testFile: string,
488
+ options: BrowserRecordingRunOptions = {}
489
+ ) {
490
+ return callBrowserRecordingTool('browser_recording_run', {
491
+ testFile,
492
+ ...options
493
+ });
494
+ }
409
495
  `;
410
496
 
411
497
  fs.writeFileSync(helperPath, helperContent.replace(/\r?\n/g, os.EOL), 'utf-8');
@@ -43,7 +43,8 @@ import type { NextRequest } from 'next/server';
43
43
  /**
44
44
  * EGDesk Database Proxy Middleware
45
45
  *
46
- * Intercepts __user_data_proxy requests and forwards them to the EGDesk MCP server.
46
+ * Intercepts __user_data_proxy and __browser_recording_proxy requests and forwards them
47
+ * to the EGDesk MCP HTTP server.
47
48
  * This allows CORS-free database access in both local and tunneled environments.
48
49
  *
49
50
  * Generated by @egdesk/next-api-plugin
@@ -86,6 +87,38 @@ export async function middleware(request: NextRequest) {
86
87
  }
87
88
  }
88
89
 
90
+ if (pathname.includes('__browser_recording_proxy')) {
91
+ try {
92
+ const body = await request.text();
93
+
94
+ const apiKey = process.env.NEXT_PUBLIC_EGDESK_API_KEY;
95
+ const apiUrl = process.env.NEXT_PUBLIC_EGDESK_API_URL || 'http://localhost:8080';
96
+
97
+ const headers: HeadersInit = {
98
+ 'Content-Type': 'application/json',
99
+ };
100
+
101
+ if (apiKey) {
102
+ headers['X-Api-Key'] = apiKey;
103
+ }
104
+
105
+ const response = await fetch(\`\${apiUrl}/browser-recording/tools/call\`, {
106
+ method: 'POST',
107
+ headers,
108
+ body,
109
+ });
110
+
111
+ const result = await response.json();
112
+
113
+ return NextResponse.json(result, { status: response.status });
114
+ } catch (error: any) {
115
+ return NextResponse.json(
116
+ { error: 'Proxy error', message: error.message },
117
+ { status: 500 }
118
+ );
119
+ }
120
+ }
121
+
89
122
  // Continue to next middleware or route
90
123
  return NextResponse.next();
91
124
  }
@@ -45,8 +45,8 @@ import type { NextRequest } from 'next/server';
45
45
  /**
46
46
  * EGDesk Database Proxy (Next.js 16+)
47
47
  *
48
- * Intercepts __user_data_proxy requests and forwards them to the EGDesk MCP server.
49
- * This allows CORS-free database access in both local and tunneled environments.
48
+ * Intercepts __user_data_proxy and __browser_recording_proxy requests and forwards them
49
+ * to the EGDesk MCP HTTP server. This avoids CORS in local and tunneled environments.
50
50
  *
51
51
  * Generated by @egdesk/next-api-plugin
52
52
  */
@@ -88,6 +88,38 @@ export async function proxy(request: NextRequest) {
88
88
  }
89
89
  }
90
90
 
91
+ if (pathname.includes('__browser_recording_proxy')) {
92
+ try {
93
+ const body = await request.text();
94
+
95
+ const apiKey = process.env.NEXT_PUBLIC_EGDESK_API_KEY;
96
+ const apiUrl = process.env.NEXT_PUBLIC_EGDESK_API_URL || 'http://localhost:8080';
97
+
98
+ const headers: HeadersInit = {
99
+ 'Content-Type': 'application/json',
100
+ };
101
+
102
+ if (apiKey) {
103
+ headers['X-Api-Key'] = apiKey;
104
+ }
105
+
106
+ const response = await fetch(\`\${apiUrl}/browser-recording/tools/call\`, {
107
+ method: 'POST',
108
+ headers,
109
+ body,
110
+ });
111
+
112
+ const result = await response.json();
113
+
114
+ return NextResponse.json(result, { status: response.status });
115
+ } catch (error: any) {
116
+ return NextResponse.json(
117
+ { error: 'Proxy error', message: error.message },
118
+ { status: 500 }
119
+ );
120
+ }
121
+ }
122
+
91
123
  // Continue to next proxy or route
92
124
  return NextResponse.next();
93
125
  }
@@ -96,7 +128,7 @@ export const config = {
96
128
  matcher: [
97
129
  /*
98
130
  * Match all paths except static assets
99
- * The proxy function itself filters for __user_data_proxy
131
+ * The proxy function filters for __user_data_proxy / __browser_recording_proxy
100
132
  */
101
133
  '/:path*',
102
134
  ],