@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.
Files changed (43) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +64 -0
  3. package/dist/adapters/express/create-control-router.d.ts +3 -0
  4. package/dist/adapters/express/create-control-router.js +47 -0
  5. package/dist/adapters/express/index.d.ts +1 -0
  6. package/dist/adapters/express/index.js +1 -0
  7. package/dist/adapters/fastify/create-control-plugin.d.ts +2 -0
  8. package/dist/adapters/fastify/create-control-plugin.js +28 -0
  9. package/dist/adapters/fastify/index.d.ts +1 -0
  10. package/dist/adapters/fastify/index.js +1 -0
  11. package/dist/adapters/nestjs/create-control-controller.d.ts +30 -0
  12. package/dist/adapters/nestjs/create-control-controller.js +92 -0
  13. package/dist/adapters/nestjs/create-control-module.d.ts +5 -0
  14. package/dist/adapters/nestjs/create-control-module.js +27 -0
  15. package/dist/adapters/nestjs/index.d.ts +3 -0
  16. package/dist/adapters/nestjs/index.js +3 -0
  17. package/dist/adapters/nestjs/nest-control-adapter.d.ts +8 -0
  18. package/dist/adapters/nestjs/nest-control-adapter.js +12 -0
  19. package/dist/contracts/capabilities.contract.d.ts +8 -0
  20. package/dist/contracts/capabilities.contract.js +1 -0
  21. package/dist/contracts/commands.contract.d.ts +31 -0
  22. package/dist/contracts/commands.contract.js +1 -0
  23. package/dist/contracts/health.contract.d.ts +6 -0
  24. package/dist/contracts/health.contract.js +1 -0
  25. package/dist/control/adapter-context.d.ts +7 -0
  26. package/dist/control/adapter-context.js +1 -0
  27. package/dist/control/capabilities.d.ts +3 -0
  28. package/dist/control/capabilities.js +23 -0
  29. package/dist/control/command-registry.d.ts +23 -0
  30. package/dist/control/command-registry.js +12 -0
  31. package/dist/control/command-types.d.ts +1 -0
  32. package/dist/control/command-types.js +1 -0
  33. package/dist/control/commands.d.ts +20 -0
  34. package/dist/control/commands.js +67 -0
  35. package/dist/control/health.d.ts +3 -0
  36. package/dist/control/health.js +8 -0
  37. package/dist/control/index.d.ts +6 -0
  38. package/dist/control/index.js +6 -0
  39. package/dist/errors/control-errors.d.ts +6 -0
  40. package/dist/errors/control-errors.js +12 -0
  41. package/dist/index.d.ts +5 -0
  42. package/dist/index.js +5 -0
  43. 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,3 @@
1
+ import { Router } from 'express';
2
+ import { MssAdapterConfig } from '../../control/adapter-context';
3
+ export declare function createControlRouter(config: MssAdapterConfig): Router;
@@ -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,2 @@
1
+ import { MssAdapterConfig } from '../../control/adapter-context';
2
+ export declare function createControlFastifyPlugin(config: MssAdapterConfig): (fastify: any) => Promise<void>;
@@ -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,5 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { MssAdapterConfig } from '../../control/adapter-context';
3
+ export declare class ControlModule {
4
+ static register(config: MssAdapterConfig): DynamicModule;
5
+ }
@@ -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,3 @@
1
+ export * from './create-control-controller';
2
+ export * from './create-control-module';
3
+ export * from './nest-control-adapter';
@@ -0,0 +1,3 @@
1
+ export * from './create-control-controller';
2
+ export * from './create-control-module';
3
+ export * from './nest-control-adapter';
@@ -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,12 @@
1
+ export class NestControlAdapter {
2
+ config;
3
+ constructor(config) {
4
+ this.config = config;
5
+ }
6
+ getConfig() {
7
+ return this.config;
8
+ }
9
+ getRegistry() {
10
+ return this.config.commandsRegistry;
11
+ }
12
+ }
@@ -0,0 +1,8 @@
1
+ export interface MssCapabilities {
2
+ service: string;
3
+ protocol_version: string;
4
+ auth_mode: string;
5
+ root_admin: string | null;
6
+ capabilities: string[];
7
+ supported_commands: string[];
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,6 @@
1
+ export interface MssControlHealth {
2
+ ok: boolean;
3
+ service: string;
4
+ status: string;
5
+ protocol_version: string;
6
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ import { MssCommandRegistry } from './command-registry';
2
+ export interface MssAdapterConfig {
3
+ serviceName: string;
4
+ authMode: 'control' | 'legacy';
5
+ capabilities?: string[];
6
+ commandsRegistry?: MssCommandRegistry;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import { MssCapabilities } from '../contracts/capabilities.contract';
2
+ import { MssAdapterConfig } from './adapter-context';
3
+ export declare function createCapabilitiesResponse(config: MssAdapterConfig): MssCapabilities;
@@ -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,3 @@
1
+ import { MssControlHealth } from '../contracts/health.contract';
2
+ import { MssAdapterConfig } from './adapter-context';
3
+ export declare function createControlHealthResponse(config: MssAdapterConfig): MssControlHealth;
@@ -0,0 +1,8 @@
1
+ export function createControlHealthResponse(config) {
2
+ return {
3
+ ok: true,
4
+ service: config.serviceName,
5
+ status: 'healthy',
6
+ protocol_version: 'v1',
7
+ };
8
+ }
@@ -0,0 +1,6 @@
1
+ export * from './capabilities';
2
+ export * from './health';
3
+ export * from './commands';
4
+ export * from './command-registry';
5
+ export * from './command-types';
6
+ export * from './adapter-context';
@@ -0,0 +1,6 @@
1
+ export * from './capabilities';
2
+ export * from './health';
3
+ export * from './commands';
4
+ export * from './command-registry';
5
+ export * from './command-types';
6
+ export * from './adapter-context';
@@ -0,0 +1,6 @@
1
+ export declare class MssControlError extends Error {
2
+ readonly code: string;
3
+ readonly status: number;
4
+ readonly details?: Record<string, any> | undefined;
5
+ constructor(code: string, message: string, status?: number, details?: Record<string, any> | undefined);
6
+ }
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ export * from './control';
2
+ export * from './contracts/capabilities.contract';
3
+ export * from './contracts/commands.contract';
4
+ export * from './contracts/health.contract';
5
+ export * from './errors/control-errors';
package/dist/index.js ADDED
@@ -0,0 +1,5 @@
1
+ export * from './control';
2
+ export * from './contracts/capabilities.contract';
3
+ export * from './contracts/commands.contract';
4
+ export * from './contracts/health.contract';
5
+ export * from './errors/control-errors';
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
+ }