@egdesk/next-api-plugin 1.0.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/README.md +176 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +60 -0
- package/dist/generate-helpers.d.ts +9 -0
- package/dist/generate-helpers.js +172 -0
- package/dist/generate-middleware.d.ts +10 -0
- package/dist/generate-middleware.js +137 -0
- package/dist/generate-proxy.d.ts +12 -0
- package/dist/generate-proxy.js +136 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +91 -0
- package/dist/setup-userdata.d.ts +37 -0
- package/dist/setup-userdata.js +225 -0
- package/package.json +34 -0
- package/src/cli.ts +63 -0
- package/src/generate-helpers.ts +140 -0
- package/src/generate-middleware.ts +108 -0
- package/src/generate-proxy.ts +107 -0
- package/src/index.ts +109 -0
- package/src/setup-userdata.ts +238 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Generate Next.js 16+ proxy for EGDesk database proxy
|
|
4
|
+
*
|
|
5
|
+
* Creates proxy.ts that intercepts __user_data_proxy requests
|
|
6
|
+
* and forwards them to the EGDesk MCP server.
|
|
7
|
+
*
|
|
8
|
+
* This is the Next.js 16+ recommended approach (replaces middleware.ts)
|
|
9
|
+
*/
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.generateProxy = generateProxy;
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
/**
|
|
48
|
+
* Detect if project uses src/ directory structure
|
|
49
|
+
*/
|
|
50
|
+
function usesSrcDirectory(projectPath) {
|
|
51
|
+
const srcPath = path.join(projectPath, 'src');
|
|
52
|
+
const srcAppPath = path.join(projectPath, 'src', 'app');
|
|
53
|
+
return fs.existsSync(srcPath) && fs.existsSync(srcAppPath);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Generate proxy.ts file in the correct location (root or src/)
|
|
57
|
+
*/
|
|
58
|
+
function generateProxy(projectPath) {
|
|
59
|
+
// Detect if project uses src/ directory
|
|
60
|
+
const hasSrc = usesSrcDirectory(projectPath);
|
|
61
|
+
const targetDir = hasSrc ? path.join(projectPath, 'src') : projectPath;
|
|
62
|
+
const proxyPath = path.join(targetDir, 'proxy.ts');
|
|
63
|
+
console.log(`📁 Detected ${hasSrc ? 'src/' : 'root'} directory structure`);
|
|
64
|
+
console.log(`📝 Generating proxy at: ${proxyPath}`);
|
|
65
|
+
// Check if proxy.ts already exists
|
|
66
|
+
if (fs.existsSync(proxyPath)) {
|
|
67
|
+
console.log('⚠️ proxy.ts already exists - backing up to proxy.backup.ts');
|
|
68
|
+
const backupPath = path.join(targetDir, 'proxy.backup.ts');
|
|
69
|
+
fs.copyFileSync(proxyPath, backupPath);
|
|
70
|
+
}
|
|
71
|
+
const proxyContent = `import { NextResponse } from 'next/server';
|
|
72
|
+
import type { NextRequest } from 'next/server';
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* EGDesk Database Proxy (Next.js 16+)
|
|
76
|
+
*
|
|
77
|
+
* Intercepts __user_data_proxy requests and forwards them to the EGDesk MCP server.
|
|
78
|
+
* This allows CORS-free database access in both local and tunneled environments.
|
|
79
|
+
*
|
|
80
|
+
* Generated by @egdesk/next-api-plugin
|
|
81
|
+
*/
|
|
82
|
+
export async function proxy(request: NextRequest) {
|
|
83
|
+
const { pathname } = request.nextUrl;
|
|
84
|
+
|
|
85
|
+
// Intercept __user_data_proxy requests
|
|
86
|
+
if (pathname.includes('__user_data_proxy')) {
|
|
87
|
+
try {
|
|
88
|
+
const body = await request.text();
|
|
89
|
+
|
|
90
|
+
// Read API key and URL from environment
|
|
91
|
+
const apiKey = process.env.NEXT_PUBLIC_EGDESK_API_KEY;
|
|
92
|
+
const apiUrl = process.env.NEXT_PUBLIC_EGDESK_API_URL || 'http://localhost:8080';
|
|
93
|
+
|
|
94
|
+
const headers: HeadersInit = {
|
|
95
|
+
'Content-Type': 'application/json',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
if (apiKey) {
|
|
99
|
+
headers['X-Api-Key'] = apiKey;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Forward to EGDesk MCP server
|
|
103
|
+
const response = await fetch(\`\${apiUrl}/user-data/tools/call\`, {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
headers,
|
|
106
|
+
body,
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const result = await response.json();
|
|
110
|
+
|
|
111
|
+
return NextResponse.json(result, { status: response.status });
|
|
112
|
+
} catch (error: any) {
|
|
113
|
+
return NextResponse.json(
|
|
114
|
+
{ error: 'Proxy error', message: error.message },
|
|
115
|
+
{ status: 500 }
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Continue to next proxy or route
|
|
121
|
+
return NextResponse.next();
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export const config = {
|
|
125
|
+
matcher: [
|
|
126
|
+
/*
|
|
127
|
+
* Match all paths except static assets
|
|
128
|
+
* The proxy function itself filters for __user_data_proxy
|
|
129
|
+
*/
|
|
130
|
+
'/:path*',
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
`;
|
|
134
|
+
fs.writeFileSync(proxyPath, proxyContent, 'utf-8');
|
|
135
|
+
console.log(`✅ Generated ${proxyPath}`);
|
|
136
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @egdesk/next-api-plugin
|
|
3
|
+
*
|
|
4
|
+
* Next.js plugin for EGDesk database proxy integration.
|
|
5
|
+
* Provides middleware-based database access for Next.js applications.
|
|
6
|
+
*/
|
|
7
|
+
export interface SetupOptions {
|
|
8
|
+
egdeskUrl?: string;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
useProxy?: boolean;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Main setup function for Next.js projects
|
|
14
|
+
*
|
|
15
|
+
* Discovers tables and generates all necessary files:
|
|
16
|
+
* - proxy.ts or middleware.ts (proxy interceptor)
|
|
17
|
+
* - egdesk.config.ts (table definitions)
|
|
18
|
+
* - egdesk-helpers.ts (helper functions)
|
|
19
|
+
* - .env.local (environment variables)
|
|
20
|
+
*/
|
|
21
|
+
export declare function setupNextApiPlugin(projectPath: string, options?: SetupOptions): Promise<void>;
|
|
22
|
+
export type { UserDataTable, UserDataConfig } from './setup-userdata';
|
|
23
|
+
export { discoverTables } from './setup-userdata';
|
|
24
|
+
export { generateMiddleware } from './generate-middleware';
|
|
25
|
+
export { generateProxy } from './generate-proxy';
|
|
26
|
+
export { generateHelpers } from './generate-helpers';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @egdesk/next-api-plugin
|
|
4
|
+
*
|
|
5
|
+
* Next.js plugin for EGDesk database proxy integration.
|
|
6
|
+
* Provides middleware-based database access for Next.js applications.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.generateHelpers = exports.generateProxy = exports.generateMiddleware = exports.discoverTables = void 0;
|
|
10
|
+
exports.setupNextApiPlugin = setupNextApiPlugin;
|
|
11
|
+
const setup_userdata_1 = require("./setup-userdata");
|
|
12
|
+
const generate_middleware_1 = require("./generate-middleware");
|
|
13
|
+
const generate_proxy_1 = require("./generate-proxy");
|
|
14
|
+
const generate_helpers_1 = require("./generate-helpers");
|
|
15
|
+
/**
|
|
16
|
+
* Main setup function for Next.js projects
|
|
17
|
+
*
|
|
18
|
+
* Discovers tables and generates all necessary files:
|
|
19
|
+
* - proxy.ts or middleware.ts (proxy interceptor)
|
|
20
|
+
* - egdesk.config.ts (table definitions)
|
|
21
|
+
* - egdesk-helpers.ts (helper functions)
|
|
22
|
+
* - .env.local (environment variables)
|
|
23
|
+
*/
|
|
24
|
+
async function setupNextApiPlugin(projectPath, options = {}) {
|
|
25
|
+
const { egdeskUrl = 'http://localhost:8080', apiKey, useProxy = true } = options;
|
|
26
|
+
console.log('🔍 Discovering EGDesk user-data tables...');
|
|
27
|
+
try {
|
|
28
|
+
const tables = await (0, setup_userdata_1.discoverTables)(egdeskUrl, apiKey);
|
|
29
|
+
if (tables.length === 0) {
|
|
30
|
+
console.warn('⚠️ No tables found. Import data in EGDesk first.');
|
|
31
|
+
console.log('');
|
|
32
|
+
console.log('Generating files anyway with empty table list...');
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
console.log(`✅ Found ${tables.length} table(s):`);
|
|
36
|
+
tables.forEach((table, index) => {
|
|
37
|
+
console.log(` ${index + 1}. ${table.displayName} (${table.rowCount} rows)`);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const config = {
|
|
41
|
+
apiKey: apiKey || null,
|
|
42
|
+
baseUrl: egdeskUrl,
|
|
43
|
+
tables,
|
|
44
|
+
generatedAt: new Date().toISOString()
|
|
45
|
+
};
|
|
46
|
+
// Generate all configuration files
|
|
47
|
+
console.log('');
|
|
48
|
+
console.log('📝 Generating configuration files...');
|
|
49
|
+
// Use proxy.ts (Next.js 16+) or middleware.ts (legacy)
|
|
50
|
+
if (useProxy) {
|
|
51
|
+
console.log('🔄 Using proxy.ts (Next.js 16+ recommended)');
|
|
52
|
+
(0, generate_proxy_1.generateProxy)(projectPath);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
console.log('🔄 Using middleware.ts (legacy)');
|
|
56
|
+
(0, generate_middleware_1.generateMiddleware)(projectPath);
|
|
57
|
+
}
|
|
58
|
+
(0, setup_userdata_1.generateConfigFile)(projectPath, config);
|
|
59
|
+
(0, generate_helpers_1.generateHelpers)(projectPath);
|
|
60
|
+
(0, setup_userdata_1.updateEnvLocal)(projectPath, config);
|
|
61
|
+
const proxyFile = useProxy ? 'proxy.ts' : 'middleware.ts';
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log('✅ Setup complete! Files generated:');
|
|
64
|
+
console.log(` - ${proxyFile} (database proxy)`);
|
|
65
|
+
console.log(' - egdesk.config.ts (type-safe config)');
|
|
66
|
+
console.log(' - egdesk-helpers.ts (helper functions)');
|
|
67
|
+
console.log(' - .env.local (environment variables)');
|
|
68
|
+
console.log('');
|
|
69
|
+
console.log('📝 Next steps:');
|
|
70
|
+
console.log(' 1. Add .env.local to your .gitignore');
|
|
71
|
+
console.log(' 2. Restart your Next.js dev server');
|
|
72
|
+
console.log(' 3. Import and use helpers in your components:');
|
|
73
|
+
console.log(' import { queryTable } from "./egdesk-helpers"');
|
|
74
|
+
console.log(' import { TABLES } from "./egdesk.config"');
|
|
75
|
+
console.log('');
|
|
76
|
+
console.log('Example usage in a component:');
|
|
77
|
+
console.log(' const data = await queryTable(TABLES.table1.name, { limit: 10 });');
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error('❌ Setup failed:', error);
|
|
81
|
+
throw error;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
var setup_userdata_2 = require("./setup-userdata");
|
|
85
|
+
Object.defineProperty(exports, "discoverTables", { enumerable: true, get: function () { return setup_userdata_2.discoverTables; } });
|
|
86
|
+
var generate_middleware_2 = require("./generate-middleware");
|
|
87
|
+
Object.defineProperty(exports, "generateMiddleware", { enumerable: true, get: function () { return generate_middleware_2.generateMiddleware; } });
|
|
88
|
+
var generate_proxy_2 = require("./generate-proxy");
|
|
89
|
+
Object.defineProperty(exports, "generateProxy", { enumerable: true, get: function () { return generate_proxy_2.generateProxy; } });
|
|
90
|
+
var generate_helpers_2 = require("./generate-helpers");
|
|
91
|
+
Object.defineProperty(exports, "generateHelpers", { enumerable: true, get: function () { return generate_helpers_2.generateHelpers; } });
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User Data Setup Utility for Next.js
|
|
3
|
+
*
|
|
4
|
+
* Automatically discovers EGDesk user-data tables and generates configuration
|
|
5
|
+
* for Next.js projects to access them.
|
|
6
|
+
*/
|
|
7
|
+
export interface UserDataTable {
|
|
8
|
+
id: string;
|
|
9
|
+
tableName: string;
|
|
10
|
+
displayName: string;
|
|
11
|
+
description?: string;
|
|
12
|
+
rowCount: number;
|
|
13
|
+
columnCount: number;
|
|
14
|
+
columns: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface UserDataConfig {
|
|
17
|
+
apiKey: string | null;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
tables: UserDataTable[];
|
|
20
|
+
generatedAt: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Fetch available tables from EGDesk
|
|
24
|
+
*/
|
|
25
|
+
export declare function discoverTables(egdeskUrl?: string, apiKey?: string): Promise<UserDataTable[]>;
|
|
26
|
+
/**
|
|
27
|
+
* Read existing .env.local file or return empty object
|
|
28
|
+
*/
|
|
29
|
+
export declare function readEnvLocal(projectPath: string): Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Update .env.local file with Next.js environment variables
|
|
32
|
+
*/
|
|
33
|
+
export declare function updateEnvLocal(projectPath: string, config: UserDataConfig): void;
|
|
34
|
+
/**
|
|
35
|
+
* Generate TypeScript config file with table definitions
|
|
36
|
+
*/
|
|
37
|
+
export declare function generateConfigFile(projectPath: string, config: UserDataConfig): void;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* User Data Setup Utility for Next.js
|
|
4
|
+
*
|
|
5
|
+
* Automatically discovers EGDesk user-data tables and generates configuration
|
|
6
|
+
* for Next.js projects to access them.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.discoverTables = discoverTables;
|
|
43
|
+
exports.readEnvLocal = readEnvLocal;
|
|
44
|
+
exports.updateEnvLocal = updateEnvLocal;
|
|
45
|
+
exports.generateConfigFile = generateConfigFile;
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
/**
|
|
49
|
+
* Fetch available tables from EGDesk
|
|
50
|
+
*/
|
|
51
|
+
async function discoverTables(egdeskUrl = 'http://localhost:8080', apiKey) {
|
|
52
|
+
try {
|
|
53
|
+
const headers = {
|
|
54
|
+
'Content-Type': 'application/json'
|
|
55
|
+
};
|
|
56
|
+
if (apiKey) {
|
|
57
|
+
headers['X-Api-Key'] = apiKey;
|
|
58
|
+
}
|
|
59
|
+
// List all tables
|
|
60
|
+
const listResponse = await fetch(`${egdeskUrl}/user-data/tools/call`, {
|
|
61
|
+
method: 'POST',
|
|
62
|
+
headers,
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
tool: 'user_data_list_tables',
|
|
65
|
+
arguments: {}
|
|
66
|
+
})
|
|
67
|
+
});
|
|
68
|
+
if (!listResponse.ok) {
|
|
69
|
+
throw new Error(`Failed to list tables: ${listResponse.statusText}`);
|
|
70
|
+
}
|
|
71
|
+
const listResult = await listResponse.json();
|
|
72
|
+
if (!listResult.success) {
|
|
73
|
+
throw new Error(listResult.error || 'Failed to list tables');
|
|
74
|
+
}
|
|
75
|
+
// Parse MCP response
|
|
76
|
+
const content = listResult.result?.content?.[0]?.text;
|
|
77
|
+
const data = content ? JSON.parse(content) : null;
|
|
78
|
+
if (!data || !data.tables) {
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
// Fetch schema for each table to get column names
|
|
82
|
+
const tablesWithColumns = [];
|
|
83
|
+
for (const table of data.tables) {
|
|
84
|
+
try {
|
|
85
|
+
const schemaResponse = await fetch(`${egdeskUrl}/user-data/tools/call`, {
|
|
86
|
+
method: 'POST',
|
|
87
|
+
headers,
|
|
88
|
+
body: JSON.stringify({
|
|
89
|
+
tool: 'user_data_get_schema',
|
|
90
|
+
arguments: { tableName: table.tableName }
|
|
91
|
+
})
|
|
92
|
+
});
|
|
93
|
+
if (schemaResponse.ok) {
|
|
94
|
+
const schemaResult = await schemaResponse.json();
|
|
95
|
+
const schemaContent = schemaResult.result?.content?.[0]?.text;
|
|
96
|
+
const schemaData = schemaContent ? JSON.parse(schemaContent) : null;
|
|
97
|
+
tablesWithColumns.push({
|
|
98
|
+
id: table.id,
|
|
99
|
+
tableName: table.tableName,
|
|
100
|
+
displayName: table.displayName,
|
|
101
|
+
description: table.description,
|
|
102
|
+
rowCount: table.rowCount,
|
|
103
|
+
columnCount: table.columnCount,
|
|
104
|
+
columns: schemaData?.schema?.map((col) => col.name) || []
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
console.warn(`Failed to fetch schema for ${table.tableName}:`, error);
|
|
110
|
+
// Add table without column info
|
|
111
|
+
tablesWithColumns.push({
|
|
112
|
+
...table,
|
|
113
|
+
columns: []
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return tablesWithColumns;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
console.error('Failed to discover tables:', error);
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Read existing .env.local file or return empty object
|
|
126
|
+
*/
|
|
127
|
+
function readEnvLocal(projectPath) {
|
|
128
|
+
const envPath = path.join(projectPath, '.env.local');
|
|
129
|
+
if (!fs.existsSync(envPath)) {
|
|
130
|
+
return {};
|
|
131
|
+
}
|
|
132
|
+
const envContent = fs.readFileSync(envPath, 'utf-8');
|
|
133
|
+
const envVars = {};
|
|
134
|
+
for (const line of envContent.split('\n')) {
|
|
135
|
+
const trimmed = line.trim();
|
|
136
|
+
if (trimmed && !trimmed.startsWith('#')) {
|
|
137
|
+
const [key, ...valueParts] = trimmed.split('=');
|
|
138
|
+
if (key && valueParts.length > 0) {
|
|
139
|
+
envVars[key.trim()] = valueParts.join('=').trim();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return envVars;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Update .env.local file with Next.js environment variables
|
|
147
|
+
*/
|
|
148
|
+
function updateEnvLocal(projectPath, config) {
|
|
149
|
+
const envPath = path.join(projectPath, '.env.local');
|
|
150
|
+
const existingVars = readEnvLocal(projectPath);
|
|
151
|
+
// Merge with existing vars, prioritizing new EGDesk values
|
|
152
|
+
const newVars = {
|
|
153
|
+
...existingVars,
|
|
154
|
+
'NEXT_PUBLIC_EGDESK_API_URL': config.baseUrl,
|
|
155
|
+
...(config.apiKey && { 'NEXT_PUBLIC_EGDESK_API_KEY': config.apiKey })
|
|
156
|
+
};
|
|
157
|
+
const envContent = [
|
|
158
|
+
'# EGDesk User Data Configuration',
|
|
159
|
+
`# Generated at: ${config.generatedAt}`,
|
|
160
|
+
'',
|
|
161
|
+
...Object.entries(newVars).map(([key, value]) => `${key}=${value}`),
|
|
162
|
+
'',
|
|
163
|
+
'# Available Tables',
|
|
164
|
+
`# Total tables: ${config.tables.length}`,
|
|
165
|
+
...config.tables.map((table, index) => `# ${index + 1}. ${table.displayName} (${table.tableName}) - ${table.rowCount} rows, ${table.columnCount} columns`),
|
|
166
|
+
''
|
|
167
|
+
].join('\n');
|
|
168
|
+
fs.writeFileSync(envPath, envContent, 'utf-8');
|
|
169
|
+
console.log(`✅ Updated ${envPath}`);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Generate TypeScript config file with table definitions
|
|
173
|
+
*/
|
|
174
|
+
function generateConfigFile(projectPath, config) {
|
|
175
|
+
const configPath = path.join(projectPath, 'egdesk.config.ts');
|
|
176
|
+
const configContent = `/**
|
|
177
|
+
* EGDesk User Data Configuration
|
|
178
|
+
* Generated at: ${config.generatedAt}
|
|
179
|
+
*
|
|
180
|
+
* This file contains type-safe definitions for your EGDesk tables.
|
|
181
|
+
*/
|
|
182
|
+
|
|
183
|
+
export const EGDESK_CONFIG = {
|
|
184
|
+
apiUrl: '${config.baseUrl}',
|
|
185
|
+
apiKey: ${config.apiKey ? `'${config.apiKey}'` : 'undefined'},
|
|
186
|
+
} as const;
|
|
187
|
+
|
|
188
|
+
export interface TableDefinition {
|
|
189
|
+
name: string;
|
|
190
|
+
displayName: string;
|
|
191
|
+
description?: string;
|
|
192
|
+
rowCount: number;
|
|
193
|
+
columnCount: number;
|
|
194
|
+
columns: string[];
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
export const TABLES = {
|
|
198
|
+
${config.tables.map((table, index) => ` table${index + 1}: {
|
|
199
|
+
name: '${table.tableName}',
|
|
200
|
+
displayName: '${table.displayName}',
|
|
201
|
+
description: ${table.description ? `'${table.description}'` : 'undefined'},
|
|
202
|
+
rowCount: ${table.rowCount},
|
|
203
|
+
columnCount: ${table.columnCount},
|
|
204
|
+
columns: [${table.columns.map(col => `'${col}'`).join(', ')}]
|
|
205
|
+
} as TableDefinition`).join(',\n')}
|
|
206
|
+
} as const;
|
|
207
|
+
|
|
208
|
+
${config.tables.length > 0 ? `
|
|
209
|
+
// Main table (first table by default)
|
|
210
|
+
export const MAIN_TABLE = TABLES.table1;
|
|
211
|
+
` : ''}
|
|
212
|
+
|
|
213
|
+
// Helper to get table by name
|
|
214
|
+
export function getTableByName(tableName: string): TableDefinition | undefined {
|
|
215
|
+
return Object.values(TABLES).find(t => t.name === tableName);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Export table names for easy access
|
|
219
|
+
export const TABLE_NAMES = {
|
|
220
|
+
${config.tables.map((table, index) => ` table${index + 1}: '${table.tableName}'`).join(',\n')}
|
|
221
|
+
} as const;
|
|
222
|
+
`;
|
|
223
|
+
fs.writeFileSync(configPath, configContent, 'utf-8');
|
|
224
|
+
console.log(`✅ Generated ${configPath}`);
|
|
225
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@egdesk/next-api-plugin",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Next.js plugin for EGDesk database proxy integration",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"egdesk-next-setup": "./dist/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"prepublishOnly": "npm run build"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"nextjs",
|
|
17
|
+
"egdesk",
|
|
18
|
+
"database",
|
|
19
|
+
"proxy"
|
|
20
|
+
],
|
|
21
|
+
"author": "EGDesk",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"next": ">=13.0.0"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"dotenv": "^16.3.1"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/node": "^20.10.0",
|
|
31
|
+
"next": "^14.0.0",
|
|
32
|
+
"typescript": "^5.3.0"
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI entry point for @egdesk/next-api-plugin
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx egdesk-next-setup
|
|
7
|
+
* npx egdesk-next-setup --url http://localhost:8080 --api-key YOUR_KEY
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { setupNextApiPlugin } from './index';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
|
|
16
|
+
// Parse command line arguments
|
|
17
|
+
let egdeskUrl = 'http://localhost:8080';
|
|
18
|
+
let apiKey: string | undefined;
|
|
19
|
+
let useProxy = true; // Use proxy.ts by default (Next.js 16+)
|
|
20
|
+
|
|
21
|
+
for (let i = 0; i < args.length; i++) {
|
|
22
|
+
if (args[i] === '--url' && i + 1 < args.length) {
|
|
23
|
+
egdeskUrl = args[i + 1];
|
|
24
|
+
i++;
|
|
25
|
+
} else if (args[i] === '--api-key' && i + 1 < args.length) {
|
|
26
|
+
apiKey = args[i + 1];
|
|
27
|
+
i++;
|
|
28
|
+
} else if (args[i] === '--legacy-middleware') {
|
|
29
|
+
useProxy = false;
|
|
30
|
+
} else if (args[i] === '--help' || args[i] === '-h') {
|
|
31
|
+
console.log('Usage: egdesk-next-setup [options]');
|
|
32
|
+
console.log('');
|
|
33
|
+
console.log('Options:');
|
|
34
|
+
console.log(' --url <url> EGDesk server URL (default: http://localhost:8080)');
|
|
35
|
+
console.log(' --api-key <key> API key for authentication');
|
|
36
|
+
console.log(' --legacy-middleware Use middleware.ts instead of proxy.ts (for Next.js <16)');
|
|
37
|
+
console.log(' --help, -h Show this help message');
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log('Example:');
|
|
40
|
+
console.log(' egdesk-next-setup --url http://localhost:8080 --api-key mykey');
|
|
41
|
+
console.log(' egdesk-next-setup --legacy-middleware # For Next.js <16');
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Get current working directory (project root)
|
|
47
|
+
const projectPath = process.cwd();
|
|
48
|
+
|
|
49
|
+
console.log('🚀 EGDesk Next.js Setup');
|
|
50
|
+
console.log(`📂 Project: ${projectPath}`);
|
|
51
|
+
console.log(`🔗 EGDesk URL: ${egdeskUrl}`);
|
|
52
|
+
console.log('');
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await setupNextApiPlugin(projectPath, { egdeskUrl, apiKey, useProxy });
|
|
56
|
+
process.exit(0);
|
|
57
|
+
} catch (error) {
|
|
58
|
+
console.error('Setup failed:', error);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
main();
|