@majkapp/plugin-kit 1.0.17 → 1.1.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/generator/cli.d.ts +3 -0
- package/dist/generator/cli.d.ts.map +1 -0
- package/dist/generator/cli.js +161 -0
- package/dist/generator/generator.d.ts +6 -0
- package/dist/generator/generator.d.ts.map +1 -0
- package/dist/generator/generator.js +389 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/plugin-kit.d.ts +28 -2
- package/dist/plugin-kit.d.ts.map +1 -1
- package/dist/plugin-kit.js +622 -19
- package/dist/registry.d.ts +38 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +143 -0
- package/dist/transports.d.ts +59 -0
- package/dist/transports.d.ts.map +1 -0
- package/dist/transports.js +171 -0
- package/dist/types.d.ts +85 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +10 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/generator/cli.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
const commander_1 = require("commander");
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const child_process_1 = require("child_process");
|
|
41
|
+
const generator_1 = require("./generator");
|
|
42
|
+
commander_1.program
|
|
43
|
+
.name('plugin-kit')
|
|
44
|
+
.version('1.0.20')
|
|
45
|
+
.description('Plugin Kit CLI - Generate TypeScript clients from plugin definitions');
|
|
46
|
+
commander_1.program
|
|
47
|
+
.command('generate')
|
|
48
|
+
.description('Generate a TypeScript client from a plugin definition')
|
|
49
|
+
.option('-e, --entry <path>', 'Path to the compiled plugin entry file', './index.js')
|
|
50
|
+
.option('-o, --output <path>', 'Output directory for generated client', './ui/src/generated')
|
|
51
|
+
.option('-w, --watch', 'Watch for changes and regenerate', false)
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
const entryPath = path.resolve(options.entry);
|
|
54
|
+
const outputPath = path.resolve(options.output);
|
|
55
|
+
const logPath = path.join(outputPath, 'generation.log');
|
|
56
|
+
// Ensure output directory exists
|
|
57
|
+
fs.mkdirSync(outputPath, { recursive: true });
|
|
58
|
+
const generate = async () => {
|
|
59
|
+
const startTime = Date.now();
|
|
60
|
+
const log = [];
|
|
61
|
+
log.push(`=== Plugin Kit Client Generation ===`);
|
|
62
|
+
log.push(`Time: ${new Date().toISOString()}`);
|
|
63
|
+
log.push(`Entry: ${entryPath}`);
|
|
64
|
+
log.push(`Output: ${outputPath}`);
|
|
65
|
+
log.push(``);
|
|
66
|
+
try {
|
|
67
|
+
// Check if entry file exists
|
|
68
|
+
if (!fs.existsSync(entryPath)) {
|
|
69
|
+
throw new Error(`Entry file not found: ${entryPath}`);
|
|
70
|
+
}
|
|
71
|
+
log.push(`✓ Found entry file`);
|
|
72
|
+
// Extract metadata from plugin
|
|
73
|
+
const metadata = await extractMetadata(entryPath);
|
|
74
|
+
log.push(`✓ Extracted metadata from plugin: ${metadata.name} v${metadata.version}`);
|
|
75
|
+
log.push(` - ${metadata.functions.length} functions`);
|
|
76
|
+
log.push(` - ${metadata.screens.length} screens`);
|
|
77
|
+
log.push(` - ${metadata.tools.length} tools`);
|
|
78
|
+
log.push(``);
|
|
79
|
+
// Generate client files
|
|
80
|
+
const result = await (0, generator_1.generateClient)(metadata, outputPath, log);
|
|
81
|
+
const duration = Date.now() - startTime;
|
|
82
|
+
log.push(``);
|
|
83
|
+
log.push(`✓ Generation completed in ${duration}ms`);
|
|
84
|
+
if (result.warnings.length > 0) {
|
|
85
|
+
log.push(``);
|
|
86
|
+
log.push(`⚠ Warnings:`);
|
|
87
|
+
result.warnings.forEach(w => log.push(` - ${w}`));
|
|
88
|
+
}
|
|
89
|
+
// Write log file (overwrite each time)
|
|
90
|
+
fs.writeFileSync(logPath, log.join('\n'), 'utf-8');
|
|
91
|
+
console.log(`✅ Client generated successfully in ${duration}ms`);
|
|
92
|
+
console.log(` Output: ${outputPath}`);
|
|
93
|
+
console.log(` Files: ${result.files.join(', ')}`);
|
|
94
|
+
if (result.warnings.length > 0) {
|
|
95
|
+
console.log(` ⚠ ${result.warnings.length} warnings (see generation.log)`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
log.push(`✗ Error: ${error.message}`);
|
|
100
|
+
log.push(error.stack || '');
|
|
101
|
+
fs.writeFileSync(logPath, log.join('\n'), 'utf-8');
|
|
102
|
+
console.error(`❌ Generation failed: ${error.message}`);
|
|
103
|
+
console.error(` See ${logPath} for details`);
|
|
104
|
+
if (!options.watch) {
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
if (options.watch) {
|
|
110
|
+
console.log(`👁 Watching for changes...`);
|
|
111
|
+
// Initial generation
|
|
112
|
+
await generate();
|
|
113
|
+
// Watch for changes
|
|
114
|
+
let timeout;
|
|
115
|
+
fs.watch(entryPath, () => {
|
|
116
|
+
clearTimeout(timeout);
|
|
117
|
+
timeout = setTimeout(() => {
|
|
118
|
+
console.log(`🔄 Changes detected, regenerating...`);
|
|
119
|
+
generate();
|
|
120
|
+
}, 500);
|
|
121
|
+
});
|
|
122
|
+
// Keep process alive
|
|
123
|
+
process.stdin.resume();
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
await generate();
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
commander_1.program.parse();
|
|
130
|
+
async function extractMetadata(entryPath) {
|
|
131
|
+
// Create a temp file for the output
|
|
132
|
+
const tempFile = path.join(path.dirname(entryPath), `.plugin-metadata-${Date.now()}.json`);
|
|
133
|
+
try {
|
|
134
|
+
// Run the plugin in extract mode with file output
|
|
135
|
+
(0, child_process_1.execSync)(`node "${entryPath}"`, {
|
|
136
|
+
env: {
|
|
137
|
+
...process.env,
|
|
138
|
+
PLUGIN_KIT_MODE: 'extract',
|
|
139
|
+
PLUGIN_KIT_OUTPUT: tempFile
|
|
140
|
+
},
|
|
141
|
+
cwd: path.dirname(entryPath),
|
|
142
|
+
stdio: 'inherit' // Let the plugin print its own messages
|
|
143
|
+
});
|
|
144
|
+
// Read the generated file
|
|
145
|
+
if (!fs.existsSync(tempFile)) {
|
|
146
|
+
throw new Error('Metadata file was not created');
|
|
147
|
+
}
|
|
148
|
+
const content = fs.readFileSync(tempFile, 'utf-8');
|
|
149
|
+
const metadata = JSON.parse(content);
|
|
150
|
+
// Clean up temp file
|
|
151
|
+
fs.unlinkSync(tempFile);
|
|
152
|
+
return metadata;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
// Clean up temp file if it exists
|
|
156
|
+
if (fs.existsSync(tempFile)) {
|
|
157
|
+
fs.unlinkSync(tempFile);
|
|
158
|
+
}
|
|
159
|
+
throw new Error(`Failed to extract metadata: ${error.message}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../src/generator/generator.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,MAAM,EAAE,GACZ,OAAO,CAAC,gBAAgB,CAAC,CAmC3B"}
|
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateClient = generateClient;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
async function generateClient(metadata, outputPath, log) {
|
|
40
|
+
const warnings = [];
|
|
41
|
+
const files = [];
|
|
42
|
+
// Helper to write files
|
|
43
|
+
const writeFile = (filename, content) => {
|
|
44
|
+
const filePath = path.join(outputPath, filename);
|
|
45
|
+
fs.writeFileSync(filePath, content, 'utf-8');
|
|
46
|
+
files.push(filename);
|
|
47
|
+
log.push(` ✓ Generated ${filename}`);
|
|
48
|
+
};
|
|
49
|
+
try {
|
|
50
|
+
// 1. Generate TypeScript types
|
|
51
|
+
const types = generateTypes(metadata, warnings, log);
|
|
52
|
+
writeFile('types.ts', types);
|
|
53
|
+
// 2. Generate client class
|
|
54
|
+
const client = generateClientClass(metadata, warnings, log);
|
|
55
|
+
writeFile('client.ts', client);
|
|
56
|
+
// 3. Generate React hooks
|
|
57
|
+
const hooks = generateReactHooks(metadata, warnings, log);
|
|
58
|
+
writeFile('hooks.ts', hooks);
|
|
59
|
+
// 4. Generate index file
|
|
60
|
+
const index = generateIndex();
|
|
61
|
+
writeFile('index.ts', index);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
warnings.push(`Partial generation error: ${error.message}`);
|
|
65
|
+
log.push(` ⚠ Partial generation error: ${error.message}`);
|
|
66
|
+
}
|
|
67
|
+
return { files, warnings };
|
|
68
|
+
}
|
|
69
|
+
function generateTypes(metadata, warnings, log) {
|
|
70
|
+
const lines = [];
|
|
71
|
+
lines.push(`/**
|
|
72
|
+
* Auto-generated TypeScript types for ${metadata.name}
|
|
73
|
+
* Generated at: ${new Date().toISOString()}
|
|
74
|
+
* Plugin version: ${metadata.version}
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
`);
|
|
78
|
+
// Extract types from function schemas
|
|
79
|
+
const processedTypes = new Set();
|
|
80
|
+
metadata.functions.forEach((func) => {
|
|
81
|
+
try {
|
|
82
|
+
// Generate input type
|
|
83
|
+
const inputTypeName = `${capitalize(func.name)}Input`;
|
|
84
|
+
if (!processedTypes.has(inputTypeName)) {
|
|
85
|
+
lines.push(`export interface ${inputTypeName} ${schemaToTypeScript(func.input, 0)}\n`);
|
|
86
|
+
processedTypes.add(inputTypeName);
|
|
87
|
+
}
|
|
88
|
+
// Generate output type
|
|
89
|
+
const outputTypeName = `${capitalize(func.name)}Output`;
|
|
90
|
+
if (!processedTypes.has(outputTypeName)) {
|
|
91
|
+
// Handle array types specially - use type alias instead of interface
|
|
92
|
+
if (func.output.type === 'array') {
|
|
93
|
+
lines.push(`export type ${outputTypeName} = ${schemaToTypeScript(func.output, 0)};\n`);
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
lines.push(`export interface ${outputTypeName} ${schemaToTypeScript(func.output, 0)}\n`);
|
|
97
|
+
}
|
|
98
|
+
processedTypes.add(outputTypeName);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
warnings.push(`Failed to generate types for ${func.name}: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
// Standard response types
|
|
106
|
+
lines.push(`
|
|
107
|
+
export interface SuccessResponse<T> {
|
|
108
|
+
success: true;
|
|
109
|
+
data: T;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface ErrorResponse {
|
|
113
|
+
success: false;
|
|
114
|
+
error: string;
|
|
115
|
+
details?: any[];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export type ApiResponse<T> = SuccessResponse<T> | ErrorResponse;
|
|
119
|
+
`);
|
|
120
|
+
return lines.join('\n');
|
|
121
|
+
}
|
|
122
|
+
function generateClientClass(metadata, warnings, log) {
|
|
123
|
+
const lines = [];
|
|
124
|
+
lines.push(`/**
|
|
125
|
+
* Auto-generated client for ${metadata.name}
|
|
126
|
+
* Generated at: ${new Date().toISOString()}
|
|
127
|
+
* Plugin version: ${metadata.version}
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
import type {
|
|
131
|
+
${metadata.functions.map((f) => ` ${capitalize(f.name)}Input,
|
|
132
|
+
${capitalize(f.name)}Output`).join(',\n')}
|
|
133
|
+
} from './types';
|
|
134
|
+
|
|
135
|
+
export class ${capitalize(toCamelCase(metadata.id))}Client {
|
|
136
|
+
constructor(private baseUrl: string = '') {}
|
|
137
|
+
|
|
138
|
+
private async request<TInput, TOutput>(
|
|
139
|
+
functionName: string,
|
|
140
|
+
input: TInput
|
|
141
|
+
): Promise<TOutput> {
|
|
142
|
+
try {
|
|
143
|
+
const response = await fetch(\`\${this.baseUrl}/api/fn/\${functionName}\`, {
|
|
144
|
+
method: 'POST',
|
|
145
|
+
headers: {
|
|
146
|
+
'Content-Type': 'application/json',
|
|
147
|
+
},
|
|
148
|
+
body: JSON.stringify(input),
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const result = await response.json();
|
|
152
|
+
|
|
153
|
+
// The transport wraps responses in { success: boolean, data?: T, error?: string }
|
|
154
|
+
// Check for errors first
|
|
155
|
+
if (result.success === false) {
|
|
156
|
+
throw new Error(result.error || \`Function \${functionName} failed\`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Return the unwrapped data
|
|
160
|
+
// The TypeScript output types represent the data inside the wrapper
|
|
161
|
+
return result.data;
|
|
162
|
+
} catch (error: any) {
|
|
163
|
+
console.error(\`Error calling \${functionName}:\`, error);
|
|
164
|
+
throw error;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
`);
|
|
168
|
+
// Generate methods for each function
|
|
169
|
+
metadata.functions.forEach((func) => {
|
|
170
|
+
try {
|
|
171
|
+
const methodName = toCamelCase(func.name);
|
|
172
|
+
const inputType = `${capitalize(func.name)}Input`;
|
|
173
|
+
const outputType = `${capitalize(func.name)}Output`;
|
|
174
|
+
lines.push(`
|
|
175
|
+
/**
|
|
176
|
+
* ${func.description}${func.deprecated ? '\n * @deprecated' : ''}
|
|
177
|
+
*/
|
|
178
|
+
async ${methodName}(input: ${inputType} = {}): Promise<${outputType}> {
|
|
179
|
+
return this.request<${inputType}, ${outputType}>('${func.name}', input);
|
|
180
|
+
}
|
|
181
|
+
`);
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
warnings.push(`Failed to generate method for ${func.name}: ${error.message}`);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
lines.push(`}
|
|
188
|
+
|
|
189
|
+
// Default singleton instance
|
|
190
|
+
export const ${toCamelCase(metadata.id)}Client = new ${capitalize(toCamelCase(metadata.id))}Client();
|
|
191
|
+
`);
|
|
192
|
+
return lines.join('');
|
|
193
|
+
}
|
|
194
|
+
function generateReactHooks(metadata, warnings, log) {
|
|
195
|
+
const lines = [];
|
|
196
|
+
lines.push(`/**
|
|
197
|
+
* Auto-generated React hooks for ${metadata.name}
|
|
198
|
+
* Generated at: ${new Date().toISOString()}
|
|
199
|
+
* Plugin version: ${metadata.version}
|
|
200
|
+
*/
|
|
201
|
+
|
|
202
|
+
import { useState, useEffect, useCallback } from 'react';
|
|
203
|
+
import { ${toCamelCase(metadata.id)}Client } from './client';
|
|
204
|
+
import type {
|
|
205
|
+
${metadata.functions.map((f) => ` ${capitalize(f.name)}Input,
|
|
206
|
+
${capitalize(f.name)}Output`).join(',\n')}
|
|
207
|
+
} from './types';
|
|
208
|
+
|
|
209
|
+
export interface UseQueryResult<T> {
|
|
210
|
+
data: T | undefined;
|
|
211
|
+
error: Error | undefined;
|
|
212
|
+
loading: boolean;
|
|
213
|
+
refetch: () => void;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface UseMutationResult<TInput, TOutput> {
|
|
217
|
+
mutate: (input: TInput) => Promise<TOutput>;
|
|
218
|
+
data: TOutput | undefined;
|
|
219
|
+
error: Error | undefined;
|
|
220
|
+
loading: boolean;
|
|
221
|
+
}
|
|
222
|
+
`);
|
|
223
|
+
// Generate hooks for each function
|
|
224
|
+
metadata.functions.forEach((func) => {
|
|
225
|
+
try {
|
|
226
|
+
const hookName = `use${capitalize(func.name)}`;
|
|
227
|
+
const inputType = `${capitalize(func.name)}Input`;
|
|
228
|
+
const outputType = `${capitalize(func.name)}Output`;
|
|
229
|
+
// Determine if it's a query or mutation based on name/tags
|
|
230
|
+
const isQuery = func.name.startsWith('get') ||
|
|
231
|
+
func.name.startsWith('list') ||
|
|
232
|
+
func.name.includes('health') ||
|
|
233
|
+
func.name.includes('status');
|
|
234
|
+
if (isQuery) {
|
|
235
|
+
lines.push(`
|
|
236
|
+
/**
|
|
237
|
+
* React hook for ${func.description}
|
|
238
|
+
*/
|
|
239
|
+
export function ${hookName}(
|
|
240
|
+
input: ${inputType} = {},
|
|
241
|
+
options?: { enabled?: boolean; refetchInterval?: number }
|
|
242
|
+
): UseQueryResult<${outputType}> {
|
|
243
|
+
const [data, setData] = useState<${outputType} | undefined>();
|
|
244
|
+
const [error, setError] = useState<Error | undefined>();
|
|
245
|
+
const [loading, setLoading] = useState(false);
|
|
246
|
+
|
|
247
|
+
const fetch = useCallback(async () => {
|
|
248
|
+
if (options?.enabled === false) return;
|
|
249
|
+
|
|
250
|
+
setLoading(true);
|
|
251
|
+
setError(undefined);
|
|
252
|
+
|
|
253
|
+
try {
|
|
254
|
+
const result = await ${toCamelCase(metadata.id)}Client.${toCamelCase(func.name)}(input);
|
|
255
|
+
setData(result);
|
|
256
|
+
} catch (err: any) {
|
|
257
|
+
setError(err);
|
|
258
|
+
} finally {
|
|
259
|
+
setLoading(false);
|
|
260
|
+
}
|
|
261
|
+
}, [JSON.stringify(input), options?.enabled]);
|
|
262
|
+
|
|
263
|
+
useEffect(() => {
|
|
264
|
+
fetch();
|
|
265
|
+
|
|
266
|
+
if (options?.refetchInterval) {
|
|
267
|
+
const interval = setInterval(fetch, options.refetchInterval);
|
|
268
|
+
return () => clearInterval(interval);
|
|
269
|
+
}
|
|
270
|
+
}, [fetch, options?.refetchInterval]);
|
|
271
|
+
|
|
272
|
+
return { data, error, loading, refetch: fetch };
|
|
273
|
+
}
|
|
274
|
+
`);
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
lines.push(`
|
|
278
|
+
/**
|
|
279
|
+
* React hook for ${func.description}
|
|
280
|
+
*/
|
|
281
|
+
export function ${hookName}(): UseMutationResult<${inputType}, ${outputType}> {
|
|
282
|
+
const [data, setData] = useState<${outputType} | undefined>();
|
|
283
|
+
const [error, setError] = useState<Error | undefined>();
|
|
284
|
+
const [loading, setLoading] = useState(false);
|
|
285
|
+
|
|
286
|
+
const mutate = useCallback(async (input: ${inputType}): Promise<${outputType}> => {
|
|
287
|
+
setLoading(true);
|
|
288
|
+
setError(undefined);
|
|
289
|
+
|
|
290
|
+
try {
|
|
291
|
+
const result = await ${toCamelCase(metadata.id)}Client.${toCamelCase(func.name)}(input);
|
|
292
|
+
setData(result);
|
|
293
|
+
return result;
|
|
294
|
+
} catch (err: any) {
|
|
295
|
+
setError(err);
|
|
296
|
+
throw err;
|
|
297
|
+
} finally {
|
|
298
|
+
setLoading(false);
|
|
299
|
+
}
|
|
300
|
+
}, []);
|
|
301
|
+
|
|
302
|
+
return { mutate, data, error, loading };
|
|
303
|
+
}
|
|
304
|
+
`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
warnings.push(`Failed to generate hook for ${func.name}: ${error.message}`);
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
return lines.join('');
|
|
312
|
+
}
|
|
313
|
+
function generateIndex() {
|
|
314
|
+
return `/**
|
|
315
|
+
* Auto-generated client exports
|
|
316
|
+
* Generated at: ${new Date().toISOString()}
|
|
317
|
+
*/
|
|
318
|
+
|
|
319
|
+
export * from './types';
|
|
320
|
+
export * from './client';
|
|
321
|
+
export * from './hooks';
|
|
322
|
+
`;
|
|
323
|
+
}
|
|
324
|
+
// Helper functions
|
|
325
|
+
function schemaToTypeScript(schema, indent) {
|
|
326
|
+
if (!schema)
|
|
327
|
+
return 'any';
|
|
328
|
+
const spaces = ' '.repeat(indent);
|
|
329
|
+
if (schema.type === 'object') {
|
|
330
|
+
const props = schema.properties || {};
|
|
331
|
+
const required = schema.required || [];
|
|
332
|
+
const lines = ['{'];
|
|
333
|
+
Object.entries(props).forEach(([key, prop]) => {
|
|
334
|
+
const optional = !required.includes(key) ? '?' : '';
|
|
335
|
+
const type = schemaToTypeScript(prop, indent + 1);
|
|
336
|
+
const description = prop.description ? `\n${spaces} /** ${prop.description} */\n${spaces} ` : '\n' + spaces + ' ';
|
|
337
|
+
lines.push(`${description}${key}${optional}: ${type};`);
|
|
338
|
+
});
|
|
339
|
+
if (Object.keys(props).length === 0) {
|
|
340
|
+
lines.push(`${spaces} [key: string]: any;`);
|
|
341
|
+
}
|
|
342
|
+
lines.push(spaces + '}');
|
|
343
|
+
return lines.join('');
|
|
344
|
+
}
|
|
345
|
+
if (schema.type === 'array') {
|
|
346
|
+
return `${schemaToTypeScript(schema.items, indent)}[]`;
|
|
347
|
+
}
|
|
348
|
+
if (schema.type === 'string') {
|
|
349
|
+
if (schema.enum) {
|
|
350
|
+
return schema.enum.map((e) => `'${e}'`).join(' | ');
|
|
351
|
+
}
|
|
352
|
+
return 'string';
|
|
353
|
+
}
|
|
354
|
+
if (schema.type === 'number' || schema.type === 'integer') {
|
|
355
|
+
return 'number';
|
|
356
|
+
}
|
|
357
|
+
if (schema.type === 'boolean') {
|
|
358
|
+
return 'boolean';
|
|
359
|
+
}
|
|
360
|
+
if (schema.type === 'null') {
|
|
361
|
+
return 'null';
|
|
362
|
+
}
|
|
363
|
+
// Handle union types
|
|
364
|
+
if (Array.isArray(schema.type)) {
|
|
365
|
+
return schema.type.map((t) => {
|
|
366
|
+
if (t === 'null')
|
|
367
|
+
return 'null';
|
|
368
|
+
if (t === 'string')
|
|
369
|
+
return 'string';
|
|
370
|
+
if (t === 'number' || t === 'integer')
|
|
371
|
+
return 'number';
|
|
372
|
+
if (t === 'boolean')
|
|
373
|
+
return 'boolean';
|
|
374
|
+
return 'any';
|
|
375
|
+
}).join(' | ');
|
|
376
|
+
}
|
|
377
|
+
// Handle anyOf/oneOf
|
|
378
|
+
if (schema.anyOf || schema.oneOf) {
|
|
379
|
+
const schemas = schema.anyOf || schema.oneOf;
|
|
380
|
+
return schemas.map((s) => schemaToTypeScript(s, indent)).join(' | ');
|
|
381
|
+
}
|
|
382
|
+
return 'any';
|
|
383
|
+
}
|
|
384
|
+
function capitalize(str) {
|
|
385
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
386
|
+
}
|
|
387
|
+
function toCamelCase(str) {
|
|
388
|
+
return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
389
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,5 +12,8 @@
|
|
|
12
12
|
* - Lifecycle hooks with cleanup management
|
|
13
13
|
*/
|
|
14
14
|
export { definePlugin, FluentBuilder } from './plugin-kit';
|
|
15
|
-
export
|
|
15
|
+
export { HttpTransport, WebSocketTransport, MCPTransport } from './transports';
|
|
16
|
+
export { FunctionRegistryImpl } from './registry';
|
|
17
|
+
export { generateClient } from './generator/generator';
|
|
18
|
+
export type { PluginContext, PluginLogger, PluginStorage, ScopedTimers, ScopedIpcRegistry, PluginCapabilities, PluginCapability, ToolImplementation, InProcessPlugin, PluginHealthStatus, ToolSpec, ToolHandler, ApiMethod, ApiRouteDef, JsonSchema, RouteHandler, RequestLike, ResponseLike, UiConfig, HistoryMode, ScreenBase, ReactScreen, HtmlScreen, ConfigWizardDef, SettingsDef, Scope, EntityType, CleanupFn, HealthCheckFn, MCPServerEntity, TeamMemberEntity, FunctionHandler, SubscriptionHandler, FunctionDefinition, SubscriptionDefinition, Transport, TransportMetadata, FunctionRegistry, ClientGenerationConfig } from './types';
|
|
16
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,YAAY,EACV,aAAa,EACb,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,WAAW,EACX,SAAS,EACT,WAAW,EACX,UAAU,EACV,YAAY,EACZ,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACV,eAAe,EACf,WAAW,EACX,KAAK,EACL,UAAU,EACV,SAAS,EACT,aAAa,EACb,eAAe,EACf,gBAAgB,EAEhB,eAAe,EACf,mBAAmB,EACnB,kBAAkB,EAClB,sBAAsB,EACtB,SAAS,EACT,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,SAAS,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
* - Lifecycle hooks with cleanup management
|
|
14
14
|
*/
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
-
exports.definePlugin = void 0;
|
|
16
|
+
exports.generateClient = exports.FunctionRegistryImpl = exports.MCPTransport = exports.WebSocketTransport = exports.HttpTransport = exports.definePlugin = void 0;
|
|
17
17
|
var plugin_kit_1 = require("./plugin-kit");
|
|
18
18
|
Object.defineProperty(exports, "definePlugin", { enumerable: true, get: function () { return plugin_kit_1.definePlugin; } });
|
|
19
|
+
var transports_1 = require("./transports");
|
|
20
|
+
Object.defineProperty(exports, "HttpTransport", { enumerable: true, get: function () { return transports_1.HttpTransport; } });
|
|
21
|
+
Object.defineProperty(exports, "WebSocketTransport", { enumerable: true, get: function () { return transports_1.WebSocketTransport; } });
|
|
22
|
+
Object.defineProperty(exports, "MCPTransport", { enumerable: true, get: function () { return transports_1.MCPTransport; } });
|
|
23
|
+
var registry_1 = require("./registry");
|
|
24
|
+
Object.defineProperty(exports, "FunctionRegistryImpl", { enumerable: true, get: function () { return registry_1.FunctionRegistryImpl; } });
|
|
25
|
+
var generator_1 = require("./generator/generator");
|
|
26
|
+
Object.defineProperty(exports, "generateClient", { enumerable: true, get: function () { return generator_1.generateClient; } });
|
package/dist/plugin-kit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PluginContext, InProcessPlugin, ToolSpec, ToolHandler, ApiRouteDef, UiConfig, ReactScreen, HtmlScreen, ConfigWizardDef, SettingsDef, Scope, EntityType, CleanupFn, HealthCheckFn, MCPServerEntity, TeamMemberEntity, MenuItemDeclaration } from './types';
|
|
1
|
+
import { PluginContext, InProcessPlugin, ToolSpec, ToolHandler, ApiRouteDef, JsonSchema, UiConfig, ReactScreen, HtmlScreen, ConfigWizardDef, SettingsDef, Scope, EntityType, CleanupFn, HealthCheckFn, MCPServerEntity, TeamMemberEntity, MenuItemDeclaration, FunctionHandler, SubscriptionHandler, Transport, ClientGenerationConfig } from './types';
|
|
2
2
|
/**
|
|
3
3
|
* Fluent Builder Interface
|
|
4
4
|
*/
|
|
@@ -17,8 +17,28 @@ export interface FluentBuilder<Id extends string> {
|
|
|
17
17
|
screenReact(screen: ReactScreen<Id>): this;
|
|
18
18
|
/** Add an HTML screen */
|
|
19
19
|
screenHtml(screen: HtmlScreen<Id>): this;
|
|
20
|
-
/** Add an API route */
|
|
20
|
+
/** Add an API route (legacy) */
|
|
21
21
|
apiRoute(route: ApiRouteDef): this;
|
|
22
|
+
/** Add a function with JSON Schema (new function-first API) */
|
|
23
|
+
function(name: string, config: {
|
|
24
|
+
description: string;
|
|
25
|
+
input: JsonSchema;
|
|
26
|
+
output: JsonSchema;
|
|
27
|
+
handler: FunctionHandler;
|
|
28
|
+
tags?: string[];
|
|
29
|
+
deprecated?: boolean;
|
|
30
|
+
}): this;
|
|
31
|
+
/** Add a subscription for real-time updates */
|
|
32
|
+
subscription(name: string, config: {
|
|
33
|
+
description: string;
|
|
34
|
+
input: JsonSchema;
|
|
35
|
+
output: JsonSchema;
|
|
36
|
+
handler: SubscriptionHandler;
|
|
37
|
+
}): this;
|
|
38
|
+
/** Configure transports */
|
|
39
|
+
transport(transport: Transport): this;
|
|
40
|
+
/** Configure client generation */
|
|
41
|
+
generateClient(config: ClientGenerationConfig): this;
|
|
22
42
|
/** Add a tool */
|
|
23
43
|
tool(scope: Scope, spec: ToolSpec, handler: ToolHandler): this;
|
|
24
44
|
/** Declare entities that this plugin provides (generic, untyped) */
|
|
@@ -27,6 +47,12 @@ export interface FluentBuilder<Id extends string> {
|
|
|
27
47
|
mcpServer(servers: MCPServerEntity[]): this;
|
|
28
48
|
/** Add team member entities with full TypeScript validation */
|
|
29
49
|
teamMember(members: TeamMemberEntity[]): this;
|
|
50
|
+
/** Add configurable entities that are only registered after plugin config exists */
|
|
51
|
+
configurableEntity(entityType: EntityType, factory: (config: any) => any[]): this;
|
|
52
|
+
/** Add configurable MCP servers (only registered after config exists) */
|
|
53
|
+
configurableMcp(factory: (config: any) => MCPServerEntity[]): this;
|
|
54
|
+
/** Add configurable team members (only registered after config exists) */
|
|
55
|
+
configurableTeamMember(factory: (config: any) => TeamMemberEntity[]): this;
|
|
30
56
|
/** Add config wizard */
|
|
31
57
|
configWizard(def: ConfigWizardDef): this;
|
|
32
58
|
/** Add settings screen */
|
package/dist/plugin-kit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin-kit.d.ts","sourceRoot":"","sources":["../src/plugin-kit.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,aAAa,EAGb,eAAe,EACf,QAAQ,EACR,WAAW,EACX,WAAW,EACX,QAAQ,EACR,WAAW,EACX,UAAU,EACV,eAAe,EACf,WAAW,EACX,KAAK,EACL,UAAU,EACV,SAAS,EACT,aAAa,EAIb,eAAe,EACf,gBAAgB,EAChB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"plugin-kit.d.ts","sourceRoot":"","sources":["../src/plugin-kit.ts"],"names":[],"mappings":"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"}
|