equipped 5.0.0-beta.9 → 5.0.0-rc.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/lib/bull/index.js +33 -44
  3. package/lib/cache/cache.d.ts +1 -0
  4. package/lib/cache/types/redis-cache.d.ts +1 -0
  5. package/lib/cache/types/redis-cache.js +8 -0
  6. package/lib/db/_instance.d.ts +2 -2
  7. package/lib/db/_instance.js +9 -25
  8. package/lib/db/mongoose/changes.d.ts +1 -26
  9. package/lib/db/mongoose/changes.js +7 -20
  10. package/lib/db/mongoose/index.d.ts +2 -27
  11. package/lib/db/mongoose/index.js +8 -24
  12. package/lib/db/mongoose/query.d.ts +0 -25
  13. package/lib/errors/customError.js +2 -0
  14. package/lib/errors/types/accessTokenExpired.js +1 -1
  15. package/lib/errors/types/badRequestError.js +1 -1
  16. package/lib/errors/types/notAuthenticatedError.js +1 -1
  17. package/lib/errors/types/notAuthorizedError.js +1 -1
  18. package/lib/errors/types/notFoundError.js +1 -1
  19. package/lib/errors/types/refreshTokenMisusedError.js +1 -1
  20. package/lib/errors/types/validationError.js +1 -1
  21. package/lib/events/index.js +1 -3
  22. package/lib/events/kafka.d.ts +1 -1
  23. package/lib/events/kafka.js +19 -25
  24. package/lib/events/rabbit.d.ts +1 -1
  25. package/lib/events/rabbit.js +9 -22
  26. package/lib/instance/index.d.ts +2 -1
  27. package/lib/instance/index.js +28 -41
  28. package/lib/instance/settings.d.ts +2 -2
  29. package/lib/instance/settings.js +4 -4
  30. package/lib/listeners/emitter.d.ts +6 -3
  31. package/lib/listeners/emitter.js +97 -109
  32. package/lib/scripts/json-schema.d.ts +2 -1
  33. package/lib/scripts/json-schema.js +29 -22
  34. package/lib/server/impls/base.d.ts +18 -7
  35. package/lib/server/impls/base.js +177 -80
  36. package/lib/server/impls/express.d.ts +0 -1
  37. package/lib/server/impls/express.js +16 -34
  38. package/lib/server/impls/fastify.d.ts +2 -4
  39. package/lib/server/impls/fastify.js +21 -39
  40. package/lib/server/middlewares/errorHandler.d.ts +2 -2
  41. package/lib/server/middlewares/notFoundHandler.d.ts +2 -2
  42. package/lib/server/middlewares/parseAuthUser.d.ts +2 -2
  43. package/lib/server/middlewares/requireAuthUser.d.ts +2 -2
  44. package/lib/server/middlewares/requireAuthUser.js +2 -2
  45. package/lib/server/middlewares/requireRefreshUser.d.ts +2 -2
  46. package/lib/server/middlewares/requireRefreshUser.js +2 -2
  47. package/lib/server/requests.d.ts +10 -7
  48. package/lib/server/requests.js +27 -21
  49. package/lib/server/routes.d.ts +4 -2
  50. package/lib/server/routes.js +33 -33
  51. package/lib/server/types.d.ts +19 -9
  52. package/lib/server/types.js +3 -0
  53. package/lib/storage/index.d.ts +0 -1
  54. package/lib/structure/baseEntity.js +7 -9
  55. package/lib/types/index.d.ts +2 -2
  56. package/lib/utils/auth.d.ts +5 -5
  57. package/lib/utils/authUser.d.ts +3 -2
  58. package/lib/utils/media.d.ts +0 -1
  59. package/lib/utils/utils.d.ts +1 -0
  60. package/lib/utils/utils.js +9 -0
  61. package/lib/validations/index.d.ts +79 -85
  62. package/lib/validations/index.js +4 -4
  63. package/package.json +24 -25
@@ -1,16 +1,4 @@
1
1
  "use strict";
2
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
3
- if (kind === "m") throw new TypeError("Private method is not writable");
4
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
5
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
6
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
7
- };
8
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
9
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
10
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
- };
13
- var _Listener_instances, _Listener_socket, _Listener_callers, _Listener_routes, _Listener_subscriber, _Listener_publisher, _Listener_getJoinCb, _Listener_emit, _Listener_setupSocketConnection;
14
2
  Object.defineProperty(exports, "__esModule", { value: true });
15
3
  exports.Listener = void 0;
16
4
  const path_to_regexp_1 = require("path-to-regexp");
@@ -25,118 +13,118 @@ var EmitTypes;
25
13
  })(EmitTypes || (EmitTypes = {}));
26
14
  const EmitterEvent = '__listener_emitter';
27
15
  class Listener {
16
+ #socket;
17
+ #callers;
18
+ #routes = {};
19
+ #subscriber = instance_1.Instance.get().eventBus.createSubscriber(EmitterEvent, async (data) => {
20
+ this.#socket.to(data.channel).emit(data.channel, data);
21
+ }, { fanout: true });
22
+ #publisher = instance_1.Instance.get().eventBus.createPublisher(EmitterEvent);
28
23
  constructor(socket, callers) {
29
- _Listener_instances.add(this);
30
- _Listener_socket.set(this, void 0);
31
- _Listener_callers.set(this, void 0);
32
- _Listener_routes.set(this, {});
33
- _Listener_subscriber.set(this, instance_1.Instance.get().eventBus.createSubscriber(EmitterEvent, async (data) => {
34
- __classPrivateFieldGet(this, _Listener_socket, "f").to(data.channel).emit(data.channel, data);
35
- }, { fanout: true }));
36
- _Listener_publisher.set(this, instance_1.Instance.get().eventBus.createPublisher(EmitterEvent));
37
- _Listener_setupSocketConnection.set(this, () => {
38
- const event = 'connection';
39
- __classPrivateFieldGet(this, _Listener_socket, "f").removeAllListeners(event);
40
- __classPrivateFieldGet(this, _Listener_socket, "f").on(event, async (socket) => {
41
- const socketId = socket.id;
42
- let user = null;
43
- if (socket.handshake.auth.token)
44
- user = await (0, tokens_1.verifyAccessToken)(socket.handshake.auth.token ?? '').catch(() => null);
45
- socket.on('leave', async (data, callback) => {
46
- if (!data.channel)
47
- return typeof (callback) === 'function' && callback({
48
- code: server_1.StatusCodes.ValidationError,
49
- message: 'channel is required',
50
- channel: ''
51
- });
52
- socket.leave(data.channel);
53
- return typeof (callback) === 'function' && callback({
54
- code: server_1.StatusCodes.Ok,
55
- message: '',
56
- channel: data.channel
57
- });
58
- });
59
- socket.on('join', async (data, callback) => {
60
- if (!data.channel)
61
- return typeof (callback) === 'function' && callback({
62
- code: server_1.StatusCodes.ValidationError,
63
- message: 'channel is required',
64
- channel: ''
65
- });
66
- const channel = data.channel;
67
- const route = __classPrivateFieldGet(this, _Listener_instances, "m", _Listener_getJoinCb).call(this, channel) ?? null;
68
- if (!route)
69
- return typeof (callback) === 'function' && callback({
70
- code: server_1.StatusCodes.BadRequest,
71
- message: 'unknown channel',
72
- channel
73
- });
74
- const newChannel = await route.onJoin({ channel, user }, route.params, data.query ?? {});
75
- if (!newChannel)
76
- return typeof (callback) === 'function' && callback({
77
- code: server_1.StatusCodes.NotAuthorized,
78
- message: 'restricted access',
79
- channel
80
- });
81
- socket.join(newChannel);
82
- return typeof (callback) === 'function' && callback({
83
- code: server_1.StatusCodes.Ok,
84
- message: '',
85
- channel: newChannel
86
- });
87
- });
88
- if (user)
89
- await __classPrivateFieldGet(this, _Listener_callers, "f").onConnect(user.id, socketId);
90
- socket.on('disconnect', async () => {
91
- if (user)
92
- await __classPrivateFieldGet(this, _Listener_callers, "f").onDisconnect(user.id, socketId);
93
- });
94
- });
95
- });
96
- __classPrivateFieldSet(this, _Listener_socket, socket, "f");
97
- __classPrivateFieldSet(this, _Listener_callers, callers, "f");
98
- __classPrivateFieldGet(this, _Listener_setupSocketConnection, "f").call(this);
24
+ this.#socket = socket;
25
+ this.#callers = callers;
26
+ this.#setupSocketConnection();
99
27
  }
100
28
  async start() {
101
- await __classPrivateFieldGet(this, _Listener_subscriber, "f").subscribe();
29
+ await this.#subscriber.subscribe();
102
30
  }
103
31
  async created(channels, data) {
104
- await __classPrivateFieldGet(this, _Listener_instances, "m", _Listener_emit).call(this, channels, EmitTypes.created, data.toJSON());
32
+ await this.#emit(channels, EmitTypes.created, { after: data.toJSON(), before: null });
105
33
  }
106
- async updated(channels, data) {
107
- await __classPrivateFieldGet(this, _Listener_instances, "m", _Listener_emit).call(this, channels, EmitTypes.updated, data.toJSON());
34
+ async updated(channels, { after, before }) {
35
+ await this.#emit(channels, EmitTypes.updated, { after: after.toJSON(), before: before.toJSON() });
108
36
  }
109
37
  async deleted(channels, data) {
110
- await __classPrivateFieldGet(this, _Listener_instances, "m", _Listener_emit).call(this, channels, EmitTypes.deleted, data.toJSON());
38
+ await this.#emit(channels, EmitTypes.deleted, { before: data.toJSON(), after: null });
111
39
  }
112
40
  set callers(callers) {
113
- __classPrivateFieldSet(this, _Listener_callers, callers, "f");
114
- __classPrivateFieldGet(this, _Listener_setupSocketConnection, "f").call(this);
41
+ this.#callers = callers;
42
+ this.#setupSocketConnection();
115
43
  }
116
44
  register(channel, onJoin) {
117
45
  if (!onJoin)
118
46
  onJoin = async ({ channel }) => channel;
119
- __classPrivateFieldGet(this, _Listener_routes, "f")[channel] = onJoin;
120
- __classPrivateFieldGet(this, _Listener_routes, "f")[channel + '/:id'] = onJoin;
47
+ this.#routes[channel] = onJoin;
48
+ this.#routes[channel + '/:id'] = onJoin;
121
49
  return this;
122
50
  }
51
+ #getJoinCb(channel) {
52
+ const matcher = (key) => (0, path_to_regexp_1.match)(key)(channel);
53
+ const matchedChannel = Object.keys(this.#routes).find(matcher) ?? null;
54
+ if (!matchedChannel)
55
+ return null;
56
+ const match = matcher(matchedChannel);
57
+ if (!match)
58
+ return null;
59
+ return {
60
+ onJoin: this.#routes[matchedChannel],
61
+ params: JSON.parse(JSON.stringify(match.params))
62
+ };
63
+ }
64
+ async #emit(channels, type, { before, after }) {
65
+ await Promise.all(channels.map(async (channel) => {
66
+ const emitData = { channel, type, before, after };
67
+ await this.#publisher.publish(emitData);
68
+ }));
69
+ }
70
+ #setupSocketConnection = () => {
71
+ const event = 'connection';
72
+ this.#socket.removeAllListeners(event);
73
+ this.#socket.on(event, async (socket) => {
74
+ const socketId = socket.id;
75
+ let user = null;
76
+ if (socket.handshake.auth.token)
77
+ user = await (0, tokens_1.verifyAccessToken)(socket.handshake.auth.token ?? '').catch(() => null);
78
+ socket.on('leave', async (data, callback) => {
79
+ if (!data.channel)
80
+ return typeof (callback) === 'function' && callback({
81
+ code: server_1.StatusCodes.ValidationError,
82
+ message: 'channel is required',
83
+ channel: ''
84
+ });
85
+ socket.leave(data.channel);
86
+ return typeof (callback) === 'function' && callback({
87
+ code: server_1.StatusCodes.Ok,
88
+ message: '',
89
+ channel: data.channel
90
+ });
91
+ });
92
+ socket.on('join', async (data, callback) => {
93
+ if (!data.channel)
94
+ return typeof (callback) === 'function' && callback({
95
+ code: server_1.StatusCodes.ValidationError,
96
+ message: 'channel is required',
97
+ channel: ''
98
+ });
99
+ const channel = data.channel;
100
+ const route = this.#getJoinCb(channel) ?? null;
101
+ if (!route)
102
+ return typeof (callback) === 'function' && callback({
103
+ code: server_1.StatusCodes.BadRequest,
104
+ message: 'unknown channel',
105
+ channel
106
+ });
107
+ const newChannel = await route.onJoin({ channel, user }, route.params, data.query ?? {});
108
+ if (!newChannel)
109
+ return typeof (callback) === 'function' && callback({
110
+ code: server_1.StatusCodes.NotAuthorized,
111
+ message: 'restricted access',
112
+ channel
113
+ });
114
+ socket.join(newChannel);
115
+ return typeof (callback) === 'function' && callback({
116
+ code: server_1.StatusCodes.Ok,
117
+ message: '',
118
+ channel: newChannel
119
+ });
120
+ });
121
+ if (user)
122
+ await this.#callers.onConnect(user.id, socketId);
123
+ socket.on('disconnect', async () => {
124
+ if (user)
125
+ await this.#callers.onDisconnect(user.id, socketId);
126
+ });
127
+ });
128
+ };
123
129
  }
124
130
  exports.Listener = Listener;
125
- _Listener_socket = new WeakMap(), _Listener_callers = new WeakMap(), _Listener_routes = new WeakMap(), _Listener_subscriber = new WeakMap(), _Listener_publisher = new WeakMap(), _Listener_setupSocketConnection = new WeakMap(), _Listener_instances = new WeakSet(), _Listener_getJoinCb = function _Listener_getJoinCb(channel) {
126
- const matcher = (key) => (0, path_to_regexp_1.match)(key, { encode: encodeURI, decode: decodeURIComponent })(channel);
127
- const matchedChannel = Object.keys(__classPrivateFieldGet(this, _Listener_routes, "f")).find(matcher) ?? null;
128
- if (!matchedChannel)
129
- return null;
130
- const match = matcher(matchedChannel);
131
- if (!match)
132
- return null;
133
- return {
134
- onJoin: __classPrivateFieldGet(this, _Listener_routes, "f")[matchedChannel],
135
- params: JSON.parse(JSON.stringify(match.params))
136
- };
137
- }, _Listener_emit = async function _Listener_emit(channels, type, data) {
138
- await Promise.all(channels.map(async (channel) => {
139
- const emitData = { channel, type, data };
140
- await __classPrivateFieldGet(this, _Listener_publisher, "f").publish(emitData);
141
- }));
142
- };
@@ -1,6 +1,7 @@
1
1
  import { Options } from 'ts-oas';
2
+ import type { CompilerOptions } from 'typescript';
2
3
  import { RouteSchema } from '../server';
3
4
  export declare function generateJSONSchema(patterns: (string | RegExp)[], paths: string[], options?: {
4
- tsConfigPath?: string | Record<string, unknown>;
5
+ tsConfig?: string | CompilerOptions;
5
6
  options?: Options;
6
7
  }): Record<string, RouteSchema>;
@@ -23,16 +23,30 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.generateJSONSchema = void 0;
26
+ exports.generateJSONSchema = generateJSONSchema;
27
27
  const ts_oas_1 = __importStar(require("ts-oas"));
28
28
  const instance_1 = require("../instance");
29
- const fileSchema = { type: 'string', format: 'binary' };
29
+ const server_1 = require("../server");
30
+ const statusCodes = Object.entries(server_1.StatusCodes);
31
+ const fileSchema = { type: 'string', format: 'binary', example: 'uploaded binary file' };
32
+ function isFile(schema) {
33
+ return schema.type === 'string' && schema.enum?.at(0) === 'equipped-file-schema';
34
+ }
30
35
  function generateJSONSchema(patterns, paths, options) {
31
- const tsProgram = (0, ts_oas_1.createProgram)(paths, options?.tsConfigPath);
36
+ const tsProgram = (0, ts_oas_1.createProgram)(paths, options?.tsConfig);
32
37
  const logger = instance_1.Instance.createLogger();
33
38
  const tsoas = new ts_oas_1.default(tsProgram, {
34
39
  ref: false,
35
40
  nullableKeyword: false,
41
+ schemaProcessor: (schema) => {
42
+ if (isFile(schema))
43
+ return fileSchema;
44
+ if (schema.anyOf)
45
+ schema.anyOf = schema.anyOf.map((s) => isFile(s) ? fileSchema : s);
46
+ if (schema.allOf)
47
+ schema.allOf = schema.allOf.map((s) => isFile(s) ? fileSchema : s);
48
+ return schema;
49
+ },
36
50
  ...(options?.options ?? {})
37
51
  });
38
52
  const jsonSchema = tsoas.getSchemas(patterns);
@@ -40,34 +54,28 @@ function generateJSONSchema(patterns, paths, options) {
40
54
  .map(([name, { properties: def }]) => {
41
55
  try {
42
56
  const key = def?.key?.enum?.at(0) ?? name;
43
- if (!def || !key || !def.method)
57
+ const isApiDef = def?.__apiDef?.type === 'boolean' && def?.__apiDef?.enum?.[0] === true;
58
+ const method = def?.method?.enum?.at?.(0)?.toLowerCase?.();
59
+ if (!def || !isApiDef || !key || !method)
44
60
  return [undefined, undefined];
45
61
  const response = def.responses.properties ?? def.responses.anyOf?.reduce((acc, cur) => {
46
62
  if (cur.properties)
47
63
  return { ...acc, ...cur.properties };
48
64
  return acc;
49
65
  }, {}) ?? undefined;
50
- const body = def.body ?? {};
51
- if (def.files?.properties) {
52
- const files = def.files ?? {};
53
- if (!body.type)
54
- body.type = 'object';
55
- if (!body.properties)
56
- body.properties = {};
57
- if (!body.required)
58
- body.required = [];
59
- Object.entries(files.properties ?? {}).forEach(([key, value]) => {
60
- const isMultiple = !!value.enum?.at(0);
61
- body.properties[key] = isMultiple ? { type: 'array', items: fileSchema } : fileSchema;
62
- if (files.required?.includes(key))
63
- body.required.push(key);
64
- });
66
+ if (response) {
67
+ for (const [key, value] of Object.entries(response)) {
68
+ const status = statusCodes.find(([_, code]) => code.toString() === key);
69
+ if (status)
70
+ value['description'] = `${status[0]} Response`;
71
+ }
65
72
  }
73
+ const supportsBody = ['post', 'put', 'patch'].includes(method);
66
74
  const schema = {
67
- body,
75
+ body: supportsBody ? def.body : undefined,
68
76
  params: def.params,
69
77
  querystring: def.query,
70
- headers: def.headers,
78
+ headers: def.requestHeaders,
71
79
  response,
72
80
  operationId: key,
73
81
  summary: name,
@@ -88,7 +96,6 @@ function generateJSONSchema(patterns, paths, options) {
88
96
  return acc;
89
97
  }, {});
90
98
  }
91
- exports.generateJSONSchema = generateJSONSchema;
92
99
  function stripEmptyObjects(obj) {
93
100
  return Object.entries(obj).reduce((acc, [key, value]) => {
94
101
  if (!value || typeof value === 'object' && Object.keys(value).length === 0)
@@ -1,6 +1,3 @@
1
- /// <reference types="node" />
2
- /// <reference types="node/http" />
3
- /// <reference types="pino-http" />
4
1
  import http from 'http';
5
2
  import { OpenAPIV3_1 } from 'openapi-types';
6
3
  import supertest from 'supertest';
@@ -10,16 +7,30 @@ import { Defined } from '../../types';
10
7
  import { Request } from '../requests';
11
8
  import { Router } from '../routes';
12
9
  import { Route } from '../types';
13
- export type FullRoute = Required<Omit<Route, 'schema' | 'tags' | 'security' | 'descriptions' | 'hideSchema' | 'onError' | 'onSetupHandler' | '__def'>> & {
10
+ export type FullRoute = Required<Omit<Route, 'schema' | 'groups' | 'security' | 'descriptions' | 'hideSchema' | 'onError' | 'onSetupHandler' | '__def'>> & {
14
11
  schema: FastifySchema;
15
12
  onError?: Route['onError'];
16
13
  };
17
14
  type Schemas = Record<string, Defined<Route['schema']>>;
15
+ declare module 'openapi-types' {
16
+ namespace OpenAPIV3 {
17
+ interface Document {
18
+ 'x-tagGroups': {
19
+ name: string;
20
+ tags: string[];
21
+ }[];
22
+ }
23
+ interface TagObject {
24
+ 'x-displayName': string;
25
+ }
26
+ }
27
+ }
18
28
  export declare abstract class Server<Req = any, Res = any> {
19
29
  #private;
20
30
  protected server: http.Server;
21
31
  protected staticPath: string;
22
32
  protected settings: import("../../instance/settings").Settings;
33
+ protected openapiJsonUrl: string;
23
34
  protected baseOpenapiDoc: OpenAPIV3_1.Document;
24
35
  protected abstract onLoad(): Promise<void>;
25
36
  protected abstract startServer(port: number): Promise<boolean>;
@@ -27,10 +38,10 @@ export declare abstract class Server<Req = any, Res = any> {
27
38
  protected abstract registerRoute(route: FullRoute): void;
28
39
  constructor(server: http.Server);
29
40
  get listener(): Listener;
30
- addRoutes(routes: Route[]): void;
31
- addSchema(schemas: Schemas): void;
41
+ addRouter(...routers: Router[]): void;
42
+ addRoute(...routes: Route[]): void;
43
+ addSchema(...schemas: Schemas[]): void;
32
44
  load(): Promise<void>;
33
- register(router: Router | Router[]): void;
34
45
  test(): import("supertest/lib/agent")<supertest.SuperTestStatic.Test>;
35
46
  start(port: number): Promise<boolean>;
36
47
  }