@dooboostore/simple-boot-http-server 1.0.22 → 1.0.24

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 (181) hide show
  1. package/README.MD +27 -3
  2. package/dist/cjs/SimpleBootHttpServer.js +93 -36
  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/HttpStatus.js +1 -0
  7. package/dist/cjs/codes/HttpStatus.js.map +2 -2
  8. package/dist/cjs/codes/Mimes.js +2 -0
  9. package/dist/cjs/codes/Mimes.js.map +2 -2
  10. package/dist/cjs/decorators/MethodMapping.js +8 -6
  11. package/dist/cjs/decorators/MethodMapping.js.map +3 -3
  12. package/dist/cjs/endpoints/WebSocketEndPoint.js +16 -0
  13. package/dist/cjs/endpoints/WebSocketEndPoint.js.map +7 -0
  14. package/dist/cjs/filters/CacheFilter.js +75 -35
  15. package/dist/cjs/filters/CacheFilter.js.map +3 -3
  16. package/dist/cjs/filters/IntentSchemeFilter.js +98 -0
  17. package/dist/cjs/filters/IntentSchemeFilter.js.map +7 -0
  18. package/dist/cjs/filters/ResourceFilter.js +4 -1
  19. package/dist/cjs/filters/ResourceFilter.js.map +2 -2
  20. package/dist/cjs/filters/TopicProtocolFilter.js +343 -0
  21. package/dist/cjs/filters/TopicProtocolFilter.js.map +7 -0
  22. package/dist/cjs/filters/index.js +2 -0
  23. package/dist/cjs/filters/index.js.map +2 -2
  24. package/dist/cjs/index.js +28 -0
  25. package/dist/cjs/index.js.map +2 -2
  26. package/dist/cjs/models/RequestResponse.js +56 -89
  27. package/dist/cjs/models/RequestResponse.js.map +3 -3
  28. package/dist/cjs/models/datas/body/ReqPathData.js +29 -0
  29. package/dist/cjs/models/datas/body/ReqPathData.js.map +7 -0
  30. package/dist/cjs/models/datas/search/ReqSearchParamsObj.js +29 -0
  31. package/dist/cjs/models/datas/search/ReqSearchParamsObj.js.map +7 -0
  32. package/dist/cjs/option/HttpServerOption.js +25 -5
  33. package/dist/cjs/option/HttpServerOption.js.map +2 -2
  34. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js +141 -0
  35. package/dist/cjs/proxy/SymbolIntentApiServiceProxy.js.map +7 -0
  36. package/dist/cjs/proxy/SymbolIntentApiServiceProxyBase.js +35 -0
  37. package/dist/cjs/proxy/SymbolIntentApiServiceProxyBase.js.map +7 -0
  38. package/dist/cjs/proxy/TopicProtocolApiServiceProxy.js +324 -0
  39. package/dist/cjs/proxy/TopicProtocolApiServiceProxy.js.map +7 -0
  40. package/dist/cjs/proxy/index.js +26 -0
  41. package/dist/cjs/proxy/index.js.map +7 -0
  42. package/dist/cjs/resolvers/ResourceResolver.js +2 -2
  43. package/dist/cjs/resolvers/ResourceResolver.js.map +2 -2
  44. package/dist/cjs/session/SessionManager.js +2 -2
  45. package/dist/cjs/session/SessionManager.js.map +2 -2
  46. package/dist/cjs/websocket/WebSocketClient.js +554 -0
  47. package/dist/cjs/websocket/WebSocketClient.js.map +7 -0
  48. package/dist/cjs/websocket/WebSocketManager.js +652 -0
  49. package/dist/cjs/websocket/WebSocketManager.js.map +7 -0
  50. package/dist/cjs/websocket/index.js +24 -0
  51. package/dist/cjs/websocket/index.js.map +7 -0
  52. package/dist/esm/SimpleBootHttpServer.js +76 -19
  53. package/dist/esm/SimpleBootHttpServer.js.map +2 -2
  54. package/dist/esm/codes/HttpHeaders.js +12 -2
  55. package/dist/esm/codes/HttpHeaders.js.map +2 -2
  56. package/dist/esm/codes/HttpStatus.js +1 -0
  57. package/dist/esm/codes/HttpStatus.js.map +2 -2
  58. package/dist/esm/codes/Mimes.js +2 -0
  59. package/dist/esm/codes/Mimes.js.map +2 -2
  60. package/dist/esm/decorators/MethodMapping.js +3 -1
  61. package/dist/esm/decorators/MethodMapping.js.map +2 -2
  62. package/dist/esm/endpoints/WebSocketEndPoint.js +1 -0
  63. package/dist/esm/endpoints/WebSocketEndPoint.js.map +7 -0
  64. package/dist/esm/filters/CacheFilter.js +67 -27
  65. package/dist/esm/filters/CacheFilter.js.map +2 -2
  66. package/dist/esm/filters/IntentSchemeFilter.js +75 -0
  67. package/dist/esm/filters/IntentSchemeFilter.js.map +7 -0
  68. package/dist/esm/filters/ResourceFilter.js +4 -1
  69. package/dist/esm/filters/ResourceFilter.js.map +2 -2
  70. package/dist/esm/filters/TopicProtocolFilter.js +310 -0
  71. package/dist/esm/filters/TopicProtocolFilter.js.map +7 -0
  72. package/dist/esm/filters/index.js +1 -0
  73. package/dist/esm/filters/index.js.map +2 -2
  74. package/dist/esm/index.js +12 -0
  75. package/dist/esm/index.js.map +2 -2
  76. package/dist/esm/models/RequestResponse.js +52 -85
  77. package/dist/esm/models/RequestResponse.js.map +2 -2
  78. package/dist/esm/models/datas/body/ReqPathData.js +6 -0
  79. package/dist/esm/models/datas/body/ReqPathData.js.map +7 -0
  80. package/dist/esm/models/datas/search/ReqSearchParamsObj.js +6 -0
  81. package/dist/esm/models/datas/search/ReqSearchParamsObj.js.map +7 -0
  82. package/dist/esm/option/HttpServerOption.js +24 -4
  83. package/dist/esm/option/HttpServerOption.js.map +2 -2
  84. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js +118 -0
  85. package/dist/esm/proxy/SymbolIntentApiServiceProxy.js.map +7 -0
  86. package/dist/esm/proxy/SymbolIntentApiServiceProxyBase.js +12 -0
  87. package/dist/esm/proxy/SymbolIntentApiServiceProxyBase.js.map +7 -0
  88. package/dist/esm/proxy/TopicProtocolApiServiceProxy.js +301 -0
  89. package/dist/esm/proxy/TopicProtocolApiServiceProxy.js.map +7 -0
  90. package/dist/esm/proxy/index.js +4 -0
  91. package/dist/esm/proxy/index.js.map +7 -0
  92. package/dist/esm/resolvers/ResourceResolver.js +1 -1
  93. package/dist/esm/resolvers/ResourceResolver.js.map +1 -1
  94. package/dist/esm/session/SessionManager.js +1 -1
  95. package/dist/esm/session/SessionManager.js.map +1 -1
  96. package/dist/esm/websocket/WebSocketClient.js +529 -0
  97. package/dist/esm/websocket/WebSocketClient.js.map +7 -0
  98. package/dist/esm/websocket/WebSocketManager.js +622 -0
  99. package/dist/esm/websocket/WebSocketManager.js.map +7 -0
  100. package/dist/esm/websocket/index.js +3 -0
  101. package/dist/esm/websocket/index.js.map +7 -0
  102. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js +13563 -5071
  103. package/dist/esm-bundle/dooboostore-simple-boot-http-server.esm.js.map +4 -4
  104. package/dist/types/SimpleBootHttpServer.d.ts +5 -3
  105. package/dist/types/SimpleBootHttpServer.d.ts.map +1 -1
  106. package/dist/types/codes/HttpHeaders.d.ts +3 -0
  107. package/dist/types/codes/HttpHeaders.d.ts.map +1 -1
  108. package/dist/types/codes/HttpStatus.d.ts +13 -1
  109. package/dist/types/codes/HttpStatus.d.ts.map +1 -1
  110. package/dist/types/codes/Mimes.d.ts +3 -1
  111. package/dist/types/codes/Mimes.d.ts.map +1 -1
  112. package/dist/types/decorators/MethodMapping.d.ts +4 -2
  113. package/dist/types/decorators/MethodMapping.d.ts.map +1 -1
  114. package/dist/types/endpoints/WebSocketEndPoint.d.ts +17 -0
  115. package/dist/types/endpoints/WebSocketEndPoint.d.ts.map +1 -0
  116. package/dist/types/filters/CacheFilter.d.ts +6 -0
  117. package/dist/types/filters/CacheFilter.d.ts.map +1 -1
  118. package/dist/types/filters/IntentSchemeFilter.d.ts +20 -0
  119. package/dist/types/filters/IntentSchemeFilter.d.ts.map +1 -0
  120. package/dist/types/filters/ResourceFilter.d.ts.map +1 -1
  121. package/dist/types/filters/TopicProtocolFilter.d.ts +34 -0
  122. package/dist/types/filters/TopicProtocolFilter.d.ts.map +1 -0
  123. package/dist/types/filters/index.d.ts +1 -0
  124. package/dist/types/filters/index.d.ts.map +1 -1
  125. package/dist/types/index.d.ts +12 -0
  126. package/dist/types/index.d.ts.map +1 -1
  127. package/dist/types/models/RequestResponse.d.ts +10 -6
  128. package/dist/types/models/RequestResponse.d.ts.map +1 -1
  129. package/dist/types/models/datas/body/ReqPathData.d.ts +4 -0
  130. package/dist/types/models/datas/body/ReqPathData.d.ts.map +1 -0
  131. package/dist/types/models/datas/search/ReqSearchParamsObj.d.ts +4 -0
  132. package/dist/types/models/datas/search/ReqSearchParamsObj.d.ts.map +1 -0
  133. package/dist/types/option/HttpServerOption.d.ts +30 -20
  134. package/dist/types/option/HttpServerOption.d.ts.map +1 -1
  135. package/dist/types/proxy/SymbolIntentApiServiceProxy.d.ts +18 -0
  136. package/dist/types/proxy/SymbolIntentApiServiceProxy.d.ts.map +1 -0
  137. package/dist/types/proxy/SymbolIntentApiServiceProxyBase.d.ts +5 -0
  138. package/dist/types/proxy/SymbolIntentApiServiceProxyBase.d.ts.map +1 -0
  139. package/dist/types/proxy/TopicProtocolApiServiceProxy.d.ts +28 -0
  140. package/dist/types/proxy/TopicProtocolApiServiceProxy.d.ts.map +1 -0
  141. package/dist/types/proxy/index.d.ts +4 -0
  142. package/dist/types/proxy/index.d.ts.map +1 -0
  143. package/dist/types/session/SessionManager.d.ts +2 -17
  144. package/dist/types/session/SessionManager.d.ts.map +1 -1
  145. package/dist/types/websocket/WebSocketClient.d.ts +88 -0
  146. package/dist/types/websocket/WebSocketClient.d.ts.map +1 -0
  147. package/dist/types/websocket/WebSocketManager.d.ts +163 -0
  148. package/dist/types/websocket/WebSocketManager.d.ts.map +1 -0
  149. package/dist/types/websocket/index.d.ts +3 -0
  150. package/dist/types/websocket/index.d.ts.map +1 -0
  151. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js +13638 -5146
  152. package/dist/umd-bundle/dooboostore-simple-boot-http-server.umd.js.map +4 -4
  153. package/dist/umd-bundle/websocket-client.umd.js +11194 -0
  154. package/dist/umd-bundle/websocket-client.umd.js.map +7 -0
  155. package/package.json +24 -15
  156. package/src/SimpleBootHttpServer.ts +367 -296
  157. package/src/codes/HttpHeaders.ts +13 -2
  158. package/src/codes/HttpStatus.ts +19 -1
  159. package/src/codes/Mimes.ts +27 -25
  160. package/src/decorators/MethodMapping.ts +6 -3
  161. package/src/endpoints/WebSocketEndPoint.ts +12 -0
  162. package/src/filters/CacheFilter.ts +112 -67
  163. package/src/filters/IntentSchemeFilter.ts +69 -0
  164. package/src/filters/ResourceFilter.ts +7 -1
  165. package/src/filters/TopicProtocolFilter.ts +349 -0
  166. package/src/filters/index.ts +1 -0
  167. package/src/index.ts +12 -12
  168. package/src/models/RequestResponse.ts +113 -240
  169. package/src/models/datas/body/ReqPathData.ts +3 -0
  170. package/src/models/datas/search/ReqSearchParamsObj.ts +3 -0
  171. package/src/option/HttpServerOption.ts +73 -23
  172. package/src/proxy/SymbolIntentApiServiceProxy.ts +120 -0
  173. package/src/proxy/SymbolIntentApiServiceProxyBase.ts +16 -0
  174. package/src/proxy/TopicProtocolApiServiceProxy.ts +328 -0
  175. package/src/proxy/index.ts +3 -0
  176. package/src/resolvers/ResourceResolver.ts +1 -1
  177. package/src/session/SessionManager.ts +3 -3
  178. package/src/websocket/WebSocketClient.ts +637 -0
  179. package/src/websocket/WebSocketManager.ts +713 -0
  180. package/src/websocket/index.ts +2 -0
  181. package/tsconfig.json +3 -1
@@ -0,0 +1,3 @@
1
+ export class ReqPathData {
2
+ [key: string]: string | string[]
3
+ }
@@ -0,0 +1,3 @@
1
+ export class ReqSearchParamsObj {
2
+ [key: string]: any
3
+ }
@@ -1,12 +1,13 @@
1
- import { InitOptionType, SimOption } from '@dooboostore/simple-boot/SimOption';
2
- import { ConstructorType } from '@dooboostore/core/types';
1
+ import { InitOptionType, SimOption } from '@dooboostore/simple-boot';
2
+ import { ConstructorType } from '@dooboostore/core';
3
3
  import { Server as HttpServer, ServerOptions } from 'http';
4
4
  import { Server as HttpsServer, ServerOptions as HttpsServerOption } from 'https';
5
5
  import { Filter } from '../filters/Filter';
6
6
  import { EndPoint } from '../endpoints/EndPoint';
7
7
  import { RequestResponse } from '../models/RequestResponse';
8
8
  import { SimpleBootHttpServer } from '../SimpleBootHttpServer';
9
- import { TransactionManager } from '@dooboostore/core/transaction/TransactionManager';
9
+ import { TransactionManager } from '@dooboostore/core';
10
+ import { WebSocketEndPoint } from '../endpoints/WebSocketEndPoint';
10
11
 
11
12
  export type Listen = { port?: number, hostname?: string, backlog?: number, listeningListener?: (server: SimpleBootHttpServer, httpServer: HttpServer | HttpsServer) => void };
12
13
 
@@ -15,6 +16,23 @@ export interface ListenData extends Listen {
15
16
  hostname: string;
16
17
  }
17
18
 
19
+ export type SessionOption = {
20
+ key: string;
21
+ expiredTime: number;
22
+ httpOnly?: boolean;
23
+ secure?: boolean;
24
+ maxAge?: number;
25
+ sameSite?: boolean | 'lax' | 'strict' | 'none';
26
+ domain?: string;
27
+ path?: string;
28
+ provider?: {
29
+ uuids: () => Promise<string[]>;
30
+ delete: (uuid: string) => Promise<void>;
31
+ get: (uuid: string) => Promise<{ access: number; data?: any }>;
32
+ set: (uuid: string, data: { access: number; data?: any }) => Promise<void>;
33
+ };
34
+ };
35
+
18
36
  export class HttpServerOption extends SimOption {
19
37
  public static readonly DEFAULT_PORT = 8081;
20
38
  public static readonly DEFAULT_HOSTNAME = '127.0.0.1';
@@ -23,36 +41,70 @@ export class HttpServerOption extends SimOption {
23
41
  public filters?: (Filter | ConstructorType<Filter>)[];
24
42
  public fileUploadTempPath?: string;
25
43
  public requestEndPoints?: (EndPoint | ConstructorType<EndPoint>)[];
44
+ public webSocketEndPoints?: (WebSocketEndPoint | ConstructorType<WebSocketEndPoint>)[];
26
45
  public closeEndPoints?: (EndPoint | ConstructorType<EndPoint>)[];
27
46
  public errorEndPoints?: (EndPoint | ConstructorType<EndPoint>)[];
28
- public sessionOption: { key: string, expiredTime: number, provider?: { uuids: () => Promise<string[]>, delete: (uuid: string) => Promise<void>, get: (uuid: string) => Promise<{ access: number, data?: any }>, set: (uuid: string, data: { access: number, data?: any }) => Promise<void> } };
47
+ public sessionOption: SessionOption;
29
48
  public globalAdvice?: any | ConstructorType<any>;
30
49
  public noSuchRouteEndPointMappingThrow?: (rr: RequestResponse) => any;
31
50
  public transactionManagerFactory?: () => TransactionManager;
32
51
 
33
- constructor({serverOption, listen, filters, requestEndPoints, closeEndPoints, errorEndPoints, sessionOption, globalAdvice, fileUploadTempPath,noSuchRouteEndPointMappingThrow, transactionManagerFactory}: {
34
- serverOption?: ServerOptions | HttpsServerOption,
35
- listen?: Listen,
36
- filters?: (Filter | ConstructorType<Filter>)[],
37
- requestEndPoints?: (EndPoint | ConstructorType<EndPoint>)[],
38
- closeEndPoints?: (EndPoint | ConstructorType<EndPoint>)[],
39
- errorEndPoints?: (EndPoint | ConstructorType<EndPoint>)[],
40
- sessionOption?: { key?: string, expiredTime?: number, provider?: { uuids: () => Promise<string[]>, delete: (uuid: string) => Promise<void>, get: (uuid: string) => Promise<{ access: number, data?: any }>, set: (uuid: string, data: { access: number, data?: any }) => Promise<void> } },
41
- globalAdvice?: any | ConstructorType<any>,
42
- fileUploadTempPath?: string,
43
- noSuchRouteEndPointMappingThrow?: (rr: RequestResponse) => any,
44
- transactionManagerFactory?: () => TransactionManager
45
- } = {}, initSimOption?: InitOptionType) {
52
+ constructor(
53
+ {
54
+ serverOption,
55
+ listen,
56
+ filters,
57
+ requestEndPoints,
58
+ closeEndPoints,
59
+ errorEndPoints,
60
+ webSocketEndPoints,
61
+ sessionOption,
62
+ globalAdvice,
63
+ fileUploadTempPath,
64
+ noSuchRouteEndPointMappingThrow,
65
+ transactionManagerFactory
66
+ }: {
67
+ serverOption?: ServerOptions | HttpsServerOption;
68
+ listen?: Listen;
69
+ filters?: (Filter | ConstructorType<Filter>)[];
70
+ requestEndPoints?: (EndPoint | ConstructorType<EndPoint>)[];
71
+ closeEndPoints?: (EndPoint | ConstructorType<EndPoint>)[];
72
+ errorEndPoints?: (EndPoint | ConstructorType<EndPoint>)[];
73
+ webSocketEndPoints?: (WebSocketEndPoint | ConstructorType<WebSocketEndPoint>)[];
74
+ sessionOption?: {
75
+ key?: string;
76
+ expiredTime?: number;
77
+ provider?: {
78
+ uuids: () => Promise<string[]>;
79
+ delete: (uuid: string) => Promise<void>;
80
+ get: (uuid: string) => Promise<{ access: number; data?: any }>;
81
+ set: (uuid: string, data: { access: number; data?: any }) => Promise<void>;
82
+ };
83
+ };
84
+ globalAdvice?: any | ConstructorType<any>;
85
+ fileUploadTempPath?: string;
86
+ noSuchRouteEndPointMappingThrow?: (rr: RequestResponse) => any;
87
+ transactionManagerFactory?: () => TransactionManager;
88
+ } = {},
89
+ initSimOption?: InitOptionType
90
+ ) {
46
91
  super(initSimOption);
47
92
  this.serverOption = serverOption;
48
- this.listen = Object.assign({port: HttpServerOption.DEFAULT_PORT, hostname: HttpServerOption.DEFAULT_HOSTNAME}, listen);
93
+ this.listen = Object.assign(
94
+ { port: HttpServerOption.DEFAULT_PORT, hostname: HttpServerOption.DEFAULT_HOSTNAME },
95
+ listen
96
+ );
49
97
  this.filters = filters;
50
98
  this.requestEndPoints = requestEndPoints;
51
99
  this.closeEndPoints = closeEndPoints;
52
100
  this.errorEndPoints = errorEndPoints;
53
- this.sessionOption = Object.assign({key: 'SBSESSIONID', expiredTime: 1000 * 60 * 30}, sessionOption);
101
+ this.webSocketEndPoints = webSocketEndPoints;
102
+ this.sessionOption = Object.assign(
103
+ { key: 'SBSESSIONID', path: '/', httpOnly: true, expiredTime: 1000 * 60 * 30 },
104
+ sessionOption
105
+ );
54
106
  this.globalAdvice = globalAdvice;
55
- this.fileUploadTempPath=fileUploadTempPath;
107
+ this.fileUploadTempPath = fileUploadTempPath;
56
108
  this.noSuchRouteEndPointMappingThrow = noSuchRouteEndPointMappingThrow;
57
109
  this.transactionManagerFactory = transactionManagerFactory;
58
110
  }
@@ -74,8 +126,6 @@ export class HttpServerOption extends SimOption {
74
126
  }
75
127
 
76
128
  get isSecure() {
77
- return this.serverOption && 'key' in this.serverOption && 'cert' in this.serverOption;
129
+ return this.serverOption && 'key' in this.serverOption && 'cert' in this.serverOption;
78
130
  }
79
-
80
-
81
131
  }
@@ -0,0 +1,120 @@
1
+ import { getSim, Sim } from '@dooboostore/simple-boot';
2
+ import { makeIntentHeaderBySymbolFor } from '../codes/HttpHeaders';
3
+ import { ConvertUtils } from '@dooboostore/core';
4
+ import { ApiService } from '@dooboostore/simple-boot';
5
+
6
+ export type Config<T = any> = {
7
+ method?: 'get' | 'post' | 'petch' | 'delete' | 'head';
8
+ multipartFormData?: boolean;
9
+ bypassTransform?: boolean;
10
+ transformText?: boolean;
11
+ headers?: HeadersInit;
12
+ body?: T;
13
+ config?: ApiService.ApiServiceConfig;
14
+ };
15
+ const _ = ApiService;
16
+
17
+ @Sim
18
+ export class SymbolIntentApiServiceProxy<T extends object> implements ProxyHandler<T> {
19
+ constructor(private apiService: ApiService) {
20
+ // console.log('-------apiService', apiService);
21
+ }
22
+
23
+ static createHandler<T extends object>(apiService: ApiService): ProxyHandler<T> {
24
+ return {
25
+ get(target: T, prop: string | symbol, receiver: any): any {
26
+ if (prop === '_SimpleBoot_origin') {
27
+ return target;
28
+ }
29
+ const simConfig = getSim(target);
30
+ const value = Reflect.get(target, prop, receiver);
31
+ if (typeof value === 'function' && simConfig?.symbol) {
32
+ return function (...args: any[]) {
33
+ const f = value as Function;
34
+ const p = (userConfig: Config) => {
35
+ const headers = { ...(userConfig?.headers ?? {}), ...makeIntentHeaderBySymbolFor(simConfig.symbol as Symbol) };
36
+ const method = userConfig?.method ?? 'post';
37
+ if (method === 'post' && userConfig?.multipartFormData) {
38
+ //@ts-ignore
39
+ return apiService.post({
40
+ target: `/${String(prop)}`,
41
+ config: {
42
+ responseTransform: userConfig?.bypassTransform ? 'response' : undefined,
43
+ transformText: userConfig?.transformText,
44
+ config: userConfig?.config,
45
+ fetch: {
46
+ credentials: 'include',
47
+ headers: headers,
48
+ body: ConvertUtils.toFormData(userConfig?.body)
49
+ }
50
+ }
51
+ });
52
+ } else if (method === 'post') {
53
+ //@ts-ignore
54
+ return apiService.postJson({
55
+ target: `/${String(prop)}`,
56
+ config: {
57
+ responseTransform: userConfig?.bypassTransform ? 'response' : undefined,
58
+ transformText: userConfig?.transformText,
59
+ config: userConfig?.config,
60
+ fetch: {
61
+ credentials: 'include',
62
+ headers: headers,
63
+ body: userConfig?.body
64
+ }
65
+ }
66
+ });
67
+ } else if (method === 'petch') {
68
+ //@ts-ignore
69
+ return apiService.patchJson({
70
+ target: `/${String(prop)}`,
71
+ config: {
72
+ responseTransform: userConfig?.bypassTransform ? 'response' : undefined,
73
+ transformText: userConfig?.transformText,
74
+ config: userConfig?.config,
75
+ fetch: {
76
+ credentials: 'include',
77
+ headers: headers,
78
+ body: userConfig?.body
79
+ }
80
+ }
81
+ });
82
+ } else {
83
+ //@ts-ignore
84
+ return apiService[method]({
85
+ target: { url: `/${String(prop)}`, searchParams: userConfig?.body },
86
+ config: {
87
+ responseTransform: userConfig?.bypassTransform ? 'response' : undefined,
88
+ transformText: userConfig?.transformText,
89
+ config: userConfig?.config,
90
+ fetch: {
91
+ credentials: 'include',
92
+ headers: headers
93
+ }
94
+ }
95
+ });
96
+ }
97
+ };
98
+ args.push(p);
99
+ return Reflect.apply(f, target, args);
100
+ };
101
+ }
102
+ return Reflect.get(target, prop, receiver);
103
+ },
104
+
105
+ apply(target: T, thisArg: any, argArray: any[]): any {
106
+ console.log('SymbolIntentApiServiceProxy apply');
107
+ // @ts-ignore
108
+ return Reflect.apply(target, thisArg, argArray);
109
+ }
110
+ };
111
+ }
112
+
113
+ get(target: T, prop: string | symbol, receiver: any): any {
114
+ return SymbolIntentApiServiceProxy.createHandler<T>(this.apiService).get!(target, prop, receiver);
115
+ }
116
+
117
+ apply(target: T, thisArg: any, argArray: any[]): any {
118
+ return SymbolIntentApiServiceProxy.createHandler<T>(this.apiService).apply!(target, thisArg, argArray);
119
+ }
120
+ }
@@ -0,0 +1,16 @@
1
+ import {ApiService} from '@dooboostore/simple-boot';
2
+ import {SymbolIntentApiServiceProxy} from './SymbolIntentApiServiceProxy';
3
+
4
+ export class SymbolIntentApiServiceProxyBase<T extends object = any> {
5
+ // 생성자는 프록시될 대상 객체(target)와 의존성을 주입받습니다.
6
+ constructor(
7
+ apiService: ApiService,
8
+ ) {
9
+ // SymbolIntentApiServiceProxy의 static handler를 사용합니다.
10
+ const handler = SymbolIntentApiServiceProxy.createHandler<T>(apiService);
11
+
12
+ // 생성자에서 Proxy 객체를 반환합니다.
13
+ // @ts-ignore
14
+ return new Proxy(this, handler);
15
+ }
16
+ }
@@ -0,0 +1,328 @@
1
+ import { getSim, Sim } from '@dooboostore/simple-boot';
2
+ import { HttpHeaders } from '../codes/HttpHeaders';
3
+ import { ApiService } from '@dooboostore/simple-boot';
4
+ import { RandomUtils } from '@dooboostore/core';
5
+ import { HttpFetcherTarget } from '@dooboostore/core';
6
+
7
+ export type TopicProtocolConfig<TBody = unknown> = {
8
+ bypassTransform?: boolean;
9
+ transformText?: boolean;
10
+ headers?: HeadersInit;
11
+ body?: TBody;
12
+ endpoint?: HttpFetcherTarget;
13
+ type?: TopicProtocolType;
14
+ config?: ApiService.ApiServiceConfig;
15
+ };
16
+
17
+ type TopicProtocolType = 'intent' | 'router';
18
+ type TopicProtocolRequest<TBody = unknown> = {
19
+ type: TopicProtocolType;
20
+ target: string;
21
+ requestUUID: string;
22
+ body?: TBody;
23
+ files?: Array<{ id: string }>;
24
+ };
25
+
26
+ type FileEntry = { id: string; file: Blob; filename?: string };
27
+ type MixedPart = { headers: Record<string, string>; body: Uint8Array };
28
+
29
+ @Sim
30
+ export class TopicProtocolApiServiceProxy<T extends object> implements ProxyHandler<T> {
31
+ constructor(private apiService: ApiService) {}
32
+
33
+ private static isFileValue(value: unknown): value is File | Blob | ArrayBuffer | Uint8Array {
34
+ if (typeof File !== 'undefined' && value instanceof File) {
35
+ return true;
36
+ }
37
+ if (typeof Blob !== 'undefined' && value instanceof Blob) {
38
+ return true;
39
+ }
40
+ if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) {
41
+ return true;
42
+ }
43
+ if (typeof Uint8Array !== 'undefined' && value instanceof Uint8Array) {
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+
49
+ private static toFileEntry(value: File | Blob | ArrayBuffer | Uint8Array, id: string): FileEntry | undefined {
50
+ if (typeof Blob === 'undefined') {
51
+ return undefined;
52
+ }
53
+ if (typeof File !== 'undefined' && value instanceof File) {
54
+ const blob = new Blob([value], { type: value.type });
55
+ return { id, file: blob, filename: value.name };
56
+ }
57
+ if (value instanceof Blob) {
58
+ return { id, file: value };
59
+ }
60
+ const view = value instanceof Uint8Array ? value : new Uint8Array(value);
61
+ const safe = value instanceof Uint8Array ? new Uint8Array(value) : new Uint8Array(view);
62
+ const blob = new Blob([safe]);
63
+ return { id, file: blob };
64
+ }
65
+
66
+ private static buildRequest<TBody>(target: string, body?: TBody, type: TopicProtocolType = 'intent') {
67
+ const fileEntries: FileEntry[] = [];
68
+ let fileIndex = 0;
69
+
70
+ const registerFile = (value: File | Blob | ArrayBuffer | Uint8Array): string | undefined => {
71
+ const id = `f${++fileIndex}`;
72
+ const entry = TopicProtocolApiServiceProxy.toFileEntry(value, id);
73
+ if (entry) {
74
+ fileEntries.push(entry);
75
+ return id;
76
+ }
77
+ return undefined;
78
+ };
79
+
80
+ const replaceFiles = (value: unknown): unknown => {
81
+ if (TopicProtocolApiServiceProxy.isFileValue(value)) {
82
+ const id = registerFile(value);
83
+ if (id) {
84
+ return { $file: id };
85
+ }
86
+ return value;
87
+ }
88
+ if (Array.isArray(value)) {
89
+ return value.map(item => replaceFiles(item));
90
+ }
91
+ if (value && typeof value === 'object') {
92
+ const result: Record<string, unknown> = {};
93
+ Object.keys(value).forEach(key => {
94
+ result[key] = replaceFiles((value as Record<string, unknown>)[key]);
95
+ });
96
+ return result;
97
+ }
98
+ return value;
99
+ };
100
+
101
+ const payload = replaceFiles(body);
102
+ const request: TopicProtocolRequest<TBody> = {
103
+ type,
104
+ target,
105
+ requestUUID: RandomUtils.uuid4(),
106
+ body: payload as TBody,
107
+ files: fileEntries.length > 0 ? fileEntries.map(entry => ({ id: entry.id })) : undefined
108
+ };
109
+
110
+ return { request, fileEntries };
111
+ }
112
+
113
+ private static async parseMultipartMixed(response: Response) {
114
+ const contentType = response.headers.get('Content-Type') ?? '';
115
+ const boundaryMatch = contentType.match(/boundary=([^;]+)/i);
116
+ if (!boundaryMatch) {
117
+ return undefined;
118
+ }
119
+ const boundary = boundaryMatch[1].replace(/^"|"$/g, '');
120
+ const buffer = new Uint8Array(await response.arrayBuffer());
121
+ const boundaryBytes = new TextEncoder().encode(`--${boundary}`);
122
+ const endBoundaryBytes = new TextEncoder().encode(`--${boundary}--`);
123
+ const separator = new TextEncoder().encode('\r\n\r\n');
124
+
125
+ const indexOf = (source: Uint8Array, needle: Uint8Array, from = 0) => {
126
+ for (let i = from; i <= source.length - needle.length; i++) {
127
+ let matched = true;
128
+ for (let j = 0; j < needle.length; j++) {
129
+ if (source[i + j] !== needle[j]) {
130
+ matched = false;
131
+ break;
132
+ }
133
+ }
134
+ if (matched) {
135
+ return i;
136
+ }
137
+ }
138
+ return -1;
139
+ };
140
+
141
+ const parts: MixedPart[] = [];
142
+ let cursor = indexOf(buffer, boundaryBytes, 0);
143
+ while (cursor !== -1) {
144
+ const nextBoundary = indexOf(buffer, boundaryBytes, cursor + boundaryBytes.length);
145
+ const endBoundary = indexOf(buffer, endBoundaryBytes, cursor + boundaryBytes.length);
146
+ const isFinal = endBoundary !== -1 && (endBoundary < nextBoundary || nextBoundary === -1);
147
+ const partStart = cursor + boundaryBytes.length;
148
+ if (isFinal) {
149
+ break;
150
+ }
151
+ let headerStart = partStart;
152
+ if (buffer[headerStart] === 13 && buffer[headerStart + 1] === 10) {
153
+ headerStart += 2;
154
+ }
155
+ const headerEnd = indexOf(buffer, separator, headerStart);
156
+ if (headerEnd === -1) {
157
+ break;
158
+ }
159
+ const headerText = new TextDecoder().decode(buffer.slice(headerStart, headerEnd));
160
+ const headers: Record<string, string> = {};
161
+ headerText.split('\r\n').forEach(line => {
162
+ const idx = line.indexOf(':');
163
+ if (idx > -1) {
164
+ const key = line.slice(0, idx).trim().toLowerCase();
165
+ headers[key] = line.slice(idx + 1).trim();
166
+ }
167
+ });
168
+ const bodyStart = headerEnd + separator.length;
169
+ const bodyEnd = nextBoundary === -1 ? buffer.length : nextBoundary - 2;
170
+ const body = buffer.slice(bodyStart, bodyEnd);
171
+ parts.push({ headers, body });
172
+ cursor = nextBoundary;
173
+ }
174
+
175
+ return { boundary, parts };
176
+ }
177
+
178
+ private static parseDispositionFilename(disposition?: string) {
179
+ if (!disposition) {
180
+ return undefined;
181
+ }
182
+ const match = disposition.match(/filename=\"?([^\";]+)\"?/i);
183
+ return match ? match[1] : undefined;
184
+ }
185
+
186
+ private static parseDispositionName(disposition?: string) {
187
+ if (!disposition) {
188
+ return undefined;
189
+ }
190
+ const match = disposition.match(/name=\"?([^\";]+)\"?/i);
191
+ return match ? match[1] : undefined;
192
+ }
193
+
194
+ private static replaceFileRefs(value: unknown, fileMap: Map<string, { name?: string; mime?: string; size: number; buffer: ArrayBuffer }>) {
195
+ if (value && typeof value === 'object' && '$file' in value) {
196
+ const fileKey = (value as { $file?: unknown }).$file;
197
+ if (typeof fileKey === 'string') {
198
+ const file = fileMap.get(fileKey);
199
+ if (file) {
200
+ return file;
201
+ }
202
+ }
203
+ }
204
+ if (Array.isArray(value)) {
205
+ return value.map(item => TopicProtocolApiServiceProxy.replaceFileRefs(item, fileMap));
206
+ }
207
+ if (value && typeof value === 'object') {
208
+ const result: Record<string, unknown> = {};
209
+ Object.keys(value).forEach(key => {
210
+ result[key] = TopicProtocolApiServiceProxy.replaceFileRefs((value as Record<string, unknown>)[key], fileMap);
211
+ });
212
+ return result;
213
+ }
214
+ return value;
215
+ }
216
+
217
+ private static normalizeResponse(value: unknown) {
218
+ if (value && typeof value === 'object' && 'state' in value && 'body' in value) {
219
+ const typed = value as { state?: string; body?: unknown };
220
+ if (typed.state === 'error') {
221
+ const message = typeof typed.body === 'object' && typed.body && 'message' in typed.body ? String((typed.body as { message?: unknown }).message) : 'TopicProtocol error';
222
+ throw new Error(message);
223
+ }
224
+ return typed.body;
225
+ }
226
+ return value;
227
+ }
228
+
229
+ static createHandler<T extends object>(apiService: ApiService): ProxyHandler<T> {
230
+ return {
231
+ get(target: T, prop: string | symbol, receiver: unknown): unknown {
232
+ const simConfig = getSim(target);
233
+ const value = Reflect.get(target, prop, receiver);
234
+ if (typeof value === 'function' && simConfig?.symbol) {
235
+ return function (...args: unknown[]) {
236
+ const f = value as Function;
237
+ const p = (userConfig?: TopicProtocolConfig) => {
238
+ const symbolValue = Array.isArray(simConfig.symbol) ? simConfig.symbol[0] : simConfig.symbol;
239
+ const symbolName = (symbolValue as Symbol | undefined)?.description ?? String(symbolValue ?? simConfig.symbol);
240
+ const targetPath = `Symbol.for(${symbolName}):/${String(prop)}`;
241
+ const { request, fileEntries } = TopicProtocolApiServiceProxy.buildRequest(targetPath, userConfig?.body, userConfig?.type ?? 'intent');
242
+ const formData = new FormData();
243
+ formData.append('body', JSON.stringify(request));
244
+ fileEntries.forEach(entry => {
245
+ if (entry.filename) {
246
+ formData.append(entry.id, entry.file, entry.filename);
247
+ } else {
248
+ formData.append(entry.id, entry.file);
249
+ }
250
+ });
251
+
252
+ const headers = {
253
+ ...(userConfig?.headers ?? {}),
254
+ [HttpHeaders.XSimpleBootHttpTopicProtocol]: 'topic'
255
+ };
256
+
257
+ const endpoint = userConfig?.endpoint ?? '/';
258
+ return apiService.post({
259
+ target: endpoint,
260
+ config: {
261
+ responseTransform: userConfig?.bypassTransform
262
+ ? 'response'
263
+ : userConfig?.transformText
264
+ ? 'text'
265
+ : async (response: Response) => {
266
+ const contentType = response.headers.get('Content-Type') ?? '';
267
+ if (contentType.toLowerCase().includes('multipart/mixed')) {
268
+ const parsed = await TopicProtocolApiServiceProxy.parseMultipartMixed(response);
269
+ if (!parsed) {
270
+ return undefined;
271
+ }
272
+ const fileMap = new Map<string, { name?: string; mime?: string; size: number; buffer: ArrayBuffer }>();
273
+ let jsonBody: unknown = undefined;
274
+ parsed.parts.forEach(part => {
275
+ const partType = part.headers['content-type'] ?? '';
276
+ const disposition = part.headers['content-disposition'];
277
+ const name = TopicProtocolApiServiceProxy.parseDispositionName(disposition);
278
+ if (partType.includes('application/json')) {
279
+ const text = new TextDecoder().decode(part.body);
280
+ jsonBody = text ? JSON.parse(text) : undefined;
281
+ return;
282
+ }
283
+ const filename = TopicProtocolApiServiceProxy.parseDispositionFilename(disposition);
284
+ if (name) {
285
+ const view = part.body;
286
+ const safe = new Uint8Array(view.byteLength);
287
+ safe.set(view);
288
+ fileMap.set(name, {
289
+ name: filename,
290
+ mime: partType || 'application/octet-stream',
291
+ size: view.byteLength,
292
+ buffer: safe.buffer
293
+ });
294
+ }
295
+ });
296
+ if (jsonBody) {
297
+ const replaced = TopicProtocolApiServiceProxy.replaceFileRefs(jsonBody, fileMap);
298
+ return TopicProtocolApiServiceProxy.normalizeResponse(replaced);
299
+ }
300
+ return undefined;
301
+ }
302
+ const text = await response.text();
303
+ const parsed = text ? JSON.parse(text) : undefined;
304
+ return TopicProtocolApiServiceProxy.normalizeResponse(parsed);
305
+ },
306
+ transformText: userConfig?.transformText,
307
+ config: userConfig?.config,
308
+ fetch: {
309
+ credentials: 'include',
310
+ headers,
311
+ body: formData
312
+ }
313
+ } as any
314
+ });
315
+ };
316
+ args.push(p);
317
+ return Reflect.apply(f, target, args);
318
+ };
319
+ }
320
+ return value;
321
+ }
322
+ };
323
+ }
324
+
325
+ get(target: T, prop: string | symbol, receiver: unknown): unknown {
326
+ return TopicProtocolApiServiceProxy.createHandler<T>(this.apiService).get!(target, prop, receiver);
327
+ }
328
+ }
@@ -0,0 +1,3 @@
1
+ export * from './SymbolIntentApiServiceProxy';
2
+ export * from './SymbolIntentApiServiceProxyBase';
3
+ export * from './TopicProtocolApiServiceProxy';
@@ -1,7 +1,7 @@
1
1
  import { Resolver } from './Resolver';
2
2
  import { RequestResponse } from '../models/RequestResponse';
3
3
  import { Resource } from '../models/datas/Resource';
4
- import { Sim } from '@dooboostore/simple-boot/decorators/SimDecorator';
4
+ import { Sim } from '@dooboostore/simple-boot';
5
5
 
6
6
  @Sim
7
7
  export class ResourceResolver implements Resolver {
@@ -1,10 +1,10 @@
1
- import {RandomUtils} from '@dooboostore/core/random/RandomUtils'
2
- import {HttpServerOption} from '../option/HttpServerOption';
1
+ import {RandomUtils} from '@dooboostore/core'
2
+ import { HttpServerOption, SessionOption } from '../option/HttpServerOption';
3
3
  import {RequestResponse} from '../models/RequestResponse';
4
4
 
5
5
  export class SessionManager {
6
6
  private sessions = new Map<string, { access: number, data?: any }>();
7
- public sessionOption: { key: string; expiredTime: number, provider?: {uuids: () => Promise<string[]>, delete: (uuid: string) => Promise<void>, get: (uuid: string) => Promise<{ access: number, data?: any }>, set: (uuid: string, data: { access: number, data?: any }) => Promise<void>} };
7
+ public sessionOption: SessionOption;
8
8
 
9
9
  constructor(private option: HttpServerOption) {
10
10
  this.sessionOption = option.sessionOption;