@magek/server 0.0.1

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 (39) hide show
  1. package/dist/index.d.ts +7 -0
  2. package/dist/index.js +95 -0
  3. package/dist/infrastructure/controllers/graphql.d.ts +7 -0
  4. package/dist/infrastructure/controllers/graphql.js +20 -0
  5. package/dist/infrastructure/controllers/health-controller.d.ts +7 -0
  6. package/dist/infrastructure/controllers/health-controller.js +28 -0
  7. package/dist/infrastructure/http.d.ts +8 -0
  8. package/dist/infrastructure/http.js +20 -0
  9. package/dist/infrastructure/scheduler.d.ts +2 -0
  10. package/dist/infrastructure/scheduler.js +25 -0
  11. package/dist/infrastructure/test-helper/local-queries.d.ts +5 -0
  12. package/dist/infrastructure/test-helper/local-queries.js +15 -0
  13. package/dist/infrastructure/test-helper/local-test-helper.d.ts +17 -0
  14. package/dist/infrastructure/test-helper/local-test-helper.js +37 -0
  15. package/dist/infrastructure/websocket-registry.d.ts +27 -0
  16. package/dist/infrastructure/websocket-registry.js +49 -0
  17. package/dist/library/api-adapter.d.ts +13 -0
  18. package/dist/library/api-adapter.js +33 -0
  19. package/dist/library/graphql-adapter.d.ts +11 -0
  20. package/dist/library/graphql-adapter.js +92 -0
  21. package/dist/library/health-adapter.d.ts +9 -0
  22. package/dist/library/health-adapter.js +70 -0
  23. package/dist/library/rocket-adapter.d.ts +2 -0
  24. package/dist/library/rocket-adapter.js +11 -0
  25. package/dist/library/scheduled-adapter.d.ts +6 -0
  26. package/dist/library/scheduled-adapter.js +14 -0
  27. package/dist/library/searcher-adapter.d.ts +17 -0
  28. package/dist/library/searcher-adapter.js +90 -0
  29. package/dist/paths.d.ts +6 -0
  30. package/dist/paths.js +14 -0
  31. package/dist/server.d.ts +44 -0
  32. package/dist/server.js +197 -0
  33. package/dist/services/graphql-service.d.ts +9 -0
  34. package/dist/services/graphql-service.js +15 -0
  35. package/dist/services/health-service.d.ts +7 -0
  36. package/dist/services/health-service.js +12 -0
  37. package/dist/services/index.d.ts +2 -0
  38. package/dist/services/index.js +5 -0
  39. package/package.json +70 -0
@@ -0,0 +1,7 @@
1
+ import { ProviderLibrary } from '@magek/common';
2
+ export * from './paths';
3
+ export * from './services';
4
+ export * from './library/graphql-adapter';
5
+ export { createServer, getWebSocketRegistry, sendWebSocketMessage } from './server';
6
+ export type { ServerOptions } from './server';
7
+ export declare const Provider: () => ProviderLibrary;
package/dist/index.js ADDED
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Provider = exports.sendWebSocketMessage = exports.getWebSocketRegistry = exports.createServer = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const common_1 = require("@magek/common");
6
+ const api_adapter_1 = require("./library/api-adapter");
7
+ const graphql_adapter_1 = require("./library/graphql-adapter");
8
+ const scheduled_adapter_1 = require("./library/scheduled-adapter");
9
+ const health_adapter_1 = require("./library/health-adapter");
10
+ tslib_1.__exportStar(require("./paths"), exports);
11
+ tslib_1.__exportStar(require("./services"), exports);
12
+ tslib_1.__exportStar(require("./library/graphql-adapter"), exports);
13
+ var server_1 = require("./server");
14
+ Object.defineProperty(exports, "createServer", { enumerable: true, get: function () { return server_1.createServer; } });
15
+ Object.defineProperty(exports, "getWebSocketRegistry", { enumerable: true, get: function () { return server_1.getWebSocketRegistry; } });
16
+ Object.defineProperty(exports, "sendWebSocketMessage", { enumerable: true, get: function () { return server_1.sendWebSocketMessage; } });
17
+ const Provider = () => ({
18
+ // ProviderGraphQLLibrary
19
+ graphQL: {
20
+ rawToEnvelope: graphql_adapter_1.rawGraphQLRequestToEnvelope,
21
+ handleResult: api_adapter_1.requestSucceeded,
22
+ },
23
+ // ProviderAPIHandling
24
+ api: {
25
+ requestSucceeded: api_adapter_1.requestSucceeded,
26
+ requestFailed: api_adapter_1.requestFailed,
27
+ healthRequestResult: api_adapter_1.healthRequestResult,
28
+ },
29
+ // ProviderMessagingLibrary
30
+ messaging: {
31
+ sendMessage: async (config, connectionID, data) => {
32
+ // Use the global WebSocket registry for message sending
33
+ const globalRegistry = global.webSocketRegistry;
34
+ if (globalRegistry && typeof globalRegistry.sendMessage === 'function') {
35
+ globalRegistry.sendMessage(connectionID, data);
36
+ }
37
+ else {
38
+ const logger = (0, common_1.getLogger)(config, 'ServerProvider');
39
+ logger.warn(`WebSocket registry not available. Message not sent to connection ${connectionID}`);
40
+ }
41
+ },
42
+ },
43
+ // ScheduledCommandsLibrary
44
+ scheduled: {
45
+ rawToEnvelope: scheduled_adapter_1.rawScheduledInputToEnvelope,
46
+ },
47
+ sensor: {
48
+ databaseEventsHealthDetails: (config) => {
49
+ var _a;
50
+ // Delegate to event store adapter health check if available
51
+ if ((_a = config.eventStoreAdapter) === null || _a === void 0 ? void 0 : _a.healthCheck) {
52
+ return config.eventStoreAdapter.healthCheck.details(config);
53
+ }
54
+ throw new Error('No event store adapter configured for health checks');
55
+ },
56
+ databaseReadModelsHealthDetails: (config) => {
57
+ var _a;
58
+ // Delegate to read model store adapter health check if available
59
+ if ((_a = config.readModelStoreAdapter) === null || _a === void 0 ? void 0 : _a.healthCheck) {
60
+ return config.readModelStoreAdapter.healthCheck.details(config);
61
+ }
62
+ throw new Error('No read model store adapter configured for health checks');
63
+ },
64
+ isDatabaseEventUp: (config) => {
65
+ var _a;
66
+ // Delegate to event store adapter health check if available
67
+ if ((_a = config.eventStoreAdapter) === null || _a === void 0 ? void 0 : _a.healthCheck) {
68
+ return config.eventStoreAdapter.healthCheck.isUp(config);
69
+ }
70
+ return Promise.resolve(false);
71
+ },
72
+ areDatabaseReadModelsUp: (config) => {
73
+ var _a;
74
+ // Delegate to read model store adapter health check if available
75
+ if ((_a = config.readModelStoreAdapter) === null || _a === void 0 ? void 0 : _a.healthCheck) {
76
+ return config.readModelStoreAdapter.healthCheck.isUp(config);
77
+ }
78
+ return Promise.resolve(false);
79
+ },
80
+ databaseUrls: (config) => {
81
+ var _a, _b, _c, _d, _e, _f;
82
+ // Get URLs from both event store and read model store adapters
83
+ const eventUrls = (_c = (_b = (_a = config.eventStoreAdapter) === null || _a === void 0 ? void 0 : _a.healthCheck) === null || _b === void 0 ? void 0 : _b.urls(config)) !== null && _c !== void 0 ? _c : Promise.resolve([]);
84
+ const readModelUrls = (_f = (_e = (_d = config.readModelStoreAdapter) === null || _d === void 0 ? void 0 : _d.healthCheck) === null || _e === void 0 ? void 0 : _e.urls(config)) !== null && _f !== void 0 ? _f : Promise.resolve([]);
85
+ return Promise.all([eventUrls, readModelUrls]).then(([events, readModels]) => [
86
+ ...events,
87
+ ...readModels
88
+ ]);
89
+ },
90
+ isGraphQLFunctionUp: health_adapter_1.isGraphQLFunctionUp,
91
+ graphQLFunctionUrl: health_adapter_1.graphqlFunctionUrl,
92
+ rawRequestToHealthEnvelope: health_adapter_1.rawRequestToSensorHealth,
93
+ },
94
+ });
95
+ exports.Provider = Provider;
@@ -0,0 +1,7 @@
1
+ import { FastifyReply, FastifyRequest } from 'fastify';
2
+ import { GraphQLService } from '../../services';
3
+ export declare class GraphQLController {
4
+ readonly graphQLService: GraphQLService;
5
+ constructor(graphQLService: GraphQLService);
6
+ handleGraphQL(request: FastifyRequest, reply: FastifyReply): Promise<void>;
7
+ }
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphQLController = void 0;
4
+ const http_1 = require("../http");
5
+ class GraphQLController {
6
+ constructor(graphQLService) {
7
+ this.graphQLService = graphQLService;
8
+ }
9
+ async handleGraphQL(request, reply) {
10
+ try {
11
+ const response = await this.graphQLService.handleGraphQLRequest(request);
12
+ reply.status(http_1.HttpCodes.Ok).send(response.result);
13
+ }
14
+ catch (e) {
15
+ await (0, http_1.requestFailed)(e, reply);
16
+ throw e;
17
+ }
18
+ }
19
+ }
20
+ exports.GraphQLController = GraphQLController;
@@ -0,0 +1,7 @@
1
+ import { FastifyReply, FastifyRequest } from 'fastify';
2
+ import { HealthService } from '../../services';
3
+ export declare class HealthController {
4
+ readonly healthService: HealthService;
5
+ constructor(healthService: HealthService);
6
+ handleHealth(request: FastifyRequest, reply: FastifyReply): Promise<void>;
7
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HealthController = void 0;
4
+ const http_1 = require("../http");
5
+ class HealthController {
6
+ constructor(healthService) {
7
+ this.healthService = healthService;
8
+ }
9
+ async handleHealth(request, reply) {
10
+ try {
11
+ const response = await this.healthService.handleHealthRequest(request);
12
+ if (response.status === 'success') {
13
+ reply.status(http_1.HttpCodes.Ok).send(response.result);
14
+ }
15
+ else {
16
+ reply.status(response.code).send({
17
+ title: response.title,
18
+ reason: response.message,
19
+ });
20
+ }
21
+ }
22
+ catch (e) {
23
+ await (0, http_1.requestFailed)(e, reply);
24
+ throw e;
25
+ }
26
+ }
27
+ }
28
+ exports.HealthController = HealthController;
@@ -0,0 +1,8 @@
1
+ import { FastifyReply } from 'fastify';
2
+ export declare enum HttpCodes {
3
+ Ok = 200,
4
+ BadRequest = 400,
5
+ NotAuthorized = 403,
6
+ InternalError = 500
7
+ }
8
+ export declare function requestFailed(error: Error, reply: FastifyReply): Promise<void>;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HttpCodes = void 0;
4
+ exports.requestFailed = requestFailed;
5
+ const common_1 = require("@magek/common");
6
+ var HttpCodes;
7
+ (function (HttpCodes) {
8
+ HttpCodes[HttpCodes["Ok"] = 200] = "Ok";
9
+ HttpCodes[HttpCodes["BadRequest"] = 400] = "BadRequest";
10
+ HttpCodes[HttpCodes["NotAuthorized"] = 403] = "NotAuthorized";
11
+ HttpCodes[HttpCodes["InternalError"] = 500] = "InternalError";
12
+ })(HttpCodes || (exports.HttpCodes = HttpCodes = {}));
13
+ // Wrapper to return a failed request through GraphQL
14
+ async function requestFailed(error, reply) {
15
+ const statusCode = (0, common_1.httpStatusCodeFor)(error);
16
+ await reply.status(statusCode).send({
17
+ title: (0, common_1.toClassTitle)(error),
18
+ reason: error.message,
19
+ });
20
+ }
@@ -0,0 +1,2 @@
1
+ import { MagekConfig } from '@magek/common';
2
+ export declare function configureScheduler(config: MagekConfig, userProject: any): void;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.configureScheduler = configureScheduler;
4
+ const scheduler = require("node-schedule");
5
+ function configureScheduler(config, userProject) {
6
+ const triggerScheduledCommands = userProject['triggerScheduledCommands'];
7
+ Object.keys(config.scheduledCommandHandlers)
8
+ .map((scheduledCommandName) => buildScheduledCommandInfo(config, scheduledCommandName))
9
+ .filter((scheduledCommandInfo) => scheduledCommandInfo.metadata.scheduledOn)
10
+ .forEach((scheduledCommandInfo) => {
11
+ scheduler.scheduleJob(scheduledCommandInfo.name, createCronExpression(scheduledCommandInfo.metadata), () => {
12
+ triggerScheduledCommands({ typeName: scheduledCommandInfo.name });
13
+ });
14
+ });
15
+ }
16
+ function createCronExpression(scheduledCommandMetadata) {
17
+ const { minute = '*', hour = '*', day = '*', month = '*', weekDay = '*' } = scheduledCommandMetadata.scheduledOn;
18
+ return `${minute} ${hour} ${day} ${month} ${weekDay}`;
19
+ }
20
+ function buildScheduledCommandInfo(config, scheduledCommandName) {
21
+ return {
22
+ name: scheduledCommandName,
23
+ metadata: config.scheduledCommandHandlers[scheduledCommandName],
24
+ };
25
+ }
@@ -0,0 +1,5 @@
1
+ export declare class LocalQueries {
2
+ constructor();
3
+ events(primaryKey: string, latestFirst?: boolean): Promise<Array<unknown>>;
4
+ readModels(primaryKey: string, readModelName: string, latestFirst?: boolean): Promise<Array<unknown>>;
5
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalQueries = void 0;
4
+ class LocalQueries {
5
+ constructor() { }
6
+ async events(primaryKey, latestFirst = true) {
7
+ // TODO implement method
8
+ return [];
9
+ }
10
+ async readModels(primaryKey, readModelName, latestFirst = true) {
11
+ // TODO implement method
12
+ return [];
13
+ }
14
+ }
15
+ exports.LocalQueries = LocalQueries;
@@ -0,0 +1,17 @@
1
+ import { LocalQueries } from './local-queries';
2
+ interface ApplicationOutputs {
3
+ graphqlURL: string;
4
+ websocketURL: string;
5
+ healthURL: string;
6
+ }
7
+ export declare class LocalTestHelper {
8
+ readonly outputs: ApplicationOutputs;
9
+ readonly queries: LocalQueries;
10
+ private constructor();
11
+ static build(appName: string): Promise<LocalTestHelper>;
12
+ private static ensureProviderIsReady;
13
+ private static graphqlURL;
14
+ private static healthURL;
15
+ private static websocketURL;
16
+ }
17
+ export {};
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LocalTestHelper = void 0;
4
+ const local_queries_1 = require("./local-queries");
5
+ class LocalTestHelper {
6
+ constructor(outputs, queries) {
7
+ this.outputs = outputs;
8
+ this.queries = queries;
9
+ }
10
+ static async build(appName) {
11
+ await this.ensureProviderIsReady();
12
+ return new LocalTestHelper({
13
+ graphqlURL: await this.graphqlURL(),
14
+ websocketURL: await this.websocketURL(),
15
+ healthURL: await this.healthURL(),
16
+ }, new local_queries_1.LocalQueries());
17
+ }
18
+ static async ensureProviderIsReady() {
19
+ const url = await this.healthURL();
20
+ const response = await fetch(url);
21
+ if (!response.ok) {
22
+ throw new Error(`Provider is not ready: ${response.status} ${response.statusText}`);
23
+ }
24
+ }
25
+ static async graphqlURL() {
26
+ const url = 'http://localhost:3000/graphql';
27
+ return url;
28
+ }
29
+ static async healthURL() {
30
+ return 'http://localhost:3000/sensor/health/';
31
+ }
32
+ static async websocketURL() {
33
+ const url = 'ws://localhost:3000/websocket';
34
+ return url;
35
+ }
36
+ }
37
+ exports.LocalTestHelper = LocalTestHelper;
@@ -0,0 +1,27 @@
1
+ import type { WebSocket } from '@fastify/websocket';
2
+ /**
3
+ * Registry to manage active WebSocket connections
4
+ */
5
+ export declare class WebSocketRegistry {
6
+ private connections;
7
+ /**
8
+ * Add a connection to the registry
9
+ */
10
+ addConnection(connectionId: string, socket: WebSocket): void;
11
+ /**
12
+ * Remove a connection from the registry
13
+ */
14
+ removeConnection(connectionId: string): void;
15
+ /**
16
+ * Send a message to a specific connection
17
+ */
18
+ sendMessage(connectionId: string, data: unknown): void;
19
+ /**
20
+ * Check if a connection exists
21
+ */
22
+ hasConnection(connectionId: string): boolean;
23
+ /**
24
+ * Get the number of active connections
25
+ */
26
+ getConnectionCount(): number;
27
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebSocketRegistry = void 0;
4
+ /**
5
+ * Registry to manage active WebSocket connections
6
+ */
7
+ class WebSocketRegistry {
8
+ constructor() {
9
+ this.connections = new Map();
10
+ }
11
+ /**
12
+ * Add a connection to the registry
13
+ */
14
+ addConnection(connectionId, socket) {
15
+ this.connections.set(connectionId, socket);
16
+ // Clean up when connection closes
17
+ socket.on('close', () => {
18
+ this.connections.delete(connectionId);
19
+ });
20
+ }
21
+ /**
22
+ * Remove a connection from the registry
23
+ */
24
+ removeConnection(connectionId) {
25
+ this.connections.delete(connectionId);
26
+ }
27
+ /**
28
+ * Send a message to a specific connection
29
+ */
30
+ sendMessage(connectionId, data) {
31
+ const connection = this.connections.get(connectionId);
32
+ if (connection && connection.readyState === connection.OPEN) {
33
+ connection.send(JSON.stringify(data));
34
+ }
35
+ }
36
+ /**
37
+ * Check if a connection exists
38
+ */
39
+ hasConnection(connectionId) {
40
+ return this.connections.has(connectionId);
41
+ }
42
+ /**
43
+ * Get the number of active connections
44
+ */
45
+ getConnectionCount() {
46
+ return this.connections.size;
47
+ }
48
+ }
49
+ exports.WebSocketRegistry = WebSocketRegistry;
@@ -0,0 +1,13 @@
1
+ export type APIResult = {
2
+ status: 'success';
3
+ result: unknown;
4
+ headers?: Record<string, number | string | ReadonlyArray<string>>;
5
+ } | {
6
+ status: 'failure';
7
+ code: number;
8
+ title: string;
9
+ reason: string;
10
+ };
11
+ export declare function requestSucceeded(body?: any, headers?: Record<string, number | string | ReadonlyArray<string>>): Promise<APIResult>;
12
+ export declare function requestFailed(error: Error): Promise<APIResult>;
13
+ export declare function healthRequestResult(body: unknown, isHealthy: boolean): Promise<APIResult>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requestSucceeded = requestSucceeded;
4
+ exports.requestFailed = requestFailed;
5
+ exports.healthRequestResult = healthRequestResult;
6
+ const common_1 = require("@magek/common");
7
+ async function requestSucceeded(body, headers) {
8
+ return {
9
+ status: 'success',
10
+ result: body,
11
+ headers: {
12
+ ...headers,
13
+ },
14
+ };
15
+ }
16
+ async function requestFailed(error) {
17
+ const statusCode = (0, common_1.httpStatusCodeFor)(error);
18
+ return {
19
+ status: 'failure',
20
+ code: statusCode,
21
+ title: (0, common_1.toClassTitle)(error),
22
+ reason: error.message,
23
+ };
24
+ }
25
+ async function healthRequestResult(body, isHealthy) {
26
+ return {
27
+ status: 'success',
28
+ result: body,
29
+ headers: {
30
+ 'status-code': isHealthy ? 200 : 503,
31
+ },
32
+ };
33
+ }
@@ -0,0 +1,11 @@
1
+ import { MagekConfig, GraphQLRequestEnvelope, GraphQLRequestEnvelopeError } from '@magek/common';
2
+ import { FastifyRequest } from 'fastify';
3
+ export interface WebSocketMessage {
4
+ connectionContext: {
5
+ connectionId: string;
6
+ eventType: 'CONNECT' | 'MESSAGE' | 'DISCONNECT';
7
+ };
8
+ data?: any;
9
+ incomingMessage?: any;
10
+ }
11
+ export declare function rawGraphQLRequestToEnvelope(config: MagekConfig, request: FastifyRequest | WebSocketMessage): Promise<GraphQLRequestEnvelope | GraphQLRequestEnvelopeError>;
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rawGraphQLRequestToEnvelope = rawGraphQLRequestToEnvelope;
4
+ const common_1 = require("@magek/common");
5
+ async function rawGraphQLRequestToEnvelope(config, request) {
6
+ const requestID = common_1.UUID.generate();
7
+ return isWebSocketMessage(request)
8
+ ? webSocketMessageToEnvelope(config, request, requestID)
9
+ : httpMessageToEnvelope(config, request, requestID);
10
+ }
11
+ function webSocketMessageToEnvelope(config, webSocketRequest, requestID) {
12
+ const logger = (0, common_1.getLogger)(config, 'graphql-adapter#webSocketMessageToEnvelope');
13
+ logger.debug('Received WebSocket GraphQL request: ', webSocketRequest);
14
+ let eventType = 'MESSAGE';
15
+ const incomingMessage = webSocketRequest.incomingMessage;
16
+ const headers = incomingMessage === null || incomingMessage === void 0 ? void 0 : incomingMessage.headers;
17
+ const data = webSocketRequest.data;
18
+ try {
19
+ const connectionContext = webSocketRequest.connectionContext;
20
+ eventType = connectionContext === null || connectionContext === void 0 ? void 0 : connectionContext.eventType;
21
+ return {
22
+ requestID,
23
+ eventType,
24
+ connectionID: connectionContext === null || connectionContext === void 0 ? void 0 : connectionContext.connectionId.toString(),
25
+ token: Array.isArray(headers === null || headers === void 0 ? void 0 : headers.authorization) ? headers.authorization[0] : headers === null || headers === void 0 ? void 0 : headers.authorization,
26
+ value: data,
27
+ context: {
28
+ request: {
29
+ headers: headers,
30
+ body: data,
31
+ },
32
+ rawContext: webSocketRequest,
33
+ },
34
+ };
35
+ }
36
+ catch (e) {
37
+ return {
38
+ error: e,
39
+ requestID,
40
+ connectionID: undefined,
41
+ eventType: eventType,
42
+ context: {
43
+ request: {
44
+ headers: headers,
45
+ body: data,
46
+ },
47
+ rawContext: webSocketRequest,
48
+ },
49
+ };
50
+ }
51
+ }
52
+ function httpMessageToEnvelope(config, httpRequest, requestId) {
53
+ const logger = (0, common_1.getLogger)(config, 'graphql-adapter#httpMessageToEnvelope');
54
+ const eventType = 'MESSAGE';
55
+ const headers = httpRequest.headers;
56
+ const data = httpRequest.body;
57
+ try {
58
+ logger.debug('Received GraphQL request: \n- Headers: ', headers, '\n- Body: ', data);
59
+ return {
60
+ connectionID: undefined,
61
+ requestID: requestId,
62
+ eventType: eventType,
63
+ token: Array.isArray(headers === null || headers === void 0 ? void 0 : headers.authorization) ? headers.authorization[0] : headers === null || headers === void 0 ? void 0 : headers.authorization,
64
+ value: data,
65
+ context: {
66
+ request: {
67
+ headers: headers,
68
+ body: data,
69
+ },
70
+ rawContext: httpRequest,
71
+ },
72
+ };
73
+ }
74
+ catch (e) {
75
+ return {
76
+ error: e,
77
+ requestID: requestId,
78
+ connectionID: undefined,
79
+ eventType: eventType,
80
+ context: {
81
+ request: {
82
+ headers: headers,
83
+ body: data,
84
+ },
85
+ rawContext: httpRequest,
86
+ },
87
+ };
88
+ }
89
+ }
90
+ function isWebSocketMessage(request) {
91
+ return 'connectionContext' in request;
92
+ }
@@ -0,0 +1,9 @@
1
+ import { HealthEnvelope } from '@magek/common';
2
+ import { FastifyRequest } from 'fastify';
3
+ import Nedb from '@seald-io/nedb';
4
+ export declare function databaseUrl(): Promise<Array<string>>;
5
+ export declare function countAll(database: Nedb): Promise<number>;
6
+ export declare function graphqlFunctionUrl(): Promise<string>;
7
+ export declare function areDatabaseReadModelsUp(): Promise<boolean>;
8
+ export declare function isGraphQLFunctionUp(): Promise<boolean>;
9
+ export declare function rawRequestToSensorHealth(rawRequest: FastifyRequest): HealthEnvelope;
@@ -0,0 +1,70 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.databaseUrl = databaseUrl;
4
+ exports.countAll = countAll;
5
+ exports.graphqlFunctionUrl = graphqlFunctionUrl;
6
+ exports.areDatabaseReadModelsUp = areDatabaseReadModelsUp;
7
+ exports.isGraphQLFunctionUp = isGraphQLFunctionUp;
8
+ exports.rawRequestToSensorHealth = rawRequestToSensorHealth;
9
+ const paths_1 = require("../paths");
10
+ const common_1 = require("@magek/common");
11
+ const fs_1 = require("fs");
12
+ async function databaseUrl() {
13
+ return [paths_1.eventsDatabase, paths_1.readModelsDatabase];
14
+ }
15
+ async function countAll(database) {
16
+ await database.loadDatabaseAsync();
17
+ const count = await database.countAsync({});
18
+ return count !== null && count !== void 0 ? count : 0;
19
+ }
20
+ async function graphqlFunctionUrl() {
21
+ try {
22
+ const port = (0, common_1.localPort)();
23
+ return `http://localhost:${port}/graphql`;
24
+ }
25
+ catch (e) {
26
+ return '';
27
+ }
28
+ }
29
+ async function areDatabaseReadModelsUp() {
30
+ return (0, fs_1.existsSync)(paths_1.readModelsDatabase);
31
+ }
32
+ async function isGraphQLFunctionUp() {
33
+ try {
34
+ const url = await graphqlFunctionUrl();
35
+ const response = await (0, common_1.request)(url, 'POST', JSON.stringify({
36
+ query: 'query { __typename }',
37
+ }));
38
+ return response.status === 200;
39
+ }
40
+ catch (e) {
41
+ return false;
42
+ }
43
+ }
44
+ function rawRequestToSensorHealthComponentPath(rawRequest) {
45
+ // For health requests, the component path is typically in the URL path
46
+ // Since we don't have a direct url property, we'll construct it from params
47
+ const params = rawRequest.params;
48
+ if (params && Object.keys(params).length > 0) {
49
+ // If there are path parameters, join them to create the component path
50
+ return Object.values(params).filter(Boolean).join('/');
51
+ }
52
+ return '';
53
+ }
54
+ function rawRequestToSensorHealth(rawRequest) {
55
+ const componentPath = rawRequestToSensorHealthComponentPath(rawRequest);
56
+ const requestID = common_1.UUID.generate();
57
+ const headers = rawRequest.headers;
58
+ return {
59
+ requestID: requestID,
60
+ context: {
61
+ request: {
62
+ headers: headers,
63
+ body: rawRequest.body || {},
64
+ },
65
+ rawContext: rawRequest,
66
+ },
67
+ componentPath: componentPath,
68
+ token: Array.isArray(headers === null || headers === void 0 ? void 0 : headers.authorization) ? headers.authorization[0] : headers === null || headers === void 0 ? void 0 : headers.authorization,
69
+ };
70
+ }
@@ -0,0 +1,2 @@
1
+ import { MagekConfig, RocketEnvelope } from '@magek/common';
2
+ export declare function rawRocketInputToEnvelope(config: MagekConfig, request: unknown): RocketEnvelope;
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rawRocketInputToEnvelope = rawRocketInputToEnvelope;
4
+ const common_1 = require("@magek/common");
5
+ function rawRocketInputToEnvelope(config, request) {
6
+ const idFromRequest = request[common_1.rocketFunctionIDEnvVar];
7
+ const id = idFromRequest !== null && idFromRequest !== void 0 ? idFromRequest : process.env[common_1.rocketFunctionIDEnvVar];
8
+ return {
9
+ rocketId: id,
10
+ };
11
+ }
@@ -0,0 +1,6 @@
1
+ import { MagekConfig, ScheduledCommandEnvelope } from '@magek/common';
2
+ interface LocalScheduleCommandEnvelope {
3
+ typeName: string;
4
+ }
5
+ export declare function rawScheduledInputToEnvelope(config: MagekConfig, input: Partial<LocalScheduleCommandEnvelope>): Promise<ScheduledCommandEnvelope>;
6
+ export {};
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.rawScheduledInputToEnvelope = rawScheduledInputToEnvelope;
4
+ const common_1 = require("@magek/common");
5
+ async function rawScheduledInputToEnvelope(config, input) {
6
+ const logger = (0, common_1.getLogger)(config, 'rawScheduledInputToEnvelope');
7
+ logger.debug('Received LocalScheduleCommand request: ', input);
8
+ if (!input.typeName)
9
+ throw new Error(`typeName is not defined or empty, scheduled command envelope should have the structure {typeName: string }, but you gave ${JSON.stringify(input)}`);
10
+ return {
11
+ requestID: common_1.UUID.generate(),
12
+ typeName: input.typeName,
13
+ };
14
+ }
@@ -0,0 +1,17 @@
1
+ import { FilterFor } from '@magek/common';
2
+ /**
3
+ * Creates a query record out of the read mode name and
4
+ * the GraphQL filters, ready to be passed into the `query`
5
+ * method of the read model registry.
6
+ */
7
+ export declare function queryRecordFor(filters: FilterFor<any>, nested?: string, queryFromFilters?: Record<string, object>): Record<string, QueryOperation<QueryValue>>;
8
+ export type QueryValue = number | string | boolean;
9
+ export type QueryOperation<TValue> = TValue | {
10
+ [TKey in '$lt' | '$lte' | '$gt' | '$gte' | '$ne' | '$exists']?: TValue;
11
+ } | {
12
+ [TKey in '$in' | '$nin']?: Array<TValue>;
13
+ } | {
14
+ [TKey in '$regex' | '$nin']?: RegExp;
15
+ } | {
16
+ [TKey in '$elemMatch']?: TValue;
17
+ };
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.queryRecordFor = queryRecordFor;
4
+ /**
5
+ * Creates a query record out of the read mode name and
6
+ * the GraphQL filters, ready to be passed into the `query`
7
+ * method of the read model registry.
8
+ */
9
+ function queryRecordFor(filters, nested, queryFromFilters = {}) {
10
+ if (Object.keys(filters).length != 0) {
11
+ for (const key in filters) {
12
+ const propName = nested ? `${nested}.${key}` : key;
13
+ const filter = filters[key];
14
+ switch (key) {
15
+ case 'not':
16
+ queryFromFilters[`$${propName}`] = queryRecordFor(filter);
17
+ break;
18
+ case 'or':
19
+ case 'and':
20
+ queryFromFilters[`$${propName}`] = filters[key].map((filter) => queryRecordFor(filter));
21
+ break;
22
+ default:
23
+ if (!Object.keys(queryOperatorTable).includes(Object.keys(filter)[0])) {
24
+ queryRecordFor(filter, propName, queryFromFilters);
25
+ }
26
+ else {
27
+ queryFromFilters[`value.${propName}`] = filterToQuery(filter);
28
+ }
29
+ break;
30
+ }
31
+ }
32
+ }
33
+ return { ...queryFromFilters };
34
+ }
35
+ /**
36
+ * Transforms a GraphQL Magek filter into an neDB query
37
+ */
38
+ function filterToQuery(filter) {
39
+ const [query] = Object.entries(filter).map(([propName, filter]) => {
40
+ const query = queryOperatorTable[propName];
41
+ const queryFilter = Array.isArray(filter) ? filter : [filter];
42
+ return query(queryFilter);
43
+ });
44
+ return query;
45
+ }
46
+ /**
47
+ * Table of equivalences between a GraphQL operation and the NeDB
48
+ * query operator.
49
+ *
50
+ * It is needed that we pass the values, because of the special case
51
+ * of `=`, in which the operator is the value itself.
52
+ */
53
+ const queryOperatorTable = {
54
+ eq: (values) => values[0],
55
+ ne: (values) => ({ $ne: values[0] }),
56
+ lt: (values) => ({ $lt: values[0] }),
57
+ gt: (values) => ({ $gt: values[0] }),
58
+ lte: (values) => ({ $lte: values[0] }),
59
+ gte: (values) => ({ $gte: values[0] }),
60
+ in: (values) => ({ $in: values }),
61
+ isDefined: (values) => ({ $exists: values[0] }),
62
+ contains: buildRegexQuery.bind(null, 'contains'),
63
+ beginsWith: buildRegexQuery.bind(null, 'begins-with'),
64
+ includes: buildIncludes.bind(null, 'contains'),
65
+ regex: buildRegexQuery.bind(null, 'regex'),
66
+ iRegex: buildRegexQuery.bind(null, 'iRegex'),
67
+ };
68
+ function buildIncludes(operation, values) {
69
+ const matcher = values[0];
70
+ if (typeof matcher === 'string') {
71
+ return { $regex: new RegExp(matcher) };
72
+ }
73
+ return { $elemMatch: matcher };
74
+ }
75
+ /**
76
+ * Builds a regex out of string GraphQL queries
77
+ */
78
+ function buildRegexQuery(operation, values) {
79
+ const matcher = values[0];
80
+ if (typeof matcher != 'string') {
81
+ throw new Error(`Attempted to perform a ${operation} operation on a non-string`);
82
+ }
83
+ if (operation === 'begins-with') {
84
+ return { $regex: new RegExp(`^${matcher}`) };
85
+ }
86
+ if (operation === 'iRegex') {
87
+ return { $regex: new RegExp(matcher, 'i') };
88
+ }
89
+ return { $regex: new RegExp(matcher) };
90
+ }
@@ -0,0 +1,6 @@
1
+ export declare const registeredUsersDatabase: string;
2
+ export declare const authenticatedUsersDatabase: string;
3
+ export declare const eventsDatabase: string;
4
+ export declare const readModelsDatabase: string;
5
+ export declare const connectionsDatabase: string;
6
+ export declare const subscriptionDatabase: string;
package/dist/paths.js ADDED
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.subscriptionDatabase = exports.connectionsDatabase = exports.readModelsDatabase = exports.eventsDatabase = exports.authenticatedUsersDatabase = exports.registeredUsersDatabase = void 0;
4
+ // Paths used by the local provider internally
5
+ const path = require("path");
6
+ exports.registeredUsersDatabase = internalPath('registered_users.json');
7
+ exports.authenticatedUsersDatabase = internalPath('authenticated_users.json');
8
+ exports.eventsDatabase = internalPath('events.json');
9
+ exports.readModelsDatabase = internalPath('read_models.json');
10
+ exports.connectionsDatabase = internalPath('connections.json');
11
+ exports.subscriptionDatabase = internalPath('subscriptions.json');
12
+ function internalPath(filename) {
13
+ return path.normalize(path.join('.', '.magek', filename));
14
+ }
@@ -0,0 +1,44 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ import { UserApp } from '@magek/common';
3
+ import { WebSocketRegistry } from './infrastructure/websocket-registry';
4
+ /**
5
+ * Get the global WebSocket registry instance
6
+ */
7
+ export declare function getWebSocketRegistry(): WebSocketRegistry;
8
+ /**
9
+ * Send a message to a WebSocket connection
10
+ */
11
+ export declare function sendWebSocketMessage(connectionId: string, data: unknown): void;
12
+ export interface ServerOptions {
13
+ /** Enable Fastify logging. Default: true */
14
+ logger?: boolean;
15
+ /** Maximum request body size in bytes. Default: 6MB */
16
+ bodyLimit?: number;
17
+ }
18
+ /**
19
+ * Creates a configured Fastify server instance for a Magek application.
20
+ *
21
+ * @param userApp - The user's Magek application module
22
+ * @param options - Optional server configuration
23
+ * @returns A configured Fastify instance ready to listen
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * import { createServer } from '@magek/server'
28
+ * import * as myApp from './dist'
29
+ *
30
+ * const server = await createServer(myApp)
31
+ * await server.listen({ port: 3000 })
32
+ * ```
33
+ */
34
+ export declare function createServer(userApp: UserApp, options?: ServerOptions): Promise<FastifyInstance>;
35
+ declare module 'http' {
36
+ interface IncomingMessage {
37
+ rawBody: Buffer;
38
+ }
39
+ }
40
+ declare module 'fastify' {
41
+ interface FastifyRequest {
42
+ rawBody: Buffer;
43
+ }
44
+ }
package/dist/server.js ADDED
@@ -0,0 +1,197 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getWebSocketRegistry = getWebSocketRegistry;
4
+ exports.sendWebSocketMessage = sendWebSocketMessage;
5
+ exports.createServer = createServer;
6
+ const fastify_1 = require("fastify");
7
+ const websocket_1 = require("@fastify/websocket");
8
+ const fastify_sse_v2_1 = require("fastify-sse-v2");
9
+ const cors_1 = require("@fastify/cors");
10
+ const services_1 = require("./services");
11
+ const graphql_1 = require("./infrastructure/controllers/graphql");
12
+ const health_controller_1 = require("./infrastructure/controllers/health-controller");
13
+ const websocket_registry_1 = require("./infrastructure/websocket-registry");
14
+ const http_1 = require("./infrastructure/http");
15
+ const scheduler_1 = require("./infrastructure/scheduler");
16
+ // Global WebSocket registry instance
17
+ let globalWebSocketRegistry;
18
+ /**
19
+ * Get the global WebSocket registry instance
20
+ */
21
+ function getWebSocketRegistry() {
22
+ if (!globalWebSocketRegistry) {
23
+ throw new Error('WebSocket registry not initialized. Make sure the server is started.');
24
+ }
25
+ return globalWebSocketRegistry;
26
+ }
27
+ /**
28
+ * Send a message to a WebSocket connection
29
+ */
30
+ function sendWebSocketMessage(connectionId, data) {
31
+ const registry = getWebSocketRegistry();
32
+ registry.sendMessage(connectionId, data);
33
+ }
34
+ /**
35
+ * Default error handling for Fastify requests.
36
+ */
37
+ async function defaultErrorHandler(error, request, reply) {
38
+ if (reply.sent) {
39
+ return;
40
+ }
41
+ console.error(error);
42
+ const err = error instanceof Error ? error : new Error(String(error));
43
+ await (0, http_1.requestFailed)(err, reply);
44
+ }
45
+ /**
46
+ * Creates a configured Fastify server instance for a Magek application.
47
+ *
48
+ * @param userApp - The user's Magek application module
49
+ * @param options - Optional server configuration
50
+ * @returns A configured Fastify instance ready to listen
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * import { createServer } from '@magek/server'
55
+ * import * as myApp from './dist'
56
+ *
57
+ * const server = await createServer(myApp)
58
+ * await server.listen({ port: 3000 })
59
+ * ```
60
+ */
61
+ async function createServer(userApp, options = {}) {
62
+ const { logger = true, bodyLimit = 6 * 1024 * 1024 } = options;
63
+ // Initialize WebSocket registry
64
+ globalWebSocketRegistry = new websocket_registry_1.WebSocketRegistry();
65
+ global.webSocketRegistry = globalWebSocketRegistry;
66
+ const fastify = (0, fastify_1.default)({
67
+ logger,
68
+ bodyLimit,
69
+ });
70
+ // Register plugins
71
+ await fastify.register(cors_1.default, {
72
+ origin: true,
73
+ credentials: true,
74
+ });
75
+ await fastify.register(websocket_1.default);
76
+ await fastify.register(fastify_sse_v2_1.FastifySSEPlugin);
77
+ // Add raw body support for GraphQL requests
78
+ fastify.addContentTypeParser('application/json', { parseAs: 'buffer' }, (req, body, done) => {
79
+ try {
80
+ const rawBody = body;
81
+ req.rawBody = rawBody;
82
+ const json = JSON.parse(rawBody.toString());
83
+ done(null, json);
84
+ }
85
+ catch (err) {
86
+ done(err, undefined);
87
+ }
88
+ });
89
+ const graphQLService = new services_1.GraphQLService(userApp);
90
+ const healthService = new services_1.HealthService(userApp);
91
+ // Register GraphQL endpoint
92
+ const graphQLController = new graphql_1.GraphQLController(graphQLService);
93
+ await fastify.register((instance) => {
94
+ instance.post('/graphql', graphQLController.handleGraphQL.bind(graphQLController));
95
+ });
96
+ // Register Health endpoint
97
+ const healthController = new health_controller_1.HealthController(healthService);
98
+ await fastify.register((instance) => {
99
+ instance.get('/sensor/health/*', healthController.handleHealth.bind(healthController));
100
+ });
101
+ // Register WebSocket endpoint
102
+ await fastify.register((instance) => {
103
+ instance.get('/websocket', { websocket: true }, (connection, req) => {
104
+ const connectionId = req.connectionId || `conn_${Date.now()}_${Math.random()}`;
105
+ globalWebSocketRegistry.addConnection(connectionId, connection.socket);
106
+ connection.socket.on('message', async (message) => {
107
+ try {
108
+ const data = JSON.parse(message.toString());
109
+ const webSocketRequest = {
110
+ connectionContext: {
111
+ connectionId,
112
+ eventType: 'MESSAGE',
113
+ },
114
+ data,
115
+ incomingMessage: req.raw,
116
+ };
117
+ await graphQLService.handleGraphQLRequest(webSocketRequest);
118
+ }
119
+ catch (error) {
120
+ console.error('WebSocket message error:', error);
121
+ connection.socket.send(JSON.stringify({
122
+ type: 'error',
123
+ payload: { message: 'Failed to process message' },
124
+ }));
125
+ }
126
+ });
127
+ connection.socket.on('close', async () => {
128
+ const webSocketRequest = {
129
+ connectionContext: {
130
+ connectionId,
131
+ eventType: 'DISCONNECT',
132
+ },
133
+ };
134
+ await graphQLService.handleGraphQLRequest(webSocketRequest);
135
+ });
136
+ const webSocketRequest = {
137
+ connectionContext: {
138
+ connectionId,
139
+ eventType: 'CONNECT',
140
+ },
141
+ incomingMessage: req.raw,
142
+ };
143
+ void graphQLService.handleGraphQLRequest(webSocketRequest);
144
+ });
145
+ });
146
+ // Register SSE endpoint
147
+ await fastify.register((instance) => {
148
+ instance.get('/sse', (request, reply) => {
149
+ const connectionId = `sse_${Date.now()}_${Math.random()}`;
150
+ reply.sse({
151
+ id: connectionId,
152
+ event: 'connection',
153
+ data: JSON.stringify({
154
+ type: 'connection_init',
155
+ payload: { connectionId },
156
+ }),
157
+ });
158
+ const webSocketRequest = {
159
+ connectionContext: {
160
+ connectionId,
161
+ eventType: 'CONNECT',
162
+ },
163
+ incomingMessage: request.raw,
164
+ };
165
+ void graphQLService.handleGraphQLRequest(webSocketRequest);
166
+ const pingInterval = setInterval(() => {
167
+ if (!reply.sent) {
168
+ reply.sse({
169
+ id: Date.now().toString(),
170
+ event: 'ping',
171
+ data: JSON.stringify({ type: 'ping', timestamp: Date.now() }),
172
+ });
173
+ }
174
+ }, 30000);
175
+ request.raw.on('close', async () => {
176
+ clearInterval(pingInterval);
177
+ const disconnectRequest = {
178
+ connectionContext: {
179
+ connectionId,
180
+ eventType: 'DISCONNECT',
181
+ },
182
+ };
183
+ await graphQLService.handleGraphQLRequest(disconnectRequest);
184
+ });
185
+ });
186
+ });
187
+ fastify.setErrorHandler(async (error, request, reply) => {
188
+ await defaultErrorHandler(error, request, reply);
189
+ });
190
+ // Configure scheduled commands
191
+ const config = userApp.Magek.config;
192
+ if (config) {
193
+ (0, scheduler_1.configureScheduler)(config, userApp);
194
+ }
195
+ await fastify.ready();
196
+ return fastify;
197
+ }
@@ -0,0 +1,9 @@
1
+ import { ReadModelEnvelope, UserApp } from '@magek/common';
2
+ import { FastifyRequest } from 'fastify';
3
+ import { WebSocketMessage } from '../library/graphql-adapter';
4
+ export declare class GraphQLService {
5
+ readonly userApp: UserApp;
6
+ constructor(userApp: UserApp);
7
+ handleGraphQLRequest(request: FastifyRequest | WebSocketMessage): Promise<any>;
8
+ handleNotificationSubscription(request: Array<ReadModelEnvelope>): Promise<unknown>;
9
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GraphQLService = void 0;
4
+ class GraphQLService {
5
+ constructor(userApp) {
6
+ this.userApp = userApp;
7
+ }
8
+ async handleGraphQLRequest(request) {
9
+ return await this.userApp.graphQLDispatcher(request);
10
+ }
11
+ async handleNotificationSubscription(request) {
12
+ return await this.userApp.notifySubscribers(request);
13
+ }
14
+ }
15
+ exports.GraphQLService = GraphQLService;
@@ -0,0 +1,7 @@
1
+ import { UserApp } from '@magek/common';
2
+ import { FastifyRequest } from 'fastify';
3
+ export declare class HealthService {
4
+ readonly userApp: UserApp;
5
+ constructor(userApp: UserApp);
6
+ handleHealthRequest(request: FastifyRequest): Promise<any>;
7
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HealthService = void 0;
4
+ class HealthService {
5
+ constructor(userApp) {
6
+ this.userApp = userApp;
7
+ }
8
+ async handleHealthRequest(request) {
9
+ return await this.userApp.health(request);
10
+ }
11
+ }
12
+ exports.HealthService = HealthService;
@@ -0,0 +1,2 @@
1
+ export * from './graphql-service';
2
+ export * from './health-service';
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./graphql-service"), exports);
5
+ tslib_1.__exportStar(require("./health-service"), exports);
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@magek/server",
3
+ "version": "0.0.1",
4
+ "description": "Debug your Magek projects locally",
5
+ "keywords": [
6
+ "server"
7
+ ],
8
+ "author": "Boosterin Labs SLU",
9
+ "homepage": "https://magek.ai",
10
+ "license": "Apache-2.0",
11
+ "publishConfig": {
12
+ "access": "public"
13
+ },
14
+ "main": "dist/index.js",
15
+ "exports": {
16
+ ".": "./dist/index.js"
17
+ },
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "repository": {
22
+ "type": "git",
23
+ "url": "git+https://github.com/theam/magek.git"
24
+ },
25
+ "engines": {
26
+ "node": ">=22.0.0 <23.0.0"
27
+ },
28
+ "dependencies": {
29
+ "@magek/common": "^0.0.1",
30
+ "@fastify/cors": "11.2.0",
31
+ "@fastify/websocket": "11.2.0",
32
+ "@seald-io/nedb": "4.1.2",
33
+ "fastify": "5.6.2",
34
+ "fastify-sse-v2": "4.2.1",
35
+ "node-schedule": "2.1.1",
36
+ "tslib": "2.8.1"
37
+ },
38
+ "bugs": {
39
+ "url": "https://github.com/theam/magek/issues"
40
+ },
41
+ "devDependencies": {
42
+ "@magek/eslint-config": "^0.0.1",
43
+ "@types/chai": "5.2.3",
44
+ "@types/chai-as-promised": "8.0.2",
45
+ "@types/mocha": "10.0.10",
46
+ "@types/node": "22.19.3",
47
+ "@types/node-schedule": "2.1.8",
48
+ "@types/sinon": "21.0.0",
49
+ "@types/sinon-chai": "4.0.0",
50
+ "chai": "6.2.2",
51
+ "chai-as-promised": "8.0.2",
52
+ "@faker-js/faker": "10.2.0",
53
+ "mocha": "11.7.5",
54
+ "c8": "^10.1.3",
55
+ "rimraf": "6.1.2",
56
+ "sinon": "21.0.1",
57
+ "sinon-chai": "4.0.1",
58
+ "tsx": "^4.19.2",
59
+ "typescript": "5.9.3"
60
+ },
61
+ "scripts": {
62
+ "format": "prettier --write --ext '.js,.ts' **/*.ts **/*/*.ts",
63
+ "lint:check": "eslint \"**/*.ts\"",
64
+ "lint:fix": "eslint --quiet --fix \"**/*.ts\"",
65
+ "build": "tsc -b tsconfig.json",
66
+ "clean": "rimraf ./dist tsconfig.tsbuildinfo",
67
+ "test:provider-local": "npm run test",
68
+ "test": "tsc --noEmit -p tsconfig.test.json && MAGEK_ENV=test c8 mocha --forbid-only \"test/**/*.test.ts\""
69
+ }
70
+ }