@dooboostore/simple-boot-http-server 1.0.23 → 1.0.25

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 (259) hide show
  1. package/README.md +113 -0
  2. package/dist/cjs/SimpleBootHttpServer.js +80 -40
  3. package/dist/cjs/SimpleBootHttpServer.js.map +3 -3
  4. package/dist/cjs/codes/HttpHeaders.js +14 -3
  5. package/dist/cjs/codes/HttpHeaders.js.map +2 -2
  6. package/dist/cjs/codes/Mimes.js +2 -0
  7. package/dist/cjs/codes/Mimes.js.map +2 -2
  8. package/dist/cjs/decorators/MethodMapping.js +40 -9
  9. package/dist/cjs/decorators/MethodMapping.js.map +3 -3
  10. package/dist/cjs/endpoints/WebSocketEndPoint.js +16 -0
  11. package/dist/cjs/endpoints/WebSocketEndPoint.js.map +7 -0
  12. package/dist/cjs/errors/BadRequestError.js +2 -1
  13. package/dist/cjs/errors/BadRequestError.js.map +2 -2
  14. package/dist/cjs/errors/ForbiddenError.js +2 -1
  15. package/dist/cjs/errors/ForbiddenError.js.map +2 -2
  16. package/dist/cjs/errors/InternalServerError.js +2 -1
  17. package/dist/cjs/errors/InternalServerError.js.map +2 -2
  18. package/dist/cjs/errors/NotFoundError.js +2 -1
  19. package/dist/cjs/errors/NotFoundError.js.map +2 -2
  20. package/dist/cjs/errors/UnauthorizedError.js +2 -1
  21. package/dist/cjs/errors/UnauthorizedError.js.map +2 -2
  22. package/dist/cjs/filters/CacheFilter.js +75 -35
  23. package/dist/cjs/filters/CacheFilter.js.map +3 -3
  24. package/dist/cjs/filters/IntentSchemeFilter.js +97 -0
  25. package/dist/cjs/filters/IntentSchemeFilter.js.map +7 -0
  26. package/dist/cjs/filters/ResourceFilter.js +6 -2
  27. package/dist/cjs/filters/ResourceFilter.js.map +2 -2
  28. package/dist/cjs/filters/TopicProtocolFilter.js +343 -0
  29. package/dist/cjs/filters/TopicProtocolFilter.js.map +7 -0
  30. package/dist/cjs/filters/index.js +5 -1
  31. package/dist/cjs/filters/index.js.map +2 -2
  32. package/dist/cjs/index.js +30 -0
  33. package/dist/cjs/index.js.map +2 -2
  34. package/dist/cjs/inject/InjectSituationType.js +1 -1
  35. package/dist/cjs/inject/InjectSituationType.js.map +2 -2
  36. package/dist/cjs/models/RequestResponse.js +70 -91
  37. package/dist/cjs/models/RequestResponse.js.map +3 -3
  38. package/dist/cjs/models/datas/body/index.js +28 -0
  39. package/dist/cjs/models/datas/body/index.js.map +7 -0
  40. package/dist/cjs/models/datas/index.js +32 -0
  41. package/dist/cjs/models/datas/index.js.map +7 -0
  42. package/dist/cjs/models/datas/path/ReqPathData.js +29 -0
  43. package/dist/cjs/models/datas/path/ReqPathData.js.map +7 -0
  44. package/dist/cjs/models/datas/{search → path}/ReqSearchParamsObj.js.map +1 -1
  45. package/dist/cjs/models/datas/path/index.js +24 -0
  46. package/dist/cjs/models/datas/path/index.js.map +7 -0
  47. package/dist/cjs/models/index.js +4 -16
  48. package/dist/cjs/models/index.js.map +2 -2
  49. package/dist/cjs/models/method/index.js +22 -0
  50. package/dist/cjs/models/method/index.js.map +7 -0
  51. package/dist/cjs/models/method/patch/index.js +22 -0
  52. package/dist/cjs/models/method/patch/index.js.map +7 -0
  53. package/dist/cjs/option/HttpServerOption.js +25 -5
  54. package/dist/cjs/option/HttpServerOption.js.map +2 -2
  55. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js +144 -0
  56. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js.map +7 -0
  57. package/dist/cjs/proxy/SymbolIntentApiServiceProxyBase.js +35 -0
  58. package/dist/cjs/proxy/SymbolIntentApiServiceProxyBase.js.map +7 -0
  59. package/dist/cjs/proxy/TopicProtocolApiServiceProxy.js +324 -0
  60. package/dist/cjs/proxy/TopicProtocolApiServiceProxy.js.map +7 -0
  61. package/dist/cjs/proxy/index.js +26 -0
  62. package/dist/cjs/proxy/index.js.map +7 -0
  63. package/dist/cjs/resolvers/ResourceResolver.js +2 -2
  64. package/dist/cjs/resolvers/ResourceResolver.js.map +2 -2
  65. package/dist/cjs/session/SessionManager.js +2 -2
  66. package/dist/cjs/session/SessionManager.js.map +2 -2
  67. package/dist/cjs/websocket/WebSocketClient.js +554 -0
  68. package/dist/cjs/websocket/WebSocketClient.js.map +7 -0
  69. package/dist/cjs/websocket/WebSocketManager.js +652 -0
  70. package/dist/cjs/websocket/WebSocketManager.js.map +7 -0
  71. package/dist/cjs/websocket/index.js +24 -0
  72. package/dist/cjs/websocket/index.js.map +7 -0
  73. package/dist/esm/SimpleBootHttpServer.js +60 -20
  74. package/dist/esm/SimpleBootHttpServer.js.map +2 -2
  75. package/dist/esm/codes/HttpHeaders.js +12 -2
  76. package/dist/esm/codes/HttpHeaders.js.map +2 -2
  77. package/dist/esm/codes/Mimes.js +2 -0
  78. package/dist/esm/codes/Mimes.js.map +2 -2
  79. package/dist/esm/decorators/MethodMapping.js +24 -3
  80. package/dist/esm/decorators/MethodMapping.js.map +2 -2
  81. package/dist/esm/endpoints/WebSocketEndPoint.js +1 -0
  82. package/dist/esm/endpoints/WebSocketEndPoint.js.map +7 -0
  83. package/dist/esm/errors/BadRequestError.js +2 -1
  84. package/dist/esm/errors/BadRequestError.js.map +2 -2
  85. package/dist/esm/errors/ForbiddenError.js +2 -1
  86. package/dist/esm/errors/ForbiddenError.js.map +2 -2
  87. package/dist/esm/errors/InternalServerError.js +2 -1
  88. package/dist/esm/errors/InternalServerError.js.map +2 -2
  89. package/dist/esm/errors/NotFoundError.js +2 -1
  90. package/dist/esm/errors/NotFoundError.js.map +2 -2
  91. package/dist/esm/errors/UnauthorizedError.js +2 -1
  92. package/dist/esm/errors/UnauthorizedError.js.map +2 -2
  93. package/dist/esm/filters/CacheFilter.js +67 -27
  94. package/dist/esm/filters/CacheFilter.js.map +2 -2
  95. package/dist/esm/filters/IntentSchemeFilter.js +74 -0
  96. package/dist/esm/filters/IntentSchemeFilter.js.map +7 -0
  97. package/dist/esm/filters/ResourceFilter.js +6 -2
  98. package/dist/esm/filters/ResourceFilter.js.map +2 -2
  99. package/dist/esm/filters/TopicProtocolFilter.js +310 -0
  100. package/dist/esm/filters/TopicProtocolFilter.js.map +7 -0
  101. package/dist/esm/filters/index.js +2 -0
  102. package/dist/esm/filters/index.js.map +2 -2
  103. package/dist/esm/index.js +13 -0
  104. package/dist/esm/index.js.map +2 -2
  105. package/dist/esm/inject/InjectSituationType.js +1 -1
  106. package/dist/esm/inject/InjectSituationType.js.map +2 -2
  107. package/dist/esm/models/RequestResponse.js +65 -86
  108. package/dist/esm/models/RequestResponse.js.map +2 -2
  109. package/dist/esm/models/datas/body/index.js +5 -0
  110. package/dist/esm/models/datas/body/index.js.map +7 -0
  111. package/dist/esm/models/datas/index.js +7 -0
  112. package/dist/esm/models/datas/index.js.map +7 -0
  113. package/dist/esm/models/datas/path/ReqPathData.js +6 -0
  114. package/dist/esm/models/datas/path/ReqPathData.js.map +7 -0
  115. package/dist/esm/models/datas/{search → path}/ReqSearchParamsObj.js.map +1 -1
  116. package/dist/esm/models/datas/path/index.js +3 -0
  117. package/dist/esm/models/datas/path/index.js.map +7 -0
  118. package/dist/esm/models/index.js +2 -8
  119. package/dist/esm/models/index.js.map +2 -2
  120. package/dist/esm/models/method/index.js +2 -0
  121. package/dist/esm/models/method/index.js.map +7 -0
  122. package/dist/esm/models/method/patch/index.js +2 -0
  123. package/dist/esm/models/method/patch/index.js.map +7 -0
  124. package/dist/esm/option/HttpServerOption.js +24 -4
  125. package/dist/esm/option/HttpServerOption.js.map +2 -2
  126. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js +121 -0
  127. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js.map +7 -0
  128. package/dist/esm/proxy/SymbolIntentApiServiceProxyBase.js +12 -0
  129. package/dist/esm/proxy/SymbolIntentApiServiceProxyBase.js.map +7 -0
  130. package/dist/esm/proxy/TopicProtocolApiServiceProxy.js +301 -0
  131. package/dist/esm/proxy/TopicProtocolApiServiceProxy.js.map +7 -0
  132. package/dist/esm/proxy/index.js +4 -0
  133. package/dist/esm/proxy/index.js.map +7 -0
  134. package/dist/esm/resolvers/ResourceResolver.js +1 -1
  135. package/dist/esm/resolvers/ResourceResolver.js.map +1 -1
  136. package/dist/esm/session/SessionManager.js +1 -1
  137. package/dist/esm/session/SessionManager.js.map +1 -1
  138. package/dist/esm/websocket/WebSocketClient.js +529 -0
  139. package/dist/esm/websocket/WebSocketClient.js.map +7 -0
  140. package/dist/esm/websocket/WebSocketManager.js +622 -0
  141. package/dist/esm/websocket/WebSocketManager.js.map +7 -0
  142. package/dist/esm/websocket/index.js +3 -0
  143. package/dist/esm/websocket/index.js.map +7 -0
  144. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js +18209 -5299
  145. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js.map +4 -4
  146. package/dist/types/SimpleBootHttpServer.d.ts +5 -3
  147. package/dist/types/SimpleBootHttpServer.d.ts.map +1 -1
  148. package/dist/types/codes/HttpHeaders.d.ts +3 -0
  149. package/dist/types/codes/HttpHeaders.d.ts.map +1 -1
  150. package/dist/types/codes/Mimes.d.ts +3 -1
  151. package/dist/types/codes/Mimes.d.ts.map +1 -1
  152. package/dist/types/decorators/MethodMapping.d.ts +13 -2
  153. package/dist/types/decorators/MethodMapping.d.ts.map +1 -1
  154. package/dist/types/endpoints/WebSocketEndPoint.d.ts +17 -0
  155. package/dist/types/endpoints/WebSocketEndPoint.d.ts.map +1 -0
  156. package/dist/types/errors/BadRequestError.d.ts +2 -2
  157. package/dist/types/errors/BadRequestError.d.ts.map +1 -1
  158. package/dist/types/errors/ForbiddenError.d.ts +2 -2
  159. package/dist/types/errors/ForbiddenError.d.ts.map +1 -1
  160. package/dist/types/errors/InternalServerError.d.ts +2 -2
  161. package/dist/types/errors/InternalServerError.d.ts.map +1 -1
  162. package/dist/types/errors/NotFoundError.d.ts +2 -2
  163. package/dist/types/errors/NotFoundError.d.ts.map +1 -1
  164. package/dist/types/errors/UnauthorizedError.d.ts +2 -2
  165. package/dist/types/errors/UnauthorizedError.d.ts.map +1 -1
  166. package/dist/types/filters/CacheFilter.d.ts +6 -0
  167. package/dist/types/filters/CacheFilter.d.ts.map +1 -1
  168. package/dist/types/filters/IntentSchemeFilter.d.ts +20 -0
  169. package/dist/types/filters/IntentSchemeFilter.d.ts.map +1 -0
  170. package/dist/types/filters/ResourceFilter.d.ts.map +1 -1
  171. package/dist/types/filters/TopicProtocolFilter.d.ts +34 -0
  172. package/dist/types/filters/TopicProtocolFilter.d.ts.map +1 -0
  173. package/dist/types/filters/index.d.ts +2 -0
  174. package/dist/types/filters/index.d.ts.map +1 -1
  175. package/dist/types/index.d.ts +13 -0
  176. package/dist/types/index.d.ts.map +1 -1
  177. package/dist/types/inject/InjectSituationType.d.ts.map +1 -1
  178. package/dist/types/models/RequestResponse.d.ts +12 -7
  179. package/dist/types/models/RequestResponse.d.ts.map +1 -1
  180. package/dist/types/models/datas/body/index.d.ts +5 -0
  181. package/dist/types/models/datas/body/index.d.ts.map +1 -0
  182. package/dist/types/models/datas/index.d.ts +7 -0
  183. package/dist/types/models/datas/index.d.ts.map +1 -0
  184. package/dist/types/models/datas/path/ReqPathData.d.ts +4 -0
  185. package/dist/types/models/datas/path/ReqPathData.d.ts.map +1 -0
  186. package/dist/types/models/datas/path/ReqSearchParamsObj.d.ts.map +1 -0
  187. package/dist/types/models/datas/path/index.d.ts +3 -0
  188. package/dist/types/models/datas/path/index.d.ts.map +1 -0
  189. package/dist/types/models/index.d.ts +2 -8
  190. package/dist/types/models/index.d.ts.map +1 -1
  191. package/dist/types/models/method/index.d.ts +2 -0
  192. package/dist/types/models/method/index.d.ts.map +1 -0
  193. package/dist/types/models/method/patch/index.d.ts +2 -0
  194. package/dist/types/models/method/patch/index.d.ts.map +1 -0
  195. package/dist/types/option/HttpServerOption.d.ts +30 -20
  196. package/dist/types/option/HttpServerOption.d.ts.map +1 -1
  197. package/dist/types/proxy/SymbolIntentApiServiceProxy.d.ts +16 -0
  198. package/dist/types/proxy/SymbolIntentApiServiceProxy.d.ts.map +1 -0
  199. package/dist/types/proxy/SymbolIntentApiServiceProxyBase.d.ts +5 -0
  200. package/dist/types/proxy/SymbolIntentApiServiceProxyBase.d.ts.map +1 -0
  201. package/dist/types/proxy/TopicProtocolApiServiceProxy.d.ts +28 -0
  202. package/dist/types/proxy/TopicProtocolApiServiceProxy.d.ts.map +1 -0
  203. package/dist/types/proxy/index.d.ts +4 -0
  204. package/dist/types/proxy/index.d.ts.map +1 -0
  205. package/dist/types/session/SessionManager.d.ts +2 -17
  206. package/dist/types/session/SessionManager.d.ts.map +1 -1
  207. package/dist/types/websocket/WebSocketClient.d.ts +88 -0
  208. package/dist/types/websocket/WebSocketClient.d.ts.map +1 -0
  209. package/dist/types/websocket/WebSocketManager.d.ts +163 -0
  210. package/dist/types/websocket/WebSocketManager.d.ts.map +1 -0
  211. package/dist/types/websocket/index.d.ts +3 -0
  212. package/dist/types/websocket/index.d.ts.map +1 -0
  213. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js +18108 -5198
  214. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js.map +4 -4
  215. package/dist/umd-bundle/websocket-client.umd.js +11374 -0
  216. package/dist/umd-bundle/websocket-client.umd.js.map +7 -0
  217. package/package.json +24 -15
  218. package/src/SimpleBootHttpServer.ts +367 -313
  219. package/src/codes/HttpHeaders.ts +13 -2
  220. package/src/codes/Mimes.ts +27 -25
  221. package/src/decorators/MethodMapping.ts +17 -4
  222. package/src/endpoints/WebSocketEndPoint.ts +12 -0
  223. package/src/errors/BadRequestError.ts +7 -3
  224. package/src/errors/ForbiddenError.ts +7 -3
  225. package/src/errors/InternalServerError.ts +7 -3
  226. package/src/errors/NotFoundError.ts +7 -3
  227. package/src/errors/UnauthorizedError.ts +7 -3
  228. package/src/filters/CacheFilter.ts +112 -67
  229. package/src/filters/IntentSchemeFilter.ts +69 -0
  230. package/src/filters/ResourceFilter.ts +10 -2
  231. package/src/filters/TopicProtocolFilter.ts +349 -0
  232. package/src/filters/index.ts +2 -0
  233. package/src/index.ts +13 -12
  234. package/src/inject/InjectSituationType.ts +1 -1
  235. package/src/models/RequestResponse.ts +136 -242
  236. package/src/models/datas/body/index.ts +4 -0
  237. package/src/models/datas/index.ts +6 -0
  238. package/src/models/datas/path/ReqPathData.ts +3 -0
  239. package/src/models/datas/path/index.ts +2 -0
  240. package/src/models/index.ts +2 -8
  241. package/src/models/method/index.ts +1 -0
  242. package/src/models/method/patch/index.ts +1 -0
  243. package/src/option/HttpServerOption.ts +73 -23
  244. package/src/proxy/SymbolIntentApiServiceProxy.ts +126 -0
  245. package/src/proxy/SymbolIntentApiServiceProxyBase.ts +16 -0
  246. package/src/proxy/TopicProtocolApiServiceProxy.ts +328 -0
  247. package/src/proxy/index.ts +3 -0
  248. package/src/resolvers/ResourceResolver.ts +1 -1
  249. package/src/session/SessionManager.ts +3 -3
  250. package/src/websocket/WebSocketClient.ts +637 -0
  251. package/src/websocket/WebSocketManager.ts +713 -0
  252. package/src/websocket/index.ts +2 -0
  253. package/tsconfig.json +3 -1
  254. package/README.MD +0 -36
  255. package/dist/types/models/datas/search/ReqSearchParamsObj.d.ts.map +0 -1
  256. /package/dist/cjs/models/datas/{search → path}/ReqSearchParamsObj.js +0 -0
  257. /package/dist/esm/models/datas/{search → path}/ReqSearchParamsObj.js +0 -0
  258. /package/dist/types/models/datas/{search → path}/ReqSearchParamsObj.d.ts +0 -0
  259. /package/src/models/datas/{search → path}/ReqSearchParamsObj.ts +0 -0
@@ -0,0 +1,349 @@
1
+ import { Filter } from './Filter';
2
+ import { Sim } from '@dooboostore/simple-boot';
3
+ import { RequestResponse } from '../models/RequestResponse';
4
+ import { SimpleBootHttpServer } from '../SimpleBootHttpServer';
5
+ import { HttpHeaders } from '../codes/HttpHeaders';
6
+ import { Mimes } from '../codes/Mimes';
7
+ import { HttpStatus } from '../codes/HttpStatus';
8
+ import { Intent } from '@dooboostore/simple-boot';
9
+ import { IntentManager } from '@dooboostore/simple-boot';
10
+ import { RouterManager } from '@dooboostore/simple-boot';
11
+ import { FileUtils } from '@dooboostore/core-node';
12
+ import { MultipartData } from '../models/datas/MultipartData';
13
+ import * as fs from 'node:fs';
14
+ import { RandomUtils } from '@dooboostore/core';
15
+
16
+ type HttpTopicType = 'intent' | 'router';
17
+
18
+ type HttpTopicRequest<TBody = unknown> = {
19
+ type?: HttpTopicType;
20
+ target?: string;
21
+ requestUUID?: string;
22
+ body?: TBody;
23
+ files?: Array<{ id: string }>;
24
+ };
25
+
26
+ type HttpTopicResponse<TBody = unknown> = {
27
+ state: 'success' | 'error';
28
+ target: string;
29
+ requestUUID?: string;
30
+ body: TBody;
31
+ };
32
+
33
+ type MultipartFormValue = string | FileUtils.File<MultipartData>;
34
+ type MultipartFormDataObject = Record<string, MultipartFormValue>;
35
+ type FileEntry = { id: string; name: string; mime: string; buffer: Buffer };
36
+ type BinaryLike = Buffer | Uint8Array | ArrayBuffer;
37
+ type BinaryPayload = { buffer: BinaryLike; name?: string; mime?: string };
38
+ type FilePayload = FileUtils.File<MultipartData> | BinaryLike | BinaryPayload;
39
+
40
+ @Sim
41
+ export class TopicProtocolFilter implements Filter {
42
+ constructor(
43
+ private intentManager: IntentManager,
44
+ private routerManager: RouterManager
45
+ ) {}
46
+
47
+ async onInit(app: SimpleBootHttpServer) {}
48
+
49
+ private isProtocolRequest(rr: RequestResponse) {
50
+ const header = rr.reqHeaderFirst(HttpHeaders.XSimpleBootHttpTopicProtocol);
51
+ const contentType = rr.reqHeaderFirst(HttpHeaders.ContentType);
52
+ return header?.toLowerCase() === 'topic' && !!contentType && contentType.includes(Mimes.MultipartFormData);
53
+ }
54
+
55
+ private buildResponse(target: string, body: unknown, requestUUID?: string): HttpTopicResponse {
56
+ return {
57
+ state: 'success',
58
+ target,
59
+ requestUUID,
60
+ body
61
+ };
62
+ }
63
+
64
+ private buildErrorResponse(target: string, body: unknown, requestUUID?: string): HttpTopicResponse {
65
+ return {
66
+ state: 'error',
67
+ target,
68
+ requestUUID,
69
+ body
70
+ };
71
+ }
72
+
73
+ private isFileRef(value: unknown): value is { $file: string } {
74
+ if (!value || typeof value !== 'object') {
75
+ return false;
76
+ }
77
+ const fileKey = (value as { $file?: unknown }).$file;
78
+ return typeof fileKey === 'string';
79
+ }
80
+
81
+ private replaceFileRefs(value: unknown, fileMap: Map<string, FileUtils.File<MultipartData>>): unknown {
82
+ if (this.isFileRef(value)) {
83
+ const file = fileMap.get(value.$file);
84
+ if (file) {
85
+ return file;
86
+ }
87
+ }
88
+ if (Array.isArray(value)) {
89
+ return value.map(item => this.replaceFileRefs(item, fileMap));
90
+ }
91
+ if (value && typeof value === 'object') {
92
+ const result: Record<string, unknown> = {};
93
+ Object.keys(value).forEach(key => {
94
+ result[key] = this.replaceFileRefs((value as Record<string, unknown>)[key], fileMap);
95
+ });
96
+ return result;
97
+ }
98
+ return value;
99
+ }
100
+
101
+ private isFileValue(value: unknown): value is FilePayload {
102
+ if (value instanceof FileUtils.File) {
103
+ return true;
104
+ }
105
+ if (Buffer.isBuffer(value)) {
106
+ return true;
107
+ }
108
+ if (value instanceof Uint8Array) {
109
+ return true;
110
+ }
111
+ if (value instanceof ArrayBuffer) {
112
+ return true;
113
+ }
114
+ if (value && typeof value === 'object' && 'buffer' in value) {
115
+ const bufferValue = (value as { buffer?: unknown }).buffer;
116
+ return Buffer.isBuffer(bufferValue) || bufferValue instanceof Uint8Array || bufferValue instanceof ArrayBuffer;
117
+ }
118
+ return false;
119
+ }
120
+
121
+ private toBuffer(value: BinaryLike): Buffer {
122
+ if (Buffer.isBuffer(value)) {
123
+ return value;
124
+ }
125
+ if (value instanceof Uint8Array) {
126
+ return Buffer.from(value);
127
+ }
128
+ return Buffer.from(value);
129
+ }
130
+
131
+ private async toFileEntry(value: FilePayload, id: string): Promise<FileEntry> {
132
+ if (value instanceof FileUtils.File) {
133
+ const meta = value.etcData as { contentType?: string } | undefined;
134
+ const mime = meta?.contentType ?? 'application/octet-stream';
135
+ const name = value.originalName ?? value.fileName ?? 'file';
136
+ const buffer = await fs.promises.readFile(value.path);
137
+ return { id, name, mime, buffer };
138
+ }
139
+
140
+ if (value && typeof value === 'object' && 'buffer' in value) {
141
+ const payload = value as BinaryPayload;
142
+ const buffer = this.toBuffer(payload.buffer);
143
+ return {
144
+ id,
145
+ name: payload.name ?? 'file',
146
+ mime: payload.mime ?? 'application/octet-stream',
147
+ buffer
148
+ };
149
+ }
150
+
151
+ const buffer = this.toBuffer(value as BinaryLike);
152
+ return { id, name: 'file', mime: 'application/octet-stream', buffer };
153
+ }
154
+
155
+ private async buildMultipartResponse(body: unknown) {
156
+ const fileEntries: FileEntry[] = [];
157
+ let fileIndex = 0;
158
+
159
+ const registerFile = async (value: FilePayload) => {
160
+ const id = `f${++fileIndex}`;
161
+ const entry = await this.toFileEntry(value, id);
162
+ fileEntries.push(entry);
163
+ return id;
164
+ };
165
+
166
+ const replaceFiles = async (value: unknown): Promise<unknown> => {
167
+ if (this.isFileValue(value)) {
168
+ return { $file: await registerFile(value) };
169
+ }
170
+ if (Array.isArray(value)) {
171
+ const replaced = [];
172
+ for (const item of value) {
173
+ replaced.push(await replaceFiles(item));
174
+ }
175
+ return replaced;
176
+ }
177
+ if (value && typeof value === 'object') {
178
+ const result: Record<string, unknown> = {};
179
+ for (const key of Object.keys(value)) {
180
+ result[key] = await replaceFiles((value as Record<string, unknown>)[key]);
181
+ }
182
+ return result;
183
+ }
184
+ return value;
185
+ };
186
+
187
+ const payload = await replaceFiles(body);
188
+ const boundary = `----simple-boot-topic-${RandomUtils.uuid4()}`;
189
+ const parts: Buffer[] = [];
190
+
191
+ const writePart = (headers: string[], content: Buffer) => {
192
+ parts.push(Buffer.from(`--${boundary}\r\n`, 'utf8'));
193
+ parts.push(Buffer.from(headers.join('\r\n') + '\r\n\r\n', 'utf8'));
194
+ parts.push(content);
195
+ parts.push(Buffer.from('\r\n', 'utf8'));
196
+ };
197
+
198
+ writePart(['Content-Type: application/json', 'Content-Disposition: form-data; name=\"body\"'], Buffer.from(JSON.stringify(payload), 'utf8'));
199
+
200
+ for (const entry of fileEntries) {
201
+ writePart([`Content-Type: ${entry.mime}`, `Content-Disposition: form-data; name=\"${entry.id}\"; filename=\"${entry.name}\"`], entry.buffer);
202
+ }
203
+
204
+ parts.push(Buffer.from(`--${boundary}--\r\n`, 'utf8'));
205
+ return { boundary, buffer: Buffer.concat(parts), hasFiles: fileEntries.length > 0 };
206
+ }
207
+
208
+ private parseRequest(meta: unknown): HttpTopicRequest | null {
209
+ if (!meta || typeof meta !== 'object') {
210
+ return null;
211
+ }
212
+ const typed = meta as Partial<HttpTopicRequest>;
213
+ if (typed.type !== undefined && typed.type !== 'intent' && typed.type !== 'router') {
214
+ return null;
215
+ }
216
+ if (typed.target !== undefined && typeof typed.target !== 'string') {
217
+ return null;
218
+ }
219
+ if (typed.requestUUID !== undefined && typeof typed.requestUUID !== 'string') {
220
+ return null;
221
+ }
222
+ if (typed.files !== undefined) {
223
+ if (!Array.isArray(typed.files)) {
224
+ return null;
225
+ }
226
+ for (const fileMeta of typed.files) {
227
+ if (!fileMeta || typeof fileMeta !== 'object' || typeof (fileMeta as { id?: unknown }).id !== 'string') {
228
+ return null;
229
+ }
230
+ }
231
+ }
232
+ return typed as HttpTopicRequest;
233
+ }
234
+
235
+ private getBodyString(formData: MultipartFormDataObject): string | undefined {
236
+ const bodyValue = formData.body;
237
+ return typeof bodyValue === 'string' ? bodyValue : undefined;
238
+ }
239
+
240
+ private getFileMap(request: HttpTopicRequest, formData: MultipartFormDataObject) {
241
+ const fileMap = new Map<string, FileUtils.File<MultipartData>>();
242
+ const fileEntries = Object.entries(formData).filter(([, value]) => value instanceof FileUtils.File);
243
+ if (request.files && request.files.length > 0) {
244
+ request.files.forEach(fileMeta => {
245
+ const value = formData[fileMeta.id];
246
+ if (value instanceof FileUtils.File) {
247
+ fileMap.set(fileMeta.id, value);
248
+ }
249
+ });
250
+ return fileMap;
251
+ }
252
+ fileEntries.forEach(([key, value]) => {
253
+ fileMap.set(key, value as FileUtils.File<MultipartData>);
254
+ });
255
+ return fileMap;
256
+ }
257
+
258
+ async proceedBefore({ rr }: { rr: RequestResponse; app: SimpleBootHttpServer; carrier: Map<string, unknown> }) {
259
+ if (!this.isProtocolRequest(rr)) {
260
+ return true;
261
+ }
262
+
263
+ try {
264
+ const formData = await rr.reqBodyMultipartFormDataObject<MultipartFormDataObject>();
265
+ const bodyString = this.getBodyString(formData);
266
+ if (!bodyString) {
267
+ rr.resStatusCode(HttpStatus.BadRequest);
268
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
269
+ await rr.resEnd(JSON.stringify(this.buildErrorResponse('', { message: 'body not found' })));
270
+ return false;
271
+ }
272
+
273
+ const meta = JSON.parse(bodyString) as unknown;
274
+ const request = this.parseRequest(meta);
275
+ if (!request) {
276
+ rr.resStatusCode(HttpStatus.BadRequest);
277
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
278
+ await rr.resEnd(JSON.stringify(this.buildErrorResponse('', { message: 'invalid body' })));
279
+ return false;
280
+ }
281
+ if (!request.target) {
282
+ rr.resStatusCode(HttpStatus.BadRequest);
283
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
284
+ await rr.resEnd(JSON.stringify(this.buildErrorResponse('', { message: 'target not found' }, request.requestUUID)));
285
+ return false;
286
+ }
287
+
288
+ const fileMap = this.getFileMap(request, formData);
289
+
290
+ const body = this.replaceFileRefs(request.body, fileMap);
291
+ let responseBody: unknown;
292
+
293
+ if (request.type === 'router') {
294
+ const intent = new Intent(request.target);
295
+ intent.data = [body, rr];
296
+ const routerModule = await this.routerManager.routing(intent);
297
+ const moduleInstance = routerModule?.getModuleInstance?.();
298
+ if (!routerModule || !moduleInstance || !routerModule.propertyKeys) {
299
+ rr.resStatusCode(HttpStatus.NotFound);
300
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
301
+ await rr.resEnd(JSON.stringify(this.buildErrorResponse(request.target, { message: 'Not found router target' }, request.requestUUID)));
302
+ return false;
303
+ }
304
+ for (const key of routerModule.propertyKeys) {
305
+ const handler = (moduleInstance as Record<string | symbol, unknown>)[key];
306
+ if (typeof handler === 'function') {
307
+ const result = (handler as (body: unknown, rr: RequestResponse) => unknown)(body, rr);
308
+ responseBody = result instanceof Promise ? await result : result;
309
+ }
310
+ break;
311
+ }
312
+ } else {
313
+ const intent = new Intent(request.target);
314
+ intent.data = [body, rr];
315
+ const result = await this.intentManager.publishMeta(intent);
316
+ if (result.target.length <= 0) {
317
+ rr.resStatusCode(HttpStatus.NotFound);
318
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
319
+ await rr.resEnd(JSON.stringify(this.buildErrorResponse(request.target, { message: 'Not found intent target' }, request.requestUUID)));
320
+ return false;
321
+ }
322
+ const rdata = result.return[0];
323
+ responseBody = rdata instanceof Promise ? await rdata : rdata;
324
+ }
325
+
326
+ const response = this.buildResponse(request.target, responseBody, request.requestUUID);
327
+ const multipart = await this.buildMultipartResponse(response);
328
+ rr.resStatusCode(HttpStatus.Ok);
329
+ if (multipart.hasFiles) {
330
+ rr.resSetHeader(HttpHeaders.ContentType, [`multipart/mixed; boundary=${multipart.boundary}`]);
331
+ await rr.resEnd(multipart.buffer);
332
+ } else {
333
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
334
+ await rr.resEnd(JSON.stringify(response));
335
+ }
336
+ return false;
337
+ } catch (error) {
338
+ rr.resStatusCode(HttpStatus.BadRequest);
339
+ rr.resSetHeader(HttpHeaders.ContentType, [Mimes.ApplicationJson]);
340
+ const message = error instanceof Error ? error.message : 'Invalid request';
341
+ await rr.resEnd(JSON.stringify(this.buildErrorResponse('', { message })));
342
+ return false;
343
+ }
344
+ }
345
+
346
+ async proceedAfter({ rr }: { rr: RequestResponse; app: SimpleBootHttpServer; carrier: Map<string, unknown> }) {
347
+ return true;
348
+ }
349
+ }
@@ -1,6 +1,8 @@
1
1
  export * from './CacheFilter';
2
2
  export * from './Filter';
3
+ export * from './TopicProtocolFilter';
3
4
  export * from './HttpStatusFilter';
4
5
  export * from './OpenApi3Filter';
5
6
  export * from './ResourceFilter';
6
7
  export * from './ThrowFilter';
8
+ export * from './IntentSchemeFilter'
package/src/index.ts CHANGED
@@ -1,13 +1,14 @@
1
- // export * from './codes';
2
- // export * from './decorators';
3
- // export * from './endpoints';
4
- // export * from './errors';
5
- // export * from './filters';
6
- // export * from './inject';
7
- // export * from './lifecycle';
8
- // export * from './models';
9
- // export * from './option';
10
- // export * from './resolvers';
11
- // export * from './session';
12
- // export * from './SimpleBootHttpServer';
1
+ export * from './codes';
2
+ export * from './decorators';
3
+ export * from './endpoints';
4
+ export * from './errors';
5
+ export * from './filters';
6
+ export * from './proxy';
7
+ export * from './inject';
8
+ export * from './lifecycle';
9
+ export * from './models';
10
+ export * from './option';
11
+ export * from './resolvers';
12
+ export * from './session';
13
+ export * from './SimpleBootHttpServer';
13
14
  export default {}
@@ -1,3 +1,3 @@
1
1
  export namespace InjectSituationType {
2
- export const TransactionManager = Symbol('TransactionManager');
2
+ export const TransactionManager = Symbol.for('simple-boot-http-server:transaction-manager-token');
3
3
  }