taon 21.0.52 → 21.0.54

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 (193) hide show
  1. package/browser/package.json +1 -1
  2. package/browser-prod/package.json +1 -1
  3. package/icon-menu-taon.svg +15 -15
  4. package/lib/build-info._auto-generated_.d.ts +1 -1
  5. package/lib/build-info._auto-generated_.js +1 -1
  6. package/lib/package.json +1 -1
  7. package/lib/ui/index.js +2 -2
  8. package/lib/ui/taon-admin-mode-configuration/index.js +2 -2
  9. package/lib-prod/base-classes/base-abstract-entity.js +19 -0
  10. package/lib-prod/base-classes/base-angular-service.js +84 -0
  11. package/lib-prod/base-classes/base-class.js +35 -0
  12. package/lib-prod/base-classes/{base-context.ts → base-context.js} +13 -15
  13. package/lib-prod/base-classes/base-controller.js +154 -0
  14. package/lib-prod/base-classes/base-crud-controller.js +264 -0
  15. package/lib-prod/base-classes/base-custom-repository.js +9 -0
  16. package/lib-prod/base-classes/{base-electron-service.ts → base-electron-service.js} +1 -12
  17. package/lib-prod/base-classes/base-entity.js +22 -0
  18. package/lib-prod/base-classes/base-file-upload.middleware.js +75 -0
  19. package/lib-prod/base-classes/base-injector.js +184 -0
  20. package/lib-prod/base-classes/base-middleware.js +9 -0
  21. package/lib-prod/base-classes/base-migration.js +20 -0
  22. package/lib-prod/base-classes/{base-provider.ts → base-provider.js} +2 -2
  23. package/lib-prod/base-classes/base-repository.js +617 -0
  24. package/lib-prod/base-classes/base-subscriber-for-entity.js +145 -0
  25. package/lib-prod/base-classes/{base.ts → base.js} +2 -15
  26. package/lib-prod/{build-info._auto-generated_.ts → build-info._auto-generated_.js} +1 -2
  27. package/lib-prod/config/controller-config.js +28 -0
  28. package/lib-prod/config/controller-options.js +3 -0
  29. package/lib-prod/config/method-config.js +7 -0
  30. package/lib-prod/config/param-config.js +3 -0
  31. package/lib-prod/constants.js +33 -0
  32. package/lib-prod/context-db-migrations.js +342 -0
  33. package/lib-prod/create-context.js +217 -0
  34. package/lib-prod/decorators/classes/controller-decorator.js +17 -0
  35. package/lib-prod/decorators/classes/entity-decorator.js +28 -0
  36. package/lib-prod/decorators/classes/middleware-decorator.js +16 -0
  37. package/lib-prod/decorators/classes/migration-decorator.js +15 -0
  38. package/lib-prod/decorators/classes/provider-decorator.js +15 -0
  39. package/lib-prod/decorators/classes/repository-decorator.js +15 -0
  40. package/lib-prod/decorators/classes/subscriber-decorator.js +15 -0
  41. package/lib-prod/decorators/decorator-abstract-opt.js +2 -0
  42. package/lib-prod/decorators/http/http-decorators.js +20 -0
  43. package/lib-prod/decorators/http/http-methods-decorators.js +102 -0
  44. package/lib-prod/decorators/http/http-params-decorators.js +42 -0
  45. package/lib-prod/dependency-injection/di-container.js +30 -0
  46. package/lib-prod/endpoint-context-storage.js +31 -0
  47. package/lib-prod/endpoint-context.js +2397 -0
  48. package/lib-prod/entity-process.js +225 -0
  49. package/lib-prod/env/{env.angular-node-app.ts → env.angular-node-app.js} +1 -1
  50. package/lib-prod/env/{env.docs-webapp.ts → env.docs-webapp.js} +1 -1
  51. package/lib-prod/env/{env.electron-app.ts → env.electron-app.js} +1 -1
  52. package/lib-prod/env/{env.mobile-app.ts → env.mobile-app.js} +1 -1
  53. package/lib-prod/env/{env.npm-lib-and-cli-tool.ts → env.npm-lib-and-cli-tool.js} +1 -1
  54. package/lib-prod/env/{env.vscode-plugin.ts → env.vscode-plugin.js} +1 -1
  55. package/lib-prod/express-types.js +1 -0
  56. package/lib-prod/formly/formly.models.js +1 -0
  57. package/lib-prod/formly/fromly.js +205 -0
  58. package/lib-prod/formly/type-from-entity.js +51 -0
  59. package/lib-prod/get-response-value.js +22 -0
  60. package/lib-prod/global-state/taon-global-state/{index.ts → index.js} +2 -2
  61. package/lib-prod/global-state/taon-global-state/{taon-global-state.abstract.context.ts → taon-global-state.abstract.context.js} +9 -11
  62. package/lib-prod/global-state/taon-global-state/taon-global-state.constants.js +7 -0
  63. package/lib-prod/global-state/taon-global-state/taon-global-state.controller.js +42 -0
  64. package/lib-prod/global-state/taon-global-state/taon-global-state.entity.js +35 -0
  65. package/lib-prod/global-state/taon-global-state/taon-global-state.middleware.js +12 -0
  66. package/lib-prod/global-state/taon-global-state/taon-global-state.models.js +44 -0
  67. package/lib-prod/global-state/taon-global-state/taon-global-state.provider.js +12 -0
  68. package/lib-prod/global-state/taon-global-state/taon-global-state.repository.js +46 -0
  69. package/lib-prod/global-state/taon-global-state/taon-global-state.subscriber.js +22 -0
  70. package/lib-prod/global-state/taon-global-state/taon-global-state.utils.js +11 -0
  71. package/lib-prod/global-state/taon-transaction-registry/{index.ts → index.js} +2 -2
  72. package/lib-prod/global-state/taon-transaction-registry/{taon-transaction-registry.abstract.context.ts → taon-transaction-registry.abstract.context.js} +10 -12
  73. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.constants.js +5 -0
  74. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.controller.js +36 -0
  75. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.entity.js +36 -0
  76. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.middleware.js +12 -0
  77. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.models.js +7 -0
  78. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.provider.js +12 -0
  79. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.repository.js +31 -0
  80. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.subscriber.js +22 -0
  81. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.utils.js +5 -0
  82. package/lib-prod/helpers/class-helpers.js +228 -0
  83. package/lib-prod/helpers/clone-obj.js +17 -0
  84. package/lib-prod/helpers/taon-helpers.js +147 -0
  85. package/lib-prod/{index._auto-generated_.ts → index._auto-generated_.js} +1 -1
  86. package/lib-prod/index.js +252 -0
  87. package/lib-prod/{inject.ts → inject.js} +35 -57
  88. package/lib-prod/migrations/index.js +2 -0
  89. package/lib-prod/migrations/{migrations_index._auto-generated_.ts → migrations_index._auto-generated_.js} +0 -2
  90. package/lib-prod/models.js +78 -0
  91. package/lib-prod/orm/columns.js +64 -0
  92. package/lib-prod/orm/index.js +56 -0
  93. package/lib-prod/package.json +1 -1
  94. package/lib-prod/realtime/realtime-client.js +198 -0
  95. package/lib-prod/realtime/realtime-core.js +81 -0
  96. package/lib-prod/realtime/realtime-server.js +237 -0
  97. package/lib-prod/realtime/realtime-strategy/{index.ts → index.js} +1 -1
  98. package/lib-prod/realtime/realtime-strategy/realtime-strategy-ipc.js +280 -0
  99. package/lib-prod/realtime/realtime-strategy/realtime-strategy-mock.js +289 -0
  100. package/lib-prod/realtime/realtime-strategy/realtime-strategy-socket-io.js +27 -0
  101. package/lib-prod/realtime/realtime-strategy/realtime-strategy.js +11 -0
  102. package/lib-prod/realtime/realtime-subs-manager.js +88 -0
  103. package/lib-prod/realtime/realtime.models.js +2 -0
  104. package/lib-prod/symbols.js +108 -0
  105. package/lib-prod/ui/index.js +1 -0
  106. package/lib-prod/ui/taon-admin-mode-configuration/index.js +1 -0
  107. package/lib-prod/validators.js +80 -0
  108. package/lib-prod.split-namespaces.json +31 -91
  109. package/package.json +1 -1
  110. package/websql/package.json +1 -1
  111. package/websql-prod/package.json +1 -1
  112. package/lib-prod/base-classes/base-abstract-entity.ts +0 -34
  113. package/lib-prod/base-classes/base-angular-service.ts +0 -107
  114. package/lib-prod/base-classes/base-class.ts +0 -46
  115. package/lib-prod/base-classes/base-controller.ts +0 -240
  116. package/lib-prod/base-classes/base-crud-controller.ts +0 -298
  117. package/lib-prod/base-classes/base-custom-repository.ts +0 -10
  118. package/lib-prod/base-classes/base-entity.ts +0 -28
  119. package/lib-prod/base-classes/base-file-upload.middleware.ts +0 -92
  120. package/lib-prod/base-classes/base-injector.ts +0 -278
  121. package/lib-prod/base-classes/base-middleware.ts +0 -71
  122. package/lib-prod/base-classes/base-migration.ts +0 -26
  123. package/lib-prod/base-classes/base-repository.ts +0 -942
  124. package/lib-prod/base-classes/base-subscriber-for-entity.ts +0 -196
  125. package/lib-prod/config/controller-config.ts +0 -58
  126. package/lib-prod/config/controller-options.ts +0 -19
  127. package/lib-prod/config/method-config.ts +0 -55
  128. package/lib-prod/config/param-config.ts +0 -16
  129. package/lib-prod/constants.ts +0 -63
  130. package/lib-prod/context-db-migrations.ts +0 -488
  131. package/lib-prod/create-context.ts +0 -345
  132. package/lib-prod/decorators/classes/controller-decorator.ts +0 -25
  133. package/lib-prod/decorators/classes/entity-decorator.ts +0 -57
  134. package/lib-prod/decorators/classes/middleware-decorator.ts +0 -29
  135. package/lib-prod/decorators/classes/migration-decorator.ts +0 -27
  136. package/lib-prod/decorators/classes/provider-decorator.ts +0 -28
  137. package/lib-prod/decorators/classes/repository-decorator.ts +0 -26
  138. package/lib-prod/decorators/classes/subscriber-decorator.ts +0 -28
  139. package/lib-prod/decorators/decorator-abstract-opt.ts +0 -4
  140. package/lib-prod/decorators/http/http-decorators.ts +0 -26
  141. package/lib-prod/decorators/http/http-methods-decorators.ts +0 -275
  142. package/lib-prod/decorators/http/http-params-decorators.ts +0 -105
  143. package/lib-prod/dependency-injection/di-container.ts +0 -39
  144. package/lib-prod/endpoint-context-storage.ts +0 -47
  145. package/lib-prod/endpoint-context.ts +0 -3110
  146. package/lib-prod/entity-process.ts +0 -286
  147. package/lib-prod/express-types.ts +0 -4
  148. package/lib-prod/formly/formly.models.ts +0 -7
  149. package/lib-prod/formly/fromly.ts +0 -261
  150. package/lib-prod/formly/type-from-entity.ts +0 -80
  151. package/lib-prod/get-response-value.ts +0 -30
  152. package/lib-prod/global-state/taon-global-state/taon-global-state.constants.ts +0 -9
  153. package/lib-prod/global-state/taon-global-state/taon-global-state.controller.ts +0 -44
  154. package/lib-prod/global-state/taon-global-state/taon-global-state.entity.ts +0 -40
  155. package/lib-prod/global-state/taon-global-state/taon-global-state.middleware.ts +0 -12
  156. package/lib-prod/global-state/taon-global-state/taon-global-state.models.ts +0 -48
  157. package/lib-prod/global-state/taon-global-state/taon-global-state.provider.ts +0 -16
  158. package/lib-prod/global-state/taon-global-state/taon-global-state.repository.ts +0 -47
  159. package/lib-prod/global-state/taon-global-state/taon-global-state.subscriber.ts +0 -18
  160. package/lib-prod/global-state/taon-global-state/taon-global-state.utils.ts +0 -21
  161. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.constants.ts +0 -7
  162. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.controller.ts +0 -38
  163. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.entity.ts +0 -54
  164. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.middleware.ts +0 -12
  165. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.models.ts +0 -6
  166. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.provider.ts +0 -16
  167. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.repository.ts +0 -29
  168. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.subscriber.ts +0 -20
  169. package/lib-prod/global-state/taon-transaction-registry/taon-transaction-registry.utils.ts +0 -9
  170. package/lib-prod/helpers/class-helpers.ts +0 -315
  171. package/lib-prod/helpers/clone-obj.ts +0 -24
  172. package/lib-prod/helpers/taon-helpers.ts +0 -181
  173. package/lib-prod/index.ts +0 -323
  174. package/lib-prod/lib-info.md +0 -8
  175. package/lib-prod/migrations/index.ts +0 -2
  176. package/lib-prod/migrations/migrations-info.md +0 -6
  177. package/lib-prod/models.ts +0 -427
  178. package/lib-prod/orm/columns.ts +0 -121
  179. package/lib-prod/orm/index.ts +0 -62
  180. package/lib-prod/realtime/realtime-client.ts +0 -288
  181. package/lib-prod/realtime/realtime-core.ts +0 -134
  182. package/lib-prod/realtime/realtime-server.ts +0 -398
  183. package/lib-prod/realtime/realtime-strategy/realtime-strategy-ipc.ts +0 -344
  184. package/lib-prod/realtime/realtime-strategy/realtime-strategy-mock.ts +0 -349
  185. package/lib-prod/realtime/realtime-strategy/realtime-strategy-socket-io.ts +0 -30
  186. package/lib-prod/realtime/realtime-strategy/realtime-strategy.ts +0 -21
  187. package/lib-prod/realtime/realtime-subs-manager.ts +0 -127
  188. package/lib-prod/realtime/realtime.models.ts +0 -33
  189. package/lib-prod/symbols.ts +0 -136
  190. package/lib-prod/ui/index.ts +0 -1
  191. package/lib-prod/ui/taon-admin-mode-configuration/index.ts +0 -1
  192. package/lib-prod/validators.ts +0 -103
  193. /package/lib-prod/env/{index.ts → index.js} +0 -0
@@ -0,0 +1,2397 @@
1
+ import { URL } from 'url'; // @backend
2
+ import axios from 'axios';
3
+ import { ipcMain } from 'electron'; // @backend
4
+ import { JSON10 } from 'json10/lib-prod';
5
+ import { walk } from 'lodash-walk-object/lib-prod';
6
+ import { Resource, RestHeaders, Mapping__NS__decode, Mapping__NS__encode } from 'ng2-rest/lib-prod';
7
+ import { from } from 'rxjs';
8
+ import { EventSubscriber } from 'taon-typeorm/lib-prod'; // @websql
9
+ import { Entity as TypeormEntity } from 'taon-typeorm/lib-prod'; // @websql
10
+ import { DataSource, } from 'taon-typeorm/lib-prod';
11
+ import { path, requireDefault } from 'tnp-core/lib-prod';
12
+ import { config } from 'tnp-core/lib-prod';
13
+ import { CoreModels__NS__TaonHttpErrorCustomProp } from 'tnp-core/lib-prod';
14
+ import { fse, http, https } from 'tnp-core/lib-prod'; // @backend
15
+ import { Utils__NS__uniqArray, UtilsOs__NS__getRealHomeDir, UtilsOs__NS__isBrowser, UtilsOs__NS__isElectron, UtilsOs__NS__isNode, UtilsOs__NS__isRunningInCliMode, UtilsOs__NS__isRunningInDocker, UtilsOs__NS__isWebSQL } from 'tnp-core/lib-prod';
16
+ import { crossPlatformPath } from 'tnp-core/lib-prod';
17
+ import { ___NS__cloneDeep, ___NS__first, ___NS__isBoolean, ___NS__isFunction, ___NS__isNil, ___NS__isObject, ___NS__isString, ___NS__isUndefined, ___NS__last, ___NS__set, ___NS__slice, ___NS__snakeCase, ___NS__startCase, Helpers__NS__error, Helpers__NS__exists, Helpers__NS__info, Helpers__NS__log, Helpers__NS__mkdirp, Helpers__NS__throwError, Helpers__NS__writeFile } from 'tnp-core/lib-prod';
18
+ import { apiPrefix } from './constants';
19
+ import { ContextDbMigrations } from './context-db-migrations';
20
+ import { DITaonContainer } from './dependency-injection/di-container';
21
+ import { EntityProcess } from './entity-process';
22
+ import { getResponseValue } from './get-response-value';
23
+ import { ClassHelpers__NS__asyncHandler, ClassHelpers__NS__getControllerConfigs, ClassHelpers__NS__getMethodsNames, ClassHelpers__NS__getName, ClassHelpers__NS__getOrginalClass } from './helpers/class-helpers';
24
+ import { TaonHelpers__NS__fillUpTo, TaonHelpers__NS__firstStringOrElemFromArray, TaonHelpers__NS__getExpressPath, TaonHelpers__NS__ipcKeyNameRequest, TaonHelpers__NS__ipcKeyNameResponse, TaonHelpers__NS__isGoodPath, TaonHelpers__NS__parseJSONwithStringJSONs, TaonHelpers__NS__tryTransformParam, TaonHelpers__NS__websqlMocks } from './helpers/taon-helpers';
25
+ import { Models__NS__ClassTypeKey, Models__NS__DatabasesFolder } from './models';
26
+ import { RealtimeCore } from './realtime/realtime-core';
27
+ import { Symbols__NS__classMethodsNames, Symbols__NS__classNameStaticProperty, Symbols__NS__ctxInClassOrClassObj, Symbols__NS__fullClassNameStaticProperty, Symbols__NS__metadata, Symbols__NS__old, Symbols__NS__orignalClass } from './symbols';
28
+ /* */
29
+ //#endregion
30
+ let bodyParser;
31
+ let cookieParser;
32
+ let cors;
33
+ let express;
34
+ let methodOverride;
35
+ let expressSession;
36
+ //#region @backend
37
+ bodyParser = requireDefault('body-parser');
38
+ cookieParser = requireDefault('cookie-parser');
39
+ cors = requireDefault('cors');
40
+ express = requireDefault('express');
41
+ methodOverride = requireDefault('method-override');
42
+ expressSession = requireDefault('express-session');
43
+ //#endregion
44
+ export class EndpointContext {
45
+ //#endregion
46
+ //#endregion
47
+ //#region fields / source context
48
+ get sourceContext() {
49
+ return this.cloneOptions?.sourceContext;
50
+ }
51
+ get isRunOrRevertOnlyMigrationAppStart() {
52
+ return !!(this.onlyMigrationRun || this.onlyMigrationRevertToTimestamp);
53
+ }
54
+ get realtimeClient() {
55
+ return this.realtime.client;
56
+ }
57
+ get realtimeServer() {
58
+ return this.realtime.server;
59
+ }
60
+ //#endregion
61
+ //#region fields / logs
62
+ get logHttp() {
63
+ if (___NS__isObject(this.config?.logs)) {
64
+ return !!this.config.logs.http;
65
+ }
66
+ return this.config?.logs === true;
67
+ }
68
+ get logRealtime() {
69
+ if (___NS__isObject(this.config?.logs)) {
70
+ return !!this.config.logs.realtime;
71
+ }
72
+ return this.config?.logs === true;
73
+ }
74
+ get logFramework() {
75
+ if (___NS__isObject(this.config?.logs)) {
76
+ return !!this.config.logs.framework;
77
+ }
78
+ return this.config?.logs === true;
79
+ }
80
+ get logRoutes() {
81
+ if (___NS__isObject(this.config?.logs)) {
82
+ return !!this.config.logs.routes;
83
+ }
84
+ return this.config?.logs === true;
85
+ }
86
+ get logDb() {
87
+ if (___NS__isObject(this.config?.logs)) {
88
+ return !!this.config.logs.db;
89
+ }
90
+ return this.config?.logs === true;
91
+ }
92
+ get logMigrations() {
93
+ if (___NS__isObject(this.config?.logs)) {
94
+ return !!this.config.logs.migrations;
95
+ }
96
+ return this.config?.logs === true;
97
+ }
98
+ constructor(originalConfig, configFn,
99
+ /**
100
+ * (@default: false)
101
+ * If TRUE context is NOT going to create db/express server/http endpoints
102
+ * PURPOSE OF THIS PROPERTY
103
+ * -> ONLY remote access from backend or frontend to specific backend
104
+ */
105
+ cloneOptions) {
106
+ this.originalConfig = originalConfig;
107
+ this.configFn = configFn;
108
+ this.cloneOptions = cloneOptions;
109
+ //#region fields
110
+ //#region fields / use mariadb mysql in docker
111
+ /**
112
+ * JUST FOR TESTING PURPOSES
113
+ */
114
+ this.USE_MARIADB_MYSQL_IN_DOCKER = false;
115
+ //#endregion
116
+ //#region fields / flags
117
+ this.disabledRealtime = false;
118
+ /**
119
+ * check whether context is inited
120
+ * (with init() function )
121
+ */
122
+ this.inited = false;
123
+ //#endregion
124
+ //#region fields / db migrations
125
+ this.dbMigrations = new ContextDbMigrations(this);
126
+ //#endregion
127
+ //#region fields / local instance obj symbol
128
+ this.localInstaceObjSymbol = Symbol('localInstaceObjSymbol');
129
+ //#endregion
130
+ //#region fields / all instances of classes from context
131
+ /**
132
+ * all instances of classes from context
133
+ * key is class name
134
+ */
135
+ this.allClassesInstances = {};
136
+ //#endregion
137
+ //#region fields / class instances by name
138
+ this.classInstancesByNameObj = {};
139
+ //#endregion
140
+ //#region fields / obj with classes instances arr
141
+ this.objWithClassesInstancesArr = {};
142
+ //#endregion
143
+ //#region fields / active routes
144
+ this.activeRoutes = [];
145
+ //#endregion
146
+ //#region fields / typeorm repositories
147
+ //#region @websql
148
+ this.repos = new Map();
149
+ //#endregion
150
+ //#region fields / skip writing server routes
151
+ this.skipWritingServerRoutes = false;
152
+ //#endregion
153
+ //#region fields / types from contexts
154
+ this.injectableTypesfromContexts = [
155
+ Models.ClassType.CONTROLLER,
156
+ Models.ClassType.PROVIDER,
157
+ Models.ClassType.MIDDLEWARE,
158
+ Models.ClassType.REPOSITORY,
159
+ Models.ClassType.SUBSCRIBER,
160
+ Models.ClassType.MIGRATION,
161
+ ];
162
+ //#endregion
163
+ //#region fields / all types from contexts
164
+ this.allTypesfromContexts = [
165
+ ...this.injectableTypesfromContexts,
166
+ Models.ClassType.ENTITY,
167
+ ];
168
+ //#endregion
169
+ //#region fields / express app
170
+ this.expressApp = {};
171
+ //#endregion
172
+ //#region fields / only migration start
173
+ this.onlyMigrationRun = false;
174
+ this.onlyMigrationRevertToTimestamp = undefined;
175
+ //#endregion
176
+ //#region fields / entities triggers
177
+ this.entitiesTriggers = {};
178
+ //#endregion
179
+ //#endregion
180
+ //#region constructor
181
+ /**
182
+ * Inside docker there is not need for https secure server
183
+ */
184
+ this.isRunningInsideDocker = false;
185
+ //#endregion
186
+ //#region methods & getters / clone class
187
+ this.cloneClassWithNewMetadata = ({ TaonBaseClass, className, config, ctx, classType, }) => {
188
+ // Return a new class that extends the base class
189
+ const cloneClass = () => {
190
+ var _a, _b, _c, _d, _e;
191
+ if (TaonBaseClass[Symbols__NS__fullClassNameStaticProperty] ===
192
+ `${ctx.contextName}.${className}`) {
193
+ return TaonBaseClass;
194
+ }
195
+ return class extends TaonBaseClass {
196
+ constructor() {
197
+ // static ['_'] = TaonBaseClass['_'];
198
+ super(...arguments);
199
+ this[_e] = ctx;
200
+ // You can override prototype properties or methods here if needed
201
+ // static properties override allowed
202
+ }
203
+ static { _a = Symbols__NS__orignalClass, _b = Symbols__NS__fullClassNameStaticProperty, _c = Symbols__NS__classNameStaticProperty, _d = Symbols__NS__ctxInClassOrClassObj, _e = Symbols__NS__ctxInClassOrClassObj; }
204
+ // @ts-ignore
205
+ static { this[_a] = TaonBaseClass; }
206
+ // @ts-ignore
207
+ static { this[_b] = `${ctx.contextName}.${className}`; }
208
+ // @ts-ignore
209
+ static { this[_c] = className; }
210
+ static { this[_d] = ctx; }
211
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
212
+ static __getFullPathForClass__(arr = []) {
213
+ const name = this[Symbols__NS__fullClassNameStaticProperty];
214
+ arr.push(name);
215
+ // @ts-ignore
216
+ if (this[Symbols__NS__orignalClass] && // @ts-ignore
217
+ this[Symbols__NS__orignalClass].__getFullPathForClass__) {
218
+ // @ts-ignore
219
+ this[Symbols__NS__orignalClass].__getFullPathForClass__(arr);
220
+ }
221
+ return arr.join('/');
222
+ }
223
+ static get fullPathForClass() {
224
+ return this.__getFullPathForClass__();
225
+ }
226
+ };
227
+ };
228
+ const cloneClassFunction = cloneClass();
229
+ //#region gather all instances for all contexts
230
+ // TODO this is not needed anymore - for typeorm I use normal entities
231
+ // this thinng belowe is nice for debugging purpose
232
+ // if (___NS__isUndefined(cloneClassFunction[Symbols__NS__orignalClassClonesObj])) {
233
+ // cloneClassFunction[Symbols__NS__orignalClassClonesObj] = {};
234
+ // }
235
+ // if (___NS__isUndefined(TaonBaseClass[Symbols__NS__orignalClassClonesObj])) {
236
+ // TaonBaseClass[Symbols__NS__orignalClassClonesObj] = {};
237
+ // }
238
+ // const all = {
239
+ // ...TaonBaseClass[Symbols__NS__orignalClassClonesObj],
240
+ // ...cloneClassFunction[Symbols__NS__orignalClassClonesObj],
241
+ // };
242
+ // all[ctx.contextName] = cloneClassFunction;
243
+ // cloneClassFunction[Symbols__NS__orignalClassClonesObj] = all;
244
+ // TaonBaseClass[Symbols__NS__orignalClassClonesObj] = all;
245
+ //#endregion
246
+ return cloneClassFunction;
247
+ };
248
+ //#endregion
249
+ //#region methods & getters / clone classes obj with new metadata
250
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
251
+ this.cloneClassesObjWithNewMetadata = ({ classesInput, config, ctx, classType, }) => {
252
+ const classes = {};
253
+ // console.log(Object.keys(classesInput))
254
+ for (const key of Object.keys(classesInput || {})) {
255
+ const TaonBaseClass = classesInput[key];
256
+ if (!TaonBaseClass) {
257
+ Helpers__NS__error(`Class ${key} is not defined in context ${ctx.contextName}
258
+
259
+ Please check if you have correct import in context file
260
+
261
+ `);
262
+ }
263
+ var className = Reflect.getMetadata(Symbols__NS__metadata.className, TaonBaseClass);
264
+ // console.log('Metadata className', className, TaonBaseClass);
265
+ // if (!className) {
266
+ // console.warn(`Please provide className for ${TaonBaseClass.name} class`);
267
+ // }
268
+ className = className || key;
269
+ TaonBaseClass[Symbols__NS__classNameStaticProperty] = className;
270
+ const clonedClass = this.cloneClassWithNewMetadata({
271
+ TaonBaseClass,
272
+ className,
273
+ config,
274
+ ctx,
275
+ classType,
276
+ });
277
+ classes[className] = clonedClass;
278
+ }
279
+ return classes;
280
+ };
281
+ this.cloneOptions = this.cloneOptions || {};
282
+ this.isRunningInsideDocker = UtilsOs__NS__isRunningInDocker();
283
+ }
284
+ //#endregion
285
+ //#region methods & getters / init
286
+ async init(options) {
287
+ const { initFromRecrusiveContextResovle, onlyMigrationRun, onlyMigrationRevertToTimestamp, } = options || {}; // TODO use it ?
288
+ this.inited = true;
289
+ // @ts-ignore
290
+ this.onlyMigrationRun = onlyMigrationRun;
291
+ // @ts-ignore
292
+ this.onlyMigrationRevertToTimestamp = onlyMigrationRevertToTimestamp;
293
+ this.config = this.configFn({});
294
+ if (___NS__isObject(this.config.database)) {
295
+ this.config.database = Models.DatabaseConfig.from(this.config.database).databaseConfigTypeORM;
296
+ }
297
+ this.config.host = this.host === null ? void 0 : this.host;
298
+ if (this.cloneOptions.overrideHost &&
299
+ !this.cloneOptions.useAsRemoteContext) {
300
+ this.config.host = this.cloneOptions.overrideHost;
301
+ }
302
+ if (this.cloneOptions.overrideRemoteHost &&
303
+ this.cloneOptions.useAsRemoteContext) {
304
+ this.config.host = this.cloneOptions.overrideRemoteHost;
305
+ }
306
+ if (this.config.host &&
307
+ !this.config.host.startsWith('http://') &&
308
+ !this.config.host.startsWith('https://')) {
309
+ Helpers__NS__throwError(`[taon-config] Your${this.host ? ' remote' : ''} 'host' must start with http:// or https://`);
310
+ }
311
+ if (___NS__isUndefined(this.config.useIpcWhenElectron)) {
312
+ this.config.useIpcWhenElectron = true;
313
+ }
314
+ // console.log(`config for ${this.contextName}`, this.config);
315
+ //#region resolve if skipping writing server routes
316
+ //@ts-expect-error overriding readonly
317
+ this.skipWritingServerRoutes = ___NS__isBoolean(this.config.skipWritingServerRoutes)
318
+ ? this.config.skipWritingServerRoutes
319
+ : false;
320
+ //#endregion
321
+ //#region resolve mode
322
+ if (this.config.host) {
323
+ this.mode = 'backend-frontend(tcp+udp)';
324
+ /* */
325
+ /* */
326
+ }
327
+ if (this.isRemoteHost) {
328
+ this.mode = 'remote-backend(tcp+udp)';
329
+ }
330
+ // console.log(`
331
+ // useIpcWhenElectron: ${this.config.useIpcWhenElectron}
332
+ // UtilsOs__NS__isElectron: ${UtilsOs__NS__isElectron}
333
+ // `)
334
+ if (this.config.useIpcWhenElectron && UtilsOs__NS__isElectron) {
335
+ if (UtilsOs__NS__isWebSQL) {
336
+ this.mode = 'backend-frontend(websql-electron)';
337
+ }
338
+ else {
339
+ this.mode = 'backend-frontend(ipc-electron)';
340
+ }
341
+ }
342
+ // mode === undefined for TaonBaseContext => ok behavior
343
+ // console.log(`Mode for BE/FE communication: ${this.mode}`);
344
+ // if(!this.mode) {
345
+ // console.log(this.config)
346
+ // }
347
+ if (!this.mode && !this.config.abstract) {
348
+ const errMsg = `You need to provide host property or ` +
349
+ `useIpcWhenElectron or mark it as abstract`;
350
+ Helpers__NS__error(`[taon][Context=${this.contextName}]: ${errMsg}`, false, true);
351
+ //#region @backend
352
+ process.exit(1);
353
+ //#endregion
354
+ }
355
+ //#endregion
356
+ //#region resolve database config
357
+ if (this.config.database === true) {
358
+ this.logFramework &&
359
+ console.log(`
360
+
361
+ ASSIGNING AUTO GENERATED DATABASE CONFIG
362
+
363
+ `);
364
+ this.databaseConfig = this.getAutoGeneratedConfig();
365
+ }
366
+ else if (___NS__isObject(this.config.database)) {
367
+ this.logFramework &&
368
+ console.log(`
369
+
370
+ OVERRIDE DATABASE CONFIG FROM CONFIGURATION
371
+
372
+ `);
373
+ this.databaseConfig = this.getAutoGeneratedConfig();
374
+ walk.Object(this.config.database, (value, lodashPath) => {
375
+ if (___NS__isNil(value) || ___NS__isFunction(value) || ___NS__isObject(value)) {
376
+ // skipping
377
+ }
378
+ else {
379
+ this.logFramework &&
380
+ console.info(`Overriding database config: ${lodashPath}=${value}`);
381
+ ___NS__set(this.databaseConfig, lodashPath, value);
382
+ }
383
+ }, {
384
+ walkGetters: false,
385
+ });
386
+ }
387
+ //#endregion
388
+ //#region resolve session
389
+ if (this.config.session) {
390
+ this.session = ___NS__cloneDeep(this.config.session);
391
+ const oneHour = 1000 * 60 * 60 * 1; // 24;
392
+ if (!this.session.cookieMaxAge) {
393
+ this.session.cookieMaxAge = oneHour;
394
+ }
395
+ // serever and browser cookie authentication
396
+ axios.defaults.withCredentials = true;
397
+ }
398
+ //#endregion
399
+ //#region prepare & gather all classes recursively
400
+ this.config.contexts = this.config.contexts || {};
401
+ this.config.entities = this.config.entities || {};
402
+ this.config.controllers = this.config.controllers || {};
403
+ this.config.repositories = this.config.repositories || {};
404
+ this.config.providers = this.config.providers || {};
405
+ this.config.subscribers = this.config.subscribers || {};
406
+ this.config.migrations = this.config.migrations || {};
407
+ this.config.entities = {
408
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.ENTITY)),
409
+ ...this.config.entities,
410
+ };
411
+ this.config.controllers = {
412
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.CONTROLLER)),
413
+ ...this.config.controllers,
414
+ };
415
+ this.config.providers = {
416
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.PROVIDER)),
417
+ ...this.config.providers,
418
+ };
419
+ this.config.middlewares = {
420
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.MIDDLEWARE)),
421
+ ...this.config.middlewares,
422
+ };
423
+ this.config.subscribers = {
424
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.SUBSCRIBER)),
425
+ ...this.config.subscribers,
426
+ };
427
+ this.config.repositories = {
428
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.REPOSITORY)),
429
+ ...this.config.repositories,
430
+ };
431
+ this.config.migrations = {
432
+ ...(await this.getRecrusiveClassesfromContextsObj(Models.ClassType.MIGRATION)),
433
+ ...this.config.migrations,
434
+ };
435
+ // console.log(this.config);
436
+ // debugger;
437
+ //#endregion
438
+ //#region prepare classes instances/functions clones
439
+ this.config.controllers = this.cloneClassesObjWithNewMetadata({
440
+ classesInput: this.config.controllers,
441
+ config: this.config,
442
+ ctx: this,
443
+ classType: Models.ClassType.CONTROLLER,
444
+ });
445
+ this.config.repositories = this.cloneClassesObjWithNewMetadata({
446
+ classesInput: this.config.repositories,
447
+ config: this.config,
448
+ ctx: this,
449
+ classType: Models.ClassType.REPOSITORY,
450
+ });
451
+ this.config.providers = this.cloneClassesObjWithNewMetadata({
452
+ classesInput: this.config.providers,
453
+ config: this.config,
454
+ ctx: this,
455
+ classType: Models.ClassType.PROVIDER,
456
+ });
457
+ this.config.middlewares = this.cloneClassesObjWithNewMetadata({
458
+ classesInput: this.config.middlewares,
459
+ config: this.config,
460
+ ctx: this,
461
+ classType: Models.ClassType.MIDDLEWARE,
462
+ });
463
+ this.config.subscribers = this.cloneClassesObjWithNewMetadata({
464
+ classesInput: this.config.subscribers,
465
+ config: this.config,
466
+ ctx: this,
467
+ classType: Models.ClassType.SUBSCRIBER,
468
+ });
469
+ this.config.migrations = this.cloneClassesObjWithNewMetadata({
470
+ classesInput: this.config.migrations,
471
+ config: this.config,
472
+ ctx: this,
473
+ classType: Models.ClassType.MIGRATION,
474
+ });
475
+ //#endregion
476
+ //#region prepare instances
477
+ for (const classTypeName of this.injectableTypesfromContexts) {
478
+ this.classInstancesByNameObj[classTypeName] = {};
479
+ this.objWithClassesInstancesArr[classTypeName] = [];
480
+ }
481
+ for (const classTypeName of this.injectableTypesfromContexts) {
482
+ await this.createInstances(this.config[Models__NS__ClassTypeKey[classTypeName]], classTypeName);
483
+ }
484
+ //#endregion
485
+ if (!this.isRunOrRevertOnlyMigrationAppStart) {
486
+ //#region prepares server
487
+ if (this.mode === 'backend-frontend(tcp+udp)' && !this.config.abstract) {
488
+ //#region @backend
489
+ this.expressApp = express();
490
+ if (process.env.NODE_ENV === 'production') {
491
+ this.expressApp.set('trust proxy', 1);
492
+ }
493
+ await this.initBackendMiddlewares();
494
+ await this.initCustomBackendMiddlewares();
495
+ const shouldStartHttpsSecureServer = this.isHttpServer && !this.isRunningInsideDocker;
496
+ this.logFramework &&
497
+ Helpers__NS__info(`
498
+
499
+ Starting server ${shouldStartHttpsSecureServer ? 'with' : 'without'} HTTPS secure server
500
+
501
+ `);
502
+ this.serverTcpUdp = shouldStartHttpsSecureServer
503
+ ? new https.Server({
504
+ key: this.config.https?.key,
505
+ cert: this.config.https?.cert,
506
+ }, this.expressApp)
507
+ : new http.Server(this.expressApp);
508
+ this.publicAssets.forEach(asset => {
509
+ this.expressApp.use(asset.serverPath, express.static(asset.locationOnDisk));
510
+ });
511
+ //#endregion
512
+ await this.initCustomClientMiddlewares();
513
+ }
514
+ //#endregion
515
+ //#region prepare realtime
516
+ if (!this.config.abstract) {
517
+ this.disabledRealtime = this.config.disabledRealtime;
518
+ if (!this.host) {
519
+ throw `
520
+
521
+ host is required for context initialization..
522
+ (Or maybe you forgot mark ${this.config.contextName} context as abstract?)
523
+
524
+ `;
525
+ }
526
+ //#region @backend
527
+ // if (UtilsOs__NS__isRunningInCliMode() && !___NS__isNil(this.config.disabledRealtime)) {
528
+ // // TODO for now...
529
+ // Helpers__NS__logInfo(`Realtime disable on backend for cli mode`);
530
+ // this.disabledRealtime = true;
531
+ // } else {
532
+ // Helpers__NS__logInfo(`Realtime enabled on backend`);
533
+ // }
534
+ //#endregion
535
+ this.logRealtime &&
536
+ Helpers__NS__info(`[ctx=${this.contextName}] Init Realtime for ${this.mode}`);
537
+ this.realtime = new RealtimeCore(this);
538
+ }
539
+ //#endregion
540
+ }
541
+ //#region show context info
542
+ // console.log({ ref })
543
+ if (this.config.abstract) {
544
+ this.logFramework &&
545
+ Helpers__NS__info(`[taon] Create abstract context: ${this.config.contextName}`);
546
+ }
547
+ else {
548
+ if (this.isRemoteHost) {
549
+ this.logFramework &&
550
+ Helpers__NS__info(`[taon] Create context for remote host: ${this.config.host}`);
551
+ }
552
+ else {
553
+ this.logFramework &&
554
+ Helpers__NS__info(`[taon] Create context for host: ${this.config.host}`);
555
+ }
556
+ }
557
+ //#endregion
558
+ // update first exposed config
559
+ Object.keys(this.config).forEach(key => {
560
+ this.originalConfig[key] = this.config[key];
561
+ });
562
+ }
563
+ //#endregion
564
+ //#region methods & getters / get auto generated config
565
+ getAutoGeneratedConfig() {
566
+ this.logFramework &&
567
+ console.log(`
568
+
569
+
570
+ IS RUNNING IN DOCKER: ${this.isRunningInsideDocker}
571
+
572
+ `);
573
+ //#region @websqlFunc
574
+ let databaseConfig = Models.DatabaseConfig.from({});
575
+ const tcpUdpDatabaseSqliteRelativeFileLocation = `${Models__NS__DatabasesFolder}/db-${this.contextName}.sqlite`;
576
+ if (this.isRunningInsideDocker) {
577
+ if (this.USE_MARIADB_MYSQL_IN_DOCKER) {
578
+ // Helpers__NS__info('Running in docker, using in mysql database');
579
+ // // TODO auto resolve database config in docker
580
+ // databaseConfig = Models.DatabaseConfig.from({
581
+ // database: `db-${this.contextName}.sqlite`,
582
+ // type: 'mysql',
583
+ // recreateMode: 'PRESERVE_DATA+MIGRATIONS',
584
+ // logging: this.logDb,
585
+ // databasePort: 3306,
586
+ // databaseHost: 'localhost',
587
+ // databaseUsername: 'root',
588
+ // databasePassword: 'admin',
589
+ // });
590
+ }
591
+ else {
592
+ // TOOD @LAST for now.. just use sqljs in docker
593
+ this.logFramework &&
594
+ console.log(`
595
+
596
+ USING GENERATED CONFIG FOR SQLJS IN DOCKER
597
+
598
+ `);
599
+ //#region @backend
600
+ const locationOfTheDatabase = crossPlatformPath([
601
+ process.cwd(),
602
+ `db-${this.contextName}.sqlite`,
603
+ ]);
604
+ //#endregion
605
+ databaseConfig = databaseConfig = Models.DatabaseConfig.from({
606
+ location: tcpUdpDatabaseSqliteRelativeFileLocation,
607
+ type: 'sqljs',
608
+ useLocalForage: false,
609
+ recreateMode: 'PRESERVE_DATA+MIGRATIONS',
610
+ logging: true,
611
+ });
612
+ //#region @backend
613
+ if (!fse.existsSync(locationOfTheDatabase)) {
614
+ databaseConfig.recreateMode = 'DROP_DB+MIGRATIONS';
615
+ }
616
+ // TODO @LAST add same thing for mariadb/mysql
617
+ this.logFramework &&
618
+ console.log(`
619
+ location of database: ${locationOfTheDatabase}
620
+ db file exists: ${fse.existsSync(locationOfTheDatabase)}
621
+ synchronize: ${databaseConfig.synchronize}
622
+ dropSchema: ${databaseConfig.dropSchema}
623
+ `);
624
+ //#endregion
625
+ }
626
+ }
627
+ else {
628
+ //#region auto resolve db config
629
+ this.logFramework &&
630
+ Helpers__NS__info(`[taon][database] Automatically resolving database config for mode ${this.mode}`);
631
+ switch (this.mode) {
632
+ //#region resolve database config for backend-frontend(ipc-electron)
633
+ case 'backend-frontend(ipc-electron)':
634
+ let dbLocationInOs;
635
+ //#region @backend
636
+ if (UtilsOs__NS__isElectron) {
637
+ dbLocationInOs = crossPlatformPath([
638
+ UtilsOs__NS__getRealHomeDir(),
639
+ `.taon/databases-for-electron-apps/${this.appId || ___NS__snakeCase(process.cwd()).replace(/\_/, '.')}/${this.contextName}.sqlite`,
640
+ ]);
641
+ if (!Helpers__NS__exists(path.dirname(dbLocationInOs))) {
642
+ Helpers__NS__mkdirp(path.dirname(dbLocationInOs));
643
+ }
644
+ }
645
+ //#endregion
646
+ databaseConfig = Models.DatabaseConfig.from({
647
+ location: UtilsOs__NS__isElectron
648
+ ? dbLocationInOs
649
+ : `db-${this.contextName}.sqlite`,
650
+ type: 'sqljs',
651
+ recreateMode: 'DROP_DB+MIGRATIONS',
652
+ logging: this.logDb,
653
+ });
654
+ break;
655
+ //#endregion
656
+ //#region resolve database config for mode backend-frontend(websql)
657
+ case 'backend-frontend(websql-electron)':
658
+ case 'backend-frontend(websql)':
659
+ let keepWebsqlDbDataAfterReload = false;
660
+ /* */
661
+ /* */
662
+ /* */
663
+ databaseConfig = databaseConfig = Models.DatabaseConfig.from({
664
+ location: `db-${this.contextName}.sqlite`,
665
+ type: 'sqljs',
666
+ useLocalForage: true, // !!window['localforage'], // TODO this need to be checked in runtime
667
+ recreateMode: keepWebsqlDbDataAfterReload
668
+ ? 'PRESERVE_DATA+MIGRATIONS'
669
+ : 'DROP_DB+MIGRATIONS',
670
+ logging: this.logDb,
671
+ });
672
+ break;
673
+ //#endregion
674
+ //#region resolve database config for mode backend-frontend(tcp+udp)
675
+ case 'backend-frontend(tcp+udp)':
676
+ databaseConfig = Models.DatabaseConfig.from({
677
+ database: `context-db-${this.contextName}`,
678
+ location: tcpUdpDatabaseSqliteRelativeFileLocation,
679
+ type: 'sqljs',
680
+ recreateMode: 'DROP_DB+MIGRATIONS',
681
+ logging: this.logDb,
682
+ });
683
+ break;
684
+ //#endregion
685
+ }
686
+ //#endregion
687
+ }
688
+ return databaseConfig.databaseConfigTypeORM;
689
+ //#endregion
690
+ }
691
+ //#endregion
692
+ //#region methods & getters / start server
693
+ async startServer() {
694
+ //#region @backendFunc
695
+ if (this.isRemoteHost || this.isRunOrRevertOnlyMigrationAppStart) {
696
+ return;
697
+ }
698
+ if (this.mode === 'backend-frontend(tcp+udp)') {
699
+ return await new Promise(resolve => {
700
+ if (this.isRunningInsideDocker) {
701
+ // this.displayRoutes(this.expressApp);
702
+ this.serverTcpUdp.listen(Number(this.uriPort), '0.0.0.0', () => {
703
+ this.logFramework &&
704
+ Helpers__NS__log(`[ctx=${this.contextName}] Express server (inside docker) started 0.0.0.0:${this.uriPort}`);
705
+ this.logFramework &&
706
+ Helpers__NS__log(`[taon][express-server]listening on port: ${this.uriPort}, hostname: ${this.uriPathname},
707
+ address: ${this.uriProtocol}//localhost:${this.uriPort}${this.uriPathname}
708
+ ExpressJS mode: ${this.expressApp.settings.env}
709
+ `);
710
+ resolve(void 0);
711
+ });
712
+ }
713
+ else {
714
+ // this.displayRoutes(this.expressApp);
715
+ this.serverTcpUdp.listen(Number(this.uriPort), () => {
716
+ this.logFramework &&
717
+ Helpers__NS__log(`[ctx=${this.contextName}] Express server (inside nodejs app) started on localhost:${this.uriPort}`);
718
+ this.logFramework &&
719
+ Helpers__NS__log(`[taon][express-server]listening on port: ${this.uriPort}, hostname: ${this.uriPathname},
720
+ address: ${this.uriProtocol}//localhost:${this.uriPort}${this.uriPathname}
721
+ expressJS mode: ${this.expressApp.settings.env}
722
+ `);
723
+ resolve(void 0);
724
+ });
725
+ }
726
+ });
727
+ }
728
+ else {
729
+ this.logFramework &&
730
+ Helpers__NS__info('Ipc communication enable instead tcp/upd');
731
+ }
732
+ //#endregion
733
+ }
734
+ //#endregion
735
+ //#region methods & getters / display express routes
736
+ displayRoutes(app) {
737
+ //#region @backend
738
+ const routes = [];
739
+ app._router?.stack.forEach(function (middleware) {
740
+ if (middleware.route) {
741
+ // routes registered directly on the app
742
+ const methods = [];
743
+ for (let method in middleware.route.methods) {
744
+ if (middleware.route.methods[method]) {
745
+ methods.push(method.toUpperCase());
746
+ }
747
+ }
748
+ routes.push({ path: middleware.route.path, methods: methods });
749
+ }
750
+ else if (middleware.name === 'router') {
751
+ // router middleware
752
+ middleware.handle.stack.forEach(function (handler) {
753
+ const methods = [];
754
+ for (let method in handler.route.methods) {
755
+ if (handler.route.methods[method]) {
756
+ methods.push(method.toUpperCase());
757
+ }
758
+ }
759
+ routes.push({ path: handler.route.path, methods: methods });
760
+ });
761
+ }
762
+ });
763
+ console.log(routes);
764
+ //#endregion
765
+ }
766
+ //#endregion
767
+ //#region methods & getters / mode allows database creation
768
+ get modeAllowsDatabaseCreation() {
769
+ return (this.mode === 'backend-frontend(tcp+udp)' ||
770
+ this.mode === 'backend-frontend(websql)' ||
771
+ this.mode === 'backend-frontend(ipc-electron)');
772
+ }
773
+ //#endregion
774
+ //#region methods & getters / get recursive classes from contexts
775
+ async getRecrusiveClassesfromContextsObj(classType) {
776
+ const arr = await this.getRecrusiveClassesfromContexts(classType);
777
+ return arr.reduce((acc, c) => {
778
+ acc[ClassHelpers__NS__getName(c)] = c;
779
+ return acc;
780
+ }, {});
781
+ }
782
+ async getRecrusiveClassesfromContexts(classType, arr = []) {
783
+ const contexts = Object.values(this.config.contexts || {});
784
+ // console.log({
785
+ // contexts,
786
+ // });
787
+ for (const ctx of contexts) {
788
+ // console.log(`STARTING ${ctx.contextName}`);
789
+ const ref = await ctx.__ref();
790
+ // console.log(`CTX FROM ${ctx.contextName}`, ref.contextName);
791
+ const classesInput = ref.getClassFunBy(classType);
792
+ // console.log(`${ref.contextName} - ${classType}`, { classesInput });
793
+ const clonedClasses = Object.values(this.cloneClassesObjWithNewMetadata({
794
+ classesInput,
795
+ config: this.config,
796
+ ctx: this,
797
+ classType,
798
+ }));
799
+ // console.log(`${classType} clonedClasses`, clonedClasses);
800
+ clonedClasses.forEach(c => arr.push(c));
801
+ await ref.getRecrusiveClassesfromContexts(classType, arr);
802
+ }
803
+ return arr;
804
+ }
805
+ //#endregion
806
+ //#region methods & getters / get class instances by class type
807
+ getClassInstanceObjBy(classType) {
808
+ return this.classInstancesByNameObj[classType];
809
+ }
810
+ //#endregion
811
+ //#region methods & getters / get class instances arr
812
+ getClassesInstancesArrBy(classType) {
813
+ return this.objWithClassesInstancesArr[classType];
814
+ }
815
+ //#endregion
816
+ //#region methods & getters / inject
817
+ inject(ctor, options) {
818
+ const className = ClassHelpers__NS__getName(ctor);
819
+ const locaInstanceConstructorArgs = options.locaInstanceConstructorArgs || [];
820
+ if (this.isCLassType(Models.ClassType.REPOSITORY, ctor)) {
821
+ options.localInstance = true;
822
+ }
823
+ if (options?.localInstance) {
824
+ const ctxClassFn = this.getClassFunByClassName(className);
825
+ let entityName = '';
826
+ // entity thing is only for repositories local repositories
827
+ // if (className === 'TaonBaseRepository') {
828
+ const entityFn = ___NS__first(locaInstanceConstructorArgs);
829
+ const entity = entityFn && entityFn();
830
+ entityName = (entity && ClassHelpers__NS__getName(entity)) || '';
831
+ // console.log(`entityName `, entityName);
832
+ // }
833
+ if (!options.contextClassInstance[this.localInstaceObjSymbol]) {
834
+ options.contextClassInstance[this.localInstaceObjSymbol] = {};
835
+ }
836
+ const instanceKey = className + (entityName ? `.${entityName}` : '');
837
+ const existed = options.contextClassInstance[this.localInstaceObjSymbol][instanceKey];
838
+ if (existed) {
839
+ // console.log(
840
+ // `EXISTED ${ClassHelpers__NS__getName(options.parentInstanceThatWillGetInjectedStuff)} Inject ${className} instanceKey "${instanceKey}"`,
841
+ // );
842
+ return existed;
843
+ }
844
+ // console.log(
845
+ // `NEW ${ClassHelpers__NS__getName(options.parentInstanceThatWillGetInjectedStuff)} Inject ${className} instanceKey "${instanceKey}"`,
846
+ // );
847
+ if (!ctxClassFn) {
848
+ throw new Error(`Not able to inject "${className}" inside context "${this.contextName}"
849
+
850
+ Make sure they share the same context or import context where "${className}" is defined.
851
+
852
+ `);
853
+ }
854
+ const injectedInstance = new ctxClassFn(...locaInstanceConstructorArgs);
855
+ options.contextClassInstance[this.localInstaceObjSymbol][instanceKey] =
856
+ injectedInstance;
857
+ // console.log(`injectedInstance `, existed)
858
+ return injectedInstance;
859
+ }
860
+ const contextScopeInstance = this.allClassesInstances[className];
861
+ // if (className === 'TopicController') {
862
+ // debugger;
863
+ // }
864
+ return contextScopeInstance;
865
+ }
866
+ /**
867
+ * alias for inject
868
+ */
869
+ getInstanceBy(ctor) {
870
+ // if (!!this.__contextForControllerInstanceAccess) {
871
+ // const className = ClassHelpers__NS__getName(ctor);
872
+ // const allControllers = this.getClassFunByArr(Models.ClassType.CONTROLLER);
873
+ // // TODO QUICK_FIX cache controllers
874
+ // for (const ctrl of allControllers) {
875
+ // if (ClassHelpers__NS__getName(ctrl) === className) {
876
+ // // console.log('injecting from contextForControllerInstanceAcesss', className);
877
+ // return this.__contextForControllerInstanceAccess.inject(ctor, {
878
+ // localInstance: false,
879
+ // });
880
+ // }
881
+ // }
882
+ // }
883
+ return this.inject(ctor, {
884
+ localInstance: false,
885
+ parentInstanceThatWillGetInjectedStuff: this,
886
+ });
887
+ }
888
+ //#endregion
889
+ //#region methods & getters / check if context initialized
890
+ checkIfContextInitialized() {
891
+ if (___NS__isUndefined(this.config)) {
892
+ throw new Error(`Please check if your context has been initialized.
893
+
894
+ // ...
895
+ await Context.initialize();
896
+ // ...
897
+
898
+
899
+ `);
900
+ }
901
+ }
902
+ //#endregion
903
+ //#region methods & getters / get class function by class type name
904
+ getClassFunBy(classType) {
905
+ this.checkIfContextInitialized();
906
+ switch (classType) {
907
+ case Models.ClassType.CONTROLLER:
908
+ return this.config.controllers;
909
+ case Models.ClassType.ENTITY:
910
+ return this.config.entities;
911
+ case Models.ClassType.PROVIDER:
912
+ return this.config.providers;
913
+ case Models.ClassType.MIDDLEWARE:
914
+ return this.config.middlewares;
915
+ case Models.ClassType.REPOSITORY:
916
+ return this.config.repositories;
917
+ case Models.ClassType.SUBSCRIBER:
918
+ return this.config.subscribers;
919
+ case Models.ClassType.MIGRATION:
920
+ return this.config.migrations;
921
+ }
922
+ }
923
+ isCLassType(classType, classFn) {
924
+ return !!this.getClassFunBy(classType)[ClassHelpers__NS__getName(classFn)];
925
+ }
926
+ /**
927
+ * Only for injectable types
928
+ * Only for classType: CONTROLLER, REPOSITORY, PROVIDER, MIDDLEWARES
929
+ */
930
+ getClassFunByClassName(className) {
931
+ for (const classTypeName of this.allTypesfromContexts) {
932
+ const classesForInjectableType = this.config[Models__NS__ClassTypeKey[classTypeName]];
933
+ if (classesForInjectableType[className]) {
934
+ return classesForInjectableType[className];
935
+ }
936
+ }
937
+ }
938
+ getClassFunByClass(classFunction) {
939
+ const className = ClassHelpers__NS__getName(classFunction);
940
+ return this.getClassFunByClassName(className);
941
+ }
942
+ getClassFunByArr(classType) {
943
+ return Object.values(this.getClassFunBy(classType) || {});
944
+ }
945
+ //#endregion
946
+ //#region methods & getters / create class instances
947
+ async createInstances(classes, classType) {
948
+ // const recrusiveValuesFromContext =
949
+ // await this.getRecrusiveClassesfromContexts(classType);
950
+ // console.log(this.config.contexts);
951
+ // console.log('recrusiveValuesFromContext', recrusiveValuesFromContext);
952
+ for (const classFn of [
953
+ // ...recrusiveValuesFromContext,
954
+ ...Object.values(classes),
955
+ ]) {
956
+ const instance = DITaonContainer.resolve(classFn);
957
+ const classInstancesByNameObj = this.classInstancesByNameObj[classType];
958
+ const className = ClassHelpers__NS__getName(classFn);
959
+ // console.log({ classFn, classType, instance, place, className, 'classInstancesByNameObj': this.classInstancesByNameObj });
960
+ classInstancesByNameObj[className] = instance;
961
+ // update config
962
+ this.config[Models__NS__ClassTypeKey[classType]][className] = classFn;
963
+ this.objWithClassesInstancesArr[classType].push(instance);
964
+ this.allClassesInstances[className] = instance;
965
+ }
966
+ }
967
+ //#endregion
968
+ //#region methods & getters / init classes
969
+ async initClasses() {
970
+ if (this.isRemoteHost) {
971
+ return;
972
+ }
973
+ //#region @websql
974
+ for (const classFun of this.getClassFunByArr(Models.ClassType.ENTITY)) {
975
+ const repo = (await this.connection.getRepository(ClassHelpers__NS__getOrginalClass(classFun)));
976
+ this.repos.set(ClassHelpers__NS__getName(classFun), repo);
977
+ }
978
+ //#endregion
979
+ for (const classTypeName of [
980
+ Models.ClassType.MIDDLEWARE,
981
+ Models.ClassType.PROVIDER,
982
+ Models.ClassType.REPOSITORY,
983
+ Models.ClassType.CONTROLLER,
984
+ Models.ClassType.ENTITY,
985
+ Models.ClassType.MIGRATION,
986
+ ]) {
987
+ //#region init class static _ property
988
+ for (const classFun of this.getClassFunByArr(classTypeName)) {
989
+ if (___NS__isFunction(classFun._)) {
990
+ await classFun._();
991
+ }
992
+ }
993
+ //#endregion
994
+ }
995
+ for (const classTypeName of [
996
+ Models.ClassType.MIDDLEWARE,
997
+ Models.ClassType.PROVIDER,
998
+ Models.ClassType.REPOSITORY,
999
+ Models.ClassType.CONTROLLER,
1000
+ Models.ClassType.MIGRATION,
1001
+ ]) {
1002
+ //#region init providers, repositories _ property
1003
+ // Helpers__NS__taskStarted(
1004
+ // `[taon] REINITING _ INS FN ${classTypeName} ${this.contextName} STARTED`,
1005
+ // );
1006
+ for (const ctrl of this.getClassesInstancesArrBy(classTypeName)) {
1007
+ if (___NS__isFunction(ctrl._)) {
1008
+ await ctrl._();
1009
+ }
1010
+ }
1011
+ // Helpers__NS__taskStarted(
1012
+ // `[taon] REINITING _ INS FN ${classTypeName} ${this.contextName} DONE`,
1013
+ // );
1014
+ //#endregion
1015
+ }
1016
+ }
1017
+ //#endregion
1018
+ //#region methods & getters / is active on
1019
+ isActiveOn(classInstance) {
1020
+ let contextRef = classInstance[Symbols__NS__ctxInClassOrClassObj];
1021
+ return this === contextRef;
1022
+ }
1023
+ //#endregion
1024
+ //#region methods & getters / uri
1025
+ get frontendHostUri() {
1026
+ const url = this.config?.frontendHost?.startsWith('http')
1027
+ ? this.config.frontendHost
1028
+ : `${globalThis?.location?.protocol || 'http:'}//${this.config?.frontendHost}`;
1029
+ const uri = new URL(url.replace(/\/$/, ''));
1030
+ return uri;
1031
+ }
1032
+ get uri() {
1033
+ const url = this.host ? new URL(this.host) : void 0;
1034
+ return url;
1035
+ }
1036
+ //#endregion
1037
+ //#region methods & getters / host uri protocol
1038
+ get uriProtocol() {
1039
+ return this.uri?.protocol;
1040
+ }
1041
+ //#endregion
1042
+ //#region methods & getters / host uri origin
1043
+ /**
1044
+ * Examples
1045
+ * http://localhost:3000
1046
+ * https://localhost (from localhost:80) *
1047
+ */
1048
+ get uriOrigin() {
1049
+ return this.uri?.origin;
1050
+ }
1051
+ //#endregion
1052
+ //#region methods & getters / host uri pathname
1053
+ /**
1054
+ * Exampels
1055
+ * http://localhost:3000/path/to/somewhere
1056
+ * https://localhost/path/to/somewhere (from localhost:80)
1057
+ */
1058
+ // get uriOriginWithPathname(): string | undefined {
1059
+ // return this.uri?.origin
1060
+ // ? this.uri?.origin + this.uriPathnameOrNothingIfRoot.replace(/\/$/, '')
1061
+ // : undefined;
1062
+ // }
1063
+ get uriPathname() {
1064
+ return this.uri?.pathname;
1065
+ }
1066
+ //#endregion
1067
+ //#region methods & getters / uri pathname or nothing if root
1068
+ /**
1069
+ * Examples
1070
+ * http://localhost:3000/path/to/somewhere -> '/path/to/somewhere'
1071
+ * http://localhost:3000 -> '' #
1072
+ * https://localhost/path/to/ -> '/path/to/somewhere' # remove last slash
1073
+ */
1074
+ get uriPathnameOrNothingIfRoot() {
1075
+ const isNonRootProperPathName = this.uri?.pathname && this.uri.pathname !== '/';
1076
+ return isNonRootProperPathName ? this.uri.pathname.replace(/\/$/, '') : '';
1077
+ }
1078
+ //#endregion
1079
+ //#region methods & getters / port from uri
1080
+ get uriPort() {
1081
+ if (!this.uri?.origin?.includes('localhost')) {
1082
+ return this.config?.hostPortNumber?.toString();
1083
+ }
1084
+ return this.uri?.port;
1085
+ }
1086
+ // TODO do i need 2 getters for port?
1087
+ /**
1088
+ * Port from uri as number
1089
+ * @returns {Number | undefined}
1090
+ */
1091
+ get port() {
1092
+ return this.uri?.port ? Number(this.uriPort) : undefined;
1093
+ }
1094
+ //#endregion
1095
+ //#region methods & getters / is https server
1096
+ get isHttpServer() {
1097
+ return this.uriProtocol === 'https:';
1098
+ }
1099
+ //#endregion
1100
+ //#region methods & getters / is remote host
1101
+ /**
1102
+ * Check if context is for remote only
1103
+ */
1104
+ get isRemoteHost() {
1105
+ return !!this.cloneOptions?.useAsRemoteContext;
1106
+ }
1107
+ //#endregion
1108
+ //#region methods & getters / context name
1109
+ /**
1110
+ * ipc/udp needs this
1111
+ */
1112
+ get contextName() {
1113
+ // console.log(this.originalConfig);
1114
+ return this.config?.contextName || this.originalConfig?.contextName;
1115
+ }
1116
+ //#endregion
1117
+ //#region methods & getters / context name for communication
1118
+ /**
1119
+ * ipc/udp needs this
1120
+ */
1121
+ get contextNameForCommunication() {
1122
+ let contextName = this.contextName;
1123
+ if (this.isRemoteHost) {
1124
+ if (this.sourceContext?.contextName) {
1125
+ contextName = this.sourceContext?.contextName;
1126
+ }
1127
+ else {
1128
+ // console.log(
1129
+ // `CANT GET SOURCE CONTEXT NAME FOR REMOTE CONTEXT ${this.contextName}`,
1130
+ // );
1131
+ }
1132
+ }
1133
+ return contextName;
1134
+ }
1135
+ //#endregion
1136
+ //#region methods & getters / get context type
1137
+ /**
1138
+ * Check context type
1139
+ */
1140
+ get contextType() {
1141
+ if (this.config.abstract) {
1142
+ return 'abstract';
1143
+ }
1144
+ if (this.host) {
1145
+ return this.isRemoteHost ? 'remote' : 'normal';
1146
+ }
1147
+ return 'invalid';
1148
+ }
1149
+ //#endregion
1150
+ //#region methods & getters / current working directory
1151
+ get cwd() {
1152
+ return this.config.cwd || process.cwd();
1153
+ }
1154
+ //#endregion
1155
+ //#region methods & getters / active context
1156
+ get activeContext() {
1157
+ return this.config.activeContext || null;
1158
+ }
1159
+ //#endregion
1160
+ //#region methods & getters / app id
1161
+ get appId() {
1162
+ return this.config.appId;
1163
+ }
1164
+ //#endregion
1165
+ //#region methods & getters / public assets
1166
+ get publicAssets() {
1167
+ return this.config?.publicAssets || [];
1168
+ }
1169
+ //#endregion
1170
+ //#region methods & getters / is production mode
1171
+ get isProductionMode() {
1172
+ return this.config.productionMode;
1173
+ }
1174
+ //#endregion
1175
+ //#region methods & getters / host
1176
+ get host() {
1177
+ return this.config.host;
1178
+ }
1179
+ //#endregion
1180
+ //#region methods & getters / origin
1181
+ get origin() {
1182
+ return this.uri?.origin;
1183
+ }
1184
+ //#endregion
1185
+ //#region methods & getters / init subscribers
1186
+ async initSubscribers() {
1187
+ //#region @websqlFunc
1188
+ if (this.isRemoteHost) {
1189
+ return;
1190
+ }
1191
+ const subscriberClasses = this.getClassFunByArr(Models.ClassType.SUBSCRIBER);
1192
+ for (const subscriberClassFn of subscriberClasses) {
1193
+ const options = Reflect.getMetadata(Symbols__NS__metadata.options.subscriber, subscriberClassFn);
1194
+ // console.log('subscriber options', options);
1195
+ // const nameForSubscriber = ClassHelpers__NS__getName(subscriber);
1196
+ EventSubscriber()(subscriberClassFn);
1197
+ }
1198
+ //#endregion
1199
+ }
1200
+ //#endregion
1201
+ //#region methods & getters / init entities
1202
+ async initEntities() {
1203
+ //#region @websql
1204
+ if (this.isRemoteHost) {
1205
+ return;
1206
+ }
1207
+ const entities = this.getClassFunByArr(Models.ClassType.ENTITY);
1208
+ for (const entity of entities) {
1209
+ const options = Reflect.getMetadata(Symbols__NS__metadata.options.entity, entity);
1210
+ const createTable = ___NS__isUndefined(options.createTable)
1211
+ ? true
1212
+ : options.createTable;
1213
+ const nameForEntity = ClassHelpers__NS__getName(entity);
1214
+ if (createTable) {
1215
+ this.logDb &&
1216
+ console.info(`[taon][typeorm] create table for entity "${nameForEntity}" ? '${createTable}'`);
1217
+ // console.log('TypeormEntity', { TypeormEntity });
1218
+ TypeormEntity(nameForEntity)(entity);
1219
+ }
1220
+ else {
1221
+ this.logDb &&
1222
+ console.info(`[taon][typeorm] create table for entity "${nameForEntity}" ? '${createTable}'`);
1223
+ }
1224
+ }
1225
+ //#endregion
1226
+ }
1227
+ //#endregion
1228
+ //#region methods & getters / destroy
1229
+ async destroy() {
1230
+ //#region @websqlFunc
1231
+ if (this.connection) {
1232
+ await this.connection?.destroy();
1233
+ delete this.connection;
1234
+ }
1235
+ if (this.serverTcpUdp) {
1236
+ await new Promise(resolve => {
1237
+ this.serverTcpUdp?.close(() => {
1238
+ resolve(true);
1239
+ });
1240
+ });
1241
+ delete this.serverTcpUdp;
1242
+ }
1243
+ delete this.expressApp;
1244
+ //#endregion
1245
+ }
1246
+ //#endregion
1247
+ //#region methods & getters / init connection
1248
+ async initDatabaseConnection() {
1249
+ //#region @websqlFunc
1250
+ if (this.isRemoteHost || !this.databaseConfig) {
1251
+ return;
1252
+ }
1253
+ const entities = this.getClassFunByArr(Models.ClassType.ENTITY).map(entityFn => {
1254
+ return ClassHelpers__NS__getOrginalClass(entityFn);
1255
+ });
1256
+ const subscribers = this.getClassFunByArr(Models.ClassType.SUBSCRIBER);
1257
+ let autoSave = false;
1258
+ if (!___NS__isNil(this.databaseConfig.autoSave)) {
1259
+ autoSave = this.databaseConfig.autoSave;
1260
+ }
1261
+ else {
1262
+ if (this.USE_MARIADB_MYSQL_IN_DOCKER) {
1263
+ autoSave = !this.isRunningInsideDocker; // in docker I am using mysql or posgress
1264
+ }
1265
+ else {
1266
+ autoSave = true; // on docker with sqljs I need to save db
1267
+ }
1268
+ }
1269
+ const dataSourceDbConfig = ___NS__isObject(this.databaseConfig)
1270
+ ? {
1271
+ type: this.databaseConfig.type,
1272
+ port: this.databaseConfig.databasePort,
1273
+ host: this.databaseConfig.databaseHost,
1274
+ database: this.databaseConfig.database,
1275
+ username: this.databaseConfig.databaseUsername,
1276
+ password: this.databaseConfig.databasePassword,
1277
+ useLocalForage: this.databaseConfig.useLocalForage,
1278
+ // I am not using typeorm migration system
1279
+ entities,
1280
+ subscribers,
1281
+ synchronize: this.isRunOrRevertOnlyMigrationAppStart
1282
+ ? false
1283
+ : this.databaseConfig.synchronize,
1284
+ autoSave,
1285
+ dropSchema: this.isRunOrRevertOnlyMigrationAppStart
1286
+ ? false
1287
+ : this.databaseConfig.dropSchema,
1288
+ logging: !!this.databaseConfig.logging,
1289
+ location: this.databaseConfig.location,
1290
+ }
1291
+ : {};
1292
+ // debugger;
1293
+ this.logFramework &&
1294
+ console.log(`[Context: "${this.contextName}"] dataSourceDbConfig`, dataSourceDbConfig);
1295
+ if (this.modeAllowsDatabaseCreation && this.databaseConfig) {
1296
+ this.logDb &&
1297
+ this.logFramework &&
1298
+ Helpers__NS__info('[taon][database] prepare typeorm connection...');
1299
+ try {
1300
+ const connection = new DataSource(dataSourceDbConfig);
1301
+ this.connection = connection;
1302
+ await this.connection.initialize();
1303
+ }
1304
+ catch (error) {
1305
+ console.error(`[taon][typeorm] Error while initializing connection for ${this.contextName}, ERROR STARTED `);
1306
+ console.error(error?.stack || '< No stack trace > ');
1307
+ console.error(error?.message || error);
1308
+ console.error(`[taon][typeorm] Error while initializing connection for ${this.contextName}, ERROR ENDS `);
1309
+ }
1310
+ if (!this.connection?.isInitialized) {
1311
+ console.log('WRONG CONFIG', dataSourceDbConfig);
1312
+ throw new Error(`Something wrong with connection init in ${this.mode}`);
1313
+ //#region @backend
1314
+ process.exit(1);
1315
+ //#endregion
1316
+ }
1317
+ if (this.logDb || this.logFramework) {
1318
+ console.info(`
1319
+
1320
+ CONTECTION OK for ${this.contextName} - ${this.mode}
1321
+
1322
+ [taon][typeorm] db prepration done.. db initialize=${this.connection?.isInitialized}
1323
+
1324
+
1325
+ `,
1326
+ // dataSourceDbConfig,
1327
+ { 'this.connection': !!this.connection });
1328
+ console.log(`Database file location: ${this.connection.options.database}`);
1329
+ }
1330
+ // const entityMetadata = getMetadataArgsStorage();
1331
+ // console.log(
1332
+ // `
1333
+ // entityMetadata after connection init for ${this.contextName} - ${this.mode}
1334
+ // `,
1335
+ // entityMetadata,
1336
+ // );
1337
+ // debugger;
1338
+ }
1339
+ else {
1340
+ Helpers__NS__info(`[taon][typeorm] Not initing db for mode ${this.mode}`);
1341
+ }
1342
+ //#endregion
1343
+ }
1344
+ //#endregion
1345
+ //#region methods & getters / initialize metadata
1346
+ //#region methods & getters / update class calculate path
1347
+ updateCalculatedPathsForControllers(rawConfigs, classConfig, controllerClassFn) {
1348
+ const parentsCalculatedPath = ___NS__slice(rawConfigs, 1)
1349
+ .reverse()
1350
+ .map(bc => {
1351
+ if (TaonHelpers__NS__isGoodPath(bc.path)) {
1352
+ return bc.path;
1353
+ }
1354
+ return bc.className;
1355
+ })
1356
+ .join('/');
1357
+ const contextNameForCommunication = this.contextNameForCommunication;
1358
+ if (TaonHelpers__NS__isGoodPath(classConfig.path)) {
1359
+ classConfig.calculatedPath = classConfig.path;
1360
+ }
1361
+ else {
1362
+ classConfig.calculatedPath = (`${this.uriPathnameOrNothingIfRoot}` +
1363
+ `/${apiPrefix}/${contextNameForCommunication}/tcp${parentsCalculatedPath}/` +
1364
+ `${ClassHelpers__NS__getName(controllerClassFn)}`)
1365
+ .replace(/\/\//g, '/')
1366
+ .split('/')
1367
+ .reduce((acc, bc) => {
1368
+ return ___NS__last(acc) === bc ? acc : [...acc, bc];
1369
+ }, [])
1370
+ .join('/');
1371
+ }
1372
+ // console.log('calculatedPath', classConfig.calculatedPath);
1373
+ }
1374
+ //#endregion
1375
+ //#region methods & getters / dedupe class configs
1376
+ mergeControllerMethodsConfigs(rawConfigs, classConfig, controllerClassFn) {
1377
+ const currentControllerMethodsConfig = classConfig.methods;
1378
+ ___NS__slice(rawConfigs, 1).forEach(bc => {
1379
+ const parentControllerMethods = ___NS__cloneDeep(bc.methods);
1380
+ for (const methodsName in parentControllerMethods) {
1381
+ if (parentControllerMethods.hasOwnProperty(methodsName)) {
1382
+ if (!currentControllerMethodsConfig[methodsName]) {
1383
+ //#region add non existed method
1384
+ const methodConfig = parentControllerMethods[methodsName];
1385
+ currentControllerMethodsConfig[methodsName] = methodConfig;
1386
+ //#endregion
1387
+ }
1388
+ }
1389
+ }
1390
+ });
1391
+ }
1392
+ //#endregion
1393
+ async initControllersHook(ctxStorage) {
1394
+ if (this.isRunOrRevertOnlyMigrationAppStart) {
1395
+ return;
1396
+ }
1397
+ const allControllers = this.getClassFunByArr(Models.ClassType.CONTROLLER);
1398
+ for (const controllerClassFn of allControllers) {
1399
+ const instance = this.getInstanceBy(controllerClassFn);
1400
+ if (___NS__isFunction(instance.afterAllCtxInited)) {
1401
+ await instance.afterAllCtxInited({ ctxStorage });
1402
+ }
1403
+ }
1404
+ }
1405
+ async initControllers() {
1406
+ if (this.isRunOrRevertOnlyMigrationAppStart) {
1407
+ return;
1408
+ }
1409
+ const allControllers = this.getClassFunByArr(Models.ClassType.CONTROLLER);
1410
+ // debugger
1411
+ // console.log('allControllers', allControllers);
1412
+ for (const controllerClassFn of allControllers) {
1413
+ // console.log(ClassHelpers__NS__getClassConfig(controllerClassFn));
1414
+ // const controllerName = ClassHelpers__NS__getName(controllerClassFn);
1415
+ // console.log(
1416
+ // `for ${controllerName}`,
1417
+ // ClassHelpers__NS__getClassConfig(controllerClassFn),
1418
+ // );
1419
+ controllerClassFn[Symbols__NS__classMethodsNames] =
1420
+ ClassHelpers__NS__getMethodsNames(controllerClassFn);
1421
+ const rawConfigs = ClassHelpers__NS__getControllerConfigs(controllerClassFn);
1422
+ // console.log(controllerName, { rawConfigs });
1423
+ // console.log(`Class config for ${ClassHelpers__NS__getName(controllerClassFn)}`, configs)
1424
+ const classConfig = rawConfigs[0];
1425
+ this.updateCalculatedPathsForControllers(rawConfigs, classConfig, controllerClassFn);
1426
+ this.mergeControllerMethodsConfigs(rawConfigs, classConfig, controllerClassFn);
1427
+ //#region combine middlewares from controllers
1428
+ classConfig.calculatedMiddlewaresControllerObj = {};
1429
+ [...rawConfigs].reverse().forEach(rc => {
1430
+ if (___NS__isFunction(rc.middlewares)) {
1431
+ classConfig.calculatedMiddlewaresControllerObj = rc.middlewares({
1432
+ parentMiddlewares: classConfig.calculatedMiddlewaresControllerObj,
1433
+ className(middlewareClass) {
1434
+ return ClassHelpers__NS__getName(controllerClassFn);
1435
+ },
1436
+ });
1437
+ }
1438
+ });
1439
+ //#endregion
1440
+ //#region group start
1441
+ //#region @backend
1442
+ if (!UtilsOs__NS__isRunningInCliMode()) {
1443
+ //#endregion
1444
+ this.logHttp &&
1445
+ console.groupCollapsed(`[taon][express-server] routes [${classConfig.className}]`);
1446
+ //#region @backend
1447
+ }
1448
+ //#endregion
1449
+ //#endregion
1450
+ //#region init client or server methods
1451
+ const methodNames = Object.keys(classConfig.methods);
1452
+ for (const methodName of methodNames) {
1453
+ const methodConfig = classConfig.methods[methodName];
1454
+ //#region combine all class methods middlewares
1455
+ let calculatedMiddlewaresMethodObj = {};
1456
+ [...rawConfigs].reverse().forEach(rc => {
1457
+ if (rc.methods[methodName]) {
1458
+ const parentMethodConfig = rc.methods[methodName];
1459
+ if (___NS__isFunction(parentMethodConfig.middlewares)) {
1460
+ calculatedMiddlewaresMethodObj = parentMethodConfig.middlewares({
1461
+ parentMiddlewares: calculatedMiddlewaresMethodObj,
1462
+ className(middlewareClass) {
1463
+ return ClassHelpers__NS__getName(controllerClassFn);
1464
+ },
1465
+ });
1466
+ }
1467
+ }
1468
+ });
1469
+ // add class middlewares to method middlewares
1470
+ methodConfig.calculatedMiddlewaresMethodObj = {
1471
+ ...calculatedMiddlewaresMethodObj,
1472
+ ...classConfig.calculatedMiddlewaresControllerObj,
1473
+ };
1474
+ methodConfig.calculatedMiddlewares = Object.values(methodConfig.calculatedMiddlewaresMethodObj || {});
1475
+ //#endregion
1476
+ // methodConfig.calculatedMiddlewares = TODO
1477
+ //#region initialized method express path
1478
+ const httpMethodType = methodConfig.type;
1479
+ // this is quick fix - in docker global path should not be used
1480
+ const globalPathPart = this.isRunningInsideDocker ||
1481
+ !this.frontendHostUri?.origin?.includes('localhost') // fe with domain -> is in docker
1482
+ ? `${this.uriPathnameOrNothingIfRoot.replace(/\/$/, '')}/${apiPrefix}/${this.contextName}`.replace(/\/\//, '/')
1483
+ : '';
1484
+ const expressPath = methodConfig.global
1485
+ ? `${globalPathPart}/${methodConfig.path?.replace(/\/$/, '')}`.replace(/\/\//, '/')
1486
+ : TaonHelpers__NS__getExpressPath(classConfig, methodConfig);
1487
+ //#endregion
1488
+ //#region init server
1489
+ // console.log({ expressPath });
1490
+ if (UtilsOs__NS__isNode || UtilsOs__NS__isWebSQL) {
1491
+ //#region @websql
1492
+ const route = this.initServer(httpMethodType, methodConfig, classConfig, expressPath, controllerClassFn);
1493
+ this.activeRoutes.push({
1494
+ expressPath: route.expressPath,
1495
+ method: route.method,
1496
+ });
1497
+ //#endregion
1498
+ }
1499
+ //#endregion
1500
+ //#region init client
1501
+ const shouldInitClient = UtilsOs__NS__isBrowser || this.isRemoteHost || UtilsOs__NS__isWebSQL;
1502
+ // console.log('shouldInitClient', shouldInitClient);
1503
+ if (shouldInitClient) {
1504
+ // console.log(
1505
+ // 'initClient',
1506
+ // ClassHelpers__NS__getFullInternalName(controllerClassFn),
1507
+ // type,
1508
+ // methodConfig,
1509
+ // expressPath,
1510
+ // );
1511
+ await this.initClient(controllerClassFn, httpMethodType, methodConfig, expressPath);
1512
+ }
1513
+ //#endregion
1514
+ }
1515
+ //#endregion
1516
+ //#region group end
1517
+ //#region @backend
1518
+ if (!UtilsOs__NS__isRunningInCliMode()) {
1519
+ //#endregion
1520
+ this.logHttp && console.groupEnd();
1521
+ //#region @backend
1522
+ }
1523
+ //#endregion
1524
+ //#endregion
1525
+ }
1526
+ }
1527
+ //#endregion
1528
+ //#region methods & getters / write active routes
1529
+ writeActiveRoutes() {
1530
+ if (this.isRemoteHost || this.isRunOrRevertOnlyMigrationAppStart) {
1531
+ return;
1532
+ }
1533
+ // const contexts: EndpointContext[] = [this];
1534
+ //#region @websql
1535
+ const troutes = Utils__NS__uniqArray(this.activeRoutes.map(f => {
1536
+ return `${f.method} ${f.expressPath}`;
1537
+ })).map(f => {
1538
+ const [method, expressPath] = f.split(' ');
1539
+ return (`\n### ${___NS__startCase(___NS__last(expressPath.split('/')))}\n` +
1540
+ TaonHelpers__NS__fillUpTo(method.toUpperCase() + ' ', 10) +
1541
+ this.uriOrigin +
1542
+ expressPath);
1543
+ // return `${TaonHelpers.string(method.toUpperCase() + ':')
1544
+ // .fillUpTo(10)}${context.uriHref.replace(/\/$/, '')}${expressPath}`
1545
+ });
1546
+ const routes = [
1547
+ ...['', `# ROUTES FOR HOST ${this.uriOrigin} `],
1548
+ ...troutes,
1549
+ ].join('\n');
1550
+ const fileName = crossPlatformPath([
1551
+ //#region @backend
1552
+ process.cwd(),
1553
+ //#endregion
1554
+ `routes/routes-${this.config.contextName}.rest`,
1555
+ ]);
1556
+ this.logFramework && console.log(`[taon] routes file: ${fileName} `);
1557
+ this.logRoutes && console.log(routes);
1558
+ //#region @backend
1559
+ if (!UtilsOs__NS__isElectron && !this.skipWritingServerRoutes) {
1560
+ Helpers__NS__writeFile(fileName, routes);
1561
+ }
1562
+ //#endregion
1563
+ //#endregion
1564
+ }
1565
+ //#endregion
1566
+ //#region methods & getters / middlewares
1567
+ get middlewares() {
1568
+ //#region @backendFunc
1569
+ return this.config.middlewares || [];
1570
+ //#endregion
1571
+ }
1572
+ //#endregion
1573
+ //#region methods & getters / init middlewares
1574
+ async initCustomClientMiddlewares() {
1575
+ const middlewares = this.getClassesInstancesArrBy(Models.ClassType.MIDDLEWARE)
1576
+ .map(f => f)
1577
+ .filter(f => ___NS__isFunction(f.interceptClient));
1578
+ middlewares.forEach(middlewareInstanceName => {
1579
+ const contextName = this.contextName;
1580
+ const interceptorName = `${contextName}-${ClassHelpers__NS__getName(middlewareInstanceName)}`;
1581
+ Resource.request.interceptors.set(interceptorName, {
1582
+ intercept: ({ req, next }) => {
1583
+ const url = new URL(req.url);
1584
+ if (url.pathname.startsWith(`${this.uriPathnameOrNothingIfRoot}/${apiPrefix}/${contextName}/`)) {
1585
+ // console.log('intercepting', url.pathname, req);
1586
+ return middlewareInstanceName.interceptClient({
1587
+ req,
1588
+ next,
1589
+ });
1590
+ }
1591
+ return next.handle(req);
1592
+ },
1593
+ });
1594
+ });
1595
+ }
1596
+ async initCustomBackendMiddlewares() {
1597
+ //#region @backend
1598
+ const app = this.expressApp;
1599
+ const middlewares = this.getClassesInstancesArrBy(Models.ClassType.MIDDLEWARE);
1600
+ for (const middleware of middlewares) {
1601
+ const middlewareInstance = middleware;
1602
+ if (___NS__isFunction(middlewareInstance.interceptServer)) {
1603
+ const middlewareFn = ClassHelpers__NS__asyncHandler(async (req, res, next) => {
1604
+ if (req.originalUrl.startsWith(`${this.uriPathnameOrNothingIfRoot}/${apiPrefix}/${this.contextName}/`)) {
1605
+ await middlewareInstance.interceptServer({
1606
+ req,
1607
+ res,
1608
+ next,
1609
+ });
1610
+ }
1611
+ else {
1612
+ next();
1613
+ }
1614
+ });
1615
+ app.use(middlewareFn);
1616
+ }
1617
+ }
1618
+ //#endregion
1619
+ }
1620
+ async initBackendMiddlewares() {
1621
+ //#region @backend
1622
+ const app = this.expressApp;
1623
+ // if (this.middlewares) {
1624
+ // this.middlewares.forEach(m => {
1625
+ // const [fun, args] = m;
1626
+ // app.use(fun.apply(null, args));
1627
+ // });
1628
+ // }
1629
+ this.expressApp.get('/helloworld', (req, res) => {
1630
+ res.send(`Hello, world from context ${this.contextName}`);
1631
+ });
1632
+ // app.use(fileUpload());
1633
+ app.use(bodyParser.urlencoded({ extended: true }));
1634
+ app.use(bodyParser.json());
1635
+ app.use(methodOverride());
1636
+ app.use(cookieParser());
1637
+ if (this.session) {
1638
+ Helpers__NS__info('[taon][express-server] session enabled for this context ' +
1639
+ this.contextName);
1640
+ const { cookieMaxAge } = this.session;
1641
+ const frontendHost = this.config.frontendHost;
1642
+ const sessionObj = {
1643
+ frontendHost,
1644
+ secret: 'mysecretsessioncookithing',
1645
+ saveUninitialized: true,
1646
+ cookieMaxAge,
1647
+ secure: frontendHost.startsWith('https://'),
1648
+ resave: false,
1649
+ };
1650
+ app.use(cors({
1651
+ credentials: true,
1652
+ origin: frontendHost,
1653
+ }));
1654
+ app.use(expressSession(sessionObj));
1655
+ console.log(`
1656
+
1657
+ CORS ENABLED FOR SESSION
1658
+
1659
+ `);
1660
+ }
1661
+ else {
1662
+ // if(this.config?.serverLogs) {
1663
+ this.logHttp &&
1664
+ Helpers__NS__info(`[taon][express-server] session not enabled for this context '${this.contextName}'`);
1665
+ // }
1666
+ app.use(cors({
1667
+ // origin: "http://localhost:5555",
1668
+ // methods: ["GET", "POST"],
1669
+ // allowedHeaders: ["my-custom-header"],
1670
+ // credentials: true
1671
+ }));
1672
+ this.logHttp &&
1673
+ console.log(`
1674
+
1675
+ CORS ENABLED WITHOUT SESSION
1676
+
1677
+ `);
1678
+ }
1679
+ (() => {
1680
+ app.use((req, res, next) => {
1681
+ //#region good for cors session obj
1682
+ // if (this.context.session) {
1683
+ // res.header('Access-Control-Allow-Origin', this.context.session.frontendHost);
1684
+ // res.header('Access-Control-Allow-Credentials', 'true');
1685
+ // res.header(
1686
+ // 'Access-Control-Allow-Headers',
1687
+ // 'Origin, X-Requested-With, Content-Type, Accept'
1688
+ // );
1689
+ // res.header("Access-Control-Allow-Methods", "PUT,POST,GET,HEAD,DELETE,OPTIONS,PATCH");
1690
+ // // maybe this
1691
+ // res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With");
1692
+ // }
1693
+ //#endregion
1694
+ res.set('Access-Control-Expose-Headers', [
1695
+ 'Content-Type',
1696
+ 'Authorization',
1697
+ 'X-Requested-With',
1698
+ Symbols__NS__old.X_TOTAL_COUNT,
1699
+ Symbols__NS__old.MAPPING_CONFIG_HEADER,
1700
+ Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY,
1701
+ Symbols__NS__old.CIRCURAL_OBJECTS_MAP_QUERY_PARAM,
1702
+ ].join(', '));
1703
+ next();
1704
+ });
1705
+ })();
1706
+ //#endregion
1707
+ }
1708
+ //#endregion
1709
+ //#region methods & getters / init methods node
1710
+ initServer(
1711
+ //#region parameters
1712
+ httpMethodType, methodConfig, classConfig, expressPath, target) {
1713
+ //#region resolve variables
1714
+ // console.log(
1715
+ // `CLIENT: expressPath: "${expressPath}" interceptor for method: ${methodConfig.calculatedMiddlewares.length}`,
1716
+ // );
1717
+ const middlewareHandlers = methodConfig.calculatedMiddlewares
1718
+ .map(middlewareClassFun => {
1719
+ const middlewareInstance = this.getInstanceBy(middlewareClassFun);
1720
+ if (middlewareInstance &&
1721
+ ___NS__isFunction(middlewareInstance.interceptServerMethod)) {
1722
+ const middlewareFn = ClassHelpers__NS__asyncHandler(async (req, res, next) => {
1723
+ await middlewareInstance.interceptServerMethod({
1724
+ req,
1725
+ res,
1726
+ next,
1727
+ }, {
1728
+ methodName: methodConfig.methodName,
1729
+ expressPath,
1730
+ httpRequestType: methodConfig.type,
1731
+ });
1732
+ });
1733
+ return middlewareFn;
1734
+ }
1735
+ })
1736
+ .filter(f => !!f);
1737
+ // const url = this.uri;
1738
+ //#region get result
1739
+ const getResult = async (resolvedParams, req, res) => {
1740
+ const response = methodConfig.descriptor.value.apply(
1741
+ /**
1742
+ * Context for method @GET,@PUT etc.
1743
+ */
1744
+ this.getInstanceBy(target),
1745
+ /**
1746
+ * Params for method @GET, @PUT etc.
1747
+ */
1748
+ resolvedParams);
1749
+ let result = await getResponseValue(response, { req, res });
1750
+ return result;
1751
+ };
1752
+ //#endregion
1753
+ // console.log(`BACKEND: expressPath: "${expressPath}" `);
1754
+ //#endregion
1755
+ if (UtilsOs__NS__isElectron) {
1756
+ //#region @backend
1757
+ const ipcKeyName = TaonHelpers__NS__ipcKeyNameRequest(target, methodConfig, expressPath);
1758
+ ipcMain.on(ipcKeyName, async (event, paramsFromBrowser) => {
1759
+ const responseJsonData = await getResult(paramsFromBrowser, void 0, void 0);
1760
+ const sendToIpsMainOn = TaonHelpers__NS__ipcKeyNameResponse(target, methodConfig, expressPath);
1761
+ // console.log({ sendToIpsMainOn });
1762
+ event.sender.send(sendToIpsMainOn, responseJsonData);
1763
+ });
1764
+ return {
1765
+ expressPath,
1766
+ method: methodConfig.type,
1767
+ };
1768
+ //#endregion
1769
+ }
1770
+ if (!this.isRemoteHost) {
1771
+ //#region apply dummy websql express routers
1772
+ //#region @websql
1773
+ if (UtilsOs__NS__isWebSQL) {
1774
+ if (!this.expressApp[httpMethodType.toLowerCase()]) {
1775
+ this.expressApp[httpMethodType.toLowerCase()] = () => { };
1776
+ // TODO add middlewares for WEBSQL and ELECTRON mode
1777
+ }
1778
+ }
1779
+ //#endregion
1780
+ //#endregion
1781
+ //#region @backend
1782
+ // this.logHttp &&
1783
+ // console.log(`[${httpMethodType.toUpperCase()}] ${expressPath} `);
1784
+ this.expressApp[httpMethodType.toLowerCase()](expressPath, ...middlewareHandlers, async (req, res) => {
1785
+ // console.log(`[${type.toUpperCase()}] ${expressPath} `);
1786
+ //#region process params
1787
+ const args = [];
1788
+ let tBody = req.body;
1789
+ let tParams = req.params;
1790
+ let tQuery = req.query;
1791
+ if (req.headers[Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY]) {
1792
+ try {
1793
+ tBody = JSON.parse(JSON.stringify(tBody), JSON.parse(TaonHelpers__NS__firstStringOrElemFromArray(req.headers[Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY])));
1794
+ }
1795
+ catch (e) { }
1796
+ }
1797
+ if (req.headers[Symbols__NS__old.CIRCURAL_OBJECTS_MAP_QUERY_PARAM]) {
1798
+ try {
1799
+ tQuery = JSON.parse(JSON.stringify(tQuery), JSON.parse(TaonHelpers__NS__firstStringOrElemFromArray(req.headers[Symbols__NS__old.CIRCURAL_OBJECTS_MAP_QUERY_PARAM])));
1800
+ }
1801
+ catch (e) { }
1802
+ }
1803
+ // make class instance from body
1804
+ // console.log('req.headers', req.headers)
1805
+ if (req.headers[Symbols__NS__old.MAPPING_CONFIG_HEADER_BODY_PARAMS]) {
1806
+ try {
1807
+ const entity = JSON.parse(TaonHelpers__NS__firstStringOrElemFromArray(req.headers[Symbols__NS__old.MAPPING_CONFIG_HEADER_BODY_PARAMS]));
1808
+ tBody = Mapping__NS__encode(tBody, entity);
1809
+ }
1810
+ catch (e) { }
1811
+ }
1812
+ else {
1813
+ Object.keys(tBody).forEach(paramName => {
1814
+ try {
1815
+ const entityForParam = JSON.parse(TaonHelpers__NS__firstStringOrElemFromArray(req.headers[`${Symbols__NS__old.MAPPING_CONFIG_HEADER_BODY_PARAMS}${paramName} `]));
1816
+ tBody[paramName] = Mapping__NS__encode(tBody[paramName], entityForParam);
1817
+ }
1818
+ catch (e) { }
1819
+ });
1820
+ }
1821
+ // make class instance from query params
1822
+ // console.log('req.headers', tQuery)
1823
+ if (req.headers[Symbols__NS__old.MAPPING_CONFIG_HEADER_QUERY_PARAMS]) {
1824
+ try {
1825
+ const entity = JSON.parse(TaonHelpers__NS__firstStringOrElemFromArray(req.headers[Symbols__NS__old.MAPPING_CONFIG_HEADER_QUERY_PARAMS]));
1826
+ tQuery = TaonHelpers__NS__parseJSONwithStringJSONs(Mapping__NS__encode(tQuery, entity));
1827
+ }
1828
+ catch (e) { }
1829
+ }
1830
+ else {
1831
+ Object.keys(tQuery).forEach(queryParamName => {
1832
+ try {
1833
+ const entityForParam = JSON.parse(TaonHelpers__NS__firstStringOrElemFromArray(req.headers[`${Symbols__NS__old.MAPPING_CONFIG_HEADER_QUERY_PARAMS}${queryParamName} `]));
1834
+ let beforeTransofrm = tQuery[queryParamName];
1835
+ if (___NS__isString(beforeTransofrm)) {
1836
+ try {
1837
+ const paresed = TaonHelpers__NS__tryTransformParam(beforeTransofrm);
1838
+ beforeTransofrm = paresed;
1839
+ }
1840
+ catch (e) { }
1841
+ }
1842
+ const afterEncoding = Mapping__NS__encode(beforeTransofrm, entityForParam);
1843
+ tQuery[queryParamName] =
1844
+ TaonHelpers__NS__parseJSONwithStringJSONs(afterEncoding);
1845
+ }
1846
+ catch (e) { }
1847
+ });
1848
+ }
1849
+ Object.keys(methodConfig.parameters).forEach(paramName => {
1850
+ let p = methodConfig.parameters[paramName];
1851
+ if (p.paramType === 'Path' && tParams) {
1852
+ args.push(tParams[p.paramName]);
1853
+ }
1854
+ if (p.paramType === 'Query' && tQuery) {
1855
+ if (p.paramName) {
1856
+ args.push(tQuery[p.paramName]);
1857
+ }
1858
+ else {
1859
+ args.push(tQuery);
1860
+ }
1861
+ }
1862
+ if (p.paramType === 'Header' && req.headers) {
1863
+ args.push(req.headers[p.paramName.toLowerCase()]);
1864
+ }
1865
+ if (p.paramType === 'Cookie' && req.cookies) {
1866
+ args.push(req.cookies[p.paramName]);
1867
+ }
1868
+ if (p.paramType === 'Body' && tBody) {
1869
+ if (p.paramName && typeof tBody === 'object') {
1870
+ args.push(tBody[p.paramName]);
1871
+ }
1872
+ else {
1873
+ args.push(tBody);
1874
+ }
1875
+ }
1876
+ });
1877
+ //#endregion
1878
+ const resolvedParams = args
1879
+ .reverse()
1880
+ .map(v => TaonHelpers__NS__tryTransformParam(v));
1881
+ try {
1882
+ let result = await getResult(resolvedParams, req, res);
1883
+ if (methodConfig.responseType)
1884
+ if (res.headersSent) {
1885
+ // SKIP FURTHER PROCESSING IF RESPONSE ALREADY SENT
1886
+ return;
1887
+ }
1888
+ if (methodConfig.overrideExpressSendAsHtml) {
1889
+ res.setHeader('Content-Type', 'text/html');
1890
+ res.send(result);
1891
+ return;
1892
+ }
1893
+ if (result instanceof Blob &&
1894
+ methodConfig.responseType ===
1895
+ 'blob') {
1896
+ // console.log('INSTANCE OF BLOB')
1897
+ //#region processs blob result type
1898
+ const blob = result;
1899
+ const file = Buffer.from(await blob.arrayBuffer());
1900
+ res.writeHead(200, {
1901
+ 'Content-Type': blob.type,
1902
+ 'Content-Length': file.length,
1903
+ });
1904
+ res.end(file);
1905
+ //#endregion
1906
+ }
1907
+ else if (___NS__isString(result) &&
1908
+ methodConfig.responseType ===
1909
+ 'blob') {
1910
+ // console.log('BASE64')
1911
+ //#region process string buffer TODO refacetor
1912
+ const img_base64 = result;
1913
+ const m = /^data:(.+?);base64,(.+)$/.exec(img_base64);
1914
+ if (!m) {
1915
+ throw new Error(`[taon - framework] Not a base64 image[${img_base64}]`);
1916
+ }
1917
+ const [_, content_type, file_base64] = m;
1918
+ const file = Buffer.from(file_base64, 'base64');
1919
+ res.writeHead(200, {
1920
+ 'Content-Type': content_type,
1921
+ 'Content-Length': file.length,
1922
+ });
1923
+ res.end(file);
1924
+ //#endregion
1925
+ }
1926
+ else {
1927
+ //#region process json request
1928
+ await EntityProcess.init(result, res);
1929
+ //#endregion
1930
+ }
1931
+ }
1932
+ catch (error) {
1933
+ if (res.headersSent) {
1934
+ // SKIP FURTHER PROCESSING IF RESPONSE ALREADY SENT
1935
+ return;
1936
+ }
1937
+ if (methodConfig.overrideExpressSendAsHtml) {
1938
+ res.setHeader('Content-Type', 'text/html');
1939
+ res.send(error);
1940
+ return;
1941
+ }
1942
+ this.sendError(res, error, req, expressPath);
1943
+ }
1944
+ });
1945
+ //#endregion
1946
+ }
1947
+ return {
1948
+ expressPath: expressPath,
1949
+ method: methodConfig.type,
1950
+ };
1951
+ }
1952
+ //#endregion
1953
+ //#region methods & getters / send error
1954
+ sendError(res, error, req, expressPath) {
1955
+ //#region @backendFunc
1956
+ let status = 500;
1957
+ let message = 'Internal Server Error';
1958
+ let details = undefined;
1959
+ let success = false;
1960
+ let code = undefined;
1961
+ if (typeof error === 'function') {
1962
+ const obj = error(res) || {};
1963
+ status = obj.status || 400;
1964
+ message = obj.message;
1965
+ details = obj.details;
1966
+ code = obj.code;
1967
+ }
1968
+ else if (typeof error === 'string') {
1969
+ message = error;
1970
+ status = 400;
1971
+ }
1972
+ else if (error instanceof Error) {
1973
+ message = error.message;
1974
+ details = process.env.NODE_ENV !== 'production' ? error.stack : undefined;
1975
+ }
1976
+ else {
1977
+ message = 'Unexpected error';
1978
+ details = error;
1979
+ }
1980
+ res.status(status).json({
1981
+ success,
1982
+ message,
1983
+ details,
1984
+ code,
1985
+ [CoreModels__NS__TaonHttpErrorCustomProp]: true,
1986
+ });
1987
+ //#endregion
1988
+ }
1989
+ //#endregion
1990
+ //#region methods & getters / init client
1991
+ /**
1992
+ * client can be browser or nodejs (when remote host)
1993
+ */
1994
+ async initClient(target, httpRequestType, methodConfig, // Models.Http.Rest.MethodConfig,
1995
+ expressPath) {
1996
+ const ctx = this;
1997
+ // console.log(
1998
+ // `CLIENT: expressPath: "${expressPath}" interceptor for method: ${methodConfig.calculatedMiddlewares?.length} `,
1999
+ // );
2000
+ //#region init middlewares
2001
+ const middlewares = methodConfig.calculatedMiddlewares;
2002
+ const middlewaresInstances = middlewares
2003
+ .map(f => this.getInstanceBy(f))
2004
+ .filter(f => ___NS__isFunction(f.interceptClientMethod));
2005
+ middlewaresInstances.forEach(instance => {
2006
+ const middlewareName = ClassHelpers__NS__getName(instance);
2007
+ // middlewareName - only needed for inheritace and uniqness of interceptors
2008
+ const interceptorKey = `${middlewareName}-${methodConfig.type?.toUpperCase()}-${expressPath}`;
2009
+ Resource.request.methodsInterceptors.set(interceptorKey, {
2010
+ intercept: ({ req, next }) => {
2011
+ return instance.interceptClientMethod({
2012
+ req,
2013
+ next,
2014
+ }, {
2015
+ methodName: methodConfig.methodName,
2016
+ expressPath,
2017
+ httpRequestType: httpRequestType,
2018
+ });
2019
+ },
2020
+ });
2021
+ });
2022
+ //#endregion
2023
+ // : { received: any; /* Rest<any, any> */ }
2024
+ // this.logHttp &&
2025
+ // console.log(`${httpRequestType?.toUpperCase()} ${expressPath} `);
2026
+ // console.log('INITING', methodConfig); // TODO inject in static
2027
+ //#region resolve storage
2028
+ // TODO not a good idea
2029
+ const storage = globalThis;
2030
+ //#endregion
2031
+ const orgMethods = target.prototype[methodConfig.methodName];
2032
+ //#region handle electron ipc request
2033
+ if (UtilsOs__NS__isElectron) {
2034
+ const ipcRenderer = window.require('electron').ipcRenderer;
2035
+ target.prototype[methodConfig.methodName] = function (...args) {
2036
+ const received = new Promise(async (resolve, reject) => {
2037
+ const headers = {};
2038
+ const { request, response } = TaonHelpers__NS__websqlMocks(headers);
2039
+ /* */
2040
+ /* */
2041
+ /* */
2042
+ /* */
2043
+ /* */
2044
+ /* */
2045
+ /* */
2046
+ /* */
2047
+ /* */
2048
+ /* */
2049
+ /* */
2050
+ /* */
2051
+ /* */
2052
+ /* */
2053
+ /* */
2054
+ /* */
2055
+ /* */
2056
+ /* */
2057
+ /* */
2058
+ /* */
2059
+ /* */
2060
+ /* */
2061
+ /* */
2062
+ /* */
2063
+ /* */
2064
+ /* */
2065
+ /* */
2066
+ /* */
2067
+ /* */
2068
+ /* */
2069
+ /* */
2070
+ /* */
2071
+ /* */
2072
+ /* */
2073
+ /* */
2074
+ /* */
2075
+ });
2076
+ received['observable'] = from(received);
2077
+ return {
2078
+ received,
2079
+ request(axiosConfig) {
2080
+ return received;
2081
+ },
2082
+ };
2083
+ };
2084
+ return;
2085
+ }
2086
+ //#endregion
2087
+ //#region handling web sql request
2088
+ /* */
2089
+ /* */
2090
+ /* */
2091
+ /* */
2092
+ /* */
2093
+ /* */
2094
+ /* */
2095
+ /* */
2096
+ /* */
2097
+ /* */
2098
+ /* */
2099
+ /* */
2100
+ /* */
2101
+ /* */
2102
+ /* */
2103
+ /* */
2104
+ /* */
2105
+ /* */
2106
+ /* */
2107
+ /* */
2108
+ /* */
2109
+ /* */
2110
+ /* */
2111
+ /* */
2112
+ /* */
2113
+ /* */
2114
+ /* */
2115
+ /* */
2116
+ /* */
2117
+ /* */
2118
+ /* */
2119
+ /* */
2120
+ /* */
2121
+ /* */
2122
+ /* */
2123
+ /* */
2124
+ /* */
2125
+ /* */
2126
+ /* */
2127
+ /* */
2128
+ /* */
2129
+ /* */
2130
+ /* */
2131
+ /* */
2132
+ /* */
2133
+ /* */
2134
+ /* */
2135
+ /* */
2136
+ /* */
2137
+ /* */
2138
+ /* */
2139
+ /* */
2140
+ /* */
2141
+ /* */
2142
+ /* */
2143
+ /* */
2144
+ /* */
2145
+ /* */
2146
+ /* */
2147
+ /* */
2148
+ /* */
2149
+ /* */
2150
+ /* */
2151
+ /* */
2152
+ /* */
2153
+ /* */
2154
+ /* */
2155
+ /* */
2156
+ /* */
2157
+ /* */
2158
+ /* */
2159
+ /* */
2160
+ /* */
2161
+ /* */
2162
+ /* */
2163
+ /* */
2164
+ /* */
2165
+ /* */
2166
+ /* */
2167
+ /* */
2168
+ /* */
2169
+ /* */
2170
+ /* */
2171
+ /* */
2172
+ /* */
2173
+ /* */
2174
+ /* */
2175
+ /* */
2176
+ /* */
2177
+ /* */
2178
+ /* */
2179
+ /* */
2180
+ /* */
2181
+ /* */
2182
+ /* */
2183
+ /* */
2184
+ /* */
2185
+ /* */
2186
+ /* */
2187
+ /* */
2188
+ /* */
2189
+ /* */
2190
+ /* */
2191
+ /* */
2192
+ /* */
2193
+ /* */
2194
+ /* */
2195
+ /* */
2196
+ /* */
2197
+ /* */
2198
+ /* */
2199
+ /* */
2200
+ /* */
2201
+ /* */
2202
+ /* */
2203
+ /* */
2204
+ /* */
2205
+ /* */
2206
+ /* */
2207
+ /* */
2208
+ /* */
2209
+ /* */
2210
+ /* */
2211
+ /* */
2212
+ /* */
2213
+ /* */
2214
+ /* */
2215
+ /* */
2216
+ /* */
2217
+ /* */
2218
+ /* */
2219
+ /* */
2220
+ /* */
2221
+ /* */
2222
+ /* */
2223
+ /* */
2224
+ /* */
2225
+ /* */
2226
+ /* */
2227
+ /* */
2228
+ /* */
2229
+ /* */
2230
+ /* */
2231
+ /* */
2232
+ /* */
2233
+ /* */
2234
+ /* */
2235
+ /* */
2236
+ /* */
2237
+ /* */
2238
+ //#endregion
2239
+ //#region handle normal request
2240
+ target.prototype[methodConfig.methodName] = function (...args) {
2241
+ // console.log('[init method browser] FRONTEND expressPath', expressPath)
2242
+ // const productionMode = FrameworkContext.isProductionMode;
2243
+ //#region resolve frontend parameters
2244
+ if (!storage[Symbols__NS__old.ENDPOINT_META_CONFIG])
2245
+ storage[Symbols__NS__old.ENDPOINT_META_CONFIG] = {};
2246
+ if (!storage[Symbols__NS__old.ENDPOINT_META_CONFIG][ctx.uriOrigin])
2247
+ storage[Symbols__NS__old.ENDPOINT_META_CONFIG][ctx.uriOrigin] = {};
2248
+ const endpoints = storage[Symbols__NS__old.ENDPOINT_META_CONFIG];
2249
+ let rest;
2250
+ if (!endpoints[ctx.uriOrigin][expressPath]) {
2251
+ let headers = {};
2252
+ if (methodConfig.contentType && !methodConfig.responseType) {
2253
+ rest = Resource.create(ctx.uriOrigin, expressPath, Symbols__NS__old.MAPPING_CONFIG_HEADER, Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY, RestHeaders.from({
2254
+ 'Content-Type': methodConfig.contentType,
2255
+ Accept: methodConfig.contentType,
2256
+ }));
2257
+ }
2258
+ else if (methodConfig.contentType && methodConfig.responseType) {
2259
+ rest = Resource.create(ctx.uriOrigin, expressPath, Symbols__NS__old.MAPPING_CONFIG_HEADER, Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY, RestHeaders.from({
2260
+ 'Content-Type': methodConfig.contentType,
2261
+ Accept: methodConfig.contentType,
2262
+ responsetypeaxios: methodConfig.responseType,
2263
+ }));
2264
+ }
2265
+ else if (!methodConfig.contentType && methodConfig.responseType) {
2266
+ rest = Resource.create(ctx.uriOrigin, expressPath, Symbols__NS__old.MAPPING_CONFIG_HEADER, Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY, RestHeaders.from({
2267
+ responsetypeaxios: methodConfig.responseType,
2268
+ }));
2269
+ }
2270
+ else {
2271
+ rest = Resource.create(ctx.uriOrigin, expressPath, Symbols__NS__old.MAPPING_CONFIG_HEADER, Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY);
2272
+ }
2273
+ endpoints[ctx.uriOrigin][expressPath] = rest;
2274
+ }
2275
+ else {
2276
+ rest = endpoints[ctx.uriOrigin][expressPath];
2277
+ }
2278
+ const method = httpRequestType.toLowerCase();
2279
+ const pathPrams = {};
2280
+ let queryParams = {};
2281
+ let bodyObject = {};
2282
+ args.forEach((param, i) => {
2283
+ let currentParam = void 0;
2284
+ for (let pp in methodConfig.parameters) {
2285
+ let v = methodConfig.parameters[pp];
2286
+ if (v.index === i) {
2287
+ currentParam = v;
2288
+ break;
2289
+ }
2290
+ }
2291
+ if (!currentParam) {
2292
+ const errorMessage = `[${config.frameworkName}] Unable to resolve parameter` +
2293
+ ` at index ${i} for method ${methodConfig.methodName} at path ${expressPath}.`;
2294
+ //#region @backend
2295
+ console.error(errorMessage);
2296
+ process.exit(0);
2297
+ //#endregion
2298
+ throw new Error(errorMessage);
2299
+ }
2300
+ if (currentParam.paramType === 'Path') {
2301
+ pathPrams[currentParam.paramName] = param;
2302
+ }
2303
+ if (currentParam.paramType === 'Query') {
2304
+ if (currentParam.paramName) {
2305
+ const mapping = Mapping__NS__decode(param, !ctx.isProductionMode);
2306
+ if (mapping) {
2307
+ rest.headers.set(`${Symbols__NS__old.MAPPING_CONFIG_HEADER_QUERY_PARAMS}${currentParam.paramName} `, JSON.stringify(mapping));
2308
+ }
2309
+ queryParams[currentParam.paramName] = param;
2310
+ }
2311
+ else {
2312
+ const mapping = Mapping__NS__decode(param, !ctx.isProductionMode);
2313
+ if (mapping) {
2314
+ rest.headers.set(Symbols__NS__old.MAPPING_CONFIG_HEADER_QUERY_PARAMS, JSON.stringify(mapping));
2315
+ }
2316
+ queryParams = ___NS__cloneDeep(param);
2317
+ }
2318
+ }
2319
+ if (currentParam.paramType === 'Header') {
2320
+ if (currentParam.paramName) {
2321
+ if (currentParam.paramName === Symbols__NS__old.MDC_KEY) {
2322
+ // parese MDC
2323
+ rest.headers.set(currentParam.paramName, encodeURIComponent(JSON.stringify(param)));
2324
+ }
2325
+ else {
2326
+ rest.headers.set(currentParam.paramName, param);
2327
+ }
2328
+ }
2329
+ else {
2330
+ for (let header in param) {
2331
+ rest.headers.set(header, param[header]);
2332
+ }
2333
+ }
2334
+ }
2335
+ if (currentParam.paramType === 'Cookie') {
2336
+ Resource.Cookies.write(currentParam.paramName, param, currentParam.expireInSeconds);
2337
+ }
2338
+ if (currentParam.paramType === 'Body') {
2339
+ if (currentParam.paramName) {
2340
+ if (ClassHelpers__NS__getName(bodyObject) === 'FormData') {
2341
+ throw new Error(`[taon - framework] Don use param names when posting / putting FormData.
2342
+ Use this:
2343
+ // ...
2344
+ (@Taon.Http.Param.Body() formData: FormData) ...
2345
+ // ...
2346
+
2347
+ instead
2348
+ // ...
2349
+ (@Taon.Http.Param.Body('${currentParam.paramName}') formData: FormData) ...
2350
+ // ...
2351
+ `);
2352
+ }
2353
+ const mapping = Mapping__NS__decode(param, !ctx.isProductionMode);
2354
+ if (mapping) {
2355
+ rest.headers.set(`${Symbols__NS__old.MAPPING_CONFIG_HEADER_BODY_PARAMS}${currentParam.paramName} `, JSON.stringify(mapping));
2356
+ }
2357
+ bodyObject[currentParam.paramName] = param;
2358
+ }
2359
+ else {
2360
+ const mapping = Mapping__NS__decode(param, !ctx.isProductionMode);
2361
+ if (mapping) {
2362
+ rest.headers.set(Symbols__NS__old.MAPPING_CONFIG_HEADER_BODY_PARAMS, JSON.stringify(mapping));
2363
+ }
2364
+ bodyObject = param;
2365
+ }
2366
+ }
2367
+ });
2368
+ if (typeof bodyObject === 'object' &&
2369
+ ClassHelpers__NS__getName(bodyObject) !== 'FormData') {
2370
+ let circuralFromItem = [];
2371
+ bodyObject = JSON10.parse(JSON10.stringify(bodyObject, void 0, void 0, circs => {
2372
+ circuralFromItem = circs;
2373
+ }));
2374
+ rest.headers.set(Symbols__NS__old.CIRCURAL_OBJECTS_MAP_BODY, JSON10.stringify(circuralFromItem));
2375
+ }
2376
+ if (typeof queryParams === 'object') {
2377
+ let circuralFromQueryParams = [];
2378
+ queryParams = JSON10.parse(JSON10.stringify(queryParams, void 0, void 0, circs => {
2379
+ circuralFromQueryParams = circs;
2380
+ }));
2381
+ rest.headers.set(Symbols__NS__old.CIRCURAL_OBJECTS_MAP_QUERY_PARAM, JSON10.stringify(circuralFromQueryParams));
2382
+ }
2383
+ //#endregion
2384
+ const httpResultObj = {
2385
+ get received() {
2386
+ return rest.model(pathPrams)[method](bodyObject, [queryParams]);
2387
+ },
2388
+ request(axiosConfig) {
2389
+ return rest
2390
+ .model(pathPrams)[method](bodyObject, [queryParams], axiosConfig);
2391
+ },
2392
+ };
2393
+ return httpResultObj;
2394
+ };
2395
+ //#endregion
2396
+ }
2397
+ }