arkos 2.0.0-next.16 → 2.0.0-next.17
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/README.md +33 -31
- package/dist/cjs/app.js +3 -10
- package/dist/cjs/app.js.map +1 -1
- package/dist/cjs/components/arkos-gateway/arkos-gateway.js +344 -0
- package/dist/cjs/components/arkos-gateway/arkos-gateway.js.map +1 -0
- package/dist/cjs/components/arkos-gateway/socket-extensions.js +166 -0
- package/dist/cjs/components/arkos-gateway/socket-extensions.js.map +1 -0
- package/dist/cjs/components/arkos-gateway/types.js +7 -0
- package/dist/cjs/components/arkos-gateway/types.js.map +1 -0
- package/dist/cjs/components/arkos-gateway/utils/helpers.js +111 -0
- package/dist/cjs/components/arkos-gateway/utils/helpers.js.map +1 -0
- package/dist/cjs/components/arkos-gateway/utils/memory-gateway-store.js +51 -0
- package/dist/cjs/components/arkos-gateway/utils/memory-gateway-store.js.map +1 -0
- package/dist/cjs/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js +43 -0
- package/dist/cjs/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js.map +1 -0
- package/dist/cjs/components/arkos-gateway/utils/rate-limiter.js +17 -0
- package/dist/cjs/components/arkos-gateway/utils/rate-limiter.js.map +1 -0
- package/dist/cjs/components/arkos-policy/index.js.map +1 -1
- package/dist/cjs/components/arkos-route-hook/index.js.map +1 -1
- package/dist/cjs/components/arkos-route-hook/reader.js.map +1 -1
- package/dist/cjs/components/arkos-route-hook/types.js.map +1 -1
- package/dist/cjs/components/arkos-service-hook/index.js.map +1 -1
- package/dist/cjs/components/arkos-service-hook/types.js.map +1 -1
- package/dist/cjs/exports/index.js +3 -1
- package/dist/cjs/exports/index.js.map +1 -1
- package/dist/cjs/exports/services/index.js +2 -2
- package/dist/cjs/exports/services/index.js.map +1 -1
- package/dist/cjs/exports/websockets.js +13 -0
- package/dist/cjs/exports/websockets.js.map +1 -0
- package/dist/cjs/generated.js.map +1 -1
- package/dist/cjs/modules/auth/auth.controller.js +1 -1
- package/dist/cjs/modules/auth/auth.controller.js.map +1 -1
- package/dist/cjs/modules/auth/auth.service.js +88 -209
- package/dist/cjs/modules/auth/auth.service.js.map +1 -1
- package/dist/cjs/modules/auth/utils/auth-error-objects.js +2 -2
- package/dist/cjs/modules/auth/utils/auth-error-objects.js.map +1 -1
- package/dist/cjs/modules/auth/utils/auth-hooks-manager.js +153 -0
- package/dist/cjs/modules/auth/utils/auth-hooks-manager.js.map +1 -0
- package/dist/cjs/modules/auth/utils/docs-links.js +9 -0
- package/dist/cjs/modules/auth/utils/docs-links.js.map +1 -0
- package/dist/cjs/modules/auth/utils/services/auth-action.service.js +5 -3
- package/dist/cjs/modules/auth/utils/services/auth-action.service.js.map +1 -1
- package/dist/cjs/modules/base/base.controller.js +10 -4
- package/dist/cjs/modules/base/base.controller.js.map +1 -1
- package/dist/cjs/modules/base/base.middlewares.js +11 -20
- package/dist/cjs/modules/base/base.middlewares.js.map +1 -1
- package/dist/cjs/modules/base/base.service.js +29 -94
- package/dist/cjs/modules/base/base.service.js.map +1 -1
- package/dist/cjs/modules/email/email.service.js +14 -7
- package/dist/cjs/modules/email/email.service.js.map +1 -1
- package/dist/cjs/modules/error-handler/error-handler.controller.js +6 -102
- package/dist/cjs/modules/error-handler/error-handler.controller.js.map +1 -1
- package/dist/cjs/modules/error-handler/utils/catch-async.js.map +1 -1
- package/dist/cjs/modules/error-handler/utils/get-handled-error.js +107 -0
- package/dist/cjs/modules/error-handler/utils/get-handled-error.js.map +1 -0
- package/dist/cjs/modules/file-upload/file-upload.router.js +9 -2
- package/dist/cjs/modules/file-upload/file-upload.router.js.map +1 -1
- package/dist/cjs/modules/file-upload/file-upload.service.js +1 -1
- package/dist/cjs/modules/file-upload/file-upload.service.js.map +1 -1
- package/dist/cjs/modules/swagger/swagger.router.js +44 -10
- package/dist/cjs/modules/swagger/swagger.router.js.map +1 -1
- package/dist/cjs/modules/swagger/utils/get-open-api-login-html.js +3 -1
- package/dist/cjs/modules/swagger/utils/get-open-api-login-html.js.map +1 -1
- package/dist/cjs/modules/swagger/utils/helpers/class-validator-to-json-schema.js.map +1 -1
- package/dist/cjs/modules/swagger/utils/helpers/openapi-schema-converter.js +4 -2
- package/dist/cjs/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
- package/dist/cjs/server.js +1 -1
- package/dist/cjs/server.js.map +1 -1
- package/dist/cjs/types/arkos.js.map +1 -1
- package/dist/cjs/types/index.js.map +1 -1
- package/dist/cjs/types/new-arkos-config.js.map +1 -1
- package/dist/cjs/types/upload.js +3 -0
- package/dist/cjs/types/upload.js.map +1 -0
- package/dist/cjs/types/validation/validation-manager.js +55 -0
- package/dist/cjs/types/validation/validation-manager.js.map +1 -0
- package/dist/cjs/types/validation/validator.js +3 -0
- package/dist/cjs/types/validation/validator.js.map +1 -0
- package/dist/cjs/utils/arkos-router/arkos-router-openapi-manager.js +9 -33
- package/dist/cjs/utils/arkos-router/arkos-router-openapi-manager.js.map +1 -1
- package/dist/cjs/utils/arkos-router/index.js +15 -3
- package/dist/cjs/utils/arkos-router/index.js.map +1 -1
- package/dist/cjs/utils/arkos-router/types/index.js.map +1 -1
- package/dist/cjs/utils/arkos-router/types/upload-config.js.map +1 -1
- package/dist/cjs/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.js +41 -9
- package/dist/cjs/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.js.map +1 -1
- package/dist/cjs/utils/arkos-router/utils/helpers/upload-manager.js +26 -6
- package/dist/cjs/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
- package/dist/cjs/utils/cli/build.js +11 -2
- package/dist/cjs/utils/cli/build.js.map +1 -1
- package/dist/cjs/utils/cli/dev.js +4 -6
- package/dist/cjs/utils/cli/dev.js.map +1 -1
- package/dist/cjs/utils/cli/index.js +1 -1
- package/dist/cjs/utils/cli/index.js.map +1 -1
- package/dist/cjs/utils/cli/start.js +20 -11
- package/dist/cjs/utils/cli/start.js.map +1 -1
- package/dist/cjs/utils/cli/utils/cli.helpers.js +1 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js +53 -17
- package/dist/cjs/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js.map +1 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/generate-multiple-components.js +3 -3
- package/dist/cjs/utils/cli/utils/template-generator/templates/generate-multiple-components.js.map +1 -1
- package/dist/cjs/utils/cli/utils/template-generator/templates/zod-schema-generator.js +18 -18
- package/dist/cjs/utils/cli/utils/template-generator/templates/zod-schema-generator.js.map +1 -1
- package/dist/cjs/utils/docs-links.js +5 -0
- package/dist/cjs/utils/docs-links.js.map +1 -0
- package/dist/cjs/utils/features/api.features.js.map +1 -1
- package/dist/cjs/utils/helpers/arkos-config.helpers.js.map +1 -1
- package/dist/cjs/utils/helpers/exit-error.js +1 -1
- package/dist/cjs/utils/helpers/exit-error.js.map +1 -1
- package/dist/cjs/utils/initialize-app.js +3 -3
- package/dist/cjs/utils/initialize-app.js.map +1 -1
- package/dist/cjs/utils/remove-dir.js +1 -1
- package/dist/cjs/utils/remove-dir.js.map +1 -1
- package/dist/cjs/utils/setup-app.js.map +1 -1
- package/dist/esm/app.js +3 -10
- package/dist/esm/app.js.map +1 -1
- package/dist/esm/components/arkos-gateway/arkos-gateway.js +337 -0
- package/dist/esm/components/arkos-gateway/arkos-gateway.js.map +1 -0
- package/dist/esm/components/arkos-gateway/socket-extensions.js +161 -0
- package/dist/esm/components/arkos-gateway/socket-extensions.js.map +1 -0
- package/dist/esm/components/arkos-gateway/types.js +3 -0
- package/dist/esm/components/arkos-gateway/types.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/helpers.js +105 -0
- package/dist/esm/components/arkos-gateway/utils/helpers.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js +47 -0
- package/dist/esm/components/arkos-gateway/utils/memory-gateway-store.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js +39 -0
- package/dist/esm/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.js.map +1 -0
- package/dist/esm/components/arkos-gateway/utils/rate-limiter.js +13 -0
- package/dist/esm/components/arkos-gateway/utils/rate-limiter.js.map +1 -0
- package/dist/esm/components/arkos-policy/index.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/index.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/reader.js.map +1 -1
- package/dist/esm/components/arkos-route-hook/types.js.map +1 -1
- package/dist/esm/components/arkos-service-hook/index.js.map +1 -1
- package/dist/esm/components/arkos-service-hook/types.js.map +1 -1
- package/dist/esm/exports/index.js +2 -1
- package/dist/esm/exports/index.js.map +1 -1
- package/dist/esm/exports/services/index.js +2 -2
- package/dist/esm/exports/services/index.js.map +1 -1
- package/dist/esm/exports/websockets.js +5 -0
- package/dist/esm/exports/websockets.js.map +1 -0
- package/dist/esm/generated.js.map +1 -1
- package/dist/esm/modules/auth/auth.controller.js +2 -2
- package/dist/esm/modules/auth/auth.controller.js.map +1 -1
- package/dist/esm/modules/auth/auth.service.js +83 -204
- package/dist/esm/modules/auth/auth.service.js.map +1 -1
- package/dist/esm/modules/auth/utils/auth-error-objects.js +2 -2
- package/dist/esm/modules/auth/utils/auth-error-objects.js.map +1 -1
- package/dist/esm/modules/auth/utils/auth-hooks-manager.js +148 -0
- package/dist/esm/modules/auth/utils/auth-hooks-manager.js.map +1 -0
- package/dist/esm/modules/auth/utils/docs-links.js +6 -0
- package/dist/esm/modules/auth/utils/docs-links.js.map +1 -0
- package/dist/esm/modules/auth/utils/services/auth-action.service.js +6 -4
- package/dist/esm/modules/auth/utils/services/auth-action.service.js.map +1 -1
- package/dist/esm/modules/base/base.controller.js +11 -5
- package/dist/esm/modules/base/base.controller.js.map +1 -1
- package/dist/esm/modules/base/base.middlewares.js +12 -21
- package/dist/esm/modules/base/base.middlewares.js.map +1 -1
- package/dist/esm/modules/base/base.service.js +27 -92
- package/dist/esm/modules/base/base.service.js.map +1 -1
- package/dist/esm/modules/email/email.service.js +14 -7
- package/dist/esm/modules/email/email.service.js.map +1 -1
- package/dist/esm/modules/error-handler/error-handler.controller.js +6 -66
- package/dist/esm/modules/error-handler/error-handler.controller.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/catch-async.js.map +1 -1
- package/dist/esm/modules/error-handler/utils/get-handled-error.js +68 -0
- package/dist/esm/modules/error-handler/utils/get-handled-error.js.map +1 -0
- package/dist/esm/modules/file-upload/file-upload.router.js +9 -2
- package/dist/esm/modules/file-upload/file-upload.router.js.map +1 -1
- package/dist/esm/modules/file-upload/file-upload.service.js +1 -1
- package/dist/esm/modules/file-upload/file-upload.service.js.map +1 -1
- package/dist/esm/modules/swagger/swagger.router.js +11 -10
- package/dist/esm/modules/swagger/swagger.router.js.map +1 -1
- package/dist/esm/modules/swagger/utils/get-open-api-login-html.js +3 -1
- package/dist/esm/modules/swagger/utils/get-open-api-login-html.js.map +1 -1
- package/dist/esm/modules/swagger/utils/helpers/class-validator-to-json-schema.js.map +1 -1
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js +4 -2
- package/dist/esm/modules/swagger/utils/helpers/openapi-schema-converter.js.map +1 -1
- package/dist/esm/server.js +1 -1
- package/dist/esm/server.js.map +1 -1
- package/dist/esm/types/arkos.js.map +1 -1
- package/dist/esm/types/index.js.map +1 -1
- package/dist/esm/types/new-arkos-config.js.map +1 -1
- package/dist/esm/types/upload.js +2 -0
- package/dist/esm/types/upload.js.map +1 -0
- package/dist/esm/types/validation/validation-manager.js +50 -0
- package/dist/esm/types/validation/validation-manager.js.map +1 -0
- package/dist/esm/types/validation/validator.js +2 -0
- package/dist/esm/types/validation/validator.js.map +1 -0
- package/dist/esm/utils/arkos-router/arkos-router-openapi-manager.js +9 -33
- package/dist/esm/utils/arkos-router/arkos-router-openapi-manager.js.map +1 -1
- package/dist/esm/utils/arkos-router/index.js +15 -3
- package/dist/esm/utils/arkos-router/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/index.js.map +1 -1
- package/dist/esm/utils/arkos-router/types/upload-config.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.js +41 -9
- package/dist/esm/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.js.map +1 -1
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js +26 -6
- package/dist/esm/utils/arkos-router/utils/helpers/upload-manager.js.map +1 -1
- package/dist/esm/utils/cli/build.js +11 -2
- package/dist/esm/utils/cli/build.js.map +1 -1
- package/dist/esm/utils/cli/dev.js +4 -6
- package/dist/esm/utils/cli/dev.js.map +1 -1
- package/dist/esm/utils/cli/index.js +1 -1
- package/dist/esm/utils/cli/index.js.map +1 -1
- package/dist/esm/utils/cli/start.js +20 -11
- package/dist/esm/utils/cli/start.js.map +1 -1
- package/dist/esm/utils/cli/utils/cli.helpers.js +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js +53 -17
- package/dist/esm/utils/cli/utils/template-generator/templates/class-validator-dto-generator.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/generate-multiple-components.js +3 -3
- package/dist/esm/utils/cli/utils/template-generator/templates/generate-multiple-components.js.map +1 -1
- package/dist/esm/utils/cli/utils/template-generator/templates/zod-schema-generator.js +18 -18
- package/dist/esm/utils/cli/utils/template-generator/templates/zod-schema-generator.js.map +1 -1
- package/dist/esm/utils/docs-links.js +2 -0
- package/dist/esm/utils/docs-links.js.map +1 -0
- package/dist/esm/utils/features/api.features.js.map +1 -1
- package/dist/esm/utils/helpers/arkos-config.helpers.js.map +1 -1
- package/dist/esm/utils/helpers/exit-error.js +1 -1
- package/dist/esm/utils/helpers/exit-error.js.map +1 -1
- package/dist/esm/utils/initialize-app.js +3 -3
- package/dist/esm/utils/initialize-app.js.map +1 -1
- package/dist/esm/utils/remove-dir.js +1 -1
- package/dist/esm/utils/remove-dir.js.map +1 -1
- package/dist/esm/utils/setup-app.js.map +1 -1
- package/dist/types/components/arkos-gateway/arkos-gateway.d.ts +121 -0
- package/dist/types/components/arkos-gateway/socket-extensions.d.ts +79 -0
- package/dist/types/components/arkos-gateway/types.d.ts +364 -0
- package/dist/types/components/arkos-gateway/utils/helpers.d.ts +9 -0
- package/dist/types/components/arkos-gateway/utils/memory-gateway-store.d.ts +14 -0
- package/dist/types/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.d.ts +20 -0
- package/dist/types/components/arkos-gateway/utils/rate-limiter.d.ts +11 -0
- package/dist/types/components/arkos-route-hook/index.d.ts +4 -4
- package/dist/types/components/arkos-route-hook/reader.d.ts +2 -2
- package/dist/types/components/arkos-route-hook/types.d.ts +6 -0
- package/dist/types/components/arkos-service-hook/index.d.ts +1 -1
- package/dist/types/components/arkos-service-hook/types.d.ts +0 -21
- package/dist/types/exports/index.d.ts +3 -1
- package/dist/types/exports/services/index.d.ts +2 -2
- package/dist/types/exports/websockets.d.ts +5 -0
- package/dist/types/modules/auth/auth.service.d.ts +12 -36
- package/dist/types/modules/auth/utils/auth-hooks-manager.d.ts +63 -0
- package/dist/types/modules/auth/utils/docs-links.d.ts +3 -0
- package/dist/types/modules/auth/utils/services/auth-action.service.d.ts +2 -2
- package/dist/types/modules/base/base.controller.d.ts +2 -2
- package/dist/types/modules/base/base.service.d.ts +4 -7
- package/dist/types/modules/error-handler/utils/catch-async.d.ts +2 -2
- package/dist/types/modules/error-handler/utils/get-handled-error.d.ts +1 -0
- package/dist/types/modules/swagger/utils/helpers/openapi-schema-converter.d.ts +6 -1
- package/dist/types/types/arkos.d.ts +1 -13
- package/dist/types/types/index.d.ts +6 -5
- package/dist/types/types/new-arkos-config.d.ts +1 -1
- package/dist/types/types/upload.d.ts +10 -0
- package/dist/types/types/validation/validation-manager.d.ts +27 -0
- package/dist/types/types/validation/validator.d.ts +2 -0
- package/dist/types/utils/arkos-router/index.d.ts +7 -0
- package/dist/types/utils/arkos-router/types/index.d.ts +35 -21
- package/dist/types/utils/arkos-router/types/upload-config.d.ts +2 -1
- package/dist/types/utils/arkos-router/utils/helpers/apply-arkos-router-proxy.d.ts +6 -7
- package/dist/types/utils/arkos-router/utils/helpers/upload-manager.d.ts +1 -0
- package/dist/types/utils/cli/build.d.ts +1 -1
- package/dist/types/utils/cli/start.d.ts +2 -0
- package/dist/types/utils/cli/utils/template-generator/templates/class-validator-dto-generator.d.ts +7 -0
- package/dist/types/utils/docs-links.d.ts +1 -0
- package/dist/types/utils/features/api.features.d.ts +1 -2
- package/dist/types/utils/helpers/arkos-config.helpers.d.ts +5 -0
- package/package.json +48 -15
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ArkosBroadcastOperatorImpl = void 0;
|
|
4
|
+
exports.mountArkosSocketExtensions = mountArkosSocketExtensions;
|
|
5
|
+
const uuidv7_1 = require("uuidv7");
|
|
6
|
+
function injectMeta(data) {
|
|
7
|
+
return {
|
|
8
|
+
...data,
|
|
9
|
+
_meta: { mid: (0, uuidv7_1.uuidv7)(), timestamp: Date.now() },
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function resolveUserSocketIds(socket, userId) {
|
|
13
|
+
const ids = Array.isArray(userId) ? userId : [userId];
|
|
14
|
+
const result = [];
|
|
15
|
+
for (const [id, s] of socket.nsp.sockets) {
|
|
16
|
+
for (const uid of ids) {
|
|
17
|
+
if (s.rooms.has(`arkos::user:${uid}`)) {
|
|
18
|
+
result.push(id);
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
class ArkosBroadcastOperatorImpl {
|
|
26
|
+
constructor(socket, operator) {
|
|
27
|
+
this.socket = socket;
|
|
28
|
+
this.operator = operator;
|
|
29
|
+
const instance = Object.create(operator);
|
|
30
|
+
instance.emit = this.emit.bind(this);
|
|
31
|
+
instance.emitWithAck = this.emitWithAck.bind(this);
|
|
32
|
+
instance.except = this.except.bind(this);
|
|
33
|
+
instance.compress = this.compress.bind(this);
|
|
34
|
+
instance.timeout = this.timeout.bind(this);
|
|
35
|
+
instance.users = this.users.bind(this);
|
|
36
|
+
Object.defineProperty(instance, "volatile", {
|
|
37
|
+
get: () => this.volatile,
|
|
38
|
+
configurable: true,
|
|
39
|
+
});
|
|
40
|
+
return instance;
|
|
41
|
+
}
|
|
42
|
+
async users() {
|
|
43
|
+
const sockets = await this.operator.fetchSockets();
|
|
44
|
+
const userIds = new Set();
|
|
45
|
+
for (const s of sockets) {
|
|
46
|
+
for (const room of s.rooms) {
|
|
47
|
+
if (room.startsWith("arkos::user:")) {
|
|
48
|
+
userIds.add(room.slice("arkos::user:".length));
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return Array.from(userIds);
|
|
54
|
+
}
|
|
55
|
+
except(room) {
|
|
56
|
+
if (typeof room === "string" || Array.isArray(room)) {
|
|
57
|
+
return new ArkosBroadcastOperatorImpl(this.socket, this.operator.except(room));
|
|
58
|
+
}
|
|
59
|
+
const socketIds = resolveUserSocketIds(this.socket, room.user);
|
|
60
|
+
let op = this.operator;
|
|
61
|
+
for (const id of socketIds)
|
|
62
|
+
op = op.except(id);
|
|
63
|
+
return new ArkosBroadcastOperatorImpl(this.socket, op);
|
|
64
|
+
}
|
|
65
|
+
emit(event, ...args) {
|
|
66
|
+
const [data, ...rest] = args;
|
|
67
|
+
return this.operator.emit(event, injectMeta(data), ...rest);
|
|
68
|
+
}
|
|
69
|
+
get volatile() {
|
|
70
|
+
return new ArkosBroadcastOperatorImpl(this.socket, this.operator.volatile);
|
|
71
|
+
}
|
|
72
|
+
compress(value) {
|
|
73
|
+
return new ArkosBroadcastOperatorImpl(this.socket, this.operator.compress(value));
|
|
74
|
+
}
|
|
75
|
+
timeout(ms) {
|
|
76
|
+
return new ArkosBroadcastOperatorImpl(this.socket, this.operator.timeout(ms));
|
|
77
|
+
}
|
|
78
|
+
async emitWithAck(event, ...args) {
|
|
79
|
+
const [data, ...rest] = args;
|
|
80
|
+
return this.operator.emitWithAck(event, injectMeta(data), ...rest);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
exports.ArkosBroadcastOperatorImpl = ArkosBroadcastOperatorImpl;
|
|
84
|
+
class ArkosRetryTargetImpl {
|
|
85
|
+
constructor(socket, maxRetries, baseDelay, multiplier) {
|
|
86
|
+
this.socket = socket;
|
|
87
|
+
this.maxRetries = maxRetries;
|
|
88
|
+
this.baseDelay = baseDelay;
|
|
89
|
+
this.multiplier = multiplier;
|
|
90
|
+
}
|
|
91
|
+
timeout(ms) {
|
|
92
|
+
this.timeoutMs = ms;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
async emitWithAck(event, data, ...rest) {
|
|
96
|
+
const patched = injectMeta(data);
|
|
97
|
+
return this.attemptEmitWithAck(event, patched, rest, 0);
|
|
98
|
+
}
|
|
99
|
+
async attemptEmitWithAck(event, data, rest, attempt) {
|
|
100
|
+
try {
|
|
101
|
+
const s = this.timeoutMs
|
|
102
|
+
? this.socket.timeout(this.timeoutMs)
|
|
103
|
+
: this.socket;
|
|
104
|
+
return await s.emitWithAck(event, data, ...rest);
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
if (attempt < this.maxRetries) {
|
|
108
|
+
const delay = Math.pow(this.multiplier, attempt) * this.baseDelay;
|
|
109
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
110
|
+
return this.attemptEmitWithAck(event, data, rest, attempt + 1);
|
|
111
|
+
}
|
|
112
|
+
throw err;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function mountArkosSocketExtensions(socket) {
|
|
117
|
+
const originalEmit = socket.emit.bind(socket);
|
|
118
|
+
const originalEmitWithAck = socket.emitWithAck.bind(socket);
|
|
119
|
+
const originalTo = socket.to.bind(socket);
|
|
120
|
+
const originalTimeout = socket.timeout.bind(socket);
|
|
121
|
+
socket.emit = function (event, data, ...rest) {
|
|
122
|
+
return originalEmit(event, injectMeta(data), ...rest);
|
|
123
|
+
};
|
|
124
|
+
socket.emitWithAck = function (event, data, ...rest) {
|
|
125
|
+
return originalEmitWithAck(event, injectMeta(data), ...rest);
|
|
126
|
+
};
|
|
127
|
+
socket.to = function (room) {
|
|
128
|
+
return new ArkosBroadcastOperatorImpl(socket, originalTo(room));
|
|
129
|
+
};
|
|
130
|
+
socket.timeout = function (ms) {
|
|
131
|
+
const timedSocket = originalTimeout(ms);
|
|
132
|
+
const originalTimedEmitWithAck = timedSocket.emitWithAck.bind(timedSocket);
|
|
133
|
+
timedSocket.emitWithAck = function (event, data, ...rest) {
|
|
134
|
+
const result = originalTimedEmitWithAck(event, injectMeta(data), ...rest);
|
|
135
|
+
return result;
|
|
136
|
+
};
|
|
137
|
+
return timedSocket;
|
|
138
|
+
};
|
|
139
|
+
const broadcastDescriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(socket), "broadcast");
|
|
140
|
+
Object.defineProperty(socket, "broadcast", {
|
|
141
|
+
get() {
|
|
142
|
+
const operator = broadcastDescriptor.get.call(socket);
|
|
143
|
+
return new ArkosBroadcastOperatorImpl(socket, operator);
|
|
144
|
+
},
|
|
145
|
+
configurable: true,
|
|
146
|
+
});
|
|
147
|
+
socket.user = function (userId) {
|
|
148
|
+
const target = new ArkosBroadcastOperatorImpl(socket, socket.nsp.to(`arkos::user:${userId}`));
|
|
149
|
+
target.activeRooms = async () => {
|
|
150
|
+
const sockets = await target.fetchSockets();
|
|
151
|
+
const roomsSet = new Set();
|
|
152
|
+
for (const s of sockets) {
|
|
153
|
+
for (const room of s.rooms) {
|
|
154
|
+
if (!room.startsWith("arkos::user:"))
|
|
155
|
+
roomsSet.add(room);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return Array.from(roomsSet);
|
|
159
|
+
};
|
|
160
|
+
return target;
|
|
161
|
+
};
|
|
162
|
+
socket.retry = function (times, baseDelay = 1000, multiplier = 2) {
|
|
163
|
+
return new ArkosRetryTargetImpl(socket, times, baseDelay, multiplier);
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=socket-extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"socket-extensions.js","sourceRoot":"","sources":["../../../../src/components/arkos-gateway/socket-extensions.ts"],"names":[],"mappings":"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","sourcesContent":["import { uuidv7 } from \"uuidv7\";\nimport {\n ArkosBroadcastOperator,\n ArkosRetryTarget,\n ArkosSocket,\n ArkosUserTarget,\n} from \"./types\";\nimport { BroadcastOperator } from \"socket.io\";\n\nfunction injectMeta<T>(\n data: T\n): T & { _meta: { mid: string; timestamp: number } } {\n return {\n ...(data as any),\n _meta: { mid: uuidv7(), timestamp: Date.now() },\n };\n}\n\nfunction resolveUserSocketIds(\n socket: ArkosSocket,\n userId: string | string[]\n): string[] {\n const ids = Array.isArray(userId) ? userId : [userId];\n const result: string[] = [];\n for (const [id, s] of socket.nsp.sockets) {\n for (const uid of ids) {\n if (s.rooms.has(`arkos::user:${uid}`)) {\n result.push(id);\n break;\n }\n }\n }\n return result;\n}\n\nexport class ArkosBroadcastOperatorImpl {\n constructor(\n private readonly socket: ArkosSocket,\n private readonly operator: BroadcastOperator<any, any>\n ) {\n const instance = Object.create(operator) as this;\n instance.emit = this.emit.bind(this);\n instance.emitWithAck = this.emitWithAck.bind(this);\n instance.except = this.except.bind(this);\n instance.compress = this.compress.bind(this);\n instance.timeout = this.timeout.bind(this);\n instance.users = this.users.bind(this);\n Object.defineProperty(instance, \"volatile\", {\n get: () => this.volatile,\n configurable: true,\n });\n return instance;\n }\n\n /**\n * Returns all unique user IDs currently in the target room(s).\n * Uses the internal `arkos::user:` room convention to map sockets to users.\n *\n * @example\n * const users = await socket.to(\"room-123\").users()\n * console.log(users) // ['user-1', 'user-2']\n */\n async users(): Promise<string[]> {\n const sockets = await this.operator.fetchSockets();\n const userIds = new Set<string>();\n for (const s of sockets) {\n for (const room of s.rooms) {\n if (room.startsWith(\"arkos::user:\")) {\n userIds.add(room.slice(\"arkos::user:\".length));\n break; // each socket has at most one user room\n }\n }\n }\n return Array.from(userIds);\n }\n\n /**\n * Excludes sockets from the broadcast.\n * Accepts a room name, socket ID, array of rooms/IDs, or `{ user: string | string[] }`\n * to exclude all sockets belonging to one or more users.\n *\n * @example\n * socket.to(\"room-101\").except(\"room-102\").emit(\"foo\", data)\n * socket.broadcast.except({ user: userId }).emit(\"foo\", data)\n * socket.broadcast.except({ user: [id1, id2] }).emit(\"foo\", data)\n */\n except(room: string | string[] | { user: string | string[] }) {\n if (typeof room === \"string\" || Array.isArray(room)) {\n return new ArkosBroadcastOperatorImpl(\n this.socket,\n this.operator.except(room)\n );\n }\n const socketIds = resolveUserSocketIds(this.socket, room.user);\n let op = this.operator;\n for (const id of socketIds) op = op.except(id);\n return new ArkosBroadcastOperatorImpl(this.socket, op);\n }\n\n /**\n * Emits an event to the target. `_meta` (`mid` + `timestamp`) is injected automatically.\n *\n * @example\n * socket.to(\"room-101\").emit(\"message\", { text: \"hello\" })\n * socket.broadcast.emit(\"announcement\", data)\n */\n emit(event: string, ...args: any[]): boolean {\n const [data, ...rest] = args;\n return this.operator.emit(event, injectMeta(data), ...rest);\n }\n\n /**\n * Sets the volatile flag — the event may be dropped if the client is not ready.\n * Useful for high-frequency non-critical events like cursor positions or typing indicators.\n *\n * @example\n * socket.to(\"room-101\").volatile.emit(\"cursor\", position)\n */\n get volatile() {\n return new ArkosBroadcastOperatorImpl(this.socket, this.operator.volatile);\n }\n\n /**\n * Sets the compress flag for the next emission.\n *\n * @example\n * socket.broadcast.compress(false).emit(\"ping\", data)\n */\n compress(value: boolean) {\n return new ArkosBroadcastOperatorImpl(\n this.socket,\n this.operator.compress(value)\n );\n }\n\n /**\n * Sets a timeout in milliseconds for `emitWithAck`.\n * Rejects the promise if no client acknowledges within the given delay.\n *\n * @example\n * socket.to(\"room-101\").timeout(3000).emitWithAck(\"confirm\", data)\n */\n timeout(ms: number) {\n return new ArkosBroadcastOperatorImpl(\n this.socket,\n this.operator.timeout(ms)\n );\n }\n\n /**\n * Emits an event and waits for acknowledgements from all matched clients.\n * `_meta` is injected automatically. Use `.timeout(ms)` to avoid hanging indefinitely.\n *\n * @example\n * const responses = await socket.to(\"room-101\").timeout(3000).emitWithAck(\"confirm\", data)\n */\n async emitWithAck(event: string, ...args: any[]): Promise<any[]> {\n const [data, ...rest] = args;\n return this.operator.emitWithAck(event, injectMeta(data), ...rest);\n }\n}\n\nclass ArkosRetryTargetImpl implements ArkosRetryTarget {\n private timeoutMs?: number;\n\n constructor(\n private readonly socket: ArkosSocket,\n private readonly maxRetries: number,\n private readonly baseDelay: number,\n private readonly multiplier: number\n ) {}\n\n /**\n * Sets a timeout in milliseconds applied on each `emitWithAck` attempt.\n *\n * @example\n * socket.retry(3).timeout(5000).emitWithAck(\"event\", data)\n */\n timeout(ms: number) {\n this.timeoutMs = ms;\n return this;\n }\n\n /**\n * Emits with ack and exponential backoff retry. `_meta` is injected automatically.\n * Each attempt respects the `.timeout(ms)` if set.\n *\n * @example\n * const ack = await socket.retry(3).timeout(5000).emitWithAck(\"confirm\", data)\n */\n async emitWithAck(event: string, data: any, ...rest: any[]): Promise<any> {\n const patched = injectMeta(data);\n return this.attemptEmitWithAck(event, patched, rest, 0);\n }\n\n private async attemptEmitWithAck(\n event: string,\n data: any,\n rest: any[],\n attempt: number\n ): Promise<any> {\n try {\n const s = this.timeoutMs\n ? this.socket.timeout(this.timeoutMs)\n : this.socket;\n return await s.emitWithAck(event, data, ...rest);\n } catch (err) {\n if (attempt < this.maxRetries) {\n const delay = Math.pow(this.multiplier, attempt) * this.baseDelay;\n await new Promise((r) => setTimeout(r, delay));\n return this.attemptEmitWithAck(event, data, rest, attempt + 1);\n }\n throw err;\n }\n }\n}\n\n/**\n * Mounts Arkos socket extensions and patches emit methods for automatic `_meta` injection.\n * Called once by the gateway at connection time, right after injecting `_arkos`.\n *\n * Patches: `emit`, `emitWithAck`, `to()`, `timeout()`, `broadcast`\n * Mounts: `user()`, `peer()`, `retry()`\n *\n * @internal\n * @since 1.7.0-canary.29\n */\nexport function mountArkosSocketExtensions(socket: ArkosSocket): void {\n const originalEmit = socket.emit.bind(socket);\n const originalEmitWithAck = socket.emitWithAck.bind(socket);\n const originalTo = socket.to.bind(socket);\n const originalTimeout = socket.timeout.bind(socket);\n\n socket.emit = function (event: string, data?: any, ...rest: any[]) {\n return originalEmit(event, injectMeta(data), ...rest);\n };\n\n socket.emitWithAck = function (event: string, data?: any, ...rest: any[]) {\n return originalEmitWithAck(event, injectMeta(data), ...rest);\n };\n\n socket.to = function (room: string | string[]) {\n return new ArkosBroadcastOperatorImpl(\n socket,\n originalTo(room)\n ) as any as ArkosBroadcastOperator;\n };\n\n socket.timeout = function (ms: number) {\n const timedSocket = originalTimeout(ms);\n const originalTimedEmitWithAck = timedSocket.emitWithAck.bind(timedSocket);\n timedSocket.emitWithAck = function (\n event: string,\n data?: any,\n ...rest: any[]\n ) {\n const result = originalTimedEmitWithAck(event, injectMeta(data), ...rest);\n return result;\n };\n return timedSocket;\n };\n\n const broadcastDescriptor = Object.getOwnPropertyDescriptor(\n Object.getPrototypeOf(socket),\n \"broadcast\"\n );\n\n Object.defineProperty(socket, \"broadcast\", {\n get() {\n const operator = broadcastDescriptor!.get!.call(socket);\n return new ArkosBroadcastOperatorImpl(socket, operator);\n },\n configurable: true,\n });\n\n socket.user = function (userId: string): ArkosUserTarget {\n const target = new ArkosBroadcastOperatorImpl(\n socket,\n socket.nsp.to(`arkos::user:${userId}`)\n ) as any as ArkosUserTarget;\n\n target.activeRooms = async () => {\n const sockets = await (\n target as unknown as ArkosBroadcastOperator\n ).fetchSockets();\n const roomsSet = new Set<string>();\n for (const s of sockets as any[]) {\n for (const room of s.rooms) {\n if (!room.startsWith(\"arkos::user:\")) roomsSet.add(room);\n }\n }\n return Array.from(roomsSet);\n };\n\n return target;\n };\n socket.retry = function (\n times: number,\n baseDelay: number = 1000,\n multiplier: number = 2\n ): ArkosRetryTarget {\n return new ArkosRetryTargetImpl(socket, times, baseDelay, multiplier);\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/components/arkos-gateway/types.ts"],"names":[],"mappings":";;;AA8dA,MAAa,sBAAsB;CAAG;AAAtC,wDAAsC","sourcesContent":["import { BroadcastOperator, Socket } from \"socket.io\";\nimport { User } from \"../../types\";\nimport { DefaultEventsMap } from \"socket.io\";\nimport { Validator } from \"../../types/validation/validator\";\nimport { Options as RateLimitOptions } from \"express-rate-limit\";\nimport { DetailedAccessControlRule } from \"../../types/auth\";\n///@ts-ignore\nimport {\n AllButLast,\n DecorateAcknowledgements,\n DecorateAcknowledgementsWithMultipleResponses,\n EventNames,\n EventNamesWithAck,\n EventNamesWithError,\n EventParams,\n FirstNonErrorArg,\n Last,\n ///@ts-ignore\n} from \"socket.io/dist/typed-events\";\n\nexport interface EventsMap {\n [event: string]: any;\n}\n\nexport interface ArkosSocket<\n ListenEvents extends EventsMap = DefaultEventsMap,\n EmitEvents extends EventsMap = ListenEvents,\n ServerSideEvents extends EventsMap = DefaultEventsMap,\n SocketData extends Validator = any,\n SocketLocals extends Record<string, any> = Record<string, any>,\n> extends Socket<ListenEvents, EmitEvents, ServerSideEvents, SocketData> {\n /**\n * Populated by Arkos after successful authentication on connection.\n * Available in all event handlers when `authentication: true` on the gateway.\n */\n currentUser?: User;\n\n /**\n * Populated by Arkos after successful validation.\n * Typed to the event's validation schema when using TypeScript.\n */\n data: SocketData;\n\n /** User access token. */\n accessToken?: string;\n\n /**\n * Metadata from the incoming message, extracted from `_meta` by Arkos.\n *\n * - `mid`: Unique message ID used for deduplication.\n * - `timestamp`: When the message was sent by the client.\n */\n meta?: {\n mid?: string;\n timestamp?: string | number | Date;\n };\n\n /**\n * Per-event local storage, scoped to the current event pipeline.\n * Use to pass data between pipes and the event handler — like Express's `res.locals`.\n * Reset automatically on each event.\n *\n * @example\n * chatGateway.pipe((socket, data) => {\n * socket.locals.enriched = enrichUser(socket.currentUser)\n * })\n *\n * chatGateway.on({ event: \"send_message\" }, (socket, data) => {\n * console.log(socket.locals.enriched)\n * })\n */\n locals?: SocketLocals;\n\n /**\n * Internal Arkos context injected by the gateway at connection time.\n *\n * @internal\n */\n _arkos: {\n store: ArkosGatewayStore;\n gatewayConfig: ArkosGatewayConfig;\n };\n\n /**\n * Targets all active socket connections of a user by their user ID.\n * Uses the internal `arkos::user:{userId}` room convention.\n *\n * Supports emit, management, and exclusion operations across all of the\n * user's active connections.\n *\n * @example\n * socket.user(userId).emit(\"notification\", data)\n * socket.user(userId).except({ user: otherUserId }).emit(\"sync\", data)\n * const sockets = await socket.user(userId).fetchSockets()\n * const online = await socket.user(userId).isOnline()\n *\n * @since 1.7.0-canary.29\n */\n user(userId: string): ArkosUserTarget;\n\n /**\n * Wraps the next `emit` or `emitWithAck` with exponential backoff retry logic.\n * Chain `.timeout(ms)` before `.emitWithAck()` as usual.\n *\n * @example\n * socket.retry(3).emit(\"event\", data)\n * socket.retry(3).timeout(5000).emitWithAck(\"event\", data)\n *\n * @since 1.7.0-canary.29\n */\n retry(\n times: number,\n initialDelay?: number,\n multiplier?: number\n ): ArkosRetryTarget;\n\n /**\n * Emits an event to this client.\n * Arkos automatically injects `_meta` (`mid` + `timestamp`) into every outgoing payload\n * for client-side deduplication and freshness checks.\n *\n * @example\n * socket.emit(\"message\", { text: \"hello\" })\n * socket.emit(\"notification\", { title: \"New order\" })\n */\n emit<Ev extends EventNames<EmitEvents>>(\n ev: Ev,\n ...args: EventParams<EmitEvents, Ev>\n ): true;\n\n /**\n * Emits an event and waits for an acknowledgement from the client.\n * Arkos injects `_meta` automatically. Use `.timeout(ms)` to avoid hanging indefinitely.\n *\n * @example\n * const response = await socket.timeout(5000).emitWithAck(\"confirm\", data)\n */\n emitWithAck<Ev extends EventNamesWithAck<EmitEvents>>(\n ev: Ev,\n ...args: AllButLast<EventParams<EmitEvents, Ev>>\n ): Promise<FirstNonErrorArg<Last<EventParams<EmitEvents, Ev>>>>;\n\n /**\n * Targets a room when broadcasting — excludes the sender.\n * Returns an {@link ArkosBroadcastOperator} with enhanced `.except({ user })` support\n * and automatic `_meta` injection on every `.emit()`.\n *\n * @example\n * socket.to(\"room-101\").emit(\"message\", data)\n * socket.to(\"room-101\").except({ user: userId }).emit(\"message\", data)\n * socket.to(\"room-101\").volatile.emit(\"typing\", data)\n * await socket.to(\"room-101\").timeout(3000).emitWithAck(\"confirm\", data)\n *\n * @since 1.7.0-canary.29\n */\n to(\n room: string | string[]\n ): ArkosBroadcastOperator<\n DecorateAcknowledgementsWithMultipleResponses<EmitEvents>,\n SocketData\n > &\n BroadcastOperator<EmitEvents, SocketData>;\n /**\n * Broadcasts to all connected clients except the sender.\n * Returns an {@link ArkosBroadcastOperator} with enhanced `.except({ user })` support\n * and automatic `_meta` injection on every `.emit()`.\n *\n * @example\n * socket.broadcast.emit(\"announcement\", data)\n * socket.broadcast.except({ user: userId }).emit(\"announcement\", data)\n * socket.broadcast.volatile.emit(\"ping\", data)\n *\n * @since 1.7.0-canary.29\n */\n get broadcast(): ArkosBroadcastOperator<\n DecorateAcknowledgementsWithMultipleResponses<EmitEvents>,\n SocketData\n > &\n BroadcastOperator<EmitEvents, SocketData>;\n}\n\n/**\n * Enhanced broadcast/room target returned by `socket.to()` and `socket.broadcast`.\n * Extends the native `BroadcastOperator` with `{ user }` exclusion support\n * and automatic `_meta` injection on emit.\n *\n * @since 1.7.0-canary.29\n */\nexport interface ArkosBroadcastOperator<\n EmitEvents extends EventsMap = DefaultEventsMap,\n SocketData extends Validator = any,\n> extends BroadcastOperator<EmitEvents, SocketData> {\n /**\n * Exclude sockets from the broadcast.\n * Accepts a room name, socket ID, or `{ user: string | string[] }` to exclude\n * all sockets belonging to one or more users.\n *\n * @example\n * socket.to(\"room-101\").except(\"room-102\").emit(\"foo\", data)\n * socket.broadcast.except({ user: userId }).emit(\"foo\", data)\n * socket.broadcast.except({ user: [userId1, userId2] }).emit(\"foo\", data)\n */\n except(\n room: string | string[] | { user: string | string[] }\n ): ArkosBroadcastOperator<EmitEvents, SocketData>;\n\n /**\n * Emits to all clients,`_meta` is injected automatically.\n *\n * @example\n * // the “foo” event will be broadcast to all connected clients\n * io.emit(\"foo\", \"bar\");\n *\n * // the “foo” event will be broadcast to all connected clients in the “room-101” room\n * io.to(\"room-101\").emit(\"foo\", \"bar\");\n *\n * // with an acknowledgement expected from all connected clients\n * io.timeout(1000).emit(\"some-event\", (err, responses) => {\n * if (err) {\n * // some clients did not acknowledge the event in the given delay\n * } else {\n * console.log(responses); // one response per client\n * }\n * });\n *\n * @return Always true\n */\n emit<Ev extends EventNames<EmitEvents>>(\n ev: Ev,\n ...args: EventParams<EmitEvents, Ev>\n ): true;\n\n /** Chain volatile flag — event may be lost if client is not ready. */\n get volatile(): ArkosBroadcastOperator<EmitEvents, SocketData>;\n\n /** Chain compress flag. */\n compress(value: boolean): ArkosBroadcastOperator<EmitEvents, SocketData>;\n\n /** Chain timeout for `emitWithAck`. */\n timeout(\n ms: number\n ): ArkosBroadcastOperator<DecorateAcknowledgements<EmitEvents>, SocketData>;\n\n /**\n * Emits an event and waits for an acknowledgement from all clients.\n * `_meta` is injected automatically\n * @example\n * try {\n * const responses = await io.timeout(1000).emitWithAck(\"some-event\");\n * console.log(responses); // one response per client\n * } catch (e) {\n * // some clients did not acknowledge the event in the given delay\n * }\n *\n * @return a Promise that will be fulfilled when all clients have acknowledged the event\n */\n emitWithAck<Ev extends EventNamesWithError<EmitEvents>>(\n ev: Ev,\n ...args: AllButLast<EventParams<EmitEvents, Ev>>\n ): Promise<FirstNonErrorArg<Last<EventParams<EmitEvents, Ev>>>>;\n /**\n * Returns all unique user IDs currently in the target room(s).\n *\n * @example\n * const users = await socket.to(\"room-123\").users()\n */\n users(): Promise<string[]>;\n}\n\n/**\n * Returned by `socket.retry(n)`. Wraps `emit` and `emitWithAck`\n * with exponential backoff. Chain `.timeout(ms)` before `.emitWithAck()` as usual.\n *\n * @since 1.7.0-canary.29\n */\nexport interface ArkosRetryTarget {\n /** Emit with ack and retry. `_meta` is injected automatically. */\n emitWithAck(event: string, data: any, ...rest: any[]): Promise<any>;\n\n /**\n * Chain a timeout before `emitWithAck`.\n *\n * @example\n * socket.retry(3).timeout(5000).emitWithAck(\"event\", data)\n */\n timeout(ms: number): ArkosRetryTarget;\n}\n\n/**\n * Returned by `socket.user(userId)`.\n * Targets all active socket connections of a user.\n *\n * @since 1.7.0-canary.29\n */\nexport interface ArkosUserTarget extends ArkosBroadcastOperator {\n /**\n * Returns all active rooms for this user.\n *\n * @example\n * const rooms = await socket.user(userId).activeRooms()\n * console.log(rooms.length) // number of active tabs/connections\n */\n activeRooms(): Promise<string[]>;\n}\n\nexport type ArkosGatewayPipe = (\n socket: ArkosSocket,\n data: any\n) => void | Promise<void>;\n\nexport type ArkosGatewayEventConfig<TSchema extends Validator = any> = {\n /** The Socket.io event name to listen for. */\n event: string;\n\n /** Zod schema or class-validator DTO to validate the incoming event payload. */\n validation?: TSchema;\n\n /** Per-event rate limiting. Overrides gateway-level `rateLimit` for this event. */\n rateLimit?: Partial<RateLimitOptions> | false;\n\n /**\n * Authorization configuration.\n *\n * @remarks Gateway `authentication` must NOT be `false` or this throws at registration time.\n */\n authorization?: {\n resource: string;\n action: string;\n rule?: DetailedAccessControlRule | string[] | \"*\";\n };\n\n /**\n * When `true`, Arkos automatically calls `ack({ success: true })` after the handler\n * finishes, unless the handler already called ack manually.\n */\n ack?: boolean;\n\n /** Disables this event handler without removing it. */\n disabled?: boolean;\n\n /**\n * Maximum age in milliseconds for incoming messages.\n * Requires `data._meta.timestamp`. Events older than this are rejected.\n */\n maxAge?: number;\n\n /** Per-event deduplication. Overrides gateway-level `dedup`. */\n dedup?:\n | {\n /** @default true */\n enabled?: boolean;\n /** Time-to-live in seconds for the dedup key. @default 3600 */\n ttl?: number;\n }\n | false;\n};\n\nexport type ArkosGatewayAckFn = (response: any) => void;\n\nexport type ArkosGatewayHandler<TData = any> = (\n socket: ArkosSocket,\n data: TData,\n ack?: ArkosGatewayAckFn\n) => void | Promise<void>;\n\nexport type ArkosGatewayEventEntry = {\n config: ArkosGatewayEventConfig;\n handler: ArkosGatewayHandler;\n pipes: ArkosGatewayPipe[];\n};\n\nexport type ArkosGatewayConnectionHandler = (\n socket: ArkosSocket\n) => void | Promise<void>;\n\nexport type ArkosGatewayHookHandler =\n | ArkosGatewayConnectionHandler\n | ArkosGatewayErrorHandler;\n\nexport type ArkosGatewayErrorHandler = (\n error: any,\n socket: ArkosSocket\n) => void | Promise<void>;\n\nexport type ArkosGatewayHookType = \"connection\" | \"disconnect\" | \"error\";\n\nexport type ArkosGatewayConfig = {\n /**\n * Socket.io namespace for this gateway.\n *\n * @example\n * name: \"/chat\"\n */\n name: string;\n\n /**\n * When `true`, Arkos runs auth middleware on connection and populates `socket.currentUser`.\n * Unauthenticated sockets are rejected.\n *\n * @default false\n */\n authentication?: boolean;\n\n /** Gateway-level rate limiting, applied per socket. Can be overridden per event. */\n rateLimit?: Partial<RateLimitOptions>;\n\n /**\n * Gateway-level deduplication. Drills down to child gateways and can be overridden\n * per child or per event listener.\n */\n dedup?:\n | {\n /** @default true */\n enabled?: boolean;\n /** @default 3600 */\n ttl?: number;\n }\n | false;\n\n /**\n * Maximum age in milliseconds for incoming messages.\n * Can be overridden per event via `maxAge` in `gateway.on()`.\n */\n maxAge?: number;\n};\n\n/**\n * Options for `gateway.register()`.\n * Passed once at the root — applies to all child gateways.\n */\nexport type ArkosGatewayRegisterOptions = {\n /**\n * Unified store for rate limiting and deduplication.\n * Defaults to an in-memory store — zero config for single-instance deployments.\n * For distributed deployments plug in a Redis-backed store.\n *\n * @example\n * store: new RedisArkosStore(redis)\n */\n store?: ArkosGatewayStore;\n};\n\n/**\n * Unified store interface for rate limiting and deduplication.\n * Implement this to plug in Redis, Valkey, or any distributed store.\n *\n * @example\n * class RedisArkosStore implements ArkosGatewayStore {\n * async increment(key, windowMs) { ... }\n * async clear(prefix) { ... }\n * async has(key) { ... }\n * async set(key, ttl) { ... }\n * async setIfNotExists(key, ttl) { ... }\n * }\n */\nexport interface ArkosGatewayStore {\n /** Increment a rate limit counter. Key format: `arkos::rl:{socketId}:{event}` */\n increment(\n key: string,\n windowMs: number\n ): Promise<{ count: number; resetAt: number }>;\n\n /** Clear all rate limit entries matching a prefix. Key format: `arkos::rl:{socketId}` */\n clear(prefix: string): Promise<void>;\n\n /** Check if a dedup key exists. */\n has(key: string): Promise<boolean>;\n\n /** Store a dedup key with TTL in seconds. */\n set(key: string, ttl: number): Promise<void>;\n\n /**\n * Atomically store a dedup key only if it does not already exist.\n * Returns `true` if created (process the message), `false` if duplicate (skip).\n */\n setIfNotExists(key: string, ttl: number): Promise<boolean>;\n}\n\nexport class ArkosGatewayController {}\n"]}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.handleArkosGatewayErrors = handleArkosGatewayErrors;
|
|
4
|
+
exports.runArkosGatewayPipes = runArkosGatewayPipes;
|
|
5
|
+
exports.handleGatewayEventLog = handleGatewayEventLog;
|
|
6
|
+
exports.handleGatewayLifecycleLog = handleGatewayLifecycleLog;
|
|
7
|
+
const arkos_config_helpers_1 = require("../../../utils/helpers/arkos-config.helpers.js");
|
|
8
|
+
const get_handled_error_1 = require("../../../modules/error-handler/utils/get-handled-error.js");
|
|
9
|
+
async function handleArkosGatewayErrors(err, socket, errorHandlers = [], loggerMeta, ack) {
|
|
10
|
+
let emitCalled = false;
|
|
11
|
+
const originalEmit = socket.emit.bind(socket);
|
|
12
|
+
socket.emit = (...args) => {
|
|
13
|
+
emitCalled = true;
|
|
14
|
+
return originalEmit(...args);
|
|
15
|
+
};
|
|
16
|
+
if (errorHandlers.length) {
|
|
17
|
+
try {
|
|
18
|
+
for (const handler of errorHandlers)
|
|
19
|
+
await handler(err, socket);
|
|
20
|
+
}
|
|
21
|
+
catch (catchedErr) {
|
|
22
|
+
err = catchedErr;
|
|
23
|
+
emitCalled = false;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
socket.emit = originalEmit;
|
|
27
|
+
if (!emitCalled) {
|
|
28
|
+
console.error("[\x1b[31mError\x1b[0m]:", err);
|
|
29
|
+
err = (0, get_handled_error_1.getHandledError)(err);
|
|
30
|
+
const payload = {
|
|
31
|
+
message: err?.message ?? "Internal server error",
|
|
32
|
+
...(err.isOperational
|
|
33
|
+
? err
|
|
34
|
+
: { code: "InternalServerError", statusCode: 500 }),
|
|
35
|
+
};
|
|
36
|
+
if ((0, arkos_config_helpers_1.isProduction)())
|
|
37
|
+
sendProductionError(err, socket);
|
|
38
|
+
else
|
|
39
|
+
sendDevelopmentError(payload, socket);
|
|
40
|
+
ack?.({ error: payload.message, ...(payload.meta || {}) });
|
|
41
|
+
handleGatewayEventLog(loggerMeta.namespace, loggerMeta.event, payload.statusCode, loggerMeta.startTime);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function sendDevelopmentError(err, socket) {
|
|
45
|
+
socket.emit("error", {
|
|
46
|
+
...err,
|
|
47
|
+
message: err.message?.split?.("\n")[err.message?.split?.("\n").length - 1],
|
|
48
|
+
stack: err?.originalError?.stack?.split?.("\n"),
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
function sendProductionError(err, socket) {
|
|
52
|
+
if (err.isOperational)
|
|
53
|
+
socket.emit("event", {
|
|
54
|
+
status: err.status,
|
|
55
|
+
message: err.message,
|
|
56
|
+
meta: err.meta || {},
|
|
57
|
+
code: err.code || "Unknown",
|
|
58
|
+
statusCode: err.statusCode || 500,
|
|
59
|
+
});
|
|
60
|
+
else
|
|
61
|
+
socket.emit("error", {
|
|
62
|
+
status: "error",
|
|
63
|
+
message: "Internal server error, please try again later.",
|
|
64
|
+
code: "InternalServerError",
|
|
65
|
+
meta: {},
|
|
66
|
+
statusCode: 500,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
async function runArkosGatewayPipes(pipes, socket, data) {
|
|
70
|
+
for (const pipe of pipes) {
|
|
71
|
+
await pipe(socket, data);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function handleGatewayEventLog(namespace, event, statusCode, startTime) {
|
|
75
|
+
const getStatusColor = (statusCode) => {
|
|
76
|
+
if (statusCode >= 100 && statusCode < 200)
|
|
77
|
+
return "\x1b[36m";
|
|
78
|
+
if (statusCode >= 200 && statusCode < 300)
|
|
79
|
+
return "\x1b[32m";
|
|
80
|
+
if (statusCode >= 300 && statusCode < 400)
|
|
81
|
+
return "\x1b[33m";
|
|
82
|
+
if (statusCode >= 400 && statusCode < 500)
|
|
83
|
+
return "\x1b[33m";
|
|
84
|
+
if (statusCode >= 500)
|
|
85
|
+
return "\x1b[31m";
|
|
86
|
+
return "\x1b[0m";
|
|
87
|
+
};
|
|
88
|
+
const duration = Date.now() - startTime;
|
|
89
|
+
const now = new Date();
|
|
90
|
+
const date = now.toISOString().split("T")[0];
|
|
91
|
+
const time = now.toTimeString().split(" ")[0];
|
|
92
|
+
const timestamp = (0, arkos_config_helpers_1.isProduction)() ? `${date} ${time}` : time;
|
|
93
|
+
const statusColor = getStatusColor(statusCode);
|
|
94
|
+
console.info(`[\x1b[36mInfo\x1b[0m] \x1b[90m${timestamp}\x1b[0m \x1b[35mWS\x1b[0m ${namespace} ${event} ${statusColor}${statusCode}\x1b[0m \x1b[35m${duration}ms\x1b[0m`);
|
|
95
|
+
}
|
|
96
|
+
function handleGatewayLifecycleLog(namespace, event, socketId, errorType) {
|
|
97
|
+
const isProduction = process.env.ARKOS_BUILD == "true";
|
|
98
|
+
const now = new Date();
|
|
99
|
+
const date = now.toISOString().split("T")[0];
|
|
100
|
+
const time = now.toTimeString().split(" ")[0];
|
|
101
|
+
const timestamp = isProduction ? `${date} ${time}` : time;
|
|
102
|
+
const eventColors = {
|
|
103
|
+
connected: "\x1b[32m",
|
|
104
|
+
disconnected: "\x1b[33m",
|
|
105
|
+
error: "\x1b[31m",
|
|
106
|
+
};
|
|
107
|
+
const eventColor = eventColors[event];
|
|
108
|
+
const extra = errorType ? ` ${errorType}` : "";
|
|
109
|
+
console.info(`[\x1b[36mInfo\x1b[0m] \x1b[90m${timestamp}\x1b[0m \x1b[35mWS\x1b[0m ${namespace} ${eventColor}${event}\x1b[0m ${socketId}${extra}`);
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../../../src/components/arkos-gateway/utils/helpers.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ArkosGatewayErrorHandler,\n ArkosGatewayPipe,\n ArkosSocket,\n} from \"../types\";\nimport { isProduction } from \"../../../utils/helpers/arkos-config.helpers\";\nimport { getHandledError } from \"../../../modules/error-handler/utils/get-handled-error\";\n\nexport async function handleArkosGatewayErrors(\n err: any,\n socket: ArkosSocket,\n errorHandlers: ArkosGatewayErrorHandler[] = [],\n loggerMeta: {\n namespace: string;\n event: string;\n startTime: number;\n },\n ack?: (response: any) => void\n) {\n let emitCalled = false;\n const originalEmit: any = socket.emit.bind(socket);\n\n socket.emit = (...args: any[]) => {\n emitCalled = true;\n return originalEmit(...args);\n };\n\n if (errorHandlers.length) {\n try {\n for (const handler of errorHandlers) await handler(err, socket);\n } catch (catchedErr: any) {\n err = catchedErr;\n emitCalled = false;\n }\n }\n\n socket.emit = originalEmit;\n\n if (!emitCalled) {\n console.error(\"[\\x1b[31mError\\x1b[0m]:\", err);\n err = getHandledError(err);\n\n const payload = {\n message: err?.message ?? \"Internal server error\",\n ...(err.isOperational\n ? err\n : { code: \"InternalServerError\", statusCode: 500 }),\n };\n\n if (isProduction()) sendProductionError(err, socket);\n else sendDevelopmentError(payload, socket);\n\n ack?.({ error: payload.message, ...(payload.meta || {}) });\n\n handleGatewayEventLog(\n loggerMeta.namespace,\n loggerMeta.event,\n payload.statusCode,\n loggerMeta.startTime\n );\n }\n}\n\nfunction sendDevelopmentError(err: any, socket: ArkosSocket): void {\n socket.emit(\"error\", {\n ...err,\n message: err.message?.split?.(\"\\n\")[err.message?.split?.(\"\\n\").length - 1],\n stack: err?.originalError?.stack?.split?.(\"\\n\"),\n });\n}\n\nfunction sendProductionError(err: any, socket: ArkosSocket): void {\n if (err.isOperational)\n socket.emit(\"event\", {\n status: err.status,\n message: err.message,\n meta: err.meta || {},\n code: err.code || \"Unknown\",\n statusCode: err.statusCode || 500,\n });\n else\n socket.emit(\"error\", {\n status: \"error\",\n message: \"Internal server error, please try again later.\",\n code: \"InternalServerError\",\n meta: {},\n statusCode: 500,\n });\n}\n\nexport async function runArkosGatewayPipes(\n pipes: ArkosGatewayPipe[],\n socket: ArkosSocket,\n data: any\n) {\n for (const pipe of pipes) {\n await pipe(socket, data);\n }\n}\n\nexport function handleGatewayEventLog(\n namespace: string,\n event: string,\n statusCode: number,\n startTime: number\n) {\n const getStatusColor = (statusCode: number) => {\n if (statusCode >= 100 && statusCode < 200) return \"\\x1b[36m\";\n if (statusCode >= 200 && statusCode < 300) return \"\\x1b[32m\";\n if (statusCode >= 300 && statusCode < 400) return \"\\x1b[33m\";\n if (statusCode >= 400 && statusCode < 500) return \"\\x1b[33m\";\n if (statusCode >= 500) return \"\\x1b[31m\";\n return \"\\x1b[0m\";\n };\n\n const duration = Date.now() - startTime;\n const now = new Date();\n const date = now.toISOString().split(\"T\")[0];\n const time = now.toTimeString().split(\" \")[0];\n const timestamp = isProduction() ? `${date} ${time}` : time;\n const statusColor = getStatusColor(statusCode);\n\n console.info(\n `[\\x1b[36mInfo\\x1b[0m] \\x1b[90m${timestamp}\\x1b[0m \\x1b[35mWS\\x1b[0m ${namespace} ${event} ${statusColor}${statusCode}\\x1b[0m \\x1b[35m${duration}ms\\x1b[0m`\n );\n}\n\nexport function handleGatewayLifecycleLog(\n namespace: string,\n event: \"connected\" | \"disconnected\" | \"error\",\n socketId: string,\n errorType?: string\n) {\n const isProduction = process.env.ARKOS_BUILD == \"true\";\n const now = new Date();\n const date = now.toISOString().split(\"T\")[0];\n const time = now.toTimeString().split(\" \")[0];\n const timestamp = isProduction ? `${date} ${time}` : time;\n\n const eventColors = {\n connected: \"\\x1b[32m\",\n disconnected: \"\\x1b[33m\",\n error: \"\\x1b[31m\",\n };\n\n const eventColor = eventColors[event];\n const extra = errorType ? ` ${errorType}` : \"\";\n\n console.info(\n `[\\x1b[36mInfo\\x1b[0m] \\x1b[90m${timestamp}\\x1b[0m \\x1b[35mWS\\x1b[0m ${namespace} ${eventColor}${event}\\x1b[0m ${socketId}${extra}`\n );\n}\n"]}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultGatewayStore = exports.MemoryGatewayStore = void 0;
|
|
4
|
+
class MemoryGatewayStore {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.rl = new Map();
|
|
7
|
+
this.dedup = new Map();
|
|
8
|
+
}
|
|
9
|
+
async increment(key, windowMs) {
|
|
10
|
+
const now = Date.now();
|
|
11
|
+
const entry = this.rl.get(key);
|
|
12
|
+
if (!entry || entry.resetAt <= now) {
|
|
13
|
+
const next = { count: 1, resetAt: now + windowMs };
|
|
14
|
+
this.rl.set(key, next);
|
|
15
|
+
return next;
|
|
16
|
+
}
|
|
17
|
+
entry.count++;
|
|
18
|
+
return entry;
|
|
19
|
+
}
|
|
20
|
+
async clear(prefix) {
|
|
21
|
+
for (const key of this.rl.keys())
|
|
22
|
+
if (key.startsWith(prefix))
|
|
23
|
+
this.rl.delete(key);
|
|
24
|
+
for (const [key, timer] of this.dedup)
|
|
25
|
+
if (key.startsWith(prefix)) {
|
|
26
|
+
clearTimeout(timer);
|
|
27
|
+
this.dedup.delete(key);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async has(key) {
|
|
31
|
+
return this.dedup.has(key);
|
|
32
|
+
}
|
|
33
|
+
async set(key, ttl) {
|
|
34
|
+
if (this.dedup.has(key))
|
|
35
|
+
clearTimeout(this.dedup.get(key));
|
|
36
|
+
const timer = setTimeout(() => this.dedup.delete(key), ttl * 1000);
|
|
37
|
+
timer.unref();
|
|
38
|
+
this.dedup.set(key, timer);
|
|
39
|
+
}
|
|
40
|
+
async setIfNotExists(key, ttl) {
|
|
41
|
+
if (this.dedup.has(key))
|
|
42
|
+
return false;
|
|
43
|
+
const timer = setTimeout(() => this.dedup.delete(key), ttl * 1000);
|
|
44
|
+
timer.unref();
|
|
45
|
+
this.dedup.set(key, timer);
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.MemoryGatewayStore = MemoryGatewayStore;
|
|
50
|
+
exports.defaultGatewayStore = new MemoryGatewayStore();
|
|
51
|
+
//# sourceMappingURL=memory-gateway-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-gateway-store.js","sourceRoot":"","sources":["../../../../../src/components/arkos-gateway/utils/memory-gateway-store.ts"],"names":[],"mappings":";;;AAEA,MAAa,kBAAkB;IAA/B;QACU,OAAE,GAAG,IAAI,GAAG,EAA8C,CAAC;QAC3D,UAAK,GAAG,IAAI,GAAG,EAA0B,CAAC;IA6CpD,CAAC;IA3CC,KAAK,CAAC,SAAS,CAAC,GAAW,EAAE,QAAgB;QAC3C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,OAAO,IAAI,GAAG,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,GAAG,QAAQ,EAAE,CAAC;YACnD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE;YAC9B,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC;gBAAE,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAClD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK;YACnC,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC3B,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,GAAW;QAChC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,CAAC;QAC5D,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,KAAK,EAAE,CAAC;QACd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,GAAW,EAAE,GAAW;QAC3C,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAEtC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,CAAC;QACnE,KAAK,CAAC,KAAK,EAAE,CAAC;QAEd,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAE3B,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AA/CD,gDA+CC;AAEY,QAAA,mBAAmB,GAAG,IAAI,kBAAkB,EAAE,CAAC","sourcesContent":["import { ArkosGatewayStore } from \"../types\";\n\nexport class MemoryGatewayStore implements ArkosGatewayStore {\n private rl = new Map<string, { count: number; resetAt: number }>();\n private dedup = new Map<string, NodeJS.Timeout>();\n\n async increment(key: string, windowMs: number) {\n const now = Date.now();\n const entry = this.rl.get(key);\n if (!entry || entry.resetAt <= now) {\n const next = { count: 1, resetAt: now + windowMs };\n this.rl.set(key, next);\n return next;\n }\n entry.count++;\n return entry;\n }\n\n async clear(prefix: string) {\n for (const key of this.rl.keys())\n if (key.startsWith(prefix)) this.rl.delete(key);\n for (const [key, timer] of this.dedup)\n if (key.startsWith(prefix)) {\n clearTimeout(timer);\n this.dedup.delete(key);\n }\n }\n\n async has(key: string) {\n return this.dedup.has(key);\n }\n\n async set(key: string, ttl: number) {\n if (this.dedup.has(key)) clearTimeout(this.dedup.get(key)!);\n const timer = setTimeout(() => this.dedup.delete(key), ttl * 1000);\n timer.unref();\n this.dedup.set(key, timer);\n }\n\n async setIfNotExists(key: string, ttl: number): Promise<boolean> {\n if (this.dedup.has(key)) return false;\n\n const timer = setTimeout(() => this.dedup.delete(key), ttl * 1000);\n timer.unref();\n\n this.dedup.set(key, timer);\n\n return true;\n }\n}\n\nexport const defaultGatewayStore = new MemoryGatewayStore();\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MultiTierArkosGatewayStore = void 0;
|
|
4
|
+
class MultiTierArkosGatewayStore {
|
|
5
|
+
constructor(tiers) {
|
|
6
|
+
this.tiers = tiers;
|
|
7
|
+
}
|
|
8
|
+
async increment(key, windowMs) {
|
|
9
|
+
const l1 = await this.tiers[0].increment(key, windowMs);
|
|
10
|
+
for (const tier of this.tiers.slice(1))
|
|
11
|
+
tier.increment(key, windowMs);
|
|
12
|
+
return l1;
|
|
13
|
+
}
|
|
14
|
+
async clear(prefix) {
|
|
15
|
+
await Promise.all(this.tiers.map((t) => t.clear(prefix)));
|
|
16
|
+
}
|
|
17
|
+
async has(key) {
|
|
18
|
+
for (const tier of this.tiers) {
|
|
19
|
+
if (await tier.has(key))
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
async set(key, ttl) {
|
|
25
|
+
await Promise.all(this.tiers.map((t) => t.set(key, ttl)));
|
|
26
|
+
}
|
|
27
|
+
async setIfNotExists(key, ttl) {
|
|
28
|
+
for (const tier of this.tiers) {
|
|
29
|
+
const acquired = await tier.setIfNotExists(key, ttl);
|
|
30
|
+
if (acquired) {
|
|
31
|
+
for (const t of this.tiers) {
|
|
32
|
+
if (t !== tier) {
|
|
33
|
+
t.set(key, ttl).catch(() => { });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
exports.MultiTierArkosGatewayStore = MultiTierArkosGatewayStore;
|
|
43
|
+
//# sourceMappingURL=multi-tier-arkos-gateway-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multi-tier-arkos-gateway-store.js","sourceRoot":"","sources":["../../../../../src/components/arkos-gateway/utils/multi-tier-arkos-gateway-store.ts"],"names":[],"mappings":";;;AASA,MAAa,0BAA0B;IACrC,YAAoB,KAA0B;QAA1B,UAAK,GAAL,KAAK,CAAqB;IAAG,CAAC;IAElD,KAAK,CAAC,SAAS,CAAC,GAAW,EAAE,QAAgB;QAE3C,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACxD,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;YAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACtE,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,MAAc;QACxB,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,MAAM,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,IAAI,CAAC;QACvC,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,GAAW;QAChC,MAAM,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,KAAK,CAAC,cAAc,CAAC,GAAW,EAAE,GAAW;QAC3C,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAErD,IAAI,QAAQ,EAAE,CAAC;gBACb,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;oBAC3B,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;wBACf,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;oBAClC,CAAC;gBACH,CAAC;gBAED,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AA1CD,gEA0CC","sourcesContent":["import { ArkosGatewayStore } from \"../types\";\n\n/**\n * Multi-tier store that chains multiple stores together.\n * Writes go to all tiers. Reads check tiers in order, promoting hits to faster tiers.\n *\n * @example\n * new MultiTierArkosStore([new MemoryArkosStore(), new RedisArkosStore(redis)])\n */\nexport class MultiTierArkosGatewayStore implements ArkosGatewayStore {\n constructor(private tiers: ArkosGatewayStore[]) {}\n\n async increment(key: string, windowMs: number) {\n // L1 first — if valid, sync to slower tiers and return\n const l1 = await this.tiers[0].increment(key, windowMs);\n for (const tier of this.tiers.slice(1)) tier.increment(key, windowMs);\n return l1;\n }\n\n async clear(prefix: string) {\n await Promise.all(this.tiers.map((t) => t.clear(prefix)));\n }\n\n async has(key: string) {\n for (const tier of this.tiers) {\n if (await tier.has(key)) return true;\n }\n return false;\n }\n\n async set(key: string, ttl: number) {\n await Promise.all(this.tiers.map((t) => t.set(key, ttl)));\n }\n\n async setIfNotExists(key: string, ttl: number): Promise<boolean> {\n for (const tier of this.tiers) {\n const acquired = await tier.setIfNotExists(key, ttl);\n\n if (acquired) {\n for (const t of this.tiers) {\n if (t !== tier) {\n t.set(key, ttl).catch(() => {});\n }\n }\n\n return true;\n }\n }\n\n return false;\n }\n}\n"]}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkRateLimit = checkRateLimit;
|
|
4
|
+
exports.clearRateLimitForSocket = clearRateLimitForSocket;
|
|
5
|
+
async function checkRateLimit(socketId, event, options, store) {
|
|
6
|
+
const windowMs = options.windowMs ?? 60000;
|
|
7
|
+
const max = options.max ?? 100;
|
|
8
|
+
const key = `arkos::rl:${socketId}:${event}`;
|
|
9
|
+
const { count, resetAt } = await store.increment(key, windowMs);
|
|
10
|
+
if (count > max)
|
|
11
|
+
return { allowed: false, retryAfter: resetAt - Date.now() };
|
|
12
|
+
return { allowed: true };
|
|
13
|
+
}
|
|
14
|
+
async function clearRateLimitForSocket(socketId, store) {
|
|
15
|
+
await store.clear(`arkos::rl:${socketId}`);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=rate-limiter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rate-limiter.js","sourceRoot":"","sources":["../../../../../src/components/arkos-gateway/utils/rate-limiter.ts"],"names":[],"mappings":";;AAOA,wCAeC;AAED,0DAKC;AAtBM,KAAK,UAAU,cAAc,CAClC,QAAgB,EAChB,KAAa,EACb,OAAkC,EAClC,KAAwB;IAExB,MAAM,QAAQ,GAAI,OAAO,CAAC,QAAmB,IAAI,KAAM,CAAC;IACxD,MAAM,GAAG,GAAI,OAAO,CAAC,GAAc,IAAI,GAAG,CAAC;IAC3C,MAAM,GAAG,GAAG,aAAa,QAAQ,IAAI,KAAK,EAAE,CAAC;IAE7C,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,KAAK,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IAEhE,IAAI,KAAK,GAAG,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAE7E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC3B,CAAC;AAEM,KAAK,UAAU,uBAAuB,CAC3C,QAAgB,EAChB,KAAwB;IAExB,MAAM,KAAK,CAAC,KAAK,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["import { Options as RateLimitOptions } from \"express-rate-limit\";\nimport { ArkosGatewayStore } from \"../types\";\n\n/**\n * Checks whether a socket has exceeded the rate limit for a given event.\n * Returns true if the request is allowed, false if rate limited.\n */\nexport async function checkRateLimit(\n socketId: string,\n event: string,\n options: Partial<RateLimitOptions>,\n store: ArkosGatewayStore\n): Promise<{ allowed: boolean; retryAfter?: number }> {\n const windowMs = (options.windowMs as number) ?? 60_000;\n const max = (options.max as number) ?? 100;\n const key = `arkos::rl:${socketId}:${event}`;\n\n const { count, resetAt } = await store.increment(key, windowMs);\n\n if (count > max) return { allowed: false, retryAfter: resetAt - Date.now() };\n\n return { allowed: true };\n}\n\nexport async function clearRateLimitForSocket(\n socketId: string,\n store: ArkosGatewayStore\n) {\n await store.clear(`arkos::rl:${socketId}`);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/arkos-policy/index.ts"],"names":[],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/arkos-policy/index.ts"],"names":[],"mappings":";;;;;AAsCA,kCAIC;AAnCD,mFAA0D;AA+B1D,SAAgB,WAAW,CACzB,QAAmB;IAEnB,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,WAAW,CAClB,QAAmB,EACnB,KAAsC;IAEtC,MAAM,IAAI,GAAG,CACX,MAAe,EACf,MAAuB,EAC2B,EAAE;QACpD,MAAM,QAAQ,GAAG,EAAE,GAAG,KAAK,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAChD,OAAO,WAAW,CAAgC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACxE,CAAC,CAAC;IAEF,MAAM,aAAa,GAAG,MAAM,CAAC,WAAW,CACtC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE;QACjD,MAAM,SAAS,GAA8C;YAC3D,QAAQ;YACR,MAAM;YACN,IAAI,EAAE,MAAM;SACb,CAAC;QAEF,MAAM,OAAO,GAAkB,sBAAW,CAAC,UAAU,CAAC,MAAM,EAAE,QAAQ,EAAE;YACtE,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,EAAE;SACvB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAExE,OAAO;YACL,CAAC,MAAM,EAAE,SAAS,CAAC;YACnB,CAAC,MAAM,EAAE,OAAO,CAAC;SAClB,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IAEF,OAAO;QACL,MAAM,EAAE,aAAsB;QAC9B,QAAQ;QACR,IAAI;QACJ,GAAG,aAAa;KACoC,CAAC;AACzD,CAAC","sourcesContent":["import {\n ArkosPolicyRule,\n IArkosPolicy,\n PolicyAuthEntry,\n PolicyChecker,\n PolicyWithActions,\n} from \"./types\";\nimport authService from \"../../modules/auth/auth.service\";\n\n/**\n * Creates a typed policy for a Prisma model resource.\n *\n * Each `.rule()` call registers an action and returns the policy\n * with a typed `can{Action}` permission checker and a typed `{Action}`\n * entry — both passable to the `authentication` field on `ArkosRouteHook`\n * and `ArkosRouter`, and callable for fine-grained permission checks.\n *\n * @param resource - The resource name in kebab-case (e.g. `\"user\"`, `\"blog-post\"`)\n *\n * @example\n * ```ts\n * const userPolicy = ArkosPolicy(\"user\")\n * .rule(\"Create\", [\"Admin\", \"Editor\"])\n * .rule(\"View\", \"*\")\n * .rule(\"Delete\", [\"Admin\"]);\n *\n * // Pass to authentication field\n * userRouter.post({ path: \"/users\", authentication: userPolicy.Create });\n * userRouteHook.deleteOne({ authentication: userPolicy.Delete });\n *\n * // Fine-grained check\n * if (userPolicy.canCreate(req.user)) { ... }\n *\n * export default userPolicy;\n * ```\n *\n * @see {@link https://www.arkosjs.com/docs/api-referency/arkos-policy}\n */\nexport function ArkosPolicy<TResource extends string>(\n resource: TResource\n): IArkosPolicy<TResource, never> {\n return buildPolicy(resource, {});\n}\n\nfunction buildPolicy<TResource extends string, TActions extends string>(\n resource: TResource,\n store: Record<string, ArkosPolicyRule>\n): PolicyWithActions<TResource, TActions> {\n const rule = <TAction extends string>(\n action: TAction,\n config: ArkosPolicyRule\n ): PolicyWithActions<TResource, TActions | TAction> => {\n const newStore = { ...store, [action]: config };\n return buildPolicy<TResource, TActions | TAction>(resource, newStore);\n };\n\n const actionEntries = Object.fromEntries(\n Object.entries(store).flatMap(([action, config]) => {\n const authEntry: PolicyAuthEntry<TResource, typeof action> = {\n resource,\n action,\n rule: config,\n };\n\n const checker: PolicyChecker = authService.permission(action, resource, {\n [action]: config || {},\n });\n\n const canKey = `can${action.charAt(0).toUpperCase()}${action.slice(1)}`;\n\n return [\n [action, authEntry],\n [canKey, checker],\n ];\n })\n );\n\n return {\n __type: \"ArkosPolicy\" as const,\n resource,\n rule,\n ...actionEntries,\n } as unknown as PolicyWithActions<TResource, TActions>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/arkos-route-hook/index.ts"],"names":[],"mappings":";;AAiCA,wCAuDC;AAvDD,SAAgB,cAAc,CAC5B,UAAa;IAEb,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,MAAM,UAAU,GACd,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,MAAkC,EAAE,EAAE;QACvD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEJ,MAAM,IAAI,GAAG;QACX,MAAM,EAAE,gBAAyB;QACjC,UAAU;QACV,MAAM,EAAE,KAAK;KACd,CAAC;IAEF,MAAM,OAAO,GAGT,EAAE,CAAC;IAEP,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,KAAK,MAAM,IAAI,IAAI;YACjB,OAAO;YACP,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,gBAAgB;SACjB,EAAE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;SAAM,IAAI,UAAU,KAAK,aAAa,IAAI,UAAU,KAAK,YAAY,EAAE,CAAC;QACvE,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE,CAAC;YAC1E,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,IAAI,IAAI;YACjB,WAAW;YACX,SAAS;YACT,UAAU;YACV,WAAW;YACX,WAAW;YACX,YAAY;YACZ,YAAY;YACZ,YAAY;SACb,EAAE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE3C,OAAO,KAA2C,CAAC;AACrD,CAAC","sourcesContent":["import {\n ArkosModuleType,\n ArkosRouteHookReturn,\n ArkosRouteHookMethodConfig,\n} from \"./types\";\n\ninterface InterceptorStore {\n [methodName: string]: ArkosRouteHookMethodConfig;\n}\n\n/**\n * Creates an interceptor for a built-in Arkos module or a generated model route.\n *\n * The returned instance exposes only the methods relevant to that module,\n * and is registered into the app via `app.load()`.\n *\n * @param moduleName - The module to intercept. Use `\"auth\"` or `\"file-upload\"`\n * for built-in modules, or any prisma model name string for generated CRUD routes.\n *\n * @example\n * ```ts\n * const
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/components/arkos-route-hook/index.ts"],"names":[],"mappings":";;AAiCA,wCAuDC;AAvDD,SAAgB,cAAc,CAC5B,UAAa;IAEb,MAAM,KAAK,GAAqB,EAAE,CAAC;IAEnC,MAAM,UAAU,GACd,CAAC,IAAY,EAAE,EAAE,CAAC,CAAC,MAAkC,EAAE,EAAE;QACvD,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC;QACrB,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;IAEJ,MAAM,IAAI,GAAG;QACX,MAAM,EAAE,gBAAyB;QACjC,UAAU;QACV,MAAM,EAAE,KAAK;KACd,CAAC;IAEF,MAAM,OAAO,GAGT,EAAE,CAAC;IAEP,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAC1B,KAAK,MAAM,IAAI,IAAI;YACjB,OAAO;YACP,OAAO;YACP,QAAQ;YACR,QAAQ;YACR,UAAU;YACV,gBAAgB;SACjB,EAAE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;SAAM,IAAI,UAAU,KAAK,aAAa,IAAI,UAAU,KAAK,YAAY,EAAE,CAAC;QACvE,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,YAAY,CAAC,EAAE,CAAC;YAC1E,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,IAAI,IAAI;YACjB,WAAW;YACX,SAAS;YACT,UAAU;YACV,WAAW;YACX,WAAW;YACX,YAAY;YACZ,YAAY;YACZ,YAAY;SACb,EAAE,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;QACnC,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAE3C,OAAO,KAA2C,CAAC;AACrD,CAAC","sourcesContent":["import {\n ArkosModuleType,\n ArkosRouteHookReturn,\n ArkosRouteHookMethodConfig,\n} from \"./types\";\n\ninterface InterceptorStore {\n [methodName: string]: ArkosRouteHookMethodConfig;\n}\n\n/**\n * Creates an interceptor for a built-in Arkos module or a generated model route.\n *\n * The returned instance exposes only the methods relevant to that module,\n * and is registered into the app via `app.load()`.\n *\n * @param moduleName - The module to intercept. Use `\"auth\"` or `\"file-upload\"`\n * for built-in modules, or any prisma model name string for generated CRUD routes.\n *\n * @example\n * ```ts\n * const userRouteHook = ArkosRouteHook(\"user\");\n *\n * userRouteHook.createOne({\n * validation: { body: CreateUserSchema },\n * before: [sanitize],\n * after: [notify]\n * });\n *\n * app.load(userRouteHook);\n * ```\n * @see {@link https://www.arkosjs.com/docs/core-concepts/components/route-hooks}\n */\nexport function ArkosRouteHook<T extends ArkosModuleType>(\n moduleName: T\n): ArkosRouteHookReturn<T> {\n const store: InterceptorStore = {};\n\n const makeMethod =\n (name: string) => (config: ArkosRouteHookMethodConfig) => {\n store[name] = config;\n return proxy;\n };\n\n const base = {\n __type: \"ArkosRouteHook\" as const,\n moduleName,\n _store: store,\n };\n\n const methods: Record<\n string,\n (config: ArkosRouteHookMethodConfig) => unknown\n > = {};\n\n if (moduleName === \"auth\") {\n for (const name of [\n \"getMe\",\n \"login\",\n \"logout\",\n \"signup\",\n \"updateMe\",\n \"updatePassword\",\n ]) {\n methods[name] = makeMethod(name);\n }\n } else if (moduleName === \"file-upload\" || moduleName === \"fileUpload\") {\n for (const name of [\"findFile\", \"uploadFile\", \"updateFile\", \"deleteFile\"]) {\n methods[name] = makeMethod(name);\n }\n } else {\n for (const name of [\n \"createOne\",\n \"findOne\",\n \"findMany\",\n \"updateOne\",\n \"deleteOne\",\n \"createMany\",\n \"updateMany\",\n \"deleteMany\",\n ]) {\n methods[name] = makeMethod(name);\n }\n }\n\n const proxy = Object.assign(base, methods);\n\n return proxy as unknown as ArkosRouteHookReturn<T>;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../../src/components/arkos-route-hook/reader.ts"],"names":[],"mappings":";;;;;;AAAA,uGAAwE;AAUxE,+CAAgD;AA4BhD,MAAM,oBAAoB;IAChB,YAAY,CAAC,UAA2B;QAC9C,OAAO,iCAAgB,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAA,iBAAS,EAAC,UAAU,CAAC,CAAC,CAAC;IAC3E,CAAC;IAEO,QAAQ,CACd,UAA2B;QAE3B,OAAQ,IAAI,CAAC,YAAY,CAAC,UAAU,CAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAC9D,CAAC;IAKD,YAAY,CACV,UAAmB,EACnB,SAAqC;QAErC,OAAO,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC;IAKD,aAAa,CACX,UAAmB,EACnB,SAAqC;QAErC,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,IAAI,IAAI,CAAC;IAChE,CAAC;IAKD,QAAQ,CACN,UAAmB,EACnB,SAAqC;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC1C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAMD,cAAc,CACZ,UAAmB,EACnB,SAAqC;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC;QACtE,OAAO,WAAW,CAAC;IACrB,CAAC;IAKD,aAAa,CACX,UAAmB,EACnB,SAAqC;QAErC,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,EAAE,UAAU,CAAC;IACpE,CAAC;IAKD,YAAY,CACV,UAAmB,EACnB,SAAqC;QAQrC,MAAM,EACJ,MAAM,GAAG,EAAE,EACX,KAAK,GAAG,EAAE,EACV,OAAO,GAAG,EAAE,GACb,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;QACrE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;IAC7D,CAAC;CACF;AAEY,QAAA,eAAe,GAAG,IAAI,oBAAoB,EAAE,CAAC","sourcesContent":["import loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport {\n ArkosModuleType,\n ArkosRouteHookHooks,\n ArkosRouteHookMethodConfig,\n ArkosRouteHookInstance,\n ArkosAuthRouteHookInstance,\n ArkosFileUploadRouteHookInstance,\n} from \"./types\";\nimport { ArkosRequestHandler, ArkosRouteConfig } from \"../../exports\";\nimport { kebabCase } from \"../../exports/utils\";\n\ntype PrismaOperations = keyof Omit<\n ArkosRouteHookInstance<any>,\n \"__type\" | \"moduleName\"\n>;\n\nexport type OperationByModule<TModule extends ArkosModuleType> =\n TModule extends \"file-upload\"\n ? keyof Omit<ArkosFileUploadRouteHookInstance, \"__type\" | \"moduleName\">\n : TModule extends \"auth\"\n ? keyof Omit<ArkosAuthRouteHookInstance, \"__type\" | \"moduleName\">\n : PrismaOperations;\n\n/**\n * Reader for `ArkosRouteHook` instances.\n * Reads config from the global loadable registry by module name.\n *\n * @example\n * ```ts\n * routeHookReader.getHooks(\"user\", \"findMany\") // { before, after, onError }\n * routeHookReader.getRouteConfig(\"user\", \"findMany\") // ArkosRouteConfig minus path and hooks\n * routeHookReader.getPrismaArgs(\"user\", \"findMany\") // prismaArgs for that operation\n * routeHookReader.getFullConfig(\"user\", \"findMany\") // full raw config object\n * routeHookReader.hasOperation(\"user\", \"findMany\") // true | false\n * routeHookReader.forOperation(\"user\", \"findMany\") // { before, after, onError, prismaArgs, routeConfig }\n * ```\n */\nclass ArkosRouteHookReader {\n private getRouteHook(moduleName: ArkosModuleType) {\n return loadableRegistry.getItem(\"ArkosRouteHook\", kebabCase(moduleName));\n }\n\n private getStore(\n moduleName: ArkosModuleType\n ): Record<string, ArkosRouteHookMethodConfig> {\n return (this.getRouteHook(moduleName) as any)?._store ?? {};\n }\n\n /**\n * Returns true if the routeHook has a config registered for the given operation.\n */\n hasOperation<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): boolean {\n return operation in this.getStore(moduleName);\n }\n\n /**\n * Returns the full raw config for the given operation, or `null` if not registered.\n */\n getFullConfig<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): ArkosRouteHookMethodConfig | null {\n return this.getStore(moduleName)[operation as string] ?? null;\n }\n\n /**\n * Returns only the lifecycle hooks (`before`, `after`, `onError`) for the given operation.\n */\n getHooks<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): ArkosRouteHookHooks | undefined {\n const config = this.getStore(moduleName)[operation as string];\n if (!config) return {};\n const { before, after, onError } = config;\n return { before, after, onError };\n }\n\n /**\n * Returns the `ArkosRouteConfig` portion of the config (excludes `path`, hooks, and `prismaArgs`)\n * for the given operation.\n */\n getRouteConfig<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): Omit<ArkosRouteConfig, \"path\"> | null {\n const config = this.getStore(moduleName)[operation as string];\n if (!config) return null;\n const { before, after, onError, prismaArgs, ...routeConfig } = config;\n return routeConfig;\n }\n\n /**\n * Returns the `prismaArgs` for the given operation, or `undefined` if not set.\n */\n getPrismaArgs<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): Record<string, any> | undefined {\n return this.getStore(moduleName)[operation as string]?.prismaArgs;\n }\n\n /**\n * Returns all extracted slices for a given operation in one call.\n */\n forOperation<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): {\n before: ArkosRequestHandler[];\n after: ArkosRequestHandler[];\n onError: ArkosRequestHandler[];\n prismaArgs?: Record<string, any>;\n routeConfig: Omit<ArkosRouteConfig, \"path\">;\n } {\n const {\n before = [],\n after = [],\n onError = [],\n } = this.getHooks(moduleName, operation) || {};\n const prismaArgs = this.getPrismaArgs(moduleName, operation);\n const routeConfig = this.getRouteConfig(moduleName, operation) ?? {};\n return { before, after, onError, prismaArgs, routeConfig };\n }\n}\n\nexport const routeHookReader = new ArkosRouteHookReader();\n"]}
|
|
1
|
+
{"version":3,"file":"reader.js","sourceRoot":"","sources":["../../../../src/components/arkos-route-hook/reader.ts"],"names":[],"mappings":";;;;;;AAAA,uGAAwE;AAUxE,+CAAgD;AA4BhD,MAAM,oBAAoB;IAChB,YAAY,CAAC,UAA2B;QAC9C,OAAO,iCAAgB,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAA,iBAAS,EAAC,UAAU,CAAC,CAAC,CAAC;IAC3E,CAAC;IAEO,QAAQ,CACd,UAA2B;QAE3B,OAAQ,IAAI,CAAC,YAAY,CAAC,UAAU,CAAS,EAAE,MAAM,IAAI,EAAE,CAAC;IAC9D,CAAC;IAKD,YAAY,CACV,UAAmB,EACnB,SAAqC;QAErC,OAAO,SAAS,IAAI,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IAChD,CAAC;IAKD,aAAa,CACX,UAAmB,EACnB,SAAqC;QAErC,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,IAAI,IAAI,CAAC;IAChE,CAAC;IAKD,QAAQ,CACN,UAAmB,EACnB,SAAqC;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QACvB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;QAC1C,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACpC,CAAC;IAMD,cAAc,CACZ,UAAmB,EACnB,SAAqC;QAErC,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,CAAC;QAC9D,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,WAAW,EAAE,GAAG,MAAM,CAAC;QACtE,OAAO,WAAW,CAAC;IACrB,CAAC;IAKD,aAAa,CACX,UAAmB,EACnB,SAAqC;QAErC,OAAO,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,SAAmB,CAAC,EAAE,UAAU,CAAC;IACpE,CAAC;IAKD,YAAY,CACV,UAAmB,EACnB,SAAqC;QAQrC,MAAM,EACJ,MAAM,GAAG,EAAE,EACX,KAAK,GAAG,EAAE,EACV,OAAO,GAAG,EAAE,GACb,GAAG,IAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;QAC/C,MAAM,UAAU,GAAG,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC;QAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,CAAC,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC;QACrE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;IAC7D,CAAC;CACF;AAEY,QAAA,eAAe,GAAG,IAAI,oBAAoB,EAAE,CAAC","sourcesContent":["import loadableRegistry from \"../../components/arkos-loadable-registry\";\nimport {\n ArkosModuleType,\n ArkosRouteHookHooks,\n ArkosRouteHookMethodConfig,\n ArkosRouteHookInstance,\n ArkosAuthRouteHookInstance,\n ArkosFileUploadRouteHookInstance,\n} from \"./types\";\nimport { ArkosRequestHandler, ArkosRouteConfig } from \"../../exports\";\nimport { kebabCase } from \"../../exports/utils\";\n\ntype PrismaOperations = keyof Omit<\n ArkosRouteHookInstance<any>,\n \"__type\" | \"moduleName\" | \"service\"\n>;\n\nexport type OperationByModule<TModule extends ArkosModuleType> =\n TModule extends \"file-upload\"\n ? keyof Omit<ArkosFileUploadRouteHookInstance, \"__type\" | \"moduleName\" | \"service\">\n : TModule extends \"auth\"\n ? keyof Omit<ArkosAuthRouteHookInstance, \"__type\" | \"moduleName\" | \"service\">\n : PrismaOperations;\n\n/**\n * Reader for `ArkosRouteHook` instances.\n * Reads config from the global loadable registry by module name.\n *\n * @example\n * ```ts\n * routeHookReader.getHooks(\"user\", \"findMany\") // { before, after, onError }\n * routeHookReader.getRouteConfig(\"user\", \"findMany\") // ArkosRouteConfig minus path and hooks\n * routeHookReader.getPrismaArgs(\"user\", \"findMany\") // prismaArgs for that operation\n * routeHookReader.getFullConfig(\"user\", \"findMany\") // full raw config object\n * routeHookReader.hasOperation(\"user\", \"findMany\") // true | false\n * routeHookReader.forOperation(\"user\", \"findMany\") // { before, after, onError, prismaArgs, routeConfig }\n * ```\n */\nclass ArkosRouteHookReader {\n private getRouteHook(moduleName: ArkosModuleType) {\n return loadableRegistry.getItem(\"ArkosRouteHook\", kebabCase(moduleName));\n }\n\n private getStore(\n moduleName: ArkosModuleType\n ): Record<string, ArkosRouteHookMethodConfig> {\n return (this.getRouteHook(moduleName) as any)?._store ?? {};\n }\n\n /**\n * Returns true if the routeHook has a config registered for the given operation.\n */\n hasOperation<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): boolean {\n return operation in this.getStore(moduleName);\n }\n\n /**\n * Returns the full raw config for the given operation, or `null` if not registered.\n */\n getFullConfig<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): ArkosRouteHookMethodConfig | null {\n return this.getStore(moduleName)[operation as string] ?? null;\n }\n\n /**\n * Returns only the lifecycle hooks (`before`, `after`, `onError`) for the given operation.\n */\n getHooks<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): ArkosRouteHookHooks | undefined {\n const config = this.getStore(moduleName)[operation as string];\n if (!config) return {};\n const { before, after, onError } = config;\n return { before, after, onError };\n }\n\n /**\n * Returns the `ArkosRouteConfig` portion of the config (excludes `path`, hooks, and `prismaArgs`)\n * for the given operation.\n */\n getRouteConfig<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): Omit<ArkosRouteConfig, \"path\"> | null {\n const config = this.getStore(moduleName)[operation as string];\n if (!config) return null;\n const { before, after, onError, prismaArgs, ...routeConfig } = config;\n return routeConfig;\n }\n\n /**\n * Returns the `prismaArgs` for the given operation, or `undefined` if not set.\n */\n getPrismaArgs<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): Record<string, any> | undefined {\n return this.getStore(moduleName)[operation as string]?.prismaArgs;\n }\n\n /**\n * Returns all extracted slices for a given operation in one call.\n */\n forOperation<TModule extends ArkosModuleType>(\n moduleName: TModule,\n operation: OperationByModule<TModule>\n ): {\n before: ArkosRequestHandler[];\n after: ArkosRequestHandler[];\n onError: ArkosRequestHandler[];\n prismaArgs?: Record<string, any>;\n routeConfig: Omit<ArkosRouteConfig, \"path\">;\n } {\n const {\n before = [],\n after = [],\n onError = [],\n } = this.getHooks(moduleName, operation) || {};\n const prismaArgs = this.getPrismaArgs(moduleName, operation);\n const routeConfig = this.getRouteConfig(moduleName, operation) ?? {};\n return { before, after, onError, prismaArgs, routeConfig };\n }\n}\n\nexport const routeHookReader = new ArkosRouteHookReader();\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/components/arkos-route-hook/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ArkosRouteConfig } from \"../../exports\";\nimport { PrismaModels } from \"../../generated\";\nimport { ArkosRequestHandler } from \"../../types\";\n\nexport type Models = keyof PrismaModels<any>;\n\nexport interface ArkosRouteHookHooks {\n before?: ArkosRequestHandler[];\n after?: ArkosRequestHandler[];\n onError?: ArkosRequestHandler[];\n}\n\n/**\n * Extracts the correct Prisma args type for a given model and operation.\n * Falls back to `Record<string, any>` if the model or operation is not found.\n */\ntype PrismaQueryFor<\n TModel extends string,\n TOp extends string,\n> = TModel extends keyof PrismaModels<any>\n ? TOp extends keyof PrismaModels<any>[TModel]\n ? Partial<PrismaModels<any>[TModel][TOp]>\n : Record<string, any>\n : Record<string, any>;\n\n/**\n * Full config for an interceptor method — inherits all ArkosRouteConfig options\n * (validation, auth, rate limiting, etc.) minus `path`, plus lifecycle hooks,\n * plus `prismaQuery` typed to the specific model and operation's Prisma args.\n */\nexport type ArkosRouteHookMethodConfig<\n TModel extends string = string,\n TOp extends string = string,\n> = Omit<ArkosRouteConfig, \"path\"> &\n ArkosRouteHookHooks & {\n /**\n * Prisma options merged into this operation's query.\n * Typed against the model's actual Prisma args for this operation.\n */\n prismaArgs?: PrismaQueryFor<TModel, TOp>;\n };\n\n/**\n * Union of all valid module name types for ArkosRouteHook.\n * `string & {}` preserves autocomplete for \"auth\" and \"file-upload\"\n * while still accepting arbitrary model names.\n */\nexport type ArkosModuleType = \"auth\" | \"file-upload\" | Models;\n\n/**\n * Route hook instance for standard CRUD model routes.\n * Each method's `prismaQuery` is typed against the model's actual Prisma args.\n */\nexport interface ArkosRouteHookInstance<TModel extends Models> {\n readonly __type: \"ArkosRouteHook\";\n readonly moduleName: TModel;\n\n createOne(config: ArkosRouteHookMethodConfig<TModel, \"CreateArgs\">): this;\n findOne(config: ArkosRouteHookMethodConfig<TModel, \"FindFirstArgs\">): this;\n findMany(config: ArkosRouteHookMethodConfig<TModel, \"FindManyArgs\">): this;\n updateOne(config: ArkosRouteHookMethodConfig<TModel, \"UpdateArgs\">): this;\n deleteOne(config: ArkosRouteHookMethodConfig<TModel, \"DeleteArgs\">): this;\n createMany(\n config: ArkosRouteHookMethodConfig<TModel, \"CreateManyArgs\">\n ): this;\n updateMany(\n config: ArkosRouteHookMethodConfig<TModel, \"UpdateManyArgs\">\n ): this;\n deleteMany(\n config: ArkosRouteHookMethodConfig<TModel, \"DeleteManyArgs\">\n ): this;\n}\n\n/**\n * Route hook instance for the built-in auth module.\n * Only exposes methods relevant to auth routes.\n */\nexport interface ArkosAuthRouteHookInstance {\n readonly __type: \"ArkosRouteHook\";\n readonly moduleName: \"auth\";\n\n getMe(config: ArkosRouteHookMethodConfig): this;\n login(config: ArkosRouteHookMethodConfig): this;\n logout(config: ArkosRouteHookMethodConfig): this;\n signup(config: ArkosRouteHookMethodConfig): this;\n updateMe(config: ArkosRouteHookMethodConfig): this;\n deleteMe(config: ArkosRouteHookMethodConfig): this;\n updatePassword(config: ArkosRouteHookMethodConfig): this;\n findOneAuthAction(config: ArkosRouteHookMethodConfig): this;\n findManyAuthAction(config: ArkosRouteHookMethodConfig): this;\n}\n\n/**\n * Route hook instance for the built-in file-upload module.\n * Only exposes methods relevant to file routes.\n */\nexport interface ArkosFileUploadRouteHookInstance {\n readonly __type: \"ArkosRouteHook\";\n readonly moduleName: \"file-upload\";\n\n findFile(config: Omit<ArkosRouteHookMethodConfig, \"after\">): this;\n uploadFile(config: ArkosRouteHookMethodConfig): this;\n updateFile(config: ArkosRouteHookMethodConfig): this;\n deleteFile(config: ArkosRouteHookMethodConfig): this;\n}\n\n/**\n * Maps the module type string to its corresponding interceptor instance type.\n * Enables ArkosRouteHook() to return a narrowed type based on the argument.\n */\nexport type ArkosRouteHookReturn<T extends ArkosModuleType> = T extends \"auth\"\n ? ArkosAuthRouteHookInstance\n : T extends \"file-upload\"\n ? ArkosFileUploadRouteHookInstance\n : ArkosRouteHookInstance<T>;\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/components/arkos-route-hook/types.ts"],"names":[],"mappings":"","sourcesContent":["import { ArkosRouteConfig } from \"../../exports\";\nimport { ArkosPrismaService } from \"../../exports/services\";\nimport { PrismaModels } from \"../../generated\";\nimport { ArkosRequestHandler } from \"../../types\";\n\nexport type Models = keyof PrismaModels<any>;\n\nexport interface ArkosRouteHookHooks {\n before?: ArkosRequestHandler[];\n after?: ArkosRequestHandler[];\n onError?: ArkosRequestHandler[];\n}\n\n/**\n * Extracts the correct Prisma args type for a given model and operation.\n * Falls back to `Record<string, any>` if the model or operation is not found.\n */\ntype PrismaQueryFor<\n TModel extends string,\n TOp extends string,\n> = TModel extends keyof PrismaModels<any>\n ? TOp extends keyof PrismaModels<any>[TModel]\n ? Partial<PrismaModels<any>[TModel][TOp]>\n : Record<string, any>\n : Record<string, any>;\n\n/**\n * Full config for an interceptor method — inherits all ArkosRouteConfig options\n * (validation, auth, rate limiting, etc.) minus `path`, plus lifecycle hooks,\n * plus `prismaQuery` typed to the specific model and operation's Prisma args.\n */\nexport type ArkosRouteHookMethodConfig<\n TModel extends string = string,\n TOp extends string = string,\n> = Omit<ArkosRouteConfig, \"path\"> &\n ArkosRouteHookHooks & {\n /**\n * Prisma options merged into this operation's query.\n * Typed against the model's actual Prisma args for this operation.\n */\n prismaArgs?: PrismaQueryFor<TModel, TOp>;\n /**\n * ArkosPrismaService instace for such model\n */\n service?: ArkosPrismaService<TModel>\n };\n\n/**\n * Union of all valid module name types for ArkosRouteHook.\n * `string & {}` preserves autocomplete for \"auth\" and \"file-upload\"\n * while still accepting arbitrary model names.\n */\nexport type ArkosModuleType = \"auth\" | \"file-upload\" | Models;\n\n/**\n * Route hook instance for standard CRUD model routes.\n * Each method's `prismaQuery` is typed against the model's actual Prisma args.\n */\nexport interface ArkosRouteHookInstance<TModel extends Models> {\n readonly __type: \"ArkosRouteHook\";\n readonly moduleName: TModel;\n readonly service?: ArkosPrismaService;\n\n createOne(config: ArkosRouteHookMethodConfig<TModel, \"CreateArgs\">): this;\n findOne(config: ArkosRouteHookMethodConfig<TModel, \"FindFirstArgs\">): this;\n findMany(config: ArkosRouteHookMethodConfig<TModel, \"FindManyArgs\">): this;\n updateOne(config: ArkosRouteHookMethodConfig<TModel, \"UpdateArgs\">): this;\n deleteOne(config: ArkosRouteHookMethodConfig<TModel, \"DeleteArgs\">): this;\n createMany(\n config: ArkosRouteHookMethodConfig<TModel, \"CreateManyArgs\">\n ): this;\n updateMany(\n config: ArkosRouteHookMethodConfig<TModel, \"UpdateManyArgs\">\n ): this;\n deleteMany(\n config: ArkosRouteHookMethodConfig<TModel, \"DeleteManyArgs\">\n ): this;\n}\n\n/**\n * Route hook instance for the built-in auth module.\n * Only exposes methods relevant to auth routes.\n */\nexport interface ArkosAuthRouteHookInstance {\n readonly __type: \"ArkosRouteHook\";\n readonly moduleName: \"auth\";\n\n getMe(config: ArkosRouteHookMethodConfig): this;\n login(config: ArkosRouteHookMethodConfig): this;\n logout(config: ArkosRouteHookMethodConfig): this;\n signup(config: ArkosRouteHookMethodConfig): this;\n updateMe(config: ArkosRouteHookMethodConfig): this;\n deleteMe(config: ArkosRouteHookMethodConfig): this;\n updatePassword(config: ArkosRouteHookMethodConfig): this;\n findOneAuthAction(config: ArkosRouteHookMethodConfig): this;\n findManyAuthAction(config: ArkosRouteHookMethodConfig): this;\n}\n\n/**\n * Route hook instance for the built-in file-upload module.\n * Only exposes methods relevant to file routes.\n */\nexport interface ArkosFileUploadRouteHookInstance {\n readonly __type: \"ArkosRouteHook\";\n readonly moduleName: \"file-upload\";\n\n findFile(config: Omit<ArkosRouteHookMethodConfig, \"after\">): this;\n uploadFile(config: ArkosRouteHookMethodConfig): this;\n updateFile(config: ArkosRouteHookMethodConfig): this;\n deleteFile(config: ArkosRouteHookMethodConfig): this;\n}\n\n/**\n * Maps the module type string to its corresponding interceptor instance type.\n * Enables ArkosRouteHook() to return a narrowed type based on the argument.\n */\nexport type ArkosRouteHookReturn<T extends ArkosModuleType> = T extends \"auth\"\n ? ArkosAuthRouteHookInstance\n : T extends \"file-upload\"\n ? ArkosFileUploadRouteHookInstance\n : ArkosRouteHookInstance<T>;\n"]}
|