backendium 0.0.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.
@@ -0,0 +1,17 @@
1
+ export default class BackendiumResponse {
2
+ constructor(expressResponse, app) {
3
+ this.expressResponse = expressResponse;
4
+ this.app = app;
5
+ this.lastStatus = 200;
6
+ }
7
+ status(status) {
8
+ this.lastStatus = status;
9
+ this.expressResponse.status(status);
10
+ }
11
+ end(data, status) {
12
+ if (status)
13
+ this.status(status);
14
+ this.lastResponse = data;
15
+ this.expressResponse.end(typeof data === "string" || data instanceof Buffer || data instanceof ArrayBuffer ? data : JSON.stringify(data));
16
+ }
17
+ }
@@ -0,0 +1,60 @@
1
+ import { BackendiumHandlerType, RawHandlerType } from "./handler.js";
2
+ import { AuthCheckerType, AuthFailedType, BackendiumRequestOptionsType } from "./request.js";
3
+ import { RequestHandler } from "express";
4
+ import Backendium from "./index.js";
5
+ import { WebSocketRouteConstructor } from "./ws.js";
6
+ import { WSRequestHandler } from "websocket-express";
7
+ export type MethodType = "use" | "all" | "get" | "post" | "put" | "delete" | "patch" | "options" | "head" | "checkout" | "connect" | "copy" | "lock" | "merge" | "mkactivity" | "mkcol" | "move" | "m-search" | "notify" | "propfind" | "proppatch" | "purge" | "report" | "search" | "subscribe" | "unsubscribe" | "trace" | "unlock" | "link" | "unlink" | "useHTTP";
8
+ export type BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType> = Array<BackendiumHandlerType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>> | [string, ...Array<BackendiumHandlerType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>>] | [
9
+ ...Array<BackendiumHandlerType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>>,
10
+ BackendiumRequestOptionsType<BodyType, ParamsType, QueryType, AuthType, HeadersType>
11
+ ] | [
12
+ string,
13
+ ...Array<BackendiumHandlerType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>>,
14
+ BackendiumRequestOptionsType<BodyType, ParamsType, QueryType, AuthType, HeadersType>
15
+ ];
16
+ export declare class BackendiumRouter<GlobalAuthType = undefined> {
17
+ protected _handlers: Array<[MethodType, string | undefined, Array<ReturnType<RawHandlerType<GlobalAuthType>>>] | ["ws", string, Array<(app: Backendium) => WSRequestHandler>]>;
18
+ authChecker: AuthCheckerType<GlobalAuthType> | undefined;
19
+ authFailed: AuthFailedType | undefined;
20
+ constructor();
21
+ get handlers(): ([MethodType, string | undefined, ((app: Backendium) => RequestHandler)[]] | ["ws", string, ((app: Backendium) => WSRequestHandler)[]])[];
22
+ protected parseArgs<BodyType, ParamsType, QueryType, AuthType, HeadersType>(args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): [string | undefined, Array<RawHandlerType<GlobalAuthType>>];
23
+ addHandler<BodyType, ParamsType, QueryType, AuthType, HeadersType>(method: MethodType, ...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
24
+ use<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
25
+ useHTTP<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
26
+ all<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
27
+ get<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
28
+ post<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
29
+ put<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
30
+ delete<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
31
+ patch<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
32
+ options<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
33
+ head<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
34
+ checkout<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
35
+ connect<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
36
+ copy<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
37
+ lock<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
38
+ merge<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
39
+ mkactivity<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
40
+ mkcol<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
41
+ move<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
42
+ "m-search"<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
43
+ notify<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
44
+ propfind<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
45
+ proppatch<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
46
+ purge<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
47
+ report<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
48
+ search<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
49
+ subscribe<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
50
+ unsubscribe<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
51
+ trace<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
52
+ unlock<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
53
+ link<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
54
+ unlink<BodyType = Buffer, ParamsType = {}, QueryType = {}, AuthType = GlobalAuthType, HeadersType = {}>(...args: BackendiumMethodArgsType<BodyType, ParamsType, QueryType, AuthType, HeadersType, GlobalAuthType>): void;
55
+ ws<InitDataType>(route: string): WebSocketRouteConstructor<InitDataType>;
56
+ protected static addPrefix([method, route, handler]: [MethodType, string | undefined, Array<(app: Backendium) => RequestHandler>], prefix: string): [MethodType, string, Array<(app: Backendium) => RequestHandler>];
57
+ protected static addPrefix([method, route, handler]: ["ws", string, Array<(app: Backendium) => WSRequestHandler>], prefix: string): ["ws", string, Array<(app: Backendium) => WSRequestHandler>];
58
+ router<AuthType>(router: BackendiumRouter<AuthType>, routePrefix?: string): void;
59
+ setAuth(checker?: AuthCheckerType<GlobalAuthType>, failHandler?: AuthFailedType): void;
60
+ }
package/dist/router.js ADDED
@@ -0,0 +1,138 @@
1
+ import backendiumHandler from "./handler.js";
2
+ import { WebSocketRouteConstructor } from "./ws.js";
3
+ export class BackendiumRouter {
4
+ constructor() {
5
+ this._handlers = [];
6
+ }
7
+ get handlers() { return this._handlers; }
8
+ parseArgs(args) {
9
+ let route = undefined, options = undefined;
10
+ let handlers = args.map(elem => {
11
+ if (typeof elem === "string")
12
+ route = elem;
13
+ if (typeof elem === "function")
14
+ return elem;
15
+ // @ts-ignore
16
+ else
17
+ options = elem;
18
+ }).filter(elem => typeof elem === "function");
19
+ return [route, handlers.map(handler => backendiumHandler(handler, options !== null && options !== void 0 ? options : { auth: false }))];
20
+ }
21
+ addHandler(method, ...args) {
22
+ let [route, handlers] = this.parseArgs(args);
23
+ this._handlers.push([method, route, handlers.map(handler => handler(this))]);
24
+ }
25
+ use(...args) {
26
+ this.addHandler("use", ...args);
27
+ }
28
+ useHTTP(...args) {
29
+ this.addHandler("useHTTP", ...args);
30
+ }
31
+ all(...args) {
32
+ this.addHandler("all", ...args);
33
+ }
34
+ get(...args) {
35
+ this.addHandler("get", ...args);
36
+ }
37
+ post(...args) {
38
+ this.addHandler("post", ...args);
39
+ }
40
+ put(...args) {
41
+ this.addHandler("put", ...args);
42
+ }
43
+ delete(...args) {
44
+ this.addHandler("delete", ...args);
45
+ }
46
+ patch(...args) {
47
+ this.addHandler("patch", ...args);
48
+ }
49
+ options(...args) {
50
+ this.addHandler("options", ...args);
51
+ }
52
+ head(...args) {
53
+ this.addHandler("head", ...args);
54
+ }
55
+ checkout(...args) {
56
+ this.addHandler("checkout", ...args);
57
+ }
58
+ connect(...args) {
59
+ this.addHandler("connect", ...args);
60
+ }
61
+ copy(...args) {
62
+ this.addHandler("copy", ...args);
63
+ }
64
+ lock(...args) {
65
+ this.addHandler("lock", ...args);
66
+ }
67
+ merge(...args) {
68
+ this.addHandler("merge", ...args);
69
+ }
70
+ mkactivity(...args) {
71
+ this.addHandler("mkactivity", ...args);
72
+ }
73
+ mkcol(...args) {
74
+ this.addHandler("mkcol", ...args);
75
+ }
76
+ move(...args) {
77
+ this.addHandler("move", ...args);
78
+ }
79
+ "m-search"(...args) {
80
+ this.addHandler("m-search", ...args);
81
+ }
82
+ notify(...args) {
83
+ this.addHandler("notify", ...args);
84
+ }
85
+ propfind(...args) {
86
+ this.addHandler("propfind", ...args);
87
+ }
88
+ proppatch(...args) {
89
+ this.addHandler("proppatch", ...args);
90
+ }
91
+ purge(...args) {
92
+ this.addHandler("purge", ...args);
93
+ }
94
+ report(...args) {
95
+ this.addHandler("report", ...args);
96
+ }
97
+ search(...args) {
98
+ this.addHandler("search", ...args);
99
+ }
100
+ subscribe(...args) {
101
+ this.addHandler("subscribe", ...args);
102
+ }
103
+ unsubscribe(...args) {
104
+ this.addHandler("unsubscribe", ...args);
105
+ }
106
+ trace(...args) {
107
+ this.addHandler("trace", ...args);
108
+ }
109
+ unlock(...args) {
110
+ this.addHandler("unlock", ...args);
111
+ }
112
+ link(...args) {
113
+ this.addHandler("link", ...args);
114
+ }
115
+ unlink(...args) {
116
+ this.addHandler("unlink", ...args);
117
+ }
118
+ ws(route) {
119
+ const constructor = new WebSocketRouteConstructor();
120
+ this._handlers.push(["ws", route, [(app) => (request, response, next) => {
121
+ constructor._handle(request, response, next, app);
122
+ }]]);
123
+ return constructor;
124
+ }
125
+ static addPrefix([method, route, handler], prefix) {
126
+ return [method, route || !(route === null || route === void 0 ? void 0 : route.startsWith("/")) ? prefix + (route !== null && route !== void 0 ? route : "") : prefix + (route !== null && route !== void 0 ? route : ""), handler];
127
+ }
128
+ router(router, routePrefix = "") {
129
+ this._handlers.push(...router._handlers.map((handler) => {
130
+ // @ts-ignore
131
+ return BackendiumRouter.addPrefix(handler, routePrefix);
132
+ }));
133
+ }
134
+ setAuth(checker, failHandler) {
135
+ this.authChecker = checker !== null && checker !== void 0 ? checker : this.authChecker;
136
+ this.authFailed = failHandler !== null && failHandler !== void 0 ? failHandler : this.authFailed;
137
+ }
138
+ }
package/dist/ws.d.ts ADDED
@@ -0,0 +1,101 @@
1
+ import { NextFunction, Request } from "express";
2
+ import { WSResponse } from "websocket-express";
3
+ import Backendium from "./index.js";
4
+ import { EventEmitter, EventKey } from "event-emitter-typescript";
5
+ import { Validator } from "checkeasy";
6
+ import * as WebSocket from "ws";
7
+ import { ClientRequest, IncomingMessage } from "node:http";
8
+ interface NextMessageOptions {
9
+ timeout?: number | undefined;
10
+ }
11
+ interface WebSocketMessage {
12
+ data: Buffer;
13
+ isBinary: boolean;
14
+ }
15
+ interface WebSocketExtension {
16
+ nextMessage(options?: NextMessageOptions): Promise<WebSocketMessage>;
17
+ }
18
+ export type WebSocketHeadEventType = {
19
+ event: string;
20
+ };
21
+ export type WebSocketHeadType = WebSocketHeadEventType | {
22
+ operation: string;
23
+ operationConfig: string;
24
+ };
25
+ export type BackendiumWebSocketEvents<InitDataType> = {
26
+ notEventMessage: [Buffer, BackendiumWebSocket<InitDataType>, Backendium, boolean];
27
+ unknownEvent: [Buffer, BackendiumWebSocket<InitDataType>, Backendium, WebSocketHeadEventType];
28
+ parsingFailed: [Buffer, BackendiumWebSocket<InitDataType>, Backendium, Validator<any> | undefined];
29
+ initParsingFailed: [Buffer, WebSocket & WebSocketExtension, Backendium, Validator<any> | undefined];
30
+ initFailed: [Buffer, WebSocket & WebSocketExtension, Backendium];
31
+ accept: [BackendiumWebSocket<InitDataType>, WebSocketRouteConstructor<InitDataType>, Backendium];
32
+ reject: [Request, WSResponse, Backendium, number | undefined, string | undefined];
33
+ message: [Buffer, BackendiumWebSocket<InitDataType>, Backendium, boolean];
34
+ messageBeforeEvents: [Buffer, BackendiumWebSocket<InitDataType>, Backendium, boolean];
35
+ close: [BackendiumWebSocket<InitDataType>, number, Buffer, Backendium];
36
+ error: [BackendiumWebSocket<InitDataType>, Error, Backendium];
37
+ init: [WebSocket & WebSocketExtension, Buffer, Backendium, string];
38
+ upgrade: [BackendiumWebSocket<InitDataType>, IncomingMessage, Backendium];
39
+ open: [BackendiumWebSocket<InitDataType>, Backendium];
40
+ ping: [BackendiumWebSocket<InitDataType>, Buffer, Backendium];
41
+ pong: [BackendiumWebSocket<InitDataType>, Buffer, Backendium];
42
+ unexpectedResponse: [BackendiumWebSocket<InitDataType>, ClientRequest, IncomingMessage, Backendium];
43
+ };
44
+ export declare class BackendiumWebSocket<InitDataType> {
45
+ socket: WebSocket & WebSocketExtension;
46
+ wsConstructor: WebSocketRouteConstructor<InitDataType>;
47
+ app: Backendium;
48
+ initData: InitDataType;
49
+ url: string;
50
+ protected eventEmitter: EventEmitter<BackendiumWebSocketEvents<InitDataType>>;
51
+ protected wsEventEmitter: EventEmitter<WebSocketEvents<InitDataType>>;
52
+ protected events: Set<string>;
53
+ protected operations: EventEmitter<WebSocketOperations<InitDataType>>;
54
+ protected useEvents: boolean;
55
+ static rawDataParse(data: WebSocket.RawData): Buffer;
56
+ protected parseEventHead(head: string, message: Buffer, socket: BackendiumWebSocket<InitDataType>, app: Backendium): WebSocketHeadType | undefined;
57
+ protected emitIncomingEvent(event: string, payload: Buffer, socket: BackendiumWebSocket<InitDataType>, app: Backendium, head: WebSocketHeadEventType): void;
58
+ protected emitIncomingOperation(operation: string, payload: Buffer, operationConfig: string, socket: BackendiumWebSocket<InitDataType>, app: Backendium): void;
59
+ protected parseEventMessage(message: Buffer, socket: BackendiumWebSocket<InitDataType>, app: Backendium, isBinary: boolean): void;
60
+ constructor(socket: WebSocket & WebSocketExtension, wsConstructor: WebSocketRouteConstructor<InitDataType>, app: Backendium, initData: InitDataType, url: string);
61
+ static eventNameCheck(str: string): void;
62
+ event<Type extends Buffer>(event: string, callback: (data: Type, socket: BackendiumWebSocket<InitDataType>, app: Backendium) => void): void;
63
+ event<Type>(event: string, callback: (data: Type, socket: BackendiumWebSocket<InitDataType>, app: Backendium, validator: Validator<Type>) => void, validator: Validator<Type>): void;
64
+ operation<E extends EventKey<WebSocketOperations<InitDataType>>>(event: E, subscriber: (...args: WebSocketOperations<InitDataType>[E]) => void): void;
65
+ on<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): () => void;
66
+ once<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): () => void;
67
+ off<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): void;
68
+ protected _send(data: any): void;
69
+ send(data: any): void;
70
+ protected static AnyToString(data: any): string;
71
+ emit(event: string, payload?: any): void;
72
+ emitOperation(event: string, operationConfig: any, payload: any): void;
73
+ }
74
+ export type WebSocketEvents<InitDataType> = {
75
+ [key: string]: [Buffer, BackendiumWebSocket<InitDataType>, Backendium];
76
+ };
77
+ export type WebSocketOperations<InitDataType> = {
78
+ [key: string]: [Buffer, string, BackendiumWebSocket<InitDataType>, Backendium];
79
+ };
80
+ export type AcceptResponseCallbackReturnType = boolean | [number | undefined] | [number | undefined, string | undefined];
81
+ export declare class WebSocketRouteConstructor<InitDataType> {
82
+ protected sockets: Array<BackendiumWebSocket<InitDataType>>;
83
+ eventEmitter: EventEmitter<BackendiumWebSocketEvents<InitDataType>>;
84
+ protected acceptRejectFn: ((request: Request, response: WSResponse, app: Backendium) => Promise<[boolean, number | undefined, string | undefined]>) | undefined;
85
+ protected eventHandlers: Array<[string, (data: any, socket: BackendiumWebSocket<InitDataType>, app: Backendium, validator: Validator<any>) => void, Validator<any> | undefined]>;
86
+ protected operations: EventEmitter<WebSocketOperations<InitDataType>>;
87
+ protected initRequired: boolean;
88
+ protected _backendiumWebsocket(socket: WebSocket & WebSocketExtension, app: Backendium, initData: InitDataType, url: string): void;
89
+ _handle(request: Request, response: WSResponse, next: NextFunction, app: Backendium): Promise<void>;
90
+ acceptReject(callback: (request: Request, response: WSResponse, app: Backendium) => AcceptResponseCallbackReturnType | Promise<AcceptResponseCallbackReturnType>): WebSocketRouteConstructor<InitDataType>;
91
+ event<Type extends Buffer>(event: string, callback: (data: Type, socket: BackendiumWebSocket<InitDataType>, app: Backendium) => void): WebSocketRouteConstructor<InitDataType>;
92
+ event<Type>(event: string, callback: (data: Type, socket: BackendiumWebSocket<InitDataType>, app: Backendium, validator: Validator<Type>) => void, validator: Validator<Type>): WebSocketRouteConstructor<InitDataType>;
93
+ operation<E extends EventKey<WebSocketOperations<InitDataType>>>(event: E, subscriber: (...args: WebSocketOperations<InitDataType>[E]) => void): void;
94
+ on_<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): () => void;
95
+ once_<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): () => void;
96
+ on<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): WebSocketRouteConstructor<InitDataType>;
97
+ once<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): WebSocketRouteConstructor<InitDataType>;
98
+ off<E extends EventKey<BackendiumWebSocketEvents<InitDataType>>>(event: E, subscriber: (...args: BackendiumWebSocketEvents<InitDataType>[E]) => void): WebSocketRouteConstructor<InitDataType>;
99
+ requireInit<Type>(callback: (connection: WebSocket & WebSocketExtension, data: Type, app: Backendium) => null | InitDataType | Promise<null | InitDataType>, validator: Validator<Type>): void;
100
+ }
101
+ export {};
package/dist/ws.js ADDED
@@ -0,0 +1,338 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { EventEmitter } from "event-emitter-typescript";
11
+ import { ValidationError } from "checkeasy";
12
+ export class BackendiumWebSocket {
13
+ static rawDataParse(data) {
14
+ return data instanceof Buffer ? data : data instanceof ArrayBuffer ? Buffer.from(data) : data.reduce((prev, cur) => Buffer.concat([prev, cur]), Buffer.alloc(0));
15
+ }
16
+ parseEventHead(head, message, socket, app) {
17
+ if (head.length < 1 || !head.startsWith("$")) {
18
+ this.eventEmitter.emit("notEventMessage", [message, socket, app, false]);
19
+ this.wsConstructor.eventEmitter.emit("notEventMessage", [message, socket, app, false]);
20
+ return;
21
+ }
22
+ let [, name, ...other] = head.split('$');
23
+ if (name.length)
24
+ return { event: name.trim() };
25
+ let [operation, ...operationConfig] = other;
26
+ return { operation: operation.trim(), operationConfig: operationConfig.join('$').trim() };
27
+ }
28
+ emitIncomingEvent(event, payload, socket, app, head) {
29
+ if (this.events.has(event))
30
+ this.wsEventEmitter.emit(event, [payload, socket, app]);
31
+ else {
32
+ this.eventEmitter.emit("unknownEvent", [payload, socket, app, head]);
33
+ this.wsConstructor.eventEmitter.emit("unknownEvent", [payload, socket, app, head]);
34
+ }
35
+ }
36
+ emitIncomingOperation(operation, payload, operationConfig, socket, app) {
37
+ this.operations.emit(operation, [payload, operationConfig, socket, app]);
38
+ }
39
+ parseEventMessage(message, socket, app, isBinary) {
40
+ var _a, _b, _c, _d;
41
+ if (isBinary) {
42
+ this.eventEmitter.emit("notEventMessage", [message, socket, app, isBinary]);
43
+ this.wsConstructor.eventEmitter.emit("notEventMessage", [message, socket, app, isBinary]);
44
+ if ((_a = app.config.logging) === null || _a === void 0 ? void 0 : _a.fullWs)
45
+ app.logger.wsInputFull(this.url, message);
46
+ else
47
+ app.logger.wsInput(this.url);
48
+ return;
49
+ }
50
+ try {
51
+ let [head_, ...data] = message.toString().split("\n");
52
+ let payload = Buffer.from(data.join("\n")), head = this.parseEventHead(head_, message, socket, app);
53
+ if (!head) {
54
+ if ((_b = app.config.logging) === null || _b === void 0 ? void 0 : _b.fullWs)
55
+ app.logger.wsInputFull(this.url, message);
56
+ else
57
+ app.logger.wsInput(this.url);
58
+ return;
59
+ }
60
+ if ("event" in head) {
61
+ this.emitIncomingEvent(head.event, payload, socket, app, head);
62
+ if ((_c = app.config.logging) === null || _c === void 0 ? void 0 : _c.fullWs)
63
+ app.logger.wsIncomingEventFull(this.url, head.event, payload.length ? payload : null);
64
+ else
65
+ app.logger.wsIncomingEvent(this.url, head.event);
66
+ }
67
+ else
68
+ this.emitIncomingOperation(head.operation, payload, head.operationConfig, socket, app);
69
+ }
70
+ catch (error) {
71
+ this.eventEmitter.emit("notEventMessage", [message, socket, app, isBinary]);
72
+ this.wsConstructor.eventEmitter.emit("notEventMessage", [message, socket, app, isBinary]);
73
+ if ((_d = app.config.logging) === null || _d === void 0 ? void 0 : _d.fullWs)
74
+ app.logger.wsInputFull(this.url, message);
75
+ else
76
+ app.logger.wsInput(this.url);
77
+ return;
78
+ }
79
+ }
80
+ constructor(socket, wsConstructor, app, initData, url) {
81
+ this.socket = socket;
82
+ this.wsConstructor = wsConstructor;
83
+ this.app = app;
84
+ this.initData = initData;
85
+ this.url = url;
86
+ this.eventEmitter = new EventEmitter;
87
+ this.wsEventEmitter = new EventEmitter;
88
+ this.events = new Set;
89
+ this.operations = new EventEmitter;
90
+ this.useEvents = false;
91
+ this.eventEmitter.emit("accept", [this, this.wsConstructor, app]);
92
+ this.wsConstructor.eventEmitter.emit("accept", [this, this.wsConstructor, app]);
93
+ socket.on("message", (data, isBinary) => {
94
+ var _a;
95
+ let buffer = BackendiumWebSocket.rawDataParse(data);
96
+ if (this.useEvents) {
97
+ this.eventEmitter.emit("messageBeforeEvents", [buffer, this, app, isBinary]);
98
+ this.wsConstructor.eventEmitter.emit("messageBeforeEvents", [buffer, this, app, isBinary]);
99
+ this.parseEventMessage(buffer, this, app, isBinary);
100
+ }
101
+ else {
102
+ this.eventEmitter.emit("notEventMessage", [buffer, this, app, isBinary]);
103
+ this.wsConstructor.eventEmitter.emit("notEventMessage", [buffer, this, app, isBinary]);
104
+ if ((_a = app.config.logging) === null || _a === void 0 ? void 0 : _a.fullWs)
105
+ app.logger.wsInputFull(url, data);
106
+ else
107
+ app.logger.wsInput(url);
108
+ }
109
+ this.eventEmitter.emit("message", [buffer, this, app, isBinary]);
110
+ this.wsConstructor.eventEmitter.emit("message", [buffer, this, app, isBinary]);
111
+ });
112
+ socket.on("close", (code, reason) => {
113
+ this.eventEmitter.emit("close", [this, code, reason, app]);
114
+ this.wsConstructor.eventEmitter.emit("close", [this, code, reason, app]);
115
+ app.logger.wsClose(url);
116
+ });
117
+ socket.on("upgrade", (request) => {
118
+ this.eventEmitter.emit("upgrade", [this, request, app]);
119
+ this.wsConstructor.eventEmitter.emit("upgrade", [this, request, app]);
120
+ });
121
+ socket.on("open", () => {
122
+ this.eventEmitter.emit("open", [this, app]);
123
+ this.wsConstructor.eventEmitter.emit("open", [this, app]);
124
+ });
125
+ socket.on("ping", (buffer) => {
126
+ this.eventEmitter.emit("ping", [this, buffer, app]);
127
+ this.wsConstructor.eventEmitter.emit("ping", [this, buffer, app]);
128
+ });
129
+ socket.on("pong", (buffer) => {
130
+ this.eventEmitter.emit("pong", [this, buffer, app]);
131
+ this.wsConstructor.eventEmitter.emit("pong", [this, buffer, app]);
132
+ });
133
+ socket.on("unexpected-response", (clientResponse, request) => {
134
+ this.eventEmitter.emit("unexpectedResponse", [this, clientResponse, request, app]);
135
+ this.wsConstructor.eventEmitter.emit("unexpectedResponse", [this, clientResponse, request, app]);
136
+ });
137
+ }
138
+ static eventNameCheck(str) {
139
+ if (str.includes("$"))
140
+ throw new Error("event name cannot contain '$'");
141
+ }
142
+ event(event, callback, validator) {
143
+ this.useEvents = true;
144
+ event = event.trim();
145
+ BackendiumWebSocket.eventNameCheck(event);
146
+ this.events.add(event);
147
+ this.wsEventEmitter.on(event, ([data, socket, app]) => {
148
+ let [mainData, parsed] = validator ? parse(data, validator) : [data, true];
149
+ if (!parsed || !mainData) {
150
+ this.eventEmitter.emit("parsingFailed", [data, socket, app, validator]);
151
+ this.wsConstructor.eventEmitter.emit("parsingFailed", [data, socket, app, validator]);
152
+ return;
153
+ }
154
+ // @ts-ignore
155
+ callback(mainData, socket, app, validator !== null && validator !== void 0 ? validator : bufferValidator);
156
+ });
157
+ }
158
+ operation(event, subscriber) {
159
+ BackendiumWebSocket.eventNameCheck(event);
160
+ this.operations.on(event, (args) => subscriber(...args));
161
+ }
162
+ ;
163
+ on(event, subscriber) {
164
+ return this.eventEmitter.on(event, (args) => subscriber(...args));
165
+ }
166
+ ;
167
+ once(event, subscriber) {
168
+ return this.eventEmitter.once(event, (args) => subscriber(...args));
169
+ }
170
+ ;
171
+ off(event, subscriber) {
172
+ this.eventEmitter.off(event, (args) => subscriber(...args));
173
+ }
174
+ ;
175
+ _send(data) {
176
+ if (!(data instanceof Buffer) && typeof data === "object" || typeof data === "boolean")
177
+ data = JSON.stringify(data);
178
+ this.socket.send(data);
179
+ }
180
+ send(data) {
181
+ var _a;
182
+ this._send(data);
183
+ if ((_a = this.app.config.logging) === null || _a === void 0 ? void 0 : _a.fullWs)
184
+ this.app.logger.wsOutputFull(this.url, data);
185
+ else
186
+ this.app.logger.wsOutput(this.url);
187
+ }
188
+ static AnyToString(data) {
189
+ return typeof data === "string" ? data : data instanceof Buffer ? data.toString() : data === undefined ? "undefined" : (typeof data === "number" && isNaN(data)) ? "NaN" : JSON.stringify(data);
190
+ }
191
+ emit(event, payload) {
192
+ var _a;
193
+ BackendiumWebSocket.eventNameCheck(event);
194
+ this._send(`$${event}\n${BackendiumWebSocket.AnyToString(payload)}`);
195
+ if ((_a = this.app.config.logging) === null || _a === void 0 ? void 0 : _a.fullWs)
196
+ this.app.logger.wsOutgoingEventFull(this.url, event, payload);
197
+ else
198
+ this.app.logger.wsOutgoingEvent(this.url, event);
199
+ }
200
+ emitOperation(event, operationConfig, payload) {
201
+ BackendiumWebSocket.eventNameCheck(event);
202
+ this._send(`$$${event}$${BackendiumWebSocket.AnyToString(operationConfig)}\n${BackendiumWebSocket.AnyToString(payload)}`);
203
+ }
204
+ }
205
+ const bufferValidator = (value, path) => {
206
+ if (value instanceof Buffer)
207
+ return value;
208
+ throw new ValidationError(`[${path}] is not buffer`);
209
+ };
210
+ function parse(data, validator) {
211
+ try {
212
+ return [validator(data, ""), true];
213
+ }
214
+ catch (error) {
215
+ try {
216
+ return [validator(data.toString(), ""), true];
217
+ }
218
+ catch (error) {
219
+ try {
220
+ return [validator(JSON.parse(data.toString()), ""), true];
221
+ }
222
+ catch (error) {
223
+ return [null, false];
224
+ }
225
+ }
226
+ }
227
+ }
228
+ export class WebSocketRouteConstructor {
229
+ constructor() {
230
+ this.sockets = [];
231
+ this.eventEmitter = new EventEmitter;
232
+ this.eventHandlers = [];
233
+ this.operations = new EventEmitter;
234
+ this.initRequired = false;
235
+ }
236
+ _backendiumWebsocket(socket, app, initData, url) {
237
+ let backendiumSocket = new BackendiumWebSocket(socket, this, app, initData, url);
238
+ // @ts-ignore
239
+ this.eventHandlers.forEach(([event, socket, validator]) => backendiumSocket.event(event, socket, validator));
240
+ }
241
+ _handle(request, response, next, app) {
242
+ return __awaiter(this, void 0, void 0, function* () {
243
+ if (this.acceptRejectFn) {
244
+ let [flag, code, message] = yield this.acceptRejectFn(request, response, app);
245
+ if (!flag) {
246
+ response.reject(code, message);
247
+ app.logger.wsRejected(request.originalUrl);
248
+ this.eventEmitter.emit("reject", [request, response, app, code, message]);
249
+ return;
250
+ }
251
+ }
252
+ let socket = yield response.accept();
253
+ app.logger.wsConnected(request.originalUrl);
254
+ if (this.initRequired) {
255
+ socket.once("message", (data) => {
256
+ this.eventEmitter.emit("init", [socket, BackendiumWebSocket.rawDataParse(data), app, request.originalUrl]);
257
+ });
258
+ }
259
+ // @ts-ignore
260
+ else
261
+ this._backendiumWebsocket(socket, app, undefined, request.originalUrl);
262
+ });
263
+ }
264
+ acceptReject(callback) {
265
+ this.acceptRejectFn = (request, response, app) => __awaiter(this, void 0, void 0, function* () {
266
+ let ans = callback(request, response, app), data;
267
+ if (ans instanceof Promise)
268
+ data = yield ans;
269
+ else
270
+ data = ans;
271
+ return typeof data === "boolean" ? [data, undefined, undefined] : [false, data[0], data[1]];
272
+ });
273
+ return this;
274
+ }
275
+ event(event, callback, validator) {
276
+ BackendiumWebSocket.eventNameCheck(event);
277
+ // @ts-ignore
278
+ this.sockets.forEach(socket => socket.event(event, callback, validator));
279
+ this.eventHandlers.push([event, callback, validator]);
280
+ return this;
281
+ }
282
+ operation(event, subscriber) {
283
+ BackendiumWebSocket.eventNameCheck(event);
284
+ this.operations.on(event, (args) => subscriber(...args));
285
+ }
286
+ on_(event, subscriber) {
287
+ return this.eventEmitter.on(event, (args) => subscriber(...args));
288
+ }
289
+ once_(event, subscriber) {
290
+ return this.eventEmitter.once(event, (args) => subscriber(...args));
291
+ }
292
+ on(event, subscriber) {
293
+ this.eventEmitter.on(event, (args) => subscriber(...args));
294
+ return this;
295
+ }
296
+ once(event, subscriber) {
297
+ this.eventEmitter.once(event, (args) => subscriber(...args));
298
+ return this;
299
+ }
300
+ off(event, subscriber) {
301
+ this.eventEmitter.off(event, (args) => subscriber(...args));
302
+ return this;
303
+ }
304
+ requireInit(callback, validator) {
305
+ this.initRequired = true;
306
+ this.on("init", (socket, data, app, url) => __awaiter(this, void 0, void 0, function* () {
307
+ var _a, _b, _c;
308
+ let [mainData, parsed] = validator ? parse(data, validator) : [data, true];
309
+ if (!parsed || !mainData) {
310
+ this.eventEmitter.emit("initParsingFailed", [data, socket, app, validator]);
311
+ if ((_a = app.config.logging) === null || _a === void 0 ? void 0 : _a.fullWs)
312
+ app.logger.wsInitFailedFull(url, data);
313
+ else
314
+ app.logger.wsInitFailed(url);
315
+ return;
316
+ }
317
+ // @ts-ignore
318
+ let ret = callback(socket, mainData, app);
319
+ if (ret instanceof Promise)
320
+ ret = yield ret;
321
+ if (ret !== null) {
322
+ if ((_b = app.config.logging) === null || _b === void 0 ? void 0 : _b.fullWs)
323
+ app.logger.wsInitFull(url, mainData);
324
+ else
325
+ app.logger.wsInit(url);
326
+ this._backendiumWebsocket(socket, app, ret, url);
327
+ }
328
+ else {
329
+ this.eventEmitter.emit("initFailed", [data, socket, app]);
330
+ if ((_c = app.config.logging) === null || _c === void 0 ? void 0 : _c.fullWs)
331
+ app.logger.wsInitFailedFull(url, mainData);
332
+ else
333
+ app.logger.wsInitFailed(url);
334
+ }
335
+ }));
336
+ }
337
+ }
338
+ // @TODO error handling +termination logging