@msssystems/mss-link-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 +24 -0
- package/README.md +64 -0
- package/dist/adapters/express/create-control-router.d.ts +3 -0
- package/dist/adapters/express/create-control-router.js +47 -0
- package/dist/adapters/express/index.d.ts +1 -0
- package/dist/adapters/express/index.js +1 -0
- package/dist/adapters/fastify/create-control-plugin.d.ts +2 -0
- package/dist/adapters/fastify/create-control-plugin.js +28 -0
- package/dist/adapters/fastify/index.d.ts +1 -0
- package/dist/adapters/fastify/index.js +1 -0
- package/dist/adapters/nestjs/create-control-controller.d.ts +30 -0
- package/dist/adapters/nestjs/create-control-controller.js +92 -0
- package/dist/adapters/nestjs/create-control-module.d.ts +5 -0
- package/dist/adapters/nestjs/create-control-module.js +27 -0
- package/dist/adapters/nestjs/index.d.ts +3 -0
- package/dist/adapters/nestjs/index.js +3 -0
- package/dist/adapters/nestjs/nest-control-adapter.d.ts +8 -0
- package/dist/adapters/nestjs/nest-control-adapter.js +12 -0
- package/dist/contracts/capabilities.contract.d.ts +8 -0
- package/dist/contracts/capabilities.contract.js +1 -0
- package/dist/contracts/commands.contract.d.ts +31 -0
- package/dist/contracts/commands.contract.js +1 -0
- package/dist/contracts/health.contract.d.ts +6 -0
- package/dist/contracts/health.contract.js +1 -0
- package/dist/control/adapter-context.d.ts +7 -0
- package/dist/control/adapter-context.js +1 -0
- package/dist/control/capabilities.d.ts +3 -0
- package/dist/control/capabilities.js +23 -0
- package/dist/control/command-registry.d.ts +23 -0
- package/dist/control/command-registry.js +12 -0
- package/dist/control/command-types.d.ts +1 -0
- package/dist/control/command-types.js +1 -0
- package/dist/control/commands.d.ts +20 -0
- package/dist/control/commands.js +67 -0
- package/dist/control/health.d.ts +3 -0
- package/dist/control/health.js +8 -0
- package/dist/control/index.d.ts +6 -0
- package/dist/control/index.js +6 -0
- package/dist/errors/control-errors.d.ts +6 -0
- package/dist/errors/control-errors.js +12 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/package.json +88 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org/>
|
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# @msssystems/mss-link-sdk
|
|
2
|
+
|
|
3
|
+
Official managed application SDK for the MSS ecosystem. Enables target applications (NestJS, Express, Fastify) to seamlessly register control capabilities and handle administration commands from the MSS Admin Panel.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Standard Health and Capabilities Handshakes**: Exposes unified endpoints under `/control/v1/*`.
|
|
8
|
+
- **Command Preview & Dry-Run**: Abstracts command validation before execution.
|
|
9
|
+
- **Typed Contracts**: Standard schemas for capabilities and health data.
|
|
10
|
+
- **Extensible Adapters**: Built-in modules and routers for NestJS, Express, and Fastify.
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
yarn add @msssystems/mss-link-sdk
|
|
16
|
+
# or
|
|
17
|
+
npm install @msssystems/mss-link-sdk
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## NestJS Adapter Usage
|
|
21
|
+
|
|
22
|
+
1. **Register Command Handlers**:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { MssCommandRegistry } from '@msssystems/mss-link-sdk/control';
|
|
26
|
+
|
|
27
|
+
export const commandRegistry = new MssCommandRegistry();
|
|
28
|
+
|
|
29
|
+
commandRegistry.register('REVOKE_SESSION', {
|
|
30
|
+
async preview(payload) {
|
|
31
|
+
return { allowed: true };
|
|
32
|
+
},
|
|
33
|
+
async dryRun(payload) {
|
|
34
|
+
return { success: true };
|
|
35
|
+
},
|
|
36
|
+
async execute(payload) {
|
|
37
|
+
// logic to revoke session
|
|
38
|
+
return { status: 'completed' };
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
2. **Import Control Module in AppModule**:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { Module } from '@nestjs/common';
|
|
47
|
+
import { ControlModule } from '@msssystems/mss-link-sdk/adapters/nestjs';
|
|
48
|
+
import { commandRegistry } from './control-registry';
|
|
49
|
+
|
|
50
|
+
@Module({
|
|
51
|
+
imports: [
|
|
52
|
+
ControlModule.register({
|
|
53
|
+
serviceName: 'mss-link.web',
|
|
54
|
+
authMode: 'control',
|
|
55
|
+
commandsRegistry: commandRegistry,
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
})
|
|
59
|
+
export class AppModule {}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
UNLICENSED
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { createCapabilitiesResponse } from '../../control/capabilities';
|
|
3
|
+
import { createControlHealthResponse } from '../../control/health';
|
|
4
|
+
import { createCommandPreviewHandler, createCommandDryRunHandler, createCommandExecuteHandler, } from '../../control/commands';
|
|
5
|
+
export function createControlRouter(config) {
|
|
6
|
+
const router = Router();
|
|
7
|
+
router.get('/health', (req, res) => {
|
|
8
|
+
res.json(createControlHealthResponse(config));
|
|
9
|
+
});
|
|
10
|
+
router.get('/capabilities', (req, res) => {
|
|
11
|
+
res.json(createCapabilitiesResponse(config));
|
|
12
|
+
});
|
|
13
|
+
router.post('/commands/preview', async (req, res, next) => {
|
|
14
|
+
try {
|
|
15
|
+
const result = await createCommandPreviewHandler(config.commandsRegistry, req.body.command_type, req.body.payload);
|
|
16
|
+
res.json(result);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
next(error);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
router.post('/commands/dry-run', async (req, res, next) => {
|
|
23
|
+
try {
|
|
24
|
+
const result = await createCommandDryRunHandler(config.commandsRegistry, req.body.command_type, req.body.payload);
|
|
25
|
+
res.json(result);
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
next(error);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
router.post('/commands/execute', async (req, res, next) => {
|
|
32
|
+
try {
|
|
33
|
+
const result = await createCommandExecuteHandler(config.commandsRegistry, req.body.command_type, req.body.payload);
|
|
34
|
+
res.json(result);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
next(error);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
router.get('/commands/:id', (req, res) => {
|
|
41
|
+
res.json({
|
|
42
|
+
command_id: req.params.id,
|
|
43
|
+
status: 'completed',
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
return router;
|
|
47
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './create-control-router';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './create-control-router';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createCapabilitiesResponse } from '../../control/capabilities';
|
|
2
|
+
import { createControlHealthResponse } from '../../control/health';
|
|
3
|
+
import { createCommandPreviewHandler, createCommandDryRunHandler, createCommandExecuteHandler, } from '../../control/commands';
|
|
4
|
+
export function createControlFastifyPlugin(config) {
|
|
5
|
+
return async function (fastify) {
|
|
6
|
+
fastify.get('/health', async () => {
|
|
7
|
+
return createControlHealthResponse(config);
|
|
8
|
+
});
|
|
9
|
+
fastify.get('/capabilities', async () => {
|
|
10
|
+
return createCapabilitiesResponse(config);
|
|
11
|
+
});
|
|
12
|
+
fastify.post('/commands/preview', async (request) => {
|
|
13
|
+
return createCommandPreviewHandler(config.commandsRegistry, request.body.command_type, request.body.payload);
|
|
14
|
+
});
|
|
15
|
+
fastify.post('/commands/dry-run', async (request) => {
|
|
16
|
+
return createCommandDryRunHandler(config.commandsRegistry, request.body.command_type, request.body.payload);
|
|
17
|
+
});
|
|
18
|
+
fastify.post('/commands/execute', async (request) => {
|
|
19
|
+
return createCommandExecuteHandler(config.commandsRegistry, request.body.command_type, request.body.payload);
|
|
20
|
+
});
|
|
21
|
+
fastify.get('/commands/:id', async (request) => {
|
|
22
|
+
return {
|
|
23
|
+
command_id: request.params.id,
|
|
24
|
+
status: 'completed',
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './create-control-plugin';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './create-control-plugin';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { MssAdapterConfig } from '../../control/adapter-context';
|
|
2
|
+
export declare class BaseControlController {
|
|
3
|
+
protected readonly config: MssAdapterConfig;
|
|
4
|
+
constructor(config: MssAdapterConfig);
|
|
5
|
+
health(): import("../..").MssControlHealth;
|
|
6
|
+
capabilities(): import("../..").MssCapabilities;
|
|
7
|
+
preview(body: any): Promise<{
|
|
8
|
+
command_type: string;
|
|
9
|
+
allowed: boolean;
|
|
10
|
+
reason: string | undefined;
|
|
11
|
+
details: any;
|
|
12
|
+
}>;
|
|
13
|
+
dryRun(body: any): Promise<{
|
|
14
|
+
command_type: string;
|
|
15
|
+
success: boolean;
|
|
16
|
+
validation_errors: string[] | undefined;
|
|
17
|
+
impact_preview: any;
|
|
18
|
+
}>;
|
|
19
|
+
execute(body: any): Promise<{
|
|
20
|
+
command_id: `${string}-${string}-${string}-${string}-${string}`;
|
|
21
|
+
command_type: string;
|
|
22
|
+
status: "completed" | "failed" | "pending";
|
|
23
|
+
error: string | undefined;
|
|
24
|
+
result: any;
|
|
25
|
+
}>;
|
|
26
|
+
getCommand(id: string): Promise<{
|
|
27
|
+
command_id: string;
|
|
28
|
+
status: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
11
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
12
|
+
};
|
|
13
|
+
import { Controller, Get, Post, Body, Param, HttpCode, Inject, HttpStatus } from '@nestjs/common';
|
|
14
|
+
import { createCapabilitiesResponse } from '../../control/capabilities';
|
|
15
|
+
import { createControlHealthResponse } from '../../control/health';
|
|
16
|
+
import { createCommandPreviewHandler, createCommandDryRunHandler, createCommandExecuteHandler, } from '../../control/commands';
|
|
17
|
+
let BaseControlController = class BaseControlController {
|
|
18
|
+
config;
|
|
19
|
+
constructor(config) {
|
|
20
|
+
this.config = config;
|
|
21
|
+
}
|
|
22
|
+
health() {
|
|
23
|
+
return createControlHealthResponse(this.config);
|
|
24
|
+
}
|
|
25
|
+
capabilities() {
|
|
26
|
+
return createCapabilitiesResponse(this.config);
|
|
27
|
+
}
|
|
28
|
+
async preview(body) {
|
|
29
|
+
return createCommandPreviewHandler(this.config.commandsRegistry, body.command_type, body.payload);
|
|
30
|
+
}
|
|
31
|
+
async dryRun(body) {
|
|
32
|
+
return createCommandDryRunHandler(this.config.commandsRegistry, body.command_type, body.payload);
|
|
33
|
+
}
|
|
34
|
+
async execute(body) {
|
|
35
|
+
return createCommandExecuteHandler(this.config.commandsRegistry, body.command_type, body.payload);
|
|
36
|
+
}
|
|
37
|
+
async getCommand(id) {
|
|
38
|
+
return {
|
|
39
|
+
command_id: id,
|
|
40
|
+
status: 'completed',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
__decorate([
|
|
45
|
+
Get('health'),
|
|
46
|
+
__metadata("design:type", Function),
|
|
47
|
+
__metadata("design:paramtypes", []),
|
|
48
|
+
__metadata("design:returntype", void 0)
|
|
49
|
+
], BaseControlController.prototype, "health", null);
|
|
50
|
+
__decorate([
|
|
51
|
+
Get('capabilities'),
|
|
52
|
+
__metadata("design:type", Function),
|
|
53
|
+
__metadata("design:paramtypes", []),
|
|
54
|
+
__metadata("design:returntype", void 0)
|
|
55
|
+
], BaseControlController.prototype, "capabilities", null);
|
|
56
|
+
__decorate([
|
|
57
|
+
Post('commands/preview'),
|
|
58
|
+
HttpCode(HttpStatus.OK),
|
|
59
|
+
__param(0, Body()),
|
|
60
|
+
__metadata("design:type", Function),
|
|
61
|
+
__metadata("design:paramtypes", [Object]),
|
|
62
|
+
__metadata("design:returntype", Promise)
|
|
63
|
+
], BaseControlController.prototype, "preview", null);
|
|
64
|
+
__decorate([
|
|
65
|
+
Post('commands/dry-run'),
|
|
66
|
+
HttpCode(HttpStatus.OK),
|
|
67
|
+
__param(0, Body()),
|
|
68
|
+
__metadata("design:type", Function),
|
|
69
|
+
__metadata("design:paramtypes", [Object]),
|
|
70
|
+
__metadata("design:returntype", Promise)
|
|
71
|
+
], BaseControlController.prototype, "dryRun", null);
|
|
72
|
+
__decorate([
|
|
73
|
+
Post('commands/execute'),
|
|
74
|
+
HttpCode(HttpStatus.OK),
|
|
75
|
+
__param(0, Body()),
|
|
76
|
+
__metadata("design:type", Function),
|
|
77
|
+
__metadata("design:paramtypes", [Object]),
|
|
78
|
+
__metadata("design:returntype", Promise)
|
|
79
|
+
], BaseControlController.prototype, "execute", null);
|
|
80
|
+
__decorate([
|
|
81
|
+
Get('commands/:id'),
|
|
82
|
+
__param(0, Param('id')),
|
|
83
|
+
__metadata("design:type", Function),
|
|
84
|
+
__metadata("design:paramtypes", [String]),
|
|
85
|
+
__metadata("design:returntype", Promise)
|
|
86
|
+
], BaseControlController.prototype, "getCommand", null);
|
|
87
|
+
BaseControlController = __decorate([
|
|
88
|
+
Controller('control/v1'),
|
|
89
|
+
__param(0, Inject('MSS_CONTROL_CONFIG')),
|
|
90
|
+
__metadata("design:paramtypes", [Object])
|
|
91
|
+
], BaseControlController);
|
|
92
|
+
export { BaseControlController };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var ControlModule_1;
|
|
8
|
+
import { Module } from '@nestjs/common';
|
|
9
|
+
import { BaseControlController } from './create-control-controller';
|
|
10
|
+
let ControlModule = ControlModule_1 = class ControlModule {
|
|
11
|
+
static register(config) {
|
|
12
|
+
const configProvider = {
|
|
13
|
+
provide: 'MSS_CONTROL_CONFIG',
|
|
14
|
+
useValue: config,
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
module: ControlModule_1,
|
|
18
|
+
controllers: [BaseControlController],
|
|
19
|
+
providers: [configProvider],
|
|
20
|
+
exports: [configProvider],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
ControlModule = ControlModule_1 = __decorate([
|
|
25
|
+
Module({})
|
|
26
|
+
], ControlModule);
|
|
27
|
+
export { ControlModule };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { MssAdapterConfig } from '../../control/adapter-context';
|
|
2
|
+
import { MssCommandRegistry } from '../../control/command-registry';
|
|
3
|
+
export declare class NestControlAdapter {
|
|
4
|
+
private readonly config;
|
|
5
|
+
constructor(config: MssAdapterConfig);
|
|
6
|
+
getConfig(): MssAdapterConfig;
|
|
7
|
+
getRegistry(): MssCommandRegistry | undefined;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface MssCommandPreviewRequest {
|
|
2
|
+
command_type: string;
|
|
3
|
+
payload: Record<string, any>;
|
|
4
|
+
}
|
|
5
|
+
export interface MssCommandPreviewResponse {
|
|
6
|
+
command_type: string;
|
|
7
|
+
allowed: boolean;
|
|
8
|
+
reason?: string;
|
|
9
|
+
details?: Record<string, any>;
|
|
10
|
+
}
|
|
11
|
+
export interface MssCommandDryRunRequest {
|
|
12
|
+
command_type: string;
|
|
13
|
+
payload: Record<string, any>;
|
|
14
|
+
}
|
|
15
|
+
export interface MssCommandDryRunResponse {
|
|
16
|
+
command_type: string;
|
|
17
|
+
success: boolean;
|
|
18
|
+
validation_errors?: string[];
|
|
19
|
+
impact_preview?: Record<string, any>;
|
|
20
|
+
}
|
|
21
|
+
export interface MssCommandExecuteRequest {
|
|
22
|
+
command_type: string;
|
|
23
|
+
payload: Record<string, any>;
|
|
24
|
+
}
|
|
25
|
+
export interface MssCommandExecuteResponse {
|
|
26
|
+
command_id: string;
|
|
27
|
+
command_type: string;
|
|
28
|
+
status: 'completed' | 'failed' | 'pending';
|
|
29
|
+
error?: string;
|
|
30
|
+
result?: Record<string, any>;
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function createCapabilitiesResponse(config) {
|
|
2
|
+
const supported_commands = config.commandsRegistry
|
|
3
|
+
? config.commandsRegistry.getSupportedCommands()
|
|
4
|
+
: [];
|
|
5
|
+
const defaultCapabilities = [
|
|
6
|
+
'overview',
|
|
7
|
+
'accounts',
|
|
8
|
+
'storage',
|
|
9
|
+
'departments',
|
|
10
|
+
'invites',
|
|
11
|
+
'sessions',
|
|
12
|
+
'abuse',
|
|
13
|
+
'onboarding',
|
|
14
|
+
];
|
|
15
|
+
return {
|
|
16
|
+
service: config.serviceName,
|
|
17
|
+
protocol_version: 'v1',
|
|
18
|
+
auth_mode: config.authMode,
|
|
19
|
+
root_admin: null,
|
|
20
|
+
capabilities: config.capabilities ?? defaultCapabilities,
|
|
21
|
+
supported_commands,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface MssCommandHandler {
|
|
2
|
+
preview(payload: any): Promise<{
|
|
3
|
+
allowed: boolean;
|
|
4
|
+
reason?: string;
|
|
5
|
+
details?: any;
|
|
6
|
+
}>;
|
|
7
|
+
dryRun(payload: any): Promise<{
|
|
8
|
+
success: boolean;
|
|
9
|
+
validation_errors?: string[];
|
|
10
|
+
impact_preview?: any;
|
|
11
|
+
}>;
|
|
12
|
+
execute(payload: any): Promise<{
|
|
13
|
+
status: 'completed' | 'failed' | 'pending';
|
|
14
|
+
error?: string;
|
|
15
|
+
result?: any;
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export declare class MssCommandRegistry {
|
|
19
|
+
private handlers;
|
|
20
|
+
register(commandType: string, handler: MssCommandHandler): void;
|
|
21
|
+
getHandler(commandType: string): MssCommandHandler | undefined;
|
|
22
|
+
getSupportedCommands(): string[];
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class MssCommandRegistry {
|
|
2
|
+
handlers = new Map();
|
|
3
|
+
register(commandType, handler) {
|
|
4
|
+
this.handlers.set(commandType, handler);
|
|
5
|
+
}
|
|
6
|
+
getHandler(commandType) {
|
|
7
|
+
return this.handlers.get(commandType);
|
|
8
|
+
}
|
|
9
|
+
getSupportedCommands() {
|
|
10
|
+
return Array.from(this.handlers.keys());
|
|
11
|
+
}
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type MssCommandType = 'REVOKE_SESSION' | 'REVOKE_DEVICE' | 'APPLY_QUOTAS' | 'MANUAL_ABUSE_ACTION';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { MssCommandRegistry } from './command-registry';
|
|
2
|
+
export declare function createCommandPreviewHandler(registry: MssCommandRegistry | undefined, commandType: string, payload: any): Promise<{
|
|
3
|
+
command_type: string;
|
|
4
|
+
allowed: boolean;
|
|
5
|
+
reason: string | undefined;
|
|
6
|
+
details: any;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function createCommandDryRunHandler(registry: MssCommandRegistry | undefined, commandType: string, payload: any): Promise<{
|
|
9
|
+
command_type: string;
|
|
10
|
+
success: boolean;
|
|
11
|
+
validation_errors: string[] | undefined;
|
|
12
|
+
impact_preview: any;
|
|
13
|
+
}>;
|
|
14
|
+
export declare function createCommandExecuteHandler(registry: MssCommandRegistry | undefined, commandType: string, payload: any): Promise<{
|
|
15
|
+
command_id: `${string}-${string}-${string}-${string}-${string}`;
|
|
16
|
+
command_type: string;
|
|
17
|
+
status: "completed" | "failed" | "pending";
|
|
18
|
+
error: string | undefined;
|
|
19
|
+
result: any;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { MssControlError } from '../errors/control-errors';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
export async function createCommandPreviewHandler(registry, commandType, payload) {
|
|
4
|
+
if (!registry) {
|
|
5
|
+
throw new MssControlError('COMMANDS_NOT_CONFIGURED', 'Command handlers are not configured', 501);
|
|
6
|
+
}
|
|
7
|
+
const handler = registry.getHandler(commandType);
|
|
8
|
+
if (!handler) {
|
|
9
|
+
throw new MssControlError('COMMAND_NOT_SUPPORTED', `Command ${commandType} is not supported`, 404);
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const result = await handler.preview(payload);
|
|
13
|
+
return {
|
|
14
|
+
command_type: commandType,
|
|
15
|
+
allowed: result.allowed,
|
|
16
|
+
reason: result.reason,
|
|
17
|
+
details: result.details,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
catch (error) {
|
|
21
|
+
throw new MssControlError('PREVIEW_FAILED', error.message || 'Preview failed', 500);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export async function createCommandDryRunHandler(registry, commandType, payload) {
|
|
25
|
+
if (!registry) {
|
|
26
|
+
throw new MssControlError('COMMANDS_NOT_CONFIGURED', 'Command handlers are not configured', 501);
|
|
27
|
+
}
|
|
28
|
+
const handler = registry.getHandler(commandType);
|
|
29
|
+
if (!handler) {
|
|
30
|
+
throw new MssControlError('COMMAND_NOT_SUPPORTED', `Command ${commandType} is not supported`, 404);
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
const result = await handler.dryRun(payload);
|
|
34
|
+
return {
|
|
35
|
+
command_type: commandType,
|
|
36
|
+
success: result.success,
|
|
37
|
+
validation_errors: result.validation_errors,
|
|
38
|
+
impact_preview: result.impact_preview,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
throw new MssControlError('DRY_RUN_FAILED', error.message || 'Dry run failed', 500);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export async function createCommandExecuteHandler(registry, commandType, payload) {
|
|
46
|
+
if (!registry) {
|
|
47
|
+
throw new MssControlError('COMMANDS_NOT_CONFIGURED', 'Command handlers are not configured', 501);
|
|
48
|
+
}
|
|
49
|
+
const handler = registry.getHandler(commandType);
|
|
50
|
+
if (!handler) {
|
|
51
|
+
throw new MssControlError('COMMAND_NOT_SUPPORTED', `Command ${commandType} is not supported`, 404);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const result = await handler.execute(payload);
|
|
55
|
+
const commandId = randomUUID();
|
|
56
|
+
return {
|
|
57
|
+
command_id: commandId,
|
|
58
|
+
command_type: commandType,
|
|
59
|
+
status: result.status,
|
|
60
|
+
error: result.error,
|
|
61
|
+
result: result.result,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
throw new MssControlError('EXECUTION_FAILED', error.message || 'Execution failed', 500);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export class MssControlError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
status;
|
|
4
|
+
details;
|
|
5
|
+
constructor(code, message, status = 400, details) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.details = details;
|
|
10
|
+
this.name = 'MssControlError';
|
|
11
|
+
}
|
|
12
|
+
}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@msssystems/mss-link-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official managed application SDK for MSS ecosystem",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./control": {
|
|
14
|
+
"types": "./dist/control/index.d.ts",
|
|
15
|
+
"import": "./dist/control/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./adapters/nestjs": {
|
|
18
|
+
"types": "./dist/adapters/nestjs/index.d.ts",
|
|
19
|
+
"import": "./dist/adapters/nestjs/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./adapters/express": {
|
|
22
|
+
"types": "./dist/adapters/express/index.d.ts",
|
|
23
|
+
"import": "./dist/adapters/express/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./adapters/fastify": {
|
|
26
|
+
"types": "./dist/adapters/fastify/index.d.ts",
|
|
27
|
+
"import": "./dist/adapters/fastify/index.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"clean": "rimraf dist",
|
|
37
|
+
"build": "yarn clean && tsc -p tsconfig.json",
|
|
38
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
39
|
+
"pack:check": "node scripts/verify-package-contents.mjs",
|
|
40
|
+
"release:check-tag": "node scripts/verify-release-tag.mjs",
|
|
41
|
+
"release:check-npm-version": "node scripts/verify-npm-version.mjs",
|
|
42
|
+
"prepack": "yarn build && yarn pack:check",
|
|
43
|
+
"prepublishOnly": "yarn build",
|
|
44
|
+
"bundle-ctx": "repomix"
|
|
45
|
+
},
|
|
46
|
+
"license": "UNLICENSED",
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public",
|
|
49
|
+
"registry": "https://registry.npmjs.org/"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
53
|
+
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
54
|
+
"express": "^4.0.0 || ^5.0.0",
|
|
55
|
+
"rxjs": "^7.0.0"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"@nestjs/common": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"@nestjs/core": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"express": {
|
|
65
|
+
"optional": true
|
|
66
|
+
},
|
|
67
|
+
"rxjs": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"devDependencies": {
|
|
72
|
+
"@nestjs/common": "^11.0.1",
|
|
73
|
+
"@nestjs/core": "^11.0.1",
|
|
74
|
+
"@types/express": "^5.0.0",
|
|
75
|
+
"@types/node": "^20.0.0",
|
|
76
|
+
"express": "^4.21.2",
|
|
77
|
+
"rimraf": "^6.0.1",
|
|
78
|
+
"rxjs": "^7.8.1",
|
|
79
|
+
"typescript": "^5.6.3"
|
|
80
|
+
},
|
|
81
|
+
"engines": {
|
|
82
|
+
"node": ">=20.0.0"
|
|
83
|
+
},
|
|
84
|
+
"packageManager": "yarn@4.14.1",
|
|
85
|
+
"dependencies": {
|
|
86
|
+
"repomix": "^1.14.1"
|
|
87
|
+
}
|
|
88
|
+
}
|