@relazio/plugin-sdk 0.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/LICENSE +22 -0
- package/README.md +255 -0
- package/dist/core/manifest.d.ts +21 -0
- package/dist/core/manifest.d.ts.map +1 -0
- package/dist/core/manifest.js +96 -0
- package/dist/core/plugin.d.ts +110 -0
- package/dist/core/plugin.d.ts.map +1 -0
- package/dist/core/plugin.js +272 -0
- package/dist/core/types.d.ts +222 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +5 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/jobs/progress.d.ts +79 -0
- package/dist/jobs/progress.d.ts.map +1 -0
- package/dist/jobs/progress.js +165 -0
- package/dist/registry/installation.d.ts +101 -0
- package/dist/registry/installation.d.ts.map +1 -0
- package/dist/registry/installation.js +148 -0
- package/dist/security/hmac.d.ts +28 -0
- package/dist/security/hmac.d.ts.map +1 -0
- package/dist/security/hmac.js +68 -0
- package/dist/server/express.d.ts +43 -0
- package/dist/server/express.d.ts.map +1 -0
- package/dist/server/express.js +279 -0
- package/package.json +52 -0
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.ExpressServer = void 0;
|
|
7
|
+
const express_1 = __importDefault(require("express"));
|
|
8
|
+
const https_1 = __importDefault(require("https"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
/**
|
|
11
|
+
* Server Express per il plugin
|
|
12
|
+
*/
|
|
13
|
+
class ExpressServer {
|
|
14
|
+
constructor(plugin, options) {
|
|
15
|
+
this.plugin = plugin;
|
|
16
|
+
this.options = options;
|
|
17
|
+
this.app = (0, express_1.default)();
|
|
18
|
+
this.setupMiddleware();
|
|
19
|
+
this.setupRoutes();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Setup middleware
|
|
23
|
+
*/
|
|
24
|
+
setupMiddleware() {
|
|
25
|
+
// Body parser
|
|
26
|
+
this.app.use(express_1.default.json({ limit: '10mb' }));
|
|
27
|
+
// CORS
|
|
28
|
+
this.app.use((req, res, next) => {
|
|
29
|
+
res.header('Access-Control-Allow-Origin', '*');
|
|
30
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
31
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type, X-Organization-Id');
|
|
32
|
+
if (req.method === 'OPTIONS') {
|
|
33
|
+
res.sendStatus(200);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
next();
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
// Request logging
|
|
40
|
+
this.app.use((req, res, next) => {
|
|
41
|
+
console.log(`[${new Date().toISOString()}] ${req.method} ${req.path}`);
|
|
42
|
+
next();
|
|
43
|
+
});
|
|
44
|
+
// Error handling
|
|
45
|
+
this.app.use((err, req, res, next) => {
|
|
46
|
+
console.error('Error:', err);
|
|
47
|
+
res.status(500).json({
|
|
48
|
+
error: 'Internal server error',
|
|
49
|
+
message: err.message,
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Setup routes
|
|
55
|
+
*/
|
|
56
|
+
setupRoutes() {
|
|
57
|
+
// Health check
|
|
58
|
+
this.app.get('/health', (req, res) => {
|
|
59
|
+
const config = this.plugin.getConfig();
|
|
60
|
+
res.json({
|
|
61
|
+
status: 'ok',
|
|
62
|
+
plugin: config.id,
|
|
63
|
+
version: config.version,
|
|
64
|
+
uptime: process.uptime(),
|
|
65
|
+
transforms: {
|
|
66
|
+
sync: this.plugin.getTransforms().length,
|
|
67
|
+
async: this.plugin.getAsyncTransforms().length,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
// Registration endpoint (multi-tenant)
|
|
72
|
+
if (this.options.multiTenant) {
|
|
73
|
+
this.app.post('/register', async (req, res) => {
|
|
74
|
+
try {
|
|
75
|
+
const registry = this.plugin.getRegistry();
|
|
76
|
+
if (!registry) {
|
|
77
|
+
res.status(501).json({ error: 'Multi-tenant not enabled' });
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const result = await registry.register(req.body);
|
|
81
|
+
res.json(result);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
85
|
+
console.error('Registration error:', error);
|
|
86
|
+
res.status(500).json({ error: 'Registration failed', message });
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
// Unregister endpoint
|
|
90
|
+
this.app.post('/unregister', async (req, res) => {
|
|
91
|
+
try {
|
|
92
|
+
const registry = this.plugin.getRegistry();
|
|
93
|
+
if (!registry) {
|
|
94
|
+
res.status(501).json({ error: 'Multi-tenant not enabled' });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const { organizationId } = req.body;
|
|
98
|
+
if (!organizationId) {
|
|
99
|
+
res.status(400).json({ error: 'Missing organizationId' });
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const success = await registry.unregister(organizationId);
|
|
103
|
+
res.json({ success, message: success ? 'Unregistered successfully' : 'Organization not found' });
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
107
|
+
console.error('Unregister error:', error);
|
|
108
|
+
res.status(500).json({ error: 'Unregister failed', message });
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
// Stats endpoint (admin)
|
|
112
|
+
this.app.get('/stats', async (req, res) => {
|
|
113
|
+
try {
|
|
114
|
+
const registry = this.plugin.getRegistry();
|
|
115
|
+
if (!registry) {
|
|
116
|
+
res.status(501).json({ error: 'Multi-tenant not enabled' });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const stats = await registry.getStats();
|
|
120
|
+
res.json(stats);
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
124
|
+
res.status(500).json({ error: message });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
// Manifest endpoint
|
|
129
|
+
this.app.get('/manifest.json', (req, res) => {
|
|
130
|
+
try {
|
|
131
|
+
const endpoint = this.getBaseUrl();
|
|
132
|
+
const manifest = this.plugin.generateManifest({ endpoint });
|
|
133
|
+
res.json(manifest);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
137
|
+
res.status(500).json({ error: message });
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
// Transform endpoints
|
|
141
|
+
const allTransforms = this.plugin.getAllTransforms();
|
|
142
|
+
for (const transform of allTransforms) {
|
|
143
|
+
this.app.post(`/${transform.id}`, async (req, res) => {
|
|
144
|
+
try {
|
|
145
|
+
await this.handleTransform(transform.id, req, res);
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
149
|
+
console.error(`Transform ${transform.id} error:`, error);
|
|
150
|
+
res.status(500).json({
|
|
151
|
+
error: 'Transform execution failed',
|
|
152
|
+
message,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
// 404 handler
|
|
158
|
+
this.app.use((req, res) => {
|
|
159
|
+
res.status(404).json({
|
|
160
|
+
error: 'Not found',
|
|
161
|
+
path: req.path,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Handler per transform
|
|
167
|
+
*/
|
|
168
|
+
async handleTransform(transformId, req, res) {
|
|
169
|
+
const body = req.body;
|
|
170
|
+
if (!body.input) {
|
|
171
|
+
res.status(400).json({ error: 'Missing input' });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
// Estrai organization ID dall'header (per multi-tenancy)
|
|
175
|
+
const organizationId = req.headers['x-organization-id'];
|
|
176
|
+
// Se il plugin è multi-tenant, organizationId è obbligatorio
|
|
177
|
+
if (this.plugin.isMultiTenant() && !organizationId) {
|
|
178
|
+
res.status(400).json({ error: 'Missing X-Organization-Id header for multi-tenant plugin' });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
// Aggiungi organizationId all'input
|
|
182
|
+
if (organizationId) {
|
|
183
|
+
body.input.organizationId = organizationId;
|
|
184
|
+
}
|
|
185
|
+
const isAsync = this.plugin.isAsyncTransform(transformId);
|
|
186
|
+
if (isAsync) {
|
|
187
|
+
// Transform asincrona
|
|
188
|
+
if (!body.callbackUrl) {
|
|
189
|
+
res.status(400).json({ error: 'Missing callbackUrl for async transform' });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const result = await this.plugin.executeAsyncTransform(transformId, body.input, body.callbackUrl, organizationId);
|
|
193
|
+
const response = {
|
|
194
|
+
async: true,
|
|
195
|
+
jobId: result.jobId,
|
|
196
|
+
estimatedTime: result.estimatedTime,
|
|
197
|
+
message: 'Job queued for processing',
|
|
198
|
+
};
|
|
199
|
+
res.json(response);
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
// Transform sincrona
|
|
203
|
+
const result = await this.plugin.executeTransform(transformId, body.input);
|
|
204
|
+
const response = {
|
|
205
|
+
async: false,
|
|
206
|
+
result,
|
|
207
|
+
};
|
|
208
|
+
res.json(response);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Ottieni base URL del server
|
|
213
|
+
*/
|
|
214
|
+
getBaseUrl() {
|
|
215
|
+
const protocol = this.options.https ? 'https' : 'http';
|
|
216
|
+
const host = this.options.host || 'localhost';
|
|
217
|
+
const port = this.options.port;
|
|
218
|
+
return `${protocol}://${host}:${port}`;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Avvia il server
|
|
222
|
+
*/
|
|
223
|
+
async start() {
|
|
224
|
+
return new Promise((resolve, reject) => {
|
|
225
|
+
try {
|
|
226
|
+
if (this.options.https) {
|
|
227
|
+
// HTTPS server
|
|
228
|
+
const httpsOptions = {
|
|
229
|
+
key: fs_1.default.readFileSync(this.options.https.key),
|
|
230
|
+
cert: fs_1.default.readFileSync(this.options.https.cert),
|
|
231
|
+
};
|
|
232
|
+
this.server = https_1.default.createServer(httpsOptions, this.app);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
// HTTP server
|
|
236
|
+
this.server = this.app.listen(this.options.port, this.options.host || '0.0.0.0');
|
|
237
|
+
}
|
|
238
|
+
this.server.listen(this.options.port, this.options.host || '0.0.0.0', () => {
|
|
239
|
+
console.log(`🚀 Server listening on ${this.getBaseUrl()}`);
|
|
240
|
+
resolve();
|
|
241
|
+
});
|
|
242
|
+
this.server.on('error', (error) => {
|
|
243
|
+
console.error('Server error:', error);
|
|
244
|
+
reject(error);
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
reject(error);
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Ferma il server
|
|
254
|
+
*/
|
|
255
|
+
async stop() {
|
|
256
|
+
return new Promise((resolve, reject) => {
|
|
257
|
+
if (!this.server) {
|
|
258
|
+
resolve();
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
this.server.close((err) => {
|
|
262
|
+
if (err) {
|
|
263
|
+
reject(err);
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
console.log('✅ Server stopped');
|
|
267
|
+
resolve();
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Ottieni Express app (per customizzazione)
|
|
274
|
+
*/
|
|
275
|
+
getApp() {
|
|
276
|
+
return this.app;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
exports.ExpressServer = ExpressServer;
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@relazio/plugin-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official SDK for building external plugins for Relazio",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"dev": "tsc --watch",
|
|
10
|
+
"prepublishOnly": "npm run build",
|
|
11
|
+
"test": "vitest",
|
|
12
|
+
"lint": "eslint src --ext .ts"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"relazio",
|
|
16
|
+
"osint",
|
|
17
|
+
"plugin",
|
|
18
|
+
"sdk",
|
|
19
|
+
"external-plugin"
|
|
20
|
+
],
|
|
21
|
+
"author": "Relazio Team",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/relazio/plugin-sdk.git"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"express": "^4.18.2",
|
|
37
|
+
"zod": "^3.22.4"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/express": "^4.17.21",
|
|
41
|
+
"@types/node": "^20.10.6",
|
|
42
|
+
"@typescript-eslint/eslint-plugin": "^6.17.0",
|
|
43
|
+
"@typescript-eslint/parser": "^6.17.0",
|
|
44
|
+
"eslint": "^8.56.0",
|
|
45
|
+
"typescript": "^5.3.3",
|
|
46
|
+
"vitest": "^1.1.0"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=18.0.0"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|