@ensera/plugin-backend 1.0.0 → 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/index.d.ts +20 -2
- package/dist/index.js +97 -0
- package/package.json +54 -54
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Request, Response, NextFunction } from 'express';
|
|
1
|
+
import { Request, Response, NextFunction, Express } from 'express';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Plugin scope extracted from JWT token
|
|
@@ -373,4 +373,22 @@ declare function toDateString(date: string | Date | null | undefined): string |
|
|
|
373
373
|
*/
|
|
374
374
|
declare function buildDateTime(dateValue: string | Date | null | undefined, timeValue: string | null | undefined, defaultHour?: number, defaultMinute?: number): Date | null;
|
|
375
375
|
|
|
376
|
-
|
|
376
|
+
declare function withCoreServiceToken(handler: (req: Request, res: Response, next: NextFunction) => unknown): (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
377
|
+
|
|
378
|
+
type CoreRequestContext = {
|
|
379
|
+
workspaceId: string;
|
|
380
|
+
spaceId: string;
|
|
381
|
+
userId: string;
|
|
382
|
+
taskScopeId?: string;
|
|
383
|
+
requestId: string;
|
|
384
|
+
};
|
|
385
|
+
type CommandHandler = (input: Record<string, unknown>, context: CoreRequestContext) => Promise<unknown>;
|
|
386
|
+
type CommandRegistry = {
|
|
387
|
+
register: (name: string, handler: CommandHandler) => void;
|
|
388
|
+
get: (name: string) => CommandHandler | undefined;
|
|
389
|
+
list: () => string[];
|
|
390
|
+
};
|
|
391
|
+
declare function createCommandRegistry(): CommandRegistry;
|
|
392
|
+
declare function createCoreRouter(app: Express, registry: CommandRegistry): void;
|
|
393
|
+
|
|
394
|
+
export { type BackendNotification, type CommandHandler, type CommandRegistry, type CoreRequestContext, type JsonObject, type JsonValue, type NotificationAction, type NotificationApiPayload, type NotificationBulkApiPayload, type NotificationBulkResponse, type NotificationCancelResponse, type NotificationCapabilities, type NotificationOptions, type NotificationPublishResponse, type NotificationPublisher, type NotificationPublisherConfig, type NotificationTypeConfig, type PluginAuthOptions, type PluginContext, PluginError, type PluginErrorResponse, type PluginScope, type RequestWithContext, type ScheduleOptions, assertPluginScope, buildDateTime, calculateScheduleTime, createCommandRegistry, createCoreRouter, createNotificationPublisher, forbidClientInstanceId, formatTime, getPluginScope, isPastDate, pluginAuth, pluginErrorHandler, requireFeature, requirePermission, requireTabView, requireTaskScope, resolveEffectiveInstanceId, toDateString, withCoreServiceToken, withInstanceOnly, withInstanceScope, withUserAndInstance };
|
package/dist/index.js
CHANGED
|
@@ -657,11 +657,107 @@ function buildDateTime(dateValue, timeValue, defaultHour = 9, defaultMinute = 0)
|
|
|
657
657
|
if (isNaN(result.getTime())) return null;
|
|
658
658
|
return result;
|
|
659
659
|
}
|
|
660
|
+
|
|
661
|
+
// src/withCoreServiceToken.ts
|
|
662
|
+
function withCoreServiceToken(handler) {
|
|
663
|
+
return async function coreServiceTokenWrapped(req, res, next) {
|
|
664
|
+
try {
|
|
665
|
+
const authHeader = req.headers.authorization;
|
|
666
|
+
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
667
|
+
const expected = process.env.CORE_SERVICE_TOKEN?.trim();
|
|
668
|
+
if (!expected) {
|
|
669
|
+
throw new PluginError({
|
|
670
|
+
status: 500,
|
|
671
|
+
code: "CORE_SERVICE_TOKEN_NOT_CONFIGURED",
|
|
672
|
+
message: "CORE_SERVICE_TOKEN is not set in environment"
|
|
673
|
+
});
|
|
674
|
+
}
|
|
675
|
+
if (!token || token !== expected) {
|
|
676
|
+
throw new PluginError({
|
|
677
|
+
status: 401,
|
|
678
|
+
code: "INVALID_CORE_SERVICE_TOKEN",
|
|
679
|
+
message: "Unauthorized: invalid or missing Core service token"
|
|
680
|
+
});
|
|
681
|
+
}
|
|
682
|
+
await handler(req, res, next);
|
|
683
|
+
} catch (e) {
|
|
684
|
+
next(e);
|
|
685
|
+
}
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// src/createCommandRegistry.ts
|
|
690
|
+
function createCommandRegistry() {
|
|
691
|
+
const registry = /* @__PURE__ */ new Map();
|
|
692
|
+
return {
|
|
693
|
+
register(name, handler) {
|
|
694
|
+
if (!name || typeof handler !== "function") {
|
|
695
|
+
throw new Error(
|
|
696
|
+
"createCommandRegistry: name and handler are required"
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
registry.set(name, handler);
|
|
700
|
+
},
|
|
701
|
+
get(name) {
|
|
702
|
+
return registry.get(name);
|
|
703
|
+
},
|
|
704
|
+
list() {
|
|
705
|
+
return Array.from(registry.keys());
|
|
706
|
+
}
|
|
707
|
+
};
|
|
708
|
+
}
|
|
709
|
+
function createCoreRouter(app, registry) {
|
|
710
|
+
app.post(
|
|
711
|
+
"/api/core/execute",
|
|
712
|
+
withCoreServiceToken(async (req, res) => {
|
|
713
|
+
const { command, input, context } = req.body ?? {};
|
|
714
|
+
if (!command || typeof command !== "string") {
|
|
715
|
+
return res.status(400).json({
|
|
716
|
+
success: false,
|
|
717
|
+
error: "MISSING_COMMAND",
|
|
718
|
+
message: "Request body must include a command string"
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
if (!context?.workspaceId || !context?.userId) {
|
|
722
|
+
return res.status(400).json({
|
|
723
|
+
success: false,
|
|
724
|
+
error: "MISSING_CONTEXT",
|
|
725
|
+
message: "Request context must include workspaceId and userId"
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
const handler = registry.get(command);
|
|
729
|
+
if (!handler) {
|
|
730
|
+
return res.status(404).json({
|
|
731
|
+
success: false,
|
|
732
|
+
error: "UNKNOWN_COMMAND",
|
|
733
|
+
message: `Command '${command}' is not registered`,
|
|
734
|
+
available: registry.list()
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
try {
|
|
738
|
+
const result = await handler(
|
|
739
|
+
input ?? {},
|
|
740
|
+
context
|
|
741
|
+
);
|
|
742
|
+
return res.json({ success: true, data: result });
|
|
743
|
+
} catch (err) {
|
|
744
|
+
console.error(`[CoreRouter] Command '${command}' failed:`, err);
|
|
745
|
+
return res.status(500).json({
|
|
746
|
+
success: false,
|
|
747
|
+
error: "COMMAND_FAILED",
|
|
748
|
+
message: err?.message ?? "Internal error"
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
})
|
|
752
|
+
);
|
|
753
|
+
}
|
|
660
754
|
export {
|
|
661
755
|
PluginError,
|
|
662
756
|
assertPluginScope,
|
|
663
757
|
buildDateTime,
|
|
664
758
|
calculateScheduleTime,
|
|
759
|
+
createCommandRegistry,
|
|
760
|
+
createCoreRouter,
|
|
665
761
|
createNotificationPublisher,
|
|
666
762
|
forbidClientInstanceId,
|
|
667
763
|
formatTime,
|
|
@@ -675,6 +771,7 @@ export {
|
|
|
675
771
|
requireTaskScope,
|
|
676
772
|
resolveEffectiveInstanceId,
|
|
677
773
|
toDateString,
|
|
774
|
+
withCoreServiceToken,
|
|
678
775
|
withInstanceOnly,
|
|
679
776
|
withInstanceScope,
|
|
680
777
|
withUserAndInstance
|
package/package.json
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@ensera/plugin-backend",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Runtime backend SDK for Ensera plugins.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"files": [
|
|
10
|
-
"dist",
|
|
11
|
-
"README.md"
|
|
12
|
-
],
|
|
13
|
-
"sideEffects": false,
|
|
14
|
-
"scripts": {
|
|
15
|
-
"build": "tsup src/index.ts --format esm --dts --clean --target es2022 --outDir dist",
|
|
16
|
-
"dev": "tsup src/index.ts --format esm --dts --watch --target es2022 --outDir dist",
|
|
17
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
18
|
-
"prepublishOnly": "npm run build && npm run typecheck"
|
|
19
|
-
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
"ensera",
|
|
22
|
-
"backend",
|
|
23
|
-
"sdk",
|
|
24
|
-
"plugin",
|
|
25
|
-
"express"
|
|
26
|
-
],
|
|
27
|
-
"publishConfig": {
|
|
28
|
-
"access": "public"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"jsonwebtoken": "^9.0.0"
|
|
32
|
-
},
|
|
33
|
-
"devDependencies": {
|
|
34
|
-
"@types/express": "^4.17.0",
|
|
35
|
-
"@types/jsonwebtoken": "^9.0.0",
|
|
36
|
-
"tsup": "^8.0.0",
|
|
37
|
-
"typescript": "^5.0.0",
|
|
38
|
-
"jsonwebtoken": "^9.0.0"
|
|
39
|
-
},
|
|
40
|
-
"engines": {
|
|
41
|
-
"node": ">=18"
|
|
42
|
-
},
|
|
43
|
-
"peerDependencies": {
|
|
44
|
-
"express": "^4.18.0",
|
|
45
|
-
"jsonwebtoken": "^9.0.0"
|
|
46
|
-
},
|
|
47
|
-
"exports": {
|
|
48
|
-
".": {
|
|
49
|
-
"types": "./dist/index.d.ts",
|
|
50
|
-
"import": "./dist/index.js"
|
|
51
|
-
},
|
|
52
|
-
"./package.json": "./package.json"
|
|
53
|
-
}
|
|
54
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@ensera/plugin-backend",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "Runtime backend SDK for Ensera plugins.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"sideEffects": false,
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsup src/index.ts --format esm --dts --clean --target es2022 --outDir dist",
|
|
16
|
+
"dev": "tsup src/index.ts --format esm --dts --watch --target es2022 --outDir dist",
|
|
17
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
18
|
+
"prepublishOnly": "npm run build && npm run typecheck"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"ensera",
|
|
22
|
+
"backend",
|
|
23
|
+
"sdk",
|
|
24
|
+
"plugin",
|
|
25
|
+
"express"
|
|
26
|
+
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"jsonwebtoken": "^9.0.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/express": "^4.17.0",
|
|
35
|
+
"@types/jsonwebtoken": "^9.0.0",
|
|
36
|
+
"tsup": "^8.0.0",
|
|
37
|
+
"typescript": "^5.0.0",
|
|
38
|
+
"jsonwebtoken": "^9.0.0"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
},
|
|
43
|
+
"peerDependencies": {
|
|
44
|
+
"express": "^4.18.0",
|
|
45
|
+
"jsonwebtoken": "^9.0.0"
|
|
46
|
+
},
|
|
47
|
+
"exports": {
|
|
48
|
+
".": {
|
|
49
|
+
"types": "./dist/index.d.ts",
|
|
50
|
+
"import": "./dist/index.js"
|
|
51
|
+
},
|
|
52
|
+
"./package.json": "./package.json"
|
|
53
|
+
}
|
|
54
|
+
}
|