topsyde-utils 1.3.2 → 2.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.
- package/dist/index.d.ts +2 -43
- package/dist/index.js +1 -38
- package/dist/index.js.map +1 -1
- package/dist/utils/Lib.d.ts +0 -12
- package/dist/utils/Lib.js +0 -65
- package/dist/utils/Lib.js.map +1 -1
- package/dist/utils/index.d.ts +0 -3
- package/dist/utils/index.js +0 -3
- package/dist/utils/index.js.map +1 -1
- package/dist/websocket.shared.types.d.ts +25 -0
- package/dist/websocket.shared.types.js +4 -0
- package/dist/websocket.shared.types.js.map +1 -0
- package/package.json +12 -66
- package/src/__tests__/singleton.test.ts +0 -143
- package/src/index.ts +2 -83
- package/src/utils/Lib.ts +0 -77
- package/src/utils/index.ts +0 -3
- package/src/websocket.shared.types.ts +27 -0
- package/dist/application.d.ts +0 -18
- package/dist/application.js +0 -60
- package/dist/application.js.map +0 -1
- package/dist/client/api/base.api.d.ts +0 -63
- package/dist/client/api/base.api.js +0 -61
- package/dist/client/api/base.api.js.map +0 -1
- package/dist/client/api/index.d.ts +0 -2
- package/dist/client/api/index.js +0 -5
- package/dist/client/api/index.js.map +0 -1
- package/dist/client/rxjs/index.d.ts +0 -1
- package/dist/client/rxjs/index.js +0 -4
- package/dist/client/rxjs/index.js.map +0 -1
- package/dist/client/rxjs/useRxjs.d.ts +0 -17
- package/dist/client/rxjs/useRxjs.js +0 -87
- package/dist/client/rxjs/useRxjs.js.map +0 -1
- package/dist/client/vite/plugins/index.d.ts +0 -2
- package/dist/client/vite/plugins/index.js +0 -5
- package/dist/client/vite/plugins/index.js.map +0 -1
- package/dist/client/vite/plugins/topsydeUtilsVitePlugin.d.ts +0 -9
- package/dist/client/vite/plugins/topsydeUtilsVitePlugin.js +0 -74
- package/dist/client/vite/plugins/topsydeUtilsVitePlugin.js.map +0 -1
- package/dist/external/index.d.ts +0 -1
- package/dist/external/index.js +0 -4
- package/dist/external/index.js.map +0 -1
- package/dist/external/re-exports.d.ts +0 -16
- package/dist/external/re-exports.js +0 -24
- package/dist/external/re-exports.js.map +0 -1
- package/dist/server/base/base.database.d.ts +0 -10
- package/dist/server/base/base.database.js +0 -23
- package/dist/server/base/base.database.js.map +0 -1
- package/dist/server/base/index.d.ts +0 -2
- package/dist/server/base/index.js +0 -5
- package/dist/server/base/index.js.map +0 -1
- package/dist/server/bun/index.d.ts +0 -3
- package/dist/server/bun/index.js +0 -6
- package/dist/server/bun/index.js.map +0 -1
- package/dist/server/bun/router/controller-discovery.d.ts +0 -13
- package/dist/server/bun/router/controller-discovery.js +0 -83
- package/dist/server/bun/router/controller-discovery.js.map +0 -1
- package/dist/server/bun/router/index.d.ts +0 -6
- package/dist/server/bun/router/index.js +0 -9
- package/dist/server/bun/router/index.js.map +0 -1
- package/dist/server/bun/router/router.d.ts +0 -12
- package/dist/server/bun/router/router.internal.d.ts +0 -15
- package/dist/server/bun/router/router.internal.js +0 -51
- package/dist/server/bun/router/router.internal.js.map +0 -1
- package/dist/server/bun/router/router.js +0 -38
- package/dist/server/bun/router/router.js.map +0 -1
- package/dist/server/bun/router/routes.d.ts +0 -5
- package/dist/server/bun/router/routes.js +0 -2
- package/dist/server/bun/router/routes.js.map +0 -1
- package/dist/server/bun/websocket/Channel.d.ts +0 -68
- package/dist/server/bun/websocket/Channel.js +0 -263
- package/dist/server/bun/websocket/Channel.js.map +0 -1
- package/dist/server/bun/websocket/Client.d.ts +0 -87
- package/dist/server/bun/websocket/Client.js +0 -193
- package/dist/server/bun/websocket/Client.js.map +0 -1
- package/dist/server/bun/websocket/Message.d.ts +0 -10
- package/dist/server/bun/websocket/Message.js +0 -103
- package/dist/server/bun/websocket/Message.js.map +0 -1
- package/dist/server/bun/websocket/Websocket.d.ts +0 -171
- package/dist/server/bun/websocket/Websocket.js +0 -336
- package/dist/server/bun/websocket/Websocket.js.map +0 -1
- package/dist/server/bun/websocket/index.d.ts +0 -11
- package/dist/server/bun/websocket/index.js +0 -14
- package/dist/server/bun/websocket/index.js.map +0 -1
- package/dist/server/bun/websocket/websocket.enums.d.ts +0 -27
- package/dist/server/bun/websocket/websocket.enums.js +0 -31
- package/dist/server/bun/websocket/websocket.enums.js.map +0 -1
- package/dist/server/bun/websocket/websocket.guards.d.ts +0 -3
- package/dist/server/bun/websocket/websocket.guards.js +0 -17
- package/dist/server/bun/websocket/websocket.guards.js.map +0 -1
- package/dist/server/bun/websocket/websocket.types.d.ts +0 -235
- package/dist/server/bun/websocket/websocket.types.js +0 -2
- package/dist/server/bun/websocket/websocket.types.js.map +0 -1
- package/dist/server/controller.d.ts +0 -62
- package/dist/server/controller.js +0 -55
- package/dist/server/controller.js.map +0 -1
- package/dist/server/index.d.ts +0 -4
- package/dist/server/index.js +0 -7
- package/dist/server/index.js.map +0 -1
- package/dist/server/service.d.ts +0 -5
- package/dist/server/service.js +0 -38
- package/dist/server/service.js.map +0 -1
- package/dist/utils/BaseDto.d.ts +0 -33
- package/dist/utils/BaseDto.js +0 -69
- package/dist/utils/BaseDto.js.map +0 -1
- package/dist/utils/BaseEntity.d.ts +0 -31
- package/dist/utils/BaseEntity.js +0 -37
- package/dist/utils/BaseEntity.js.map +0 -1
- package/dist/utils/dto_validators/IsNumberOrRangeConstraint.d.ts +0 -9
- package/dist/utils/dto_validators/IsNumberOrRangeConstraint.js +0 -85
- package/dist/utils/dto_validators/IsNumberOrRangeConstraint.js.map +0 -1
- package/dist/utils/dto_validators/index.d.ts +0 -1
- package/dist/utils/dto_validators/index.js +0 -4
- package/dist/utils/dto_validators/index.js.map +0 -1
- package/src/__tests__/app.test.ts +0 -206
- package/src/application.ts +0 -73
- package/src/client/api/base.api.ts +0 -111
- package/src/client/api/index.ts +0 -5
- package/src/client/rxjs/index.ts +0 -4
- package/src/client/rxjs/useRxjs.ts +0 -113
- package/src/client/vite/plugins/index.ts +0 -5
- package/src/client/vite/plugins/topsydeUtilsVitePlugin.ts +0 -80
- package/src/external/index.ts +0 -4
- package/src/external/re-exports.ts +0 -54
- package/src/server/base/base.database.ts +0 -31
- package/src/server/base/index.ts +0 -5
- package/src/server/bun/index.ts +0 -6
- package/src/server/bun/router/controller-discovery.ts +0 -94
- package/src/server/bun/router/index.ts +0 -9
- package/src/server/bun/router/router.internal.ts +0 -64
- package/src/server/bun/router/router.ts +0 -51
- package/src/server/bun/router/routes.ts +0 -7
- package/src/server/bun/websocket/Channel.ts +0 -310
- package/src/server/bun/websocket/Client.ts +0 -243
- package/src/server/bun/websocket/ISSUES.md +0 -1175
- package/src/server/bun/websocket/Message.ts +0 -120
- package/src/server/bun/websocket/Websocket.ts +0 -402
- package/src/server/bun/websocket/index.ts +0 -14
- package/src/server/bun/websocket/websocket.enums.ts +0 -29
- package/src/server/bun/websocket/websocket.guards.ts +0 -22
- package/src/server/bun/websocket/websocket.types.ts +0 -252
- package/src/server/controller.ts +0 -121
- package/src/server/index.ts +0 -7
- package/src/server/service.ts +0 -36
- package/src/utils/BaseDto.ts +0 -77
- package/src/utils/BaseEntity.ts +0 -49
- package/src/utils/dto_validators/IsNumberOrRangeConstraint.ts +0 -32
- package/src/utils/dto_validators/index.ts +0 -4
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { ValidatorConstraintInterface, ValidationArguments } from "class-validator";
|
|
2
|
-
/**
|
|
3
|
-
* Custom validator for number | number[] type
|
|
4
|
-
* Validates that value is either a single number or a 2-element number array [min, max]
|
|
5
|
-
*/
|
|
6
|
-
export declare class IsNumberOrRangeConstraint implements ValidatorConstraintInterface {
|
|
7
|
-
validate(value: any, args: ValidationArguments): boolean;
|
|
8
|
-
defaultMessage(args: ValidationArguments): string;
|
|
9
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
2
|
-
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
3
|
-
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
4
|
-
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
5
|
-
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
6
|
-
var _, done = false;
|
|
7
|
-
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
8
|
-
var context = {};
|
|
9
|
-
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
10
|
-
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
11
|
-
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
12
|
-
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
13
|
-
if (kind === "accessor") {
|
|
14
|
-
if (result === void 0) continue;
|
|
15
|
-
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
16
|
-
if (_ = accept(result.get)) descriptor.get = _;
|
|
17
|
-
if (_ = accept(result.set)) descriptor.set = _;
|
|
18
|
-
if (_ = accept(result.init)) initializers.unshift(_);
|
|
19
|
-
}
|
|
20
|
-
else if (_ = accept(result)) {
|
|
21
|
-
if (kind === "field") initializers.unshift(_);
|
|
22
|
-
else descriptor[key] = _;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
26
|
-
done = true;
|
|
27
|
-
};
|
|
28
|
-
var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
|
|
29
|
-
var useValue = arguments.length > 2;
|
|
30
|
-
for (var i = 0; i < initializers.length; i++) {
|
|
31
|
-
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
32
|
-
}
|
|
33
|
-
return useValue ? value : void 0;
|
|
34
|
-
};
|
|
35
|
-
var __setFunctionName = (this && this.__setFunctionName) || function (f, name, prefix) {
|
|
36
|
-
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
37
|
-
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
38
|
-
};
|
|
39
|
-
import { ValidatorConstraint } from "class-validator";
|
|
40
|
-
/**
|
|
41
|
-
* Custom validator for number | number[] type
|
|
42
|
-
* Validates that value is either a single number or a 2-element number array [min, max]
|
|
43
|
-
*/
|
|
44
|
-
let IsNumberOrRangeConstraint = (() => {
|
|
45
|
-
let _classDecorators = [ValidatorConstraint({ name: "isNumberOrRange", async: false })];
|
|
46
|
-
let _classDescriptor;
|
|
47
|
-
let _classExtraInitializers = [];
|
|
48
|
-
let _classThis;
|
|
49
|
-
var IsNumberOrRangeConstraint = _classThis = class {
|
|
50
|
-
validate(value, args) {
|
|
51
|
-
// Allow single number
|
|
52
|
-
if (typeof value === "number" && !isNaN(value)) {
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
// Allow array of exactly 2 numbers (range)
|
|
56
|
-
if (Array.isArray(value)) {
|
|
57
|
-
if (value.length !== 2)
|
|
58
|
-
return false;
|
|
59
|
-
if (typeof value[0] !== "number" || isNaN(value[0]))
|
|
60
|
-
return false;
|
|
61
|
-
if (typeof value[1] !== "number" || isNaN(value[1]))
|
|
62
|
-
return false;
|
|
63
|
-
// Optional: Validate min <= max
|
|
64
|
-
if (value[0] > value[1])
|
|
65
|
-
return false;
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
defaultMessage(args) {
|
|
71
|
-
return "Value must be a number or a 2-element number array [min, max]";
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
__setFunctionName(_classThis, "IsNumberOrRangeConstraint");
|
|
75
|
-
(() => {
|
|
76
|
-
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
77
|
-
__esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
|
|
78
|
-
IsNumberOrRangeConstraint = _classThis = _classDescriptor.value;
|
|
79
|
-
if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
80
|
-
__runInitializers(_classThis, _classExtraInitializers);
|
|
81
|
-
})();
|
|
82
|
-
return IsNumberOrRangeConstraint = _classThis;
|
|
83
|
-
})();
|
|
84
|
-
export { IsNumberOrRangeConstraint };
|
|
85
|
-
//# sourceMappingURL=IsNumberOrRangeConstraint.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"IsNumberOrRangeConstraint.js","sourceRoot":"","sources":["../../../src/utils/dto_validators/IsNumberOrRangeConstraint.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,OAAO,EAAE,mBAAmB,EAAqD,MAAM,iBAAiB,CAAC;AAEzG;;;GAGG;IAGU,yBAAyB;4BADrC,mBAAmB,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;;;;;QAE9D,QAAQ,CAAC,KAAU,EAAE,IAAyB;YAC7C,sBAAsB;YACtB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBAChD,OAAO,IAAI,CAAC;YACb,CAAC;YAED,2CAA2C;YAC3C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;oBAAE,OAAO,KAAK,CAAC;gBACrC,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAAE,OAAO,KAAK,CAAC;gBAClE,IAAI,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;oBAAE,OAAO,KAAK,CAAC;gBAClE,gCAAgC;gBAChC,IAAI,KAAK,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC;oBAAE,OAAO,KAAK,CAAC;gBACtC,OAAO,IAAI,CAAC;YACb,CAAC;YAED,OAAO,KAAK,CAAC;QACd,CAAC;QAED,cAAc,CAAC,IAAyB;YACvC,OAAO,+DAA+D,CAAC;QACxE,CAAC;;;;;QAtBF,6KAuBC;;;QAvBY,uDAAyB;;;;SAAzB,yBAAyB","sourcesContent":["import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from \"class-validator\";\n\n/**\n * Custom validator for number | number[] type\n * Validates that value is either a single number or a 2-element number array [min, max]\n */\n\n@ValidatorConstraint({ name: \"isNumberOrRange\", async: false })\nexport class IsNumberOrRangeConstraint implements ValidatorConstraintInterface {\n\tvalidate(value: any, args: ValidationArguments) {\n\t\t// Allow single number\n\t\tif (typeof value === \"number\" && !isNaN(value)) {\n\t\t\treturn true;\n\t\t}\n\n\t\t// Allow array of exactly 2 numbers (range)\n\t\tif (Array.isArray(value)) {\n\t\t\tif (value.length !== 2) return false;\n\t\t\tif (typeof value[0] !== \"number\" || isNaN(value[0])) return false;\n\t\t\tif (typeof value[1] !== \"number\" || isNaN(value[1])) return false;\n\t\t\t// Optional: Validate min <= max\n\t\t\tif (value[0] > value[1]) return false;\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tdefaultMessage(args: ValidationArguments) {\n\t\treturn \"Value must be a number or a 2-element number array [min, max]\";\n\t}\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from './IsNumberOrRangeConstraint';
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/utils/dto_validators/index.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,iCAAiC;AAEjC,cAAc,6BAA6B,CAAC","sourcesContent":["// This file is auto-generated by scripts/generate-indexes.ts\n// Do not edit this file directly\n\nexport * from './IsNumberOrRangeConstraint';\n"]}
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import * as app from "../server/bun/websocket";
|
|
2
|
-
import { WebsocketStructuredMessage } from "../server/bun/websocket/websocket.types";
|
|
3
|
-
import Singleton from "../singleton";
|
|
4
|
-
|
|
5
|
-
describe("Websocket Tests", () => {
|
|
6
|
-
const _Websocket = app.Websocket;
|
|
7
|
-
let server: any;
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
// Reset all singleton instances before each test
|
|
11
|
-
Singleton.ResetAllInstances();
|
|
12
|
-
|
|
13
|
-
// Create a mock server
|
|
14
|
-
server = {
|
|
15
|
-
publish: (channel: string, message: string) => {},
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
// Set up the Websocket instance with the server
|
|
19
|
-
const wsInstance = _Websocket.GetInstance<app.Websocket>();
|
|
20
|
-
wsInstance.set(server);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
it("should set up the websocket server correctly", () => {
|
|
24
|
-
const wsInstance = _Websocket.GetInstance<app.Websocket>();
|
|
25
|
-
expect(_Websocket.Server()).toBe(server);
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("should broadcast messages to channels", () => {
|
|
29
|
-
// Test broadcasting a message
|
|
30
|
-
const message: WebsocketStructuredMessage = {
|
|
31
|
-
type: "test",
|
|
32
|
-
content: {
|
|
33
|
-
text: "Hello, World!",
|
|
34
|
-
},
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
// This should work because the server is set
|
|
38
|
-
_Websocket.Broadcast("global", message);
|
|
39
|
-
// No assertion needed, just checking it doesn't throw
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
it("should handle the case when server is not set", () => {
|
|
43
|
-
// Create a new instance with Singleton.ResetInstance and don't set a server
|
|
44
|
-
const newWs = _Websocket.GetInstance<app.Websocket>();
|
|
45
|
-
(newWs.server as any) = null;
|
|
46
|
-
// This should log a warning but not throw an error
|
|
47
|
-
const message: WebsocketStructuredMessage = {
|
|
48
|
-
type: "test",
|
|
49
|
-
content: { text: "This should warn but not error" },
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// expect newWs.server.publish("global", JSON.stringify(message)); to throw an error
|
|
53
|
-
expect(() => newWs.server.publish("global", JSON.stringify(message))).toThrow();
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
it("should join and leave channels", () => {
|
|
57
|
-
// Create a properly mocked WebSocket client with the required methods
|
|
58
|
-
const mockWs = {
|
|
59
|
-
send: (data: string) => {},
|
|
60
|
-
subscribe: (channel: string) => {},
|
|
61
|
-
unsubscribe: (channel: string) => {},
|
|
62
|
-
data: { id: "test-client" },
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
const mockClient = {
|
|
66
|
-
id: "123",
|
|
67
|
-
ws: mockWs as any,
|
|
68
|
-
name: "test-client",
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Join a channel
|
|
72
|
-
_Websocket.Join("global", mockClient);
|
|
73
|
-
|
|
74
|
-
// Leave the channel
|
|
75
|
-
_Websocket.Leave("global", mockClient);
|
|
76
|
-
// No assertion needed, just checking it doesn't throw
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("should publish messages to all channels", () => {
|
|
80
|
-
// Test publishing a message to all channels
|
|
81
|
-
const message: WebsocketStructuredMessage = {
|
|
82
|
-
type: "test",
|
|
83
|
-
content: { text: "Broadcast to all channels" },
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
_Websocket.BroadCastAll(message);
|
|
87
|
-
// No assertion needed, just checking it doesn't throw
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
it("should verify static method behavior with inheritance", () => {
|
|
91
|
-
// This test specifically checks if static methods are called on the correct class
|
|
92
|
-
// when using inheritance
|
|
93
|
-
|
|
94
|
-
// Create a second derived class to test inheritance behavior
|
|
95
|
-
class AnotherWebsocket extends app.Websocket {}
|
|
96
|
-
|
|
97
|
-
// Get instances of both classes
|
|
98
|
-
const wsInstance1 = _Websocket.GetInstance<app.Websocket>();
|
|
99
|
-
const wsInstance2 = AnotherWebsocket.GetInstance<AnotherWebsocket>();
|
|
100
|
-
|
|
101
|
-
// Each class should have its own singleton instance
|
|
102
|
-
expect(wsInstance1).not.toBe(wsInstance2);
|
|
103
|
-
|
|
104
|
-
// Set up server for both instances
|
|
105
|
-
wsInstance1.set(server);
|
|
106
|
-
wsInstance2.set(server);
|
|
107
|
-
|
|
108
|
-
// Both classes should share the same server instance
|
|
109
|
-
expect(_Websocket.Server()).toBe(server);
|
|
110
|
-
expect(AnotherWebsocket.Server()).toBe(server);
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
it("should test static method calls from derived class instance", () => {
|
|
114
|
-
// This test checks if calling static methods from a derived class instance
|
|
115
|
-
// correctly uses the static methods of the derived class
|
|
116
|
-
|
|
117
|
-
// Create a derived class with a custom static method
|
|
118
|
-
class CustomWebsocket extends app.Websocket {
|
|
119
|
-
public static CustomServer() {
|
|
120
|
-
// This should call the Server() method on CustomWebsocket, not on Websocket
|
|
121
|
-
return this.Server();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Override the Broadcast method to add logging
|
|
125
|
-
public static Broadcast(channel: string, message: WebsocketStructuredMessage) {
|
|
126
|
-
console.log("CustomWebsocket.Broadcast called");
|
|
127
|
-
// Call the parent method
|
|
128
|
-
super.Broadcast(channel, message);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Get an instance of the custom class and set up its server
|
|
133
|
-
const customWs = CustomWebsocket.GetInstance<CustomWebsocket>();
|
|
134
|
-
customWs.set(server);
|
|
135
|
-
|
|
136
|
-
// Both classes should share the same server instance
|
|
137
|
-
expect(_Websocket.Server()).toBe(server);
|
|
138
|
-
expect(CustomWebsocket.Server()).toBe(server);
|
|
139
|
-
|
|
140
|
-
// Test broadcasting a message through the custom class
|
|
141
|
-
const message: WebsocketStructuredMessage = {
|
|
142
|
-
type: "test",
|
|
143
|
-
content: { text: "Hello from custom test" },
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
// This should use the overridden Broadcast method
|
|
147
|
-
CustomWebsocket.Broadcast("global", message);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it("should simulate the real-world scenario with modules", () => {
|
|
151
|
-
// This test simulates the real-world scenario where a derived class is used in a different module
|
|
152
|
-
|
|
153
|
-
// First, let's create a module-like structure
|
|
154
|
-
const moduleA = {
|
|
155
|
-
// This represents the topsyde-utils module
|
|
156
|
-
Websocket: app.Websocket,
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// Create a derived class that extends the base Websocket
|
|
160
|
-
class DerivedWebsocket extends moduleA.Websocket {
|
|
161
|
-
protected constructor() {
|
|
162
|
-
super();
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const moduleB = {
|
|
167
|
-
// This represents the server_rune_matchmaking module
|
|
168
|
-
Websocket: DerivedWebsocket,
|
|
169
|
-
};
|
|
170
|
-
|
|
171
|
-
// Now simulate the app.ts setup
|
|
172
|
-
class TestApp {
|
|
173
|
-
private websocket: app.Websocket;
|
|
174
|
-
|
|
175
|
-
constructor() {
|
|
176
|
-
this.websocket = moduleB.Websocket.GetInstance();
|
|
177
|
-
// Set up the server for this instance
|
|
178
|
-
this.websocket.set(server);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
setup() {
|
|
182
|
-
return server;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
broadcast(message: WebsocketStructuredMessage) {
|
|
186
|
-
moduleB.Websocket.Broadcast("global", message);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Create and set up the app
|
|
191
|
-
const testApp = new TestApp();
|
|
192
|
-
testApp.setup();
|
|
193
|
-
|
|
194
|
-
// Test broadcasting a message
|
|
195
|
-
const message: WebsocketStructuredMessage = {
|
|
196
|
-
type: "test",
|
|
197
|
-
content: { text: "Hello from app test" },
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
// This should work because the server is set
|
|
201
|
-
testApp.broadcast(message);
|
|
202
|
-
|
|
203
|
-
// Verify that the server is set correctly
|
|
204
|
-
expect(moduleB.Websocket.Server()).toBeDefined();
|
|
205
|
-
});
|
|
206
|
-
});
|
package/src/application.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { I_ApplicationResponse } from "./types";
|
|
2
|
-
|
|
3
|
-
export const RESPONSE_INIT = (status?: number, headers?: HeadersInit): ResponseInit => {
|
|
4
|
-
return {
|
|
5
|
-
status: status ?? 200,
|
|
6
|
-
headers: HEADERS_INIT(headers),
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
export const HEADERS_INIT = (headers?: HeadersInit): HeadersInit => {
|
|
11
|
-
return {
|
|
12
|
-
"Access-Control-Allow-Origin": "*", // Specific origin
|
|
13
|
-
"Content-Type": "application/json",
|
|
14
|
-
"Access-Control-Allow-Methods": "GET, POST, OPTIONS, PUT, DELETE",
|
|
15
|
-
"Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With, Origin, Accept",
|
|
16
|
-
"Access-Control-Allow-Credentials": "true",
|
|
17
|
-
"Access-Control-Max-Age": "86400", // 24 hours
|
|
18
|
-
...headers,
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
export const RESPONSE_METHOD_OPTIONS = {
|
|
23
|
-
name: "Access-Control-Max-Age",
|
|
24
|
-
value: "86400",
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
function isApplicationResponse<T>(data: T | I_ApplicationResponse<T>): data is I_ApplicationResponse<T> {
|
|
28
|
-
return typeof data === "object" && data !== null && "status" in data;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
class Application {
|
|
32
|
-
public static Response<T>(
|
|
33
|
-
data: T | I_ApplicationResponse<T>,
|
|
34
|
-
options?: { after_action?: () => void | Promise<void>; before_action?: () => void },
|
|
35
|
-
status = 200,
|
|
36
|
-
headers?: HeadersInit,
|
|
37
|
-
): Response {
|
|
38
|
-
const { after_action, before_action } = options || {};
|
|
39
|
-
Application.BeforeAction(before_action);
|
|
40
|
-
const response = isApplicationResponse(data) ? data : { status: true, data };
|
|
41
|
-
const output = Response.json(response, RESPONSE_INIT(status, headers));
|
|
42
|
-
Application.AfterAction(after_action);
|
|
43
|
-
return output;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
private static AfterAction(after_action?: () => void | Promise<void>) {
|
|
47
|
-
if (after_action) {
|
|
48
|
-
queueMicrotask(async () => {
|
|
49
|
-
try {
|
|
50
|
-
await after_action();
|
|
51
|
-
} catch (error) {
|
|
52
|
-
console.error("[Application] After-action error:", error);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
private static BeforeAction(before_action?: () => void) {
|
|
59
|
-
if (before_action) before_action();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
public static Error<T extends BodyInit | unknown | Error>(error: T | I_ApplicationResponse<T>, status = 200, headers?: HeadersInit): Response {
|
|
63
|
-
const response = isApplicationResponse(error) ? error : { status: false, data: error, error };
|
|
64
|
-
return Response.json(response, RESPONSE_INIT(status, headers));
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
public static Throw<T extends BodyInit | unknown | Error>(error: T | I_ApplicationResponse<T>, status = 400, headers?: HeadersInit): Response {
|
|
68
|
-
const response = isApplicationResponse(error) ? error : { status: false, data: error, error };
|
|
69
|
-
return Response.json(response, RESPONSE_INIT(status, headers));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
export default Application;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import Axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, isAxiosError } from "axios";
|
|
2
|
-
class BaseAPI {
|
|
3
|
-
private api: AxiosInstance;
|
|
4
|
-
protected controller: string;
|
|
5
|
-
protected base_url: string;
|
|
6
|
-
|
|
7
|
-
constructor(controller: string, base_url?: string) {
|
|
8
|
-
this.controller = controller;
|
|
9
|
-
this.base_url = base_url || import.meta.env.VITE_HOST || "";
|
|
10
|
-
this.api = this.initAxios();
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
private initAxios(): AxiosInstance {
|
|
14
|
-
const config: AxiosRequestConfig = {
|
|
15
|
-
headers: {
|
|
16
|
-
"Content-Type": "application/json",
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const instance = Axios.create(config);
|
|
21
|
-
|
|
22
|
-
// Add interceptor to modify request config
|
|
23
|
-
instance.interceptors.request.use((config) => {
|
|
24
|
-
// Ensure the correct content type
|
|
25
|
-
config.headers["Content-Type"] = "application/json";
|
|
26
|
-
|
|
27
|
-
return config;
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
return instance;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
public static Status(response: AxiosResponse<{ status: boolean }>) {
|
|
34
|
-
if (!response.data.status) throw new Error("Something went wrong");
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* @description Axios GET request wrapper
|
|
39
|
-
* @param endpoint string
|
|
40
|
-
* @generic T
|
|
41
|
-
* @returns Promise<AxiosResponse<T>>
|
|
42
|
-
*/
|
|
43
|
-
async get<T extends { status: boolean }>(endpoint: string): Promise<AxiosResponse<T>>;
|
|
44
|
-
/**
|
|
45
|
-
* @description Axios GET request wrapper
|
|
46
|
-
* @param controller string - which controller to use
|
|
47
|
-
* @param endpoint string - controller action to call
|
|
48
|
-
* @generic T
|
|
49
|
-
* @returns Promise<AxiosResponse<T>>
|
|
50
|
-
*/
|
|
51
|
-
async get<T extends { status: boolean }>(controller: string, endpoint: string): Promise<AxiosResponse<T>>;
|
|
52
|
-
/**
|
|
53
|
-
* @description Axios GET request wrapper
|
|
54
|
-
* @param controller string - which controller to use
|
|
55
|
-
* @param endpoint string - controller action to call
|
|
56
|
-
* @param debounceDelay number - debounce delay
|
|
57
|
-
* @generic T
|
|
58
|
-
* @returns Promise<AxiosResponse<T>>
|
|
59
|
-
*/
|
|
60
|
-
async get<T extends { status: boolean }>(controller: string, endpoint: string, debounceDelay?: number): Promise<AxiosResponse<T>>;
|
|
61
|
-
async get<T extends { status: boolean }>(controllerOrEndpoint: string, endpoint?: string | undefined, _debounceDelay?: number): Promise<AxiosResponse<T>> {
|
|
62
|
-
let controller = endpoint ? controllerOrEndpoint : this.controller;
|
|
63
|
-
let action = endpoint ? endpoint : controllerOrEndpoint;
|
|
64
|
-
|
|
65
|
-
return this.api.get<T>(`${this.base_url}/${controller}/${action}`).catch((err) => {
|
|
66
|
-
if (isAxiosError(err)) throw err.response;
|
|
67
|
-
throw err;
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @description Axios POST request wrapper
|
|
73
|
-
* @param endpoint string - controller action to call
|
|
74
|
-
* @param payload any
|
|
75
|
-
* @generic T
|
|
76
|
-
* @returns Promise<AxiosResponse<T>>
|
|
77
|
-
*/
|
|
78
|
-
async post<T extends { status: boolean }>(endpoint: string, payload: any): Promise<AxiosResponse<T>>;
|
|
79
|
-
/**
|
|
80
|
-
* @description Axios POST request wrapper
|
|
81
|
-
* @param controller string - which controller to use
|
|
82
|
-
* @param endpoint string - controller action to call
|
|
83
|
-
* @param payload any
|
|
84
|
-
* @generic T
|
|
85
|
-
* @returns Promise<AxiosResponse<T>>
|
|
86
|
-
*/
|
|
87
|
-
async post<T extends { status: boolean }>(controller: string, endpoint: string, payload: any): Promise<AxiosResponse<T>>;
|
|
88
|
-
async post<T extends { status: boolean }>(controllerOrEndpoint: string, endpointOrPayload: string | any, payload?: any): Promise<AxiosResponse<T>> {
|
|
89
|
-
let controller: string;
|
|
90
|
-
let action: string;
|
|
91
|
-
let data: any;
|
|
92
|
-
|
|
93
|
-
if (payload !== null && payload !== undefined) {
|
|
94
|
-
controller = controllerOrEndpoint;
|
|
95
|
-
action = endpointOrPayload;
|
|
96
|
-
data = payload;
|
|
97
|
-
} else {
|
|
98
|
-
controller = this.controller;
|
|
99
|
-
action = controllerOrEndpoint;
|
|
100
|
-
data = endpointOrPayload;
|
|
101
|
-
}
|
|
102
|
-
const response = await this.api.post<T>(`${this.base_url}/${controller}/${action}`, data).catch((err) => {
|
|
103
|
-
if (isAxiosError(err)) throw err.response;
|
|
104
|
-
throw err;
|
|
105
|
-
});
|
|
106
|
-
if (!response.data.status) throw new Error("Something went wrong");
|
|
107
|
-
return response;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export default BaseAPI;
|
package/src/client/api/index.ts
DELETED
package/src/client/rxjs/index.ts
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { Subscription } from "rxjs";
|
|
2
|
-
import { onBeforeUnmount, onMounted, ref } from "vue";
|
|
3
|
-
import { Guards, Lib } from "../../utils";
|
|
4
|
-
import { I_RxjsPayload, Rxjs, RxjsNamespaces } from "../../utils/Rxjs";
|
|
5
|
-
|
|
6
|
-
export type RxjsDataType = string | Record<string, any>;
|
|
7
|
-
export type NamespaceActions = Record<string, (data: any) => void>;
|
|
8
|
-
export type MultiNamespaceActions<T extends string> = Partial<Record<RxjsNamespaces<T>, NamespaceActions>>;
|
|
9
|
-
|
|
10
|
-
export const useRxjs = <T extends string>(
|
|
11
|
-
_namespace: RxjsNamespaces<T> | RxjsNamespaces<T>[],
|
|
12
|
-
actions?: NamespaceActions | MultiNamespaceActions<T>,
|
|
13
|
-
options?: { static_instance: boolean },
|
|
14
|
-
) => {
|
|
15
|
-
const subs = ref<Map<RxjsNamespaces<T>, Subscription>>(new Map());
|
|
16
|
-
const _actions = ref(actions);
|
|
17
|
-
const instance = Rxjs.GetInstance<Rxjs<T>>();
|
|
18
|
-
const namespaces = ref<RxjsNamespaces<T>[]>(Guards.IsArray(_namespace) ? _namespace : [_namespace]);
|
|
19
|
-
|
|
20
|
-
namespaces.value.forEach((ns) => {
|
|
21
|
-
if (instance.has(ns)) return;
|
|
22
|
-
console.log("Creating namespace", ns);
|
|
23
|
-
instance.create(ns);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
function _getAction(cta: string, ns: RxjsNamespaces<T>) {
|
|
27
|
-
if (Guards.IsArray(_namespace)) return _actions.value?.[ns]?.[cta];
|
|
28
|
-
return _actions.value?.[cta];
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function $next(namespace: RxjsNamespaces<T>, payload: I_RxjsPayload<any>): void;
|
|
32
|
-
function $next(cta: string, data: RxjsDataType): void;
|
|
33
|
-
function $next(firstParam: RxjsNamespaces<T> | string, secondParam: I_RxjsPayload<RxjsDataType> | any): void {
|
|
34
|
-
// Check if second param is a payload object (has both 'cta' and 'data' properties)
|
|
35
|
-
if (secondParam && typeof secondParam === "object" && "cta" in secondParam && "data" in secondParam) {
|
|
36
|
-
const ns = firstParam as RxjsNamespaces<T>;
|
|
37
|
-
const payload: I_RxjsPayload<any> = secondParam;
|
|
38
|
-
instance.next(ns, payload);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// Otherwise treat first param as cta and second as data
|
|
43
|
-
const cta = firstParam as string;
|
|
44
|
-
const data = secondParam as RxjsDataType;
|
|
45
|
-
const namespaces = Guards.IsArray(_namespace) ? _namespace : [_namespace];
|
|
46
|
-
namespaces.forEach((ns) => {
|
|
47
|
-
instance.next(ns, { cta, data });
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function $clear(namespace: RxjsNamespaces<T>) {
|
|
52
|
-
instance.clear(namespace);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
function $subscribe(actions: NamespaceActions | MultiNamespaceActions<T>) {
|
|
56
|
-
_actions.value = actions;
|
|
57
|
-
$unsubscribe(); // Clear existing subscriptions
|
|
58
|
-
|
|
59
|
-
const namespaces = Guards.IsArray(_namespace) ? _namespace : [_namespace];
|
|
60
|
-
|
|
61
|
-
namespaces.forEach((ns) => {
|
|
62
|
-
if (!instance.namespaces.has(ns)) {
|
|
63
|
-
Lib.Warn(`Rxjs namespace ${ns} does not exist`);
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
if (subs.value.has(ns)) return;
|
|
68
|
-
|
|
69
|
-
subs.value.set(
|
|
70
|
-
ns,
|
|
71
|
-
instance.subscribe(ns, ({ cta, data }) => {
|
|
72
|
-
const action = _getAction(cta, ns) || (() => {});
|
|
73
|
-
action(data);
|
|
74
|
-
}),
|
|
75
|
-
);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function $unsubscribe() {
|
|
80
|
-
subs.value.forEach((sub) => sub.unsubscribe());
|
|
81
|
-
subs.value.clear();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function $mount() {
|
|
85
|
-
if (subs.value.size > 0 || !actions) return;
|
|
86
|
-
$subscribe(actions);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function $unmount() {
|
|
90
|
-
$unsubscribe();
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
if (!options?.static_instance) {
|
|
94
|
-
onMounted(() => {
|
|
95
|
-
$mount();
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (!options?.static_instance) {
|
|
100
|
-
onBeforeUnmount(() => {
|
|
101
|
-
$unmount();
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return {
|
|
106
|
-
$next,
|
|
107
|
-
$clear,
|
|
108
|
-
$subscribe,
|
|
109
|
-
$unsubscribe,
|
|
110
|
-
$mount,
|
|
111
|
-
$unmount,
|
|
112
|
-
};
|
|
113
|
-
};
|