@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.
- package/dist/generate-helpers.js +87 -1
- package/dist/generate-middleware.js +34 -1
- package/dist/generate-proxy.js +35 -3
- package/package.json +1 -1
- package/src/generate-helpers.ts +87 -1
- package/src/generate-middleware.ts +34 -1
- package/src/generate-proxy.ts +35 -3
package/dist/generate-helpers.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
}
|
package/dist/generate-proxy.js
CHANGED
|
@@ -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
|
|
79
|
-
* This
|
|
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
|
|
161
|
+
* The proxy function filters for __user_data_proxy / __browser_recording_proxy
|
|
130
162
|
*/
|
|
131
163
|
'/:path*',
|
|
132
164
|
],
|
package/package.json
CHANGED
package/src/generate-helpers.ts
CHANGED
|
@@ -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
|
|
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
|
|
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
|
}
|
package/src/generate-proxy.ts
CHANGED
|
@@ -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
|
|
49
|
-
* This
|
|
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
|
|
131
|
+
* The proxy function filters for __user_data_proxy / __browser_recording_proxy
|
|
100
132
|
*/
|
|
101
133
|
'/:path*',
|
|
102
134
|
],
|