@lakutata/entrypoint 3.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +23 -0
- package/README.md +183 -0
- package/THIRD_PARTY_NOTICES.md +206 -0
- package/dist/cjs/Entrypoint.d.ts +868 -0
- package/dist/cjs/Entrypoint.js +998 -0
- package/dist/cjs/adapter/commander/CommanderCLIEntrypoint.d.ts +192 -0
- package/dist/cjs/adapter/commander/CommanderCLIEntrypoint.js +439 -0
- package/dist/cjs/adapter/commander/Prompt.d.ts +22 -0
- package/dist/cjs/adapter/commander/Prompt.js +164 -0
- package/dist/cjs/adapter/commander/Width.d.ts +12 -0
- package/dist/cjs/adapter/commander/Width.js +67 -0
- package/dist/cjs/adapter/electron/ElectronIPCServiceEntrypoint.d.ts +203 -0
- package/dist/cjs/adapter/electron/ElectronIPCServiceEntrypoint.js +249 -0
- package/dist/cjs/adapter/express/ExpressHTTPEntrypoint.d.ts +172 -0
- package/dist/cjs/adapter/express/ExpressHTTPEntrypoint.js +301 -0
- package/dist/cjs/adapter/express/Responders.d.ts +89 -0
- package/dist/cjs/adapter/express/Responders.js +71 -0
- package/dist/cjs/adapter/express/StaticUI.d.ts +83 -0
- package/dist/cjs/adapter/express/StaticUI.js +104 -0
- package/dist/cjs/adapter/fastify/FastifyHTTPEntrypoint.d.ts +156 -0
- package/dist/cjs/adapter/fastify/FastifyHTTPEntrypoint.js +339 -0
- package/dist/cjs/adapter/fastify/Responders.d.ts +88 -0
- package/dist/cjs/adapter/fastify/Responders.js +77 -0
- package/dist/cjs/adapter/http/HTTPServiceEntrypoint.d.ts +117 -0
- package/dist/cjs/adapter/http/HTTPServiceEntrypoint.js +257 -0
- package/dist/cjs/adapter/jsonrpc/JSONRPCProtocol.d.ts +194 -0
- package/dist/cjs/adapter/jsonrpc/JSONRPCProtocol.js +187 -0
- package/dist/cjs/adapter/jsonrpc/JSONRPCServiceEntrypoint.d.ts +154 -0
- package/dist/cjs/adapter/jsonrpc/JSONRPCServiceEntrypoint.js +397 -0
- package/dist/cjs/adapter/schedule/ScheduleEntrypoint.d.ts +86 -0
- package/dist/cjs/adapter/schedule/ScheduleEntrypoint.js +275 -0
- package/dist/cjs/adapter/socket.io/SocketIOServiceEntrypoint.d.ts +138 -0
- package/dist/cjs/adapter/socket.io/SocketIOServiceEntrypoint.js +216 -0
- package/dist/cjs/channel/BuiltinChannels.d.ts +18 -0
- package/dist/cjs/channel/BuiltinChannels.js +128 -0
- package/dist/cjs/channel/Channel.d.ts +196 -0
- package/dist/cjs/channel/Channel.js +106 -0
- package/dist/cjs/channel/EntrypointAdapter.d.ts +195 -0
- package/dist/cjs/channel/EntrypointAdapter.js +43 -0
- package/dist/cjs/context/BaseContext.d.ts +75 -0
- package/dist/cjs/context/BaseContext.js +90 -0
- package/dist/cjs/context/CLIContext.d.ts +38 -0
- package/dist/cjs/context/CLIContext.js +53 -0
- package/dist/cjs/context/HTTPContext.d.ts +52 -0
- package/dist/cjs/context/HTTPContext.js +78 -0
- package/dist/cjs/context/ScheduleContext.d.ts +47 -0
- package/dist/cjs/context/ScheduleContext.js +65 -0
- package/dist/cjs/context/ServiceContext.d.ts +47 -0
- package/dist/cjs/context/ServiceContext.js +62 -0
- package/dist/cjs/decorators/CLIAction.d.ts +120 -0
- package/dist/cjs/decorators/CLIAction.js +13 -0
- package/dist/cjs/decorators/HTTPAction.d.ts +178 -0
- package/dist/cjs/decorators/HTTPAction.js +14 -0
- package/dist/cjs/decorators/Prefix.d.ts +44 -0
- package/dist/cjs/decorators/Prefix.js +48 -0
- package/dist/cjs/decorators/Schedule.d.ts +120 -0
- package/dist/cjs/decorators/Schedule.js +64 -0
- package/dist/cjs/decorators/ServiceAction.d.ts +116 -0
- package/dist/cjs/decorators/ServiceAction.js +12 -0
- package/dist/cjs/decorators/UseMiddlewares.d.ts +52 -0
- package/dist/cjs/decorators/UseMiddlewares.js +58 -0
- package/dist/cjs/decorators/http/DELETE.d.ts +87 -0
- package/dist/cjs/decorators/http/DELETE.js +7 -0
- package/dist/cjs/decorators/http/GET.d.ts +89 -0
- package/dist/cjs/decorators/http/GET.js +7 -0
- package/dist/cjs/decorators/http/HEAD.d.ts +84 -0
- package/dist/cjs/decorators/http/HEAD.js +7 -0
- package/dist/cjs/decorators/http/OPTIONS.d.ts +80 -0
- package/dist/cjs/decorators/http/OPTIONS.js +7 -0
- package/dist/cjs/decorators/http/PATCH.d.ts +90 -0
- package/dist/cjs/decorators/http/PATCH.js +7 -0
- package/dist/cjs/decorators/http/POST.d.ts +91 -0
- package/dist/cjs/decorators/http/POST.js +7 -0
- package/dist/cjs/decorators/http/PUT.d.ts +92 -0
- package/dist/cjs/decorators/http/PUT.js +7 -0
- package/dist/cjs/exceptions/AccessDeniedException.d.ts +10 -0
- package/dist/cjs/exceptions/AccessDeniedException.js +17 -0
- package/dist/cjs/exceptions/ControllerActionNotFoundException.d.ts +9 -0
- package/dist/cjs/exceptions/ControllerActionNotFoundException.js +16 -0
- package/dist/cjs/exceptions/DuplicateActionNameException.d.ts +8 -0
- package/dist/cjs/exceptions/DuplicateActionNameException.js +15 -0
- package/dist/cjs/exceptions/EntrypointStoppedException.d.ts +9 -0
- package/dist/cjs/exceptions/EntrypointStoppedException.js +16 -0
- package/dist/cjs/exceptions/InvalidActionGroupException.d.ts +4 -0
- package/dist/cjs/exceptions/InvalidActionGroupException.js +11 -0
- package/dist/cjs/exceptions/InvalidChannelException.d.ts +8 -0
- package/dist/cjs/exceptions/InvalidChannelException.js +15 -0
- package/dist/cjs/exceptions/InvalidEntrypointAdapterException.d.ts +9 -0
- package/dist/cjs/exceptions/InvalidEntrypointAdapterException.js +16 -0
- package/dist/cjs/exceptions/InvalidMiddlewareException.d.ts +8 -0
- package/dist/cjs/exceptions/InvalidMiddlewareException.js +15 -0
- package/dist/cjs/exceptions/InvalidPrefixException.d.ts +8 -0
- package/dist/cjs/exceptions/InvalidPrefixException.js +15 -0
- package/dist/cjs/exceptions/MiddlewareNextCalledException.d.ts +8 -0
- package/dist/cjs/exceptions/MiddlewareNextCalledException.js +15 -0
- package/dist/cjs/exceptions/RouteNotFoundException.d.ts +9 -0
- package/dist/cjs/exceptions/RouteNotFoundException.js +16 -0
- package/dist/cjs/exceptions/ServiceInvokeException.d.ts +11 -0
- package/dist/cjs/exceptions/ServiceInvokeException.js +14 -0
- package/dist/cjs/exports/CTRLDecorators.d.ts +13 -0
- package/dist/cjs/exports/CTRLDecorators.js +38 -0
- package/dist/cjs/exports/Channel.d.ts +14 -0
- package/dist/cjs/exports/Channel.js +33 -0
- package/dist/cjs/exports/CommanderAdapter.d.ts +1 -0
- package/dist/cjs/exports/CommanderAdapter.js +8 -0
- package/dist/cjs/exports/ElectronAdapter.d.ts +1 -0
- package/dist/cjs/exports/ElectronAdapter.js +9 -0
- package/dist/cjs/exports/Entrypoint.d.ts +24 -0
- package/dist/cjs/exports/Entrypoint.js +55 -0
- package/dist/cjs/exports/ExpressAdapter.d.ts +4 -0
- package/dist/cjs/exports/ExpressAdapter.js +15 -0
- package/dist/cjs/exports/FastifyAdapter.d.ts +4 -0
- package/dist/cjs/exports/FastifyAdapter.js +14 -0
- package/dist/cjs/exports/JSONRPCAdapter.d.ts +2 -0
- package/dist/cjs/exports/JSONRPCAdapter.js +11 -0
- package/dist/cjs/exports/SocketIOAdapter.d.ts +1 -0
- package/dist/cjs/exports/SocketIOAdapter.js +9 -0
- package/dist/cjs/lib/AccessControl.d.ts +118 -0
- package/dist/cjs/lib/AccessControl.js +208 -0
- package/dist/cjs/lib/AccessControlRule.d.ts +91 -0
- package/dist/cjs/lib/AccessControlRule.js +76 -0
- package/dist/cjs/lib/ActionOptions.d.ts +67 -0
- package/dist/cjs/lib/ActionOptions.js +67 -0
- package/dist/cjs/lib/ActionResult.d.ts +28 -0
- package/dist/cjs/lib/ActionResult.js +28 -0
- package/dist/cjs/lib/ApplicationOf.d.ts +6 -0
- package/dist/cjs/lib/ApplicationOf.js +14 -0
- package/dist/cjs/lib/Controller.d.ts +59 -0
- package/dist/cjs/lib/Controller.js +64 -0
- package/dist/cjs/lib/ControllerEntrypoint.d.ts +168 -0
- package/dist/cjs/lib/ControllerEntrypoint.js +239 -0
- package/dist/cjs/lib/GetActionDTOAndOptions.d.ts +29 -0
- package/dist/cjs/lib/GetActionDTOAndOptions.js +49 -0
- package/dist/cjs/lib/HTTPErrors.d.ts +55 -0
- package/dist/cjs/lib/HTTPErrors.js +52 -0
- package/dist/cjs/lib/Middleware.d.ts +146 -0
- package/dist/cjs/lib/Middleware.js +144 -0
- package/dist/cjs/lib/Prefix.d.ts +98 -0
- package/dist/cjs/lib/Prefix.js +151 -0
- package/dist/cjs/lib/Result.d.ts +173 -0
- package/dist/cjs/lib/Result.js +153 -0
- package/dist/cjs/lib/ServiceResponseCodec.d.ts +82 -0
- package/dist/cjs/lib/ServiceResponseCodec.js +117 -0
- package/dist/cjs/lib/StringifyPattern.d.ts +7 -0
- package/dist/cjs/lib/StringifyPattern.js +58 -0
- package/dist/cjs/lib/UnsetValue.d.ts +12 -0
- package/dist/cjs/lib/UnsetValue.js +216 -0
- package/dist/cjs/lib/pattern/GlobPattern.d.ts +34 -0
- package/dist/cjs/lib/pattern/GlobPattern.js +68 -0
- package/dist/cjs/lib/pattern/PatternManager.d.ts +103 -0
- package/dist/cjs/lib/pattern/PatternManager.js +233 -0
- package/dist/cjs/lib/schedule/Cron.d.ts +56 -0
- package/dist/cjs/lib/schedule/Cron.js +282 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/types/CLIContextParams.d.ts +14 -0
- package/dist/cjs/types/CLIContextParams.js +2 -0
- package/dist/cjs/types/ErrorDescription.d.ts +14 -0
- package/dist/cjs/types/ErrorDescription.js +2 -0
- package/dist/cjs/types/HTTPContextParams.d.ts +27 -0
- package/dist/cjs/types/HTTPContextParams.js +2 -0
- package/dist/cjs/types/ScheduleContextParams.d.ts +21 -0
- package/dist/cjs/types/ScheduleContextParams.js +2 -0
- package/dist/cjs/types/ServiceContextParams.d.ts +16 -0
- package/dist/cjs/types/ServiceContextParams.js +2 -0
- package/dist/esm/Entrypoint.js +985 -0
- package/dist/esm/adapter/commander/CommanderCLIEntrypoint.js +433 -0
- package/dist/esm/adapter/commander/Prompt.js +127 -0
- package/dist/esm/adapter/commander/Width.js +63 -0
- package/dist/esm/adapter/electron/ElectronIPCServiceEntrypoint.js +212 -0
- package/dist/esm/adapter/express/ExpressHTTPEntrypoint.js +295 -0
- package/dist/esm/adapter/express/Responders.js +66 -0
- package/dist/esm/adapter/express/StaticUI.js +96 -0
- package/dist/esm/adapter/fastify/FastifyHTTPEntrypoint.js +333 -0
- package/dist/esm/adapter/fastify/Responders.js +73 -0
- package/dist/esm/adapter/http/HTTPServiceEntrypoint.js +253 -0
- package/dist/esm/adapter/jsonrpc/JSONRPCProtocol.js +182 -0
- package/dist/esm/adapter/jsonrpc/JSONRPCServiceEntrypoint.js +361 -0
- package/dist/esm/adapter/schedule/ScheduleEntrypoint.js +272 -0
- package/dist/esm/adapter/socket.io/SocketIOServiceEntrypoint.js +212 -0
- package/dist/esm/channel/BuiltinChannels.js +125 -0
- package/dist/esm/channel/Channel.js +100 -0
- package/dist/esm/channel/EntrypointAdapter.js +39 -0
- package/dist/esm/context/BaseContext.js +87 -0
- package/dist/esm/context/CLIContext.js +49 -0
- package/dist/esm/context/HTTPContext.js +74 -0
- package/dist/esm/context/ScheduleContext.js +61 -0
- package/dist/esm/context/ServiceContext.js +58 -0
- package/dist/esm/decorators/CLIAction.js +10 -0
- package/dist/esm/decorators/HTTPAction.js +11 -0
- package/dist/esm/decorators/Prefix.js +45 -0
- package/dist/esm/decorators/Schedule.js +61 -0
- package/dist/esm/decorators/ServiceAction.js +9 -0
- package/dist/esm/decorators/UseMiddlewares.js +55 -0
- package/dist/esm/decorators/http/DELETE.js +4 -0
- package/dist/esm/decorators/http/GET.js +4 -0
- package/dist/esm/decorators/http/HEAD.js +4 -0
- package/dist/esm/decorators/http/OPTIONS.js +4 -0
- package/dist/esm/decorators/http/PATCH.js +4 -0
- package/dist/esm/decorators/http/POST.js +4 -0
- package/dist/esm/decorators/http/PUT.js +4 -0
- package/dist/esm/exceptions/AccessDeniedException.js +13 -0
- package/dist/esm/exceptions/ControllerActionNotFoundException.js +12 -0
- package/dist/esm/exceptions/DuplicateActionNameException.js +11 -0
- package/dist/esm/exceptions/EntrypointStoppedException.js +12 -0
- package/dist/esm/exceptions/InvalidActionGroupException.js +7 -0
- package/dist/esm/exceptions/InvalidChannelException.js +11 -0
- package/dist/esm/exceptions/InvalidEntrypointAdapterException.js +12 -0
- package/dist/esm/exceptions/InvalidMiddlewareException.js +11 -0
- package/dist/esm/exceptions/InvalidPrefixException.js +11 -0
- package/dist/esm/exceptions/MiddlewareNextCalledException.js +11 -0
- package/dist/esm/exceptions/RouteNotFoundException.js +12 -0
- package/dist/esm/exceptions/ServiceInvokeException.js +10 -0
- package/dist/esm/exports/CTRLDecorators.js +19 -0
- package/dist/esm/exports/Channel.js +11 -0
- package/dist/esm/exports/CommanderAdapter.js +1 -0
- package/dist/esm/exports/ElectronAdapter.js +1 -0
- package/dist/esm/exports/Entrypoint.js +22 -0
- package/dist/esm/exports/ExpressAdapter.js +3 -0
- package/dist/esm/exports/FastifyAdapter.js +3 -0
- package/dist/esm/exports/JSONRPCAdapter.js +2 -0
- package/dist/esm/exports/SocketIOAdapter.js +1 -0
- package/dist/esm/lib/AccessControl.js +204 -0
- package/dist/esm/lib/AccessControlRule.js +72 -0
- package/dist/esm/lib/ActionOptions.js +63 -0
- package/dist/esm/lib/ActionResult.js +24 -0
- package/dist/esm/lib/ApplicationOf.js +11 -0
- package/dist/esm/lib/Controller.js +61 -0
- package/dist/esm/lib/ControllerEntrypoint.js +229 -0
- package/dist/esm/lib/GetActionDTOAndOptions.js +46 -0
- package/dist/esm/lib/HTTPErrors.js +48 -0
- package/dist/esm/lib/Middleware.js +134 -0
- package/dist/esm/lib/Prefix.js +143 -0
- package/dist/esm/lib/Result.js +147 -0
- package/dist/esm/lib/ServiceResponseCodec.js +113 -0
- package/dist/esm/lib/StringifyPattern.js +55 -0
- package/dist/esm/lib/UnsetValue.js +213 -0
- package/dist/esm/lib/pattern/GlobPattern.js +64 -0
- package/dist/esm/lib/pattern/PatternManager.js +229 -0
- package/dist/esm/lib/schedule/Cron.js +277 -0
- package/dist/esm/types/CLIContextParams.js +1 -0
- package/dist/esm/types/ErrorDescription.js +1 -0
- package/dist/esm/types/HTTPContextParams.js +1 -0
- package/dist/esm/types/ScheduleContextParams.js +1 -0
- package/dist/esm/types/ServiceContextParams.js +1 -0
- package/dist/types/Entrypoint.d.ts +868 -0
- package/dist/types/adapter/commander/CommanderCLIEntrypoint.d.ts +192 -0
- package/dist/types/adapter/commander/Prompt.d.ts +22 -0
- package/dist/types/adapter/commander/Width.d.ts +12 -0
- package/dist/types/adapter/electron/ElectronIPCServiceEntrypoint.d.ts +203 -0
- package/dist/types/adapter/express/ExpressHTTPEntrypoint.d.ts +172 -0
- package/dist/types/adapter/express/Responders.d.ts +89 -0
- package/dist/types/adapter/express/StaticUI.d.ts +83 -0
- package/dist/types/adapter/fastify/FastifyHTTPEntrypoint.d.ts +156 -0
- package/dist/types/adapter/fastify/Responders.d.ts +88 -0
- package/dist/types/adapter/http/HTTPServiceEntrypoint.d.ts +117 -0
- package/dist/types/adapter/jsonrpc/JSONRPCProtocol.d.ts +194 -0
- package/dist/types/adapter/jsonrpc/JSONRPCServiceEntrypoint.d.ts +154 -0
- package/dist/types/adapter/schedule/ScheduleEntrypoint.d.ts +86 -0
- package/dist/types/adapter/socket.io/SocketIOServiceEntrypoint.d.ts +138 -0
- package/dist/types/channel/BuiltinChannels.d.ts +18 -0
- package/dist/types/channel/Channel.d.ts +196 -0
- package/dist/types/channel/EntrypointAdapter.d.ts +195 -0
- package/dist/types/context/BaseContext.d.ts +75 -0
- package/dist/types/context/CLIContext.d.ts +38 -0
- package/dist/types/context/HTTPContext.d.ts +52 -0
- package/dist/types/context/ScheduleContext.d.ts +47 -0
- package/dist/types/context/ServiceContext.d.ts +47 -0
- package/dist/types/decorators/CLIAction.d.ts +120 -0
- package/dist/types/decorators/HTTPAction.d.ts +178 -0
- package/dist/types/decorators/Prefix.d.ts +44 -0
- package/dist/types/decorators/Schedule.d.ts +120 -0
- package/dist/types/decorators/ServiceAction.d.ts +116 -0
- package/dist/types/decorators/UseMiddlewares.d.ts +52 -0
- package/dist/types/decorators/http/DELETE.d.ts +87 -0
- package/dist/types/decorators/http/GET.d.ts +89 -0
- package/dist/types/decorators/http/HEAD.d.ts +84 -0
- package/dist/types/decorators/http/OPTIONS.d.ts +80 -0
- package/dist/types/decorators/http/PATCH.d.ts +90 -0
- package/dist/types/decorators/http/POST.d.ts +91 -0
- package/dist/types/decorators/http/PUT.d.ts +92 -0
- package/dist/types/exceptions/AccessDeniedException.d.ts +10 -0
- package/dist/types/exceptions/ControllerActionNotFoundException.d.ts +9 -0
- package/dist/types/exceptions/DuplicateActionNameException.d.ts +8 -0
- package/dist/types/exceptions/EntrypointStoppedException.d.ts +9 -0
- package/dist/types/exceptions/InvalidActionGroupException.d.ts +4 -0
- package/dist/types/exceptions/InvalidChannelException.d.ts +8 -0
- package/dist/types/exceptions/InvalidEntrypointAdapterException.d.ts +9 -0
- package/dist/types/exceptions/InvalidMiddlewareException.d.ts +8 -0
- package/dist/types/exceptions/InvalidPrefixException.d.ts +8 -0
- package/dist/types/exceptions/MiddlewareNextCalledException.d.ts +8 -0
- package/dist/types/exceptions/RouteNotFoundException.d.ts +9 -0
- package/dist/types/exceptions/ServiceInvokeException.d.ts +11 -0
- package/dist/types/exports/CTRLDecorators.d.ts +13 -0
- package/dist/types/exports/Channel.d.ts +14 -0
- package/dist/types/exports/CommanderAdapter.d.ts +1 -0
- package/dist/types/exports/ElectronAdapter.d.ts +1 -0
- package/dist/types/exports/Entrypoint.d.ts +24 -0
- package/dist/types/exports/ExpressAdapter.d.ts +4 -0
- package/dist/types/exports/FastifyAdapter.d.ts +4 -0
- package/dist/types/exports/JSONRPCAdapter.d.ts +2 -0
- package/dist/types/exports/SocketIOAdapter.d.ts +1 -0
- package/dist/types/lib/AccessControl.d.ts +118 -0
- package/dist/types/lib/AccessControlRule.d.ts +91 -0
- package/dist/types/lib/ActionOptions.d.ts +67 -0
- package/dist/types/lib/ActionResult.d.ts +28 -0
- package/dist/types/lib/ApplicationOf.d.ts +6 -0
- package/dist/types/lib/Controller.d.ts +59 -0
- package/dist/types/lib/ControllerEntrypoint.d.ts +168 -0
- package/dist/types/lib/GetActionDTOAndOptions.d.ts +29 -0
- package/dist/types/lib/HTTPErrors.d.ts +55 -0
- package/dist/types/lib/Middleware.d.ts +146 -0
- package/dist/types/lib/Prefix.d.ts +98 -0
- package/dist/types/lib/Result.d.ts +173 -0
- package/dist/types/lib/ServiceResponseCodec.d.ts +82 -0
- package/dist/types/lib/StringifyPattern.d.ts +7 -0
- package/dist/types/lib/UnsetValue.d.ts +12 -0
- package/dist/types/lib/pattern/GlobPattern.d.ts +34 -0
- package/dist/types/lib/pattern/PatternManager.d.ts +103 -0
- package/dist/types/lib/schedule/Cron.d.ts +56 -0
- package/dist/types/types/CLIContextParams.d.ts +14 -0
- package/dist/types/types/ErrorDescription.d.ts +14 -0
- package/dist/types/types/HTTPContextParams.d.ts +27 -0
- package/dist/types/types/ScheduleContextParams.d.ts +21 -0
- package/dist/types/types/ServiceContextParams.d.ts +16 -0
- package/package.json +152 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { DTO } from '@lakutata/core';
|
|
11
|
+
import { Expect } from '@lakutata/core/decorator/dto';
|
|
12
|
+
/**
|
|
13
|
+
* The options of a controller action, the last argument of the action decorators (`@GET`, `@CLIAction`,
|
|
14
|
+
* `@ServiceAction`, `@Schedule`…).
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* import {Controller, type HTTPContext} from 'lakutata/com/entrypoint'
|
|
18
|
+
* import {type ActionOptions} from '@lakutata/entrypoint/channel'
|
|
19
|
+
* import {GET} from 'lakutata/decorator/ctrl'
|
|
20
|
+
*
|
|
21
|
+
* //Only the requests carrying the admin token reach the action
|
|
22
|
+
* const adminOnly: ActionOptions<HTTPContext> = {
|
|
23
|
+
* acl: true,
|
|
24
|
+
* name: 'listUsers',
|
|
25
|
+
* description: 'List the users',
|
|
26
|
+
* groups: ['admin'],
|
|
27
|
+
* rule: async (context: HTTPContext): Promise<boolean> => context.request.headers.authorization === 'Bearer admin'
|
|
28
|
+
* }
|
|
29
|
+
*
|
|
30
|
+
* class UserController extends Controller {
|
|
31
|
+
* @GET('/users', adminOnly)
|
|
32
|
+
* public async list(): Promise<string[]> {
|
|
33
|
+
* return []
|
|
34
|
+
* }
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export class ActionOptions extends DTO {
|
|
39
|
+
}
|
|
40
|
+
__decorate([
|
|
41
|
+
Expect(DTO.Boolean().optional().default(false)),
|
|
42
|
+
__metadata("design:type", Boolean)
|
|
43
|
+
], ActionOptions.prototype, "acl", void 0);
|
|
44
|
+
__decorate([
|
|
45
|
+
Expect(DTO.String().allow('').optional().default('')),
|
|
46
|
+
__metadata("design:type", String)
|
|
47
|
+
], ActionOptions.prototype, "name", void 0);
|
|
48
|
+
__decorate([
|
|
49
|
+
Expect(DTO.String().allow('').optional().default('')),
|
|
50
|
+
__metadata("design:type", String)
|
|
51
|
+
], ActionOptions.prototype, "description", void 0);
|
|
52
|
+
__decorate([
|
|
53
|
+
Expect(DTO.Array(DTO.String()).optional().default([])),
|
|
54
|
+
__metadata("design:type", Array)
|
|
55
|
+
], ActionOptions.prototype, "groups", void 0);
|
|
56
|
+
__decorate([
|
|
57
|
+
Expect(DTO.Function().optional()),
|
|
58
|
+
__metadata("design:type", Function)
|
|
59
|
+
], ActionOptions.prototype, "rule", void 0);
|
|
60
|
+
__decorate([
|
|
61
|
+
Expect(DTO.Array(DTO.Function()).optional().default([])),
|
|
62
|
+
__metadata("design:type", Array)
|
|
63
|
+
], ActionOptions.prototype, "middlewares", void 0);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The base of the results an action returns to describe its output beyond its data (a status, headers, a file, an
|
|
3
|
+
* event stream): {@link StatusResult}, {@link FileResult}, {@link EventsResult}, built with `Result`. The HTTP and CLI
|
|
4
|
+
* adapters output the results they support, and the `data` of the others; the service adapters (Socket.IO, JSON-RPC,
|
|
5
|
+
* Electron IPC, the HTTP service, gRPC, NATS) send the `data` of a `StatusResult` and answer a `FileResult` or an
|
|
6
|
+
* `EventsResult` with an error.
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import {ActionResult} from 'lakutata/com/entrypoint'
|
|
10
|
+
*
|
|
11
|
+
* //A result carrying a page of items, an adapter of its own may output its paging
|
|
12
|
+
* export class PageResult<T> extends ActionResult {
|
|
13
|
+
* constructor(public readonly items: T[], public readonly next?: string) {
|
|
14
|
+
* super()
|
|
15
|
+
* }
|
|
16
|
+
*
|
|
17
|
+
* public get data(): T[] {
|
|
18
|
+
* return this.items
|
|
19
|
+
* }
|
|
20
|
+
* }
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class ActionResult {
|
|
24
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Application } from '@lakutata/core';
|
|
2
|
+
/**
|
|
3
|
+
* The application a module belongs to (undefined out of an application: a container of the tests)
|
|
4
|
+
* @param module
|
|
5
|
+
*/
|
|
6
|
+
export function applicationOf(module) {
|
|
7
|
+
let target = module;
|
|
8
|
+
while (target && !(target instanceof Application))
|
|
9
|
+
target = target.getParent?.();
|
|
10
|
+
return target;
|
|
11
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { Provider, DTO } from '@lakutata/core';
|
|
11
|
+
import { Scoped, Configurable } from '@lakutata/core/decorator/di';
|
|
12
|
+
import { BaseContext } from '../context/BaseContext.js';
|
|
13
|
+
/**
|
|
14
|
+
* The base class of the controllers: classes whose methods, decorated with the action decorators (`@GET`, `@POST`…,
|
|
15
|
+
* `@CLIAction`, `@ServiceAction`, `@Schedule`), serve the entrypoint's requests. Give the controller classes to the
|
|
16
|
+
* entrypoint's `controllers` option.
|
|
17
|
+
*
|
|
18
|
+
* A controller is scoped: each request creates its own instance in the request's container, with the request's
|
|
19
|
+
* context and abort signal, and destroys it when the request ends; its injected providers are scoped to the request
|
|
20
|
+
* too. An action method receives its input (the request's data merged with the address parameters, validated by the
|
|
21
|
+
* action's DTO, its defaults applied) and returns the result the adapter outputs; the actions declared in a parent
|
|
22
|
+
* class are served by the registered subclasses.
|
|
23
|
+
* @example
|
|
24
|
+
* ```typescript
|
|
25
|
+
* import {DTO} from 'lakutata'
|
|
26
|
+
* import {Controller, HTTPContext} from 'lakutata/com/entrypoint'
|
|
27
|
+
* import {CLIAction, GET, ServiceAction} from 'lakutata/decorator/ctrl'
|
|
28
|
+
* import {Expect} from 'lakutata/decorator/dto'
|
|
29
|
+
*
|
|
30
|
+
* class FindUserDTO extends DTO {
|
|
31
|
+
* @Expect(DTO.String().required())
|
|
32
|
+
* public id: string
|
|
33
|
+
* }
|
|
34
|
+
*
|
|
35
|
+
* class UserController extends Controller {
|
|
36
|
+
* //The same action over HTTP (GET /users/:id), the CLI (user-get --id 1) and the services ({act: 'user.get', id})
|
|
37
|
+
* @GET('/users/:id', FindUserDTO)
|
|
38
|
+
* @CLIAction('user-get', FindUserDTO)
|
|
39
|
+
* @ServiceAction({act: 'user.get'}, FindUserDTO)
|
|
40
|
+
* public async get(input: FindUserDTO): Promise<{id: string, via: string}> {
|
|
41
|
+
* this.signal?.throwIfAborted()
|
|
42
|
+
* const via: string = this.context instanceof HTTPContext ? this.context.request.headers['user-agent'] ?? 'http' : this.context.type
|
|
43
|
+
* return {id: input.id, via: via}
|
|
44
|
+
* }
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
let Controller = class Controller extends Provider {
|
|
49
|
+
};
|
|
50
|
+
__decorate([
|
|
51
|
+
Configurable(DTO.InstanceOf(BaseContext).required()),
|
|
52
|
+
__metadata("design:type", Object)
|
|
53
|
+
], Controller.prototype, "context", void 0);
|
|
54
|
+
__decorate([
|
|
55
|
+
Configurable(DTO.InstanceOf(AbortSignal).optional()),
|
|
56
|
+
__metadata("design:type", AbortSignal)
|
|
57
|
+
], Controller.prototype, "signal", void 0);
|
|
58
|
+
Controller = __decorate([
|
|
59
|
+
Scoped(true)
|
|
60
|
+
], Controller);
|
|
61
|
+
export { Controller };
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { objectConstructor, As, objectParentConstructors, objectHash, getObjectNestingDepth, UUID } from '@lakutata/utils';
|
|
2
|
+
import { InvalidActionPatternDepthException } from '@lakutata/core';
|
|
3
|
+
import { validateMiddlewares } from './Middleware.js';
|
|
4
|
+
import { getPrefix } from './Prefix.js';
|
|
5
|
+
import { getChannel } from '../channel/Channel.js';
|
|
6
|
+
import { CLIChannel, HTTPChannel, ServiceChannel } from '../channel/BuiltinChannels.js';
|
|
7
|
+
//The channels of the actions declared by a controller class
|
|
8
|
+
const CONTROLLER_CHANNELS = Symbol('CONTROLLER.CHANNELS');
|
|
9
|
+
//The actions of the controllers bound to an entrypoint, by channel
|
|
10
|
+
const COMPONENT_CTRL_MAP = Symbol('COMPONENT.CTRL.MAP');
|
|
11
|
+
/**
|
|
12
|
+
* The metadata key of the actions of a channel
|
|
13
|
+
* @param channel
|
|
14
|
+
*/
|
|
15
|
+
function channelActionsKey(channel) {
|
|
16
|
+
return `ENTRYPOINT.CHANNEL.ACTIONS.${channel}`;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Get action info
|
|
20
|
+
* @param controllerPrototype
|
|
21
|
+
* @param propertyKey
|
|
22
|
+
* @param actionOptions
|
|
23
|
+
* @param extra
|
|
24
|
+
*/
|
|
25
|
+
function getActionInfo(controllerPrototype, propertyKey, actionOptions, extra) {
|
|
26
|
+
const action = `${As(objectConstructor(controllerPrototype)).className}:${String(propertyKey)}`;
|
|
27
|
+
const id = UUID.v5(`${action}:${extra}`, UUID.NIL);
|
|
28
|
+
const name = actionOptions.name ? actionOptions.name : action;
|
|
29
|
+
const description = actionOptions.description ? actionOptions.description : '';
|
|
30
|
+
return {
|
|
31
|
+
id: id,
|
|
32
|
+
acl: !!actionOptions.acl,
|
|
33
|
+
action: action,
|
|
34
|
+
name: name,
|
|
35
|
+
description: description,
|
|
36
|
+
groups: actionOptions.groups ? actionOptions.groups : [],
|
|
37
|
+
rule: actionOptions.rule
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Validate action pattern definition
|
|
42
|
+
* @param actionPattern
|
|
43
|
+
*/
|
|
44
|
+
function validateActionPatternDefinition(actionPattern) {
|
|
45
|
+
const depth = getObjectNestingDepth(actionPattern);
|
|
46
|
+
if (depth > 2)
|
|
47
|
+
throw new InvalidActionPatternDepthException('The maximum nesting depth of ActionPattern objects cannot be greater than 2 levels. The current nesting depth of the object is {0} levels', [depth]);
|
|
48
|
+
return actionPattern;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get controller's internal action pattern map of a channel
|
|
52
|
+
* @param channel
|
|
53
|
+
* @param target
|
|
54
|
+
* @constructor
|
|
55
|
+
*/
|
|
56
|
+
function getInternalControllerActionPatternMap(channel, target) {
|
|
57
|
+
const key = channelActionsKey(channel);
|
|
58
|
+
const internalActionPatternMap = new Map();
|
|
59
|
+
//From the farthest parent: the closest declaration of an action wins
|
|
60
|
+
objectParentConstructors(target).reverse().forEach(parentConstructor => {
|
|
61
|
+
const parentActionPatternMap = Reflect.getOwnMetadata(key, parentConstructor) || new Map();
|
|
62
|
+
parentActionPatternMap.forEach((value, hash) => internalActionPatternMap.set(hash, value));
|
|
63
|
+
});
|
|
64
|
+
As(Reflect.getOwnMetadata(key, target) || new Map()).forEach((value, hash) => internalActionPatternMap.set(hash, value));
|
|
65
|
+
return internalActionPatternMap;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* The channels of the actions of a controller, its parent classes included
|
|
69
|
+
* @param target
|
|
70
|
+
*/
|
|
71
|
+
export function getControllerChannels(target) {
|
|
72
|
+
const names = new Set();
|
|
73
|
+
for (const constructor of [target, ...objectParentConstructors(target)]) {
|
|
74
|
+
const own = Reflect.getOwnMetadata(CONTROLLER_CHANNELS, constructor);
|
|
75
|
+
own?.forEach((name) => names.add(name));
|
|
76
|
+
}
|
|
77
|
+
return [...names];
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Register an action of a controller on a channel
|
|
81
|
+
* @param channel
|
|
82
|
+
* @param target
|
|
83
|
+
* @param actionPattern
|
|
84
|
+
* @param details
|
|
85
|
+
* @constructor
|
|
86
|
+
*/
|
|
87
|
+
export function registerChannelAction(channel, target, actionPattern, details) {
|
|
88
|
+
actionPattern = validateActionPatternDefinition(channel.validate ? channel.validate(actionPattern) : actionPattern);
|
|
89
|
+
const internalActionPatternMap = getInternalControllerActionPatternMap(channel.name, target);
|
|
90
|
+
internalActionPatternMap.set(objectHash(actionPattern), {
|
|
91
|
+
pattern: actionPattern,
|
|
92
|
+
details: { ...details, pattern: actionPattern }
|
|
93
|
+
});
|
|
94
|
+
Reflect.defineMetadata(channelActionsKey(channel.name), internalActionPatternMap, target);
|
|
95
|
+
const own = Reflect.getOwnMetadata(CONTROLLER_CHANNELS, target) || new Set();
|
|
96
|
+
Reflect.defineMetadata(CONTROLLER_CHANNELS, own.add(channel.name), target);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Register a controller method as an action of a channel, for the decorators of the packages providing a channel
|
|
100
|
+
* (the built-in `@HTTPAction`, `@CLIAction` and `@ServiceAction` call it). The action is served by the controller class
|
|
101
|
+
* and its subclasses registered in an entrypoint. Registering the same address again for the class replaces the
|
|
102
|
+
* previous action.
|
|
103
|
+
* @param channel The channel's definition (see {@link defineChannel}).
|
|
104
|
+
* @param controllerPrototype The prototype of the controller class (the decorator's target).
|
|
105
|
+
* @param propertyKey The name of the method running the action.
|
|
106
|
+
* @param actionPattern The action's address, checked by the channel's `validate`; at most 2 levels of nesting.
|
|
107
|
+
* @param dtoConstructor The DTO validating the action's input (`FlexibleDTO` to accept any input).
|
|
108
|
+
* @param actionOptions The action's options (name, description, groups, access control, middlewares); give them
|
|
109
|
+
* validated (as {@link getActionDTOAndOptions} returns them).
|
|
110
|
+
* @throws {InvalidActionPatternDepthException} When the address is nested more than 2 levels deep.
|
|
111
|
+
* @throws {InvalidMiddlewareException} When a middleware of the options is neither a function nor a `Middleware` subclass.
|
|
112
|
+
* @example
|
|
113
|
+
* ```typescript
|
|
114
|
+
* import {DTO} from 'lakutata'
|
|
115
|
+
* import {Controller, type ControllerProperty} from 'lakutata/com/entrypoint'
|
|
116
|
+
* import {getActionDTOAndOptions, getChannel, registerControllerAction, type ActionOptions} from '@lakutata/entrypoint/channel'
|
|
117
|
+
*
|
|
118
|
+
* //A decorator declaring the actions of a "queue" channel defined by its package
|
|
119
|
+
* export function OnMessage(topic: string, dtoOrOptions?: typeof DTO | ActionOptions<any>, options?: ActionOptions<any>) {
|
|
120
|
+
* return <ClassPrototype extends Controller>(target: ClassPrototype, propertyKey: ControllerProperty<ClassPrototype>): void => {
|
|
121
|
+
* const [dtoConstructor, actionOptions] = getActionDTOAndOptions(dtoOrOptions, options)
|
|
122
|
+
* registerControllerAction(getChannel('queue'), target, propertyKey, {topic: topic}, dtoConstructor, actionOptions)
|
|
123
|
+
* }
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
export function registerControllerAction(channel, controllerPrototype, propertyKey, actionPattern, dtoConstructor, actionOptions) {
|
|
128
|
+
const constructor = As(objectConstructor(controllerPrototype));
|
|
129
|
+
const actionInfo = getActionInfo(controllerPrototype, propertyKey, actionOptions, channel.identify(actionPattern));
|
|
130
|
+
registerChannelAction(channel, constructor, actionPattern, {
|
|
131
|
+
...actionInfo,
|
|
132
|
+
pattern: actionPattern,
|
|
133
|
+
constructor: constructor,
|
|
134
|
+
method: propertyKey,
|
|
135
|
+
dtoConstructor: dtoConstructor,
|
|
136
|
+
jsonSchema: dtoConstructor.toJsonSchema(),
|
|
137
|
+
middlewares: validateMiddlewares(actionOptions.middlewares ?? []),
|
|
138
|
+
getActionInfo: () => actionInfo
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Bind controller to component
|
|
143
|
+
* @param component
|
|
144
|
+
* @param controllerConstructor
|
|
145
|
+
* @constructor
|
|
146
|
+
*/
|
|
147
|
+
export function bindControllerToComponent(component, controllerConstructor) {
|
|
148
|
+
const totalInternalActionPatternMap = Reflect.getOwnMetadata(COMPONENT_CTRL_MAP, component) || new Map();
|
|
149
|
+
const prefix = getPrefix(controllerConstructor);
|
|
150
|
+
//The actions inherited from a parent controller are run by the registered controller
|
|
151
|
+
const bind = (channel, value) => {
|
|
152
|
+
const details = { ...value.details, constructor: controllerConstructor };
|
|
153
|
+
const prefixed = prefix && channel.prefix ? channel.prefix(prefix, value.pattern) : undefined;
|
|
154
|
+
if (prefixed === undefined)
|
|
155
|
+
return ['', { pattern: value.pattern, details: details }];
|
|
156
|
+
const pattern = validateActionPatternDefinition(channel.validate ? channel.validate(prefixed) : prefixed);
|
|
157
|
+
//A prefixed action is named after the registered controller, so the controllers sharing a parent have distinct actions
|
|
158
|
+
const action = `${controllerConstructor.className}:${String(details.method)}`;
|
|
159
|
+
details.name = details.name === details.action ? action : details.name;
|
|
160
|
+
details.action = action;
|
|
161
|
+
details.id = UUID.v5(`${action}:${channel.identify(pattern)}`, UUID.NIL);
|
|
162
|
+
details.pattern = pattern;
|
|
163
|
+
const actionInfo = { id: details.id, acl: details.acl, action: action, name: details.name, description: details.description, groups: details.groups, rule: details.rule };
|
|
164
|
+
details.getActionInfo = () => actionInfo;
|
|
165
|
+
return [objectHash(pattern), { pattern: pattern, details: details }];
|
|
166
|
+
};
|
|
167
|
+
for (const name of getControllerChannels(controllerConstructor)) {
|
|
168
|
+
const channel = getChannel(name);
|
|
169
|
+
const map = totalInternalActionPatternMap.get(name) ?? new Map();
|
|
170
|
+
getInternalControllerActionPatternMap(name, controllerConstructor).forEach((value, hash) => {
|
|
171
|
+
const [prefixedHash, bound] = bind(channel, value);
|
|
172
|
+
map.set(prefixedHash || hash, bound);
|
|
173
|
+
});
|
|
174
|
+
totalInternalActionPatternMap.set(name, map);
|
|
175
|
+
}
|
|
176
|
+
Reflect.defineMetadata(COMPONENT_CTRL_MAP, totalInternalActionPatternMap, component);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get module controller action map
|
|
180
|
+
* @constructor
|
|
181
|
+
* @param component
|
|
182
|
+
*/
|
|
183
|
+
export function getComponentControllerActionMap(component) {
|
|
184
|
+
const totalInternalActionPatternMap = Reflect.getOwnMetadata(COMPONENT_CTRL_MAP, component) || new Map();
|
|
185
|
+
const totalActionPatternMap = new Map();
|
|
186
|
+
totalInternalActionPatternMap.forEach((map, channel) => {
|
|
187
|
+
const actions = new Map();
|
|
188
|
+
map.forEach((value) => actions.set(value.pattern, value.details));
|
|
189
|
+
totalActionPatternMap.set(channel, actions);
|
|
190
|
+
});
|
|
191
|
+
return totalActionPatternMap;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Register http action
|
|
195
|
+
* @param route
|
|
196
|
+
* @param methods
|
|
197
|
+
* @param controllerPrototype
|
|
198
|
+
* @param propertyKey
|
|
199
|
+
* @param dtoConstructor
|
|
200
|
+
* @param actionOptions
|
|
201
|
+
* @constructor
|
|
202
|
+
*/
|
|
203
|
+
export function registerHTTPAction(route, methods, controllerPrototype, propertyKey, dtoConstructor, actionOptions) {
|
|
204
|
+
methods.forEach((method) => registerControllerAction(HTTPChannel, controllerPrototype, propertyKey, { route: route, method: method }, dtoConstructor, actionOptions));
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Register cli action
|
|
208
|
+
* @param command
|
|
209
|
+
* @param controllerPrototype
|
|
210
|
+
* @param propertyKey
|
|
211
|
+
* @param dtoConstructor
|
|
212
|
+
* @param actionOptions
|
|
213
|
+
* @constructor
|
|
214
|
+
*/
|
|
215
|
+
export function registerCLIAction(command, controllerPrototype, propertyKey, dtoConstructor, actionOptions) {
|
|
216
|
+
registerControllerAction(CLIChannel, controllerPrototype, propertyKey, { command: command }, dtoConstructor, actionOptions);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Register service action
|
|
220
|
+
* @param pattern
|
|
221
|
+
* @param controllerPrototype
|
|
222
|
+
* @param propertyKey
|
|
223
|
+
* @param dtoConstructor
|
|
224
|
+
* @param actionOptions
|
|
225
|
+
* @constructor
|
|
226
|
+
*/
|
|
227
|
+
export function registerServiceAction(pattern, controllerPrototype, propertyKey, dtoConstructor, actionOptions) {
|
|
228
|
+
registerControllerAction(ServiceChannel, controllerPrototype, propertyKey, pattern, dtoConstructor, actionOptions);
|
|
229
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ActionOptions } from './ActionOptions.js';
|
|
2
|
+
import { FlexibleDTO } from '@lakutata/core/dtos';
|
|
3
|
+
/**
|
|
4
|
+
* Sort out the optional arguments of an action decorator (`(dto?)`, `(options?)` or `(dto, options)`): a function is
|
|
5
|
+
* the DTO, an object the options. The options are validated, their defaults applied.
|
|
6
|
+
* @param dtoConstructorOrOptions The DTO validating the action's input, or the action's options.
|
|
7
|
+
* @param options The action's options, when the first argument is the DTO.
|
|
8
|
+
* @returns The DTO (`FlexibleDTO`, accepting any input, when none is given) and the validated options.
|
|
9
|
+
* @throws {Error} When the options are invalid (the validation error of {@link ActionOptions}).
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import {DTO} from 'lakutata'
|
|
13
|
+
* import {FlexibleDTO} from 'lakutata/dtos'
|
|
14
|
+
* import {Expect} from 'lakutata/decorator/dto'
|
|
15
|
+
* import {getActionDTOAndOptions} from '@lakutata/entrypoint/channel'
|
|
16
|
+
*
|
|
17
|
+
* class SendDTO extends DTO {
|
|
18
|
+
* @Expect(DTO.String().required())
|
|
19
|
+
* public text: string
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* const [dto, options] = getActionDTOAndOptions(SendDTO, {name: 'send'})
|
|
23
|
+
* console.log(dto === SendDTO, options.groups) //true []
|
|
24
|
+
* const [anyInput] = getActionDTOAndOptions({acl: true})
|
|
25
|
+
* console.log(anyInput === FlexibleDTO) //true
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export function getActionDTOAndOptions(dtoConstructorOrOptions, options) {
|
|
29
|
+
let dtoConstructor = FlexibleDTO;
|
|
30
|
+
let actionOptions = {};
|
|
31
|
+
if (options) {
|
|
32
|
+
//The DTO may be omitted (undefined) before the options
|
|
33
|
+
if (dtoConstructorOrOptions)
|
|
34
|
+
dtoConstructor = dtoConstructorOrOptions;
|
|
35
|
+
actionOptions = options;
|
|
36
|
+
}
|
|
37
|
+
else if (dtoConstructorOrOptions) {
|
|
38
|
+
if (dtoConstructorOrOptions.constructor.name.toUpperCase() === 'FUNCTION') {
|
|
39
|
+
dtoConstructor = dtoConstructorOrOptions;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
actionOptions = dtoConstructorOrOptions;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return [dtoConstructor, ActionOptions.validate(actionOptions)];
|
|
46
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Find the HTTP status of an error, read from its `statusCode` or `status`: the first client error (4xx) found on the
|
|
3
|
+
* error or along its `cause` chain, else the error's own status when it is between 400 and 599, else 500. A validation
|
|
4
|
+
* failure, wrapped in an exception whose cause is the 400 validation error, thus gives 400.
|
|
5
|
+
* @param error The error, any value.
|
|
6
|
+
* @returns The HTTP status, from 400 to 599.
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import {statusOfError} from 'lakutata/adapter/express'
|
|
10
|
+
*
|
|
11
|
+
* class NotFound extends Error {
|
|
12
|
+
* public readonly statusCode: number = 404
|
|
13
|
+
* }
|
|
14
|
+
*
|
|
15
|
+
* console.log(statusOfError(new NotFound('No such order'))) //404
|
|
16
|
+
* console.log(statusOfError(new Error('Failed', {cause: new NotFound('No such order')}))) //404
|
|
17
|
+
* console.log(statusOfError(new Error('Boom'))) //500
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function statusOfError(error) {
|
|
21
|
+
for (let current = error; current && typeof current === 'object'; current = current.cause) {
|
|
22
|
+
const status = current.statusCode ?? current.status;
|
|
23
|
+
if (typeof status === 'number' && status >= 400 && status < 500)
|
|
24
|
+
return status;
|
|
25
|
+
}
|
|
26
|
+
const status = error?.statusCode ?? error?.status;
|
|
27
|
+
return typeof status === 'number' && status >= 400 && status < 600 ? status : 500;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Describe an error as the JSON responders send it: its `errno` (or `code`, `E_UNKNOWN` without either) and its
|
|
31
|
+
* `errMsg` (or `message`, or the error converted to a string).
|
|
32
|
+
* @param error The error, any value.
|
|
33
|
+
* @returns The error's number and message.
|
|
34
|
+
* @example
|
|
35
|
+
* ```typescript
|
|
36
|
+
* import {describeError, type ErrorDescription} from 'lakutata/adapter/express'
|
|
37
|
+
*
|
|
38
|
+
* const description: ErrorDescription = describeError(new Error('Boom'))
|
|
39
|
+
* console.log(description) //{errno: 'E_UNKNOWN', errMsg: 'Boom'}
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function describeError(error) {
|
|
43
|
+
const described = error ?? {};
|
|
44
|
+
return {
|
|
45
|
+
errno: described.errno ?? described.code ?? 'E_UNKNOWN',
|
|
46
|
+
errMsg: described.errMsg ?? described.message ?? String(error)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { Provider } from '@lakutata/core';
|
|
2
|
+
import { isSubclassOf } from '@lakutata/utils';
|
|
3
|
+
import { InvalidMiddlewareException } from '../exceptions/InvalidMiddlewareException.js';
|
|
4
|
+
import { MiddlewareNextCalledException } from '../exceptions/MiddlewareNextCalledException.js';
|
|
5
|
+
/**
|
|
6
|
+
* A middleware class: it runs around the actions, created in each request's container (its dependencies are
|
|
7
|
+
* injected). Give it, or a {@link MiddlewareHandler} function, to the entrypoint's `middlewares` option (every
|
|
8
|
+
* action), an adapter's `middlewares` option (its requests), `@UseMiddlewares` (a controller class or a method) or an
|
|
9
|
+
* action's `middlewares` option. They run in that order: the entrypoint's, the adapter's, the controller parents'
|
|
10
|
+
* then the controller's, the action option's, then the method's.
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import {Application} from 'lakutata'
|
|
14
|
+
* import {buildEntrypoints, Controller, Middleware, type ActionInvocation, type Next} from 'lakutata/com/entrypoint'
|
|
15
|
+
* import {GET, UseMiddlewares} from 'lakutata/decorator/ctrl'
|
|
16
|
+
*
|
|
17
|
+
* //Log the duration of each request
|
|
18
|
+
* class Timing extends Middleware {
|
|
19
|
+
* public async handle(invocation: ActionInvocation, next: Next): Promise<unknown> {
|
|
20
|
+
* const start: number = Date.now()
|
|
21
|
+
* try {
|
|
22
|
+
* return await next()
|
|
23
|
+
* } finally {
|
|
24
|
+
* console.log(`${invocation.action.name}: ${Date.now() - start}ms`)
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* @UseMiddlewares(async (invocation: ActionInvocation, next: Next): Promise<unknown> => {
|
|
30
|
+
* //Short-circuit: the action does not run
|
|
31
|
+
* if (invocation.context.data.maintenance) return {error: 'maintenance'}
|
|
32
|
+
* return next()
|
|
33
|
+
* })
|
|
34
|
+
* class StatusController extends Controller {
|
|
35
|
+
* @GET('/status')
|
|
36
|
+
* public async status(): Promise<string> {
|
|
37
|
+
* return 'ok'
|
|
38
|
+
* }
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* Application.run(() => ({
|
|
42
|
+
* id: 'status.app',
|
|
43
|
+
* name: 'Status',
|
|
44
|
+
* components: {
|
|
45
|
+
* entrypoint: buildEntrypoints({
|
|
46
|
+
* controllers: [StatusController],
|
|
47
|
+
* middlewares: [Timing]
|
|
48
|
+
* })
|
|
49
|
+
* }
|
|
50
|
+
* }))
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export class Middleware extends Provider {
|
|
54
|
+
}
|
|
55
|
+
const CLASS_MIDDLEWARES = Symbol('ENTRYPOINT.CLASS.MIDDLEWARES');
|
|
56
|
+
const METHOD_MIDDLEWARES = Symbol('ENTRYPOINT.METHOD.MIDDLEWARES');
|
|
57
|
+
/**
|
|
58
|
+
* Whether a middleware is a middleware class
|
|
59
|
+
* @param middleware
|
|
60
|
+
*/
|
|
61
|
+
export function isMiddlewareClass(middleware) {
|
|
62
|
+
return isSubclassOf(middleware, Middleware);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Check middleware definitions: middleware classes or functions
|
|
66
|
+
* @param middlewares
|
|
67
|
+
*/
|
|
68
|
+
export function validateMiddlewares(middlewares) {
|
|
69
|
+
for (const middleware of middlewares) {
|
|
70
|
+
if (typeof middleware !== 'function')
|
|
71
|
+
throw new InvalidMiddlewareException('A middleware must be a function or a class extending Middleware');
|
|
72
|
+
if (!isMiddlewareClass(middleware) && /^class[\s{]/.test(Function.prototype.toString.call(middleware)))
|
|
73
|
+
throw new InvalidMiddlewareException('The middleware class "{0}" does not extend Middleware', [middleware.name]);
|
|
74
|
+
}
|
|
75
|
+
return middlewares;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Add middlewares to a controller class or an action method, the middlewares of each decorator run in their order,
|
|
79
|
+
* the decorators from top to bottom
|
|
80
|
+
* @param target
|
|
81
|
+
* @param propertyKey
|
|
82
|
+
* @param middlewares
|
|
83
|
+
*/
|
|
84
|
+
export function addMiddlewares(target, propertyKey, middlewares) {
|
|
85
|
+
const key = propertyKey === undefined ? CLASS_MIDDLEWARES : METHOD_MIDDLEWARES;
|
|
86
|
+
const existing = (propertyKey === undefined ? Reflect.getOwnMetadata(key, target) : Reflect.getOwnMetadata(key, target, propertyKey)) || [];
|
|
87
|
+
//The decorators are applied from bottom to top
|
|
88
|
+
const merged = [...validateMiddlewares(middlewares), ...existing];
|
|
89
|
+
propertyKey === undefined ? Reflect.defineMetadata(key, merged, target) : Reflect.defineMetadata(key, merged, target, propertyKey);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The middlewares of a controller class, the ones of its parent classes first
|
|
93
|
+
* @param controller
|
|
94
|
+
*/
|
|
95
|
+
export function getClassMiddlewares(controller) {
|
|
96
|
+
const chain = [];
|
|
97
|
+
for (let current = controller; current && current !== Function.prototype; current = Object.getPrototypeOf(current))
|
|
98
|
+
chain.unshift(current);
|
|
99
|
+
return chain.flatMap((constructor) => Reflect.getOwnMetadata(CLASS_MIDDLEWARES, constructor) || []);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The middlewares of an action method, declared on the method in the class hierarchy
|
|
103
|
+
* @param controller
|
|
104
|
+
* @param method
|
|
105
|
+
*/
|
|
106
|
+
export function getMethodMiddlewares(controller, method) {
|
|
107
|
+
for (let prototype = controller.prototype; prototype; prototype = Object.getPrototypeOf(prototype)) {
|
|
108
|
+
const middlewares = Reflect.getOwnMetadata(METHOD_MIDDLEWARES, prototype, method);
|
|
109
|
+
if (middlewares)
|
|
110
|
+
return middlewares;
|
|
111
|
+
}
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Compose middlewares around the innermost runner
|
|
116
|
+
* @param middlewares
|
|
117
|
+
* @param innermost
|
|
118
|
+
*/
|
|
119
|
+
export function composeMiddlewares(middlewares, innermost) {
|
|
120
|
+
return middlewares.reduceRight((next, middleware) => {
|
|
121
|
+
const handle = isMiddlewareClass(middleware)
|
|
122
|
+
? async (invocation, nextStep) => (await invocation.container.get(middleware)).handle(invocation, nextStep)
|
|
123
|
+
: middleware;
|
|
124
|
+
return (invocation) => {
|
|
125
|
+
let called = false;
|
|
126
|
+
return handle(invocation, () => {
|
|
127
|
+
if (called)
|
|
128
|
+
return Promise.reject(new MiddlewareNextCalledException('next() is called more than once'));
|
|
129
|
+
called = true;
|
|
130
|
+
return next(invocation);
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
}, innermost);
|
|
134
|
+
}
|