lemon-core 3.1.0 → 3.1.1

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 (101) hide show
  1. package/README.md +1 -0
  2. package/dist/controllers/dummy-controller.d.ts +1 -1
  3. package/dist/controllers/dummy-controller.js +2 -2
  4. package/dist/controllers/dummy-controller.js.map +1 -1
  5. package/dist/controllers/general-api-controller.d.ts +1 -1
  6. package/dist/cores/api/api-service.d.ts +239 -0
  7. package/dist/cores/api/api-service.js +674 -0
  8. package/dist/cores/api/api-service.js.map +1 -0
  9. package/dist/cores/api/index.d.ts +10 -0
  10. package/dist/cores/api/index.js +27 -0
  11. package/dist/cores/api/index.js.map +1 -0
  12. package/dist/cores/aws/aws-kms-service.d.ts +53 -2
  13. package/dist/cores/aws/aws-kms-service.js +104 -17
  14. package/dist/cores/aws/aws-kms-service.js.map +1 -1
  15. package/dist/cores/cache/cache-service.d.ts +440 -0
  16. package/dist/cores/cache/cache-service.js +967 -0
  17. package/dist/cores/cache/cache-service.js.map +1 -0
  18. package/dist/cores/cache/index.d.ts +10 -0
  19. package/dist/cores/cache/index.js +27 -0
  20. package/dist/cores/cache/index.js.map +1 -0
  21. package/dist/cores/cache-service.d.ts +54 -18
  22. package/dist/cores/cache-service.js +37 -26
  23. package/dist/cores/cache-service.js.map +1 -1
  24. package/dist/cores/core-types.d.ts +42 -12
  25. package/dist/cores/dynamo/dynamo-query-service.d.ts +52 -0
  26. package/dist/cores/dynamo/dynamo-query-service.js +127 -0
  27. package/dist/cores/dynamo/dynamo-query-service.js.map +1 -0
  28. package/dist/cores/dynamo/dynamo-scan-service.d.ts +70 -0
  29. package/dist/cores/dynamo/dynamo-scan-service.js +164 -0
  30. package/dist/cores/dynamo/dynamo-scan-service.js.map +1 -0
  31. package/dist/cores/dynamo/dynamo-service.d.ts +192 -0
  32. package/dist/cores/dynamo/dynamo-service.js +525 -0
  33. package/dist/cores/dynamo/dynamo-service.js.map +1 -0
  34. package/dist/cores/dynamo/index.d.ts +12 -0
  35. package/dist/cores/dynamo/index.js +29 -0
  36. package/dist/cores/dynamo/index.js.map +1 -0
  37. package/dist/cores/elastic/elastic6-query-service.d.ts +104 -0
  38. package/dist/cores/elastic/elastic6-query-service.js +510 -0
  39. package/dist/cores/elastic/elastic6-query-service.js.map +1 -0
  40. package/dist/cores/elastic/elastic6-service.d.ts +273 -0
  41. package/dist/cores/elastic/elastic6-service.js +903 -0
  42. package/dist/cores/elastic/elastic6-service.js.map +1 -0
  43. package/dist/cores/elastic/hangul-service.d.ts +102 -0
  44. package/dist/cores/elastic/hangul-service.js +205 -0
  45. package/dist/cores/elastic/hangul-service.js.map +1 -0
  46. package/dist/cores/elastic/index.d.ts +12 -0
  47. package/dist/cores/elastic/index.js +29 -0
  48. package/dist/cores/elastic/index.js.map +1 -0
  49. package/dist/cores/hangul-service.d.ts +17 -3
  50. package/dist/cores/hangul-service.js +17 -8
  51. package/dist/cores/hangul-service.js.map +1 -1
  52. package/dist/cores/index.d.ts +5 -11
  53. package/dist/cores/index.js +8 -13
  54. package/dist/cores/index.js.map +1 -1
  55. package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +2 -2
  56. package/dist/cores/lambda/lambda-web-handler.d.ts +158 -8
  57. package/dist/cores/lambda/lambda-web-handler.js +283 -77
  58. package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
  59. package/dist/cores/protocol/protocol-service.d.ts +4 -0
  60. package/dist/cores/protocol/protocol-service.js +12 -7
  61. package/dist/cores/protocol/protocol-service.js.map +1 -1
  62. package/dist/cores/storage/http-storage-service.d.ts +22 -0
  63. package/dist/cores/storage/http-storage-service.js +129 -0
  64. package/dist/cores/storage/http-storage-service.js.map +1 -0
  65. package/dist/cores/storage/index.d.ts +14 -0
  66. package/dist/cores/storage/index.js +31 -0
  67. package/dist/cores/storage/index.js.map +1 -0
  68. package/dist/cores/storage/model-manager.d.ts +93 -0
  69. package/dist/cores/storage/model-manager.js +192 -0
  70. package/dist/cores/storage/model-manager.js.map +1 -0
  71. package/dist/cores/storage/proxy-storage-service.d.ts +573 -0
  72. package/dist/cores/storage/proxy-storage-service.js +913 -0
  73. package/dist/cores/storage/proxy-storage-service.js.map +1 -0
  74. package/dist/cores/storage/redis-storage-service.d.ts +183 -0
  75. package/dist/cores/storage/redis-storage-service.js +391 -0
  76. package/dist/cores/storage/redis-storage-service.js.map +1 -0
  77. package/dist/cores/storage/storage-service.d.ts +169 -0
  78. package/dist/cores/storage/storage-service.js +374 -0
  79. package/dist/cores/storage/storage-service.js.map +1 -0
  80. package/dist/cores/storage-service.d.ts +1 -1
  81. package/dist/cores/storage-service.js +2 -2
  82. package/dist/cores/storage-service.js.map +1 -1
  83. package/dist/engine/utilities.d.ts +4 -3
  84. package/dist/engine/utilities.js +6 -6
  85. package/dist/engine/utilities.js.map +1 -1
  86. package/dist/environ.d.ts +2 -2
  87. package/dist/environ.js +7 -4
  88. package/dist/environ.js.map +1 -1
  89. package/dist/extended/abstract-service.d.ts +533 -0
  90. package/dist/extended/abstract-service.js +915 -0
  91. package/dist/extended/abstract-service.js.map +1 -0
  92. package/dist/extended/index.d.ts +10 -0
  93. package/dist/extended/index.js +27 -0
  94. package/dist/extended/index.js.map +1 -0
  95. package/dist/helpers/helpers.d.ts +7 -0
  96. package/dist/helpers/helpers.js +7 -0
  97. package/dist/helpers/helpers.js.map +1 -1
  98. package/dist/index.d.ts +1 -0
  99. package/dist/index.js +3 -1
  100. package/dist/index.js.map +1 -1
  101. package/package.json +6 -4
@@ -0,0 +1,674 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ var _a, _b;
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.MocksAPIService = exports.createHttpWebProxy = exports.APIService = exports.APIProxyClient = void 0;
17
+ /**
18
+ * `api-service.ts`
19
+ * - common external rest-api service.
20
+ * - support http-proxy with backbone to overcome VPC restriction.
21
+ *
22
+ *
23
+ * @author Steve Jung <steve@lemoncloud.io>
24
+ * @date 2019-05-23 initial version
25
+ * @date 2019-12-03 refactoring for `lemon-core#2.0.0`
26
+ *
27
+ * @copyright (C) lemoncloud.io 2019 - All Rights Reserved.
28
+ */
29
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
30
+ const engine_1 = require("../../engine/");
31
+ const shared_1 = require("../../tools/shared");
32
+ const test_helper_1 = require("../../common/test-helper");
33
+ const fs_1 = __importDefault(require("fs"));
34
+ const NS = engine_1.$U.NS('APIS', 'green'); // NAMESPACE TO BE PRINTED.
35
+ /**
36
+ * class: `APIProxyClient`
37
+ * - proxed APIServiceClient
38
+ */
39
+ class APIProxyClient {
40
+ constructor(service) {
41
+ this.hello = () => this.service.hello();
42
+ this.service = service;
43
+ }
44
+ doGet(id, cmd, param, body, hash) {
45
+ return this.service.doGet(id, cmd, param, body, hash);
46
+ }
47
+ doPut(id, cmd, param, body, hash) {
48
+ return this.service.doPut(id, cmd, param, body, hash);
49
+ }
50
+ doPost(id, cmd, param, body, hash) {
51
+ return this.service.doPost(id, cmd, param, body, hash);
52
+ }
53
+ doPatch(id, cmd, param, body, hash) {
54
+ return this.service.doPatch(id, cmd, param, body, hash);
55
+ }
56
+ doDelete(id, cmd, param, body, hash) {
57
+ return this.service.doDelete(id, cmd, param, body, hash);
58
+ }
59
+ }
60
+ exports.APIProxyClient = APIProxyClient;
61
+ /**
62
+ * class: `APIService`
63
+ * - use internal http-proxy service due to restriction internet-face in VPC lambda.
64
+ */
65
+ class APIService {
66
+ /**
67
+ * create API service.
68
+ *
69
+ * ```js
70
+ * // basic
71
+ * const api = new API('web', 'http://localhost:8081', {});
72
+ * api.doGet('');
73
+ *
74
+ * // via python
75
+ * const api = new API('residents', 'http://localhost:8113', {});
76
+ * api.doGet('123'); // http GET :8113/residents/123
77
+ *
78
+ * // proxy server
79
+ * const api = new API('web', 'http://localhost:8081', {}, null, proxy);
80
+ * api.doGet('');
81
+ * ```
82
+ *
83
+ * @param type type in endpoint
84
+ * @param endpoint base endpoint (support ONLY http, https)
85
+ * @param headers common headers.
86
+ * @param client real api-client to use (or use proxy, or create default)
87
+ * @param proxy proxy-service to use if there is no client (or use backbone server)
88
+ */
89
+ constructor(type, endpoint, headers, client, proxy) {
90
+ //! relay hello.
91
+ this.hello = () => `api-service:${this.client.hello()}`;
92
+ /**
93
+ * GET HOST/PATH?$param
94
+ */
95
+ this.doGet = (id, cmd, $param, $body, hash) => __awaiter(this, void 0, void 0, function* () {
96
+ return this.client.doGet(id, cmd, $param, $body, hash);
97
+ });
98
+ /**
99
+ * PUT HOST/PATH?$param
100
+ */
101
+ this.doPut = (id, cmd, $param, $body, hash) => __awaiter(this, void 0, void 0, function* () {
102
+ return this.client.doPut(id, cmd, $param, $body, hash);
103
+ });
104
+ /**
105
+ * POST HOST/PATH?$param
106
+ */
107
+ this.doPost = (id, cmd, $param, $body, hash) => __awaiter(this, void 0, void 0, function* () {
108
+ return this.client.doPost(id, cmd, $param, $body, hash);
109
+ });
110
+ /**
111
+ * PATCH HOST/PATH?$param
112
+ */
113
+ this.doPatch = (id, cmd, $param, $body, hash) => __awaiter(this, void 0, void 0, function* () {
114
+ return this.client.doPatch(id, cmd, $param, $body, hash);
115
+ });
116
+ /**
117
+ * DELETE HOST/PATH?$param
118
+ */
119
+ this.doDelete = (id, cmd, $param, $body, hash) => __awaiter(this, void 0, void 0, function* () {
120
+ return this.client.doDelete(id, cmd, $param, $body, hash);
121
+ });
122
+ if (!endpoint)
123
+ throw new Error('@endpoint (url) is required');
124
+ if (!endpoint.startsWith('http://') && !endpoint.startsWith('https://'))
125
+ throw new Error(`@endpoint (url) is not valid http-url:${endpoint}`);
126
+ this.type = type;
127
+ this.endpoint = endpoint;
128
+ this.headers = headers;
129
+ if (client) {
130
+ this.client = client;
131
+ }
132
+ else if (proxy) {
133
+ this.client = APIService.buildClient(this.type, this.endpoint, this.headers, null, proxy);
134
+ }
135
+ else {
136
+ //! use default `env.BACKBONE_API` to detect proxy-server.
137
+ const BACKBONE = engine_1.$engine.environ('BACKBONE_API', 'http://localhost:8081');
138
+ this.client = APIService.buildClient(this.type, this.endpoint, this.headers, BACKBONE);
139
+ }
140
+ }
141
+ /**
142
+ * helper to make http client
143
+ *
144
+ * @param backbone backbone address like 'http://localhost:8081'
145
+ */
146
+ static buildClient(type, endpoint, headers, backbone, proxy) {
147
+ (0, engine_1._log)(NS, `buildClient(${type || ''})...`);
148
+ if (!endpoint)
149
+ throw new Error('@endpoint (url) is required');
150
+ const host = `${endpoint || ''}`.split('/')[2];
151
+ //! if using backbone, need host+path for full-url. or need only `type` + `id/cmd` pair for direct http agent.
152
+ const base = !proxy && backbone ? `${endpoint || ''}` : undefined;
153
+ //! make the default proxy-client if not in.
154
+ if (proxy) {
155
+ proxy = proxy;
156
+ }
157
+ else if (backbone) {
158
+ //! use web-proxy configuration.
159
+ const NAME = `WEB:${host}-${type || ''}`;
160
+ const encoder = (name, path) => encodeURIComponent(path);
161
+ const relayHeaderKey = 'x-lemon-';
162
+ const resultKey = 'result';
163
+ //! use default backbone's web-proxy service.
164
+ proxy = (0, exports.createHttpWebProxy)(NAME, `${backbone}/web`, headers, encoder, relayHeaderKey, resultKey);
165
+ }
166
+ else {
167
+ //! use direct web request.. (only read `type` + `id/cmd` later)
168
+ const NAME = `API:${host}-${type || ''}`;
169
+ proxy = (0, exports.createHttpWebProxy)(NAME, endpoint, headers, (n, s) => s, '');
170
+ }
171
+ /**
172
+ * create internal client to translate of full url path with `host`+`path`
173
+ */
174
+ return new APIService.ProxyServiceClient(proxy, base, type);
175
+ }
176
+ /**
177
+ * make a client for sub-typed endpoint.
178
+ * @param type sub-type path.
179
+ */
180
+ buildSubTypeClient(type, useRecord, folder) {
181
+ const client = new APIService.SubTypeClient(this, type);
182
+ return useRecord ? new APIService.APIServiceClientRecorder(client, `${this.endpoint}/${type}`, folder) : client;
183
+ }
184
+ /**
185
+ * make api recorder of this service.
186
+ * @param folder base folder (default `./logs`)
187
+ */
188
+ buildRecorder(folder) {
189
+ return new APIService.APIServiceClientRecorder(this, this.endpoint, folder);
190
+ }
191
+ }
192
+ exports.APIService = APIService;
193
+ /**
194
+ * class: `TypedEndpoint`
195
+ * - by using common proxy, extends endpoint by type.
196
+ * - endpoint := base+'/'+type.
197
+ */
198
+ APIService.ProxyServiceClient = class {
199
+ constructor(proxy, base, type) {
200
+ this.asPath = (id, cmd) => {
201
+ const type = this.type;
202
+ const _isNa = (a) => a === undefined || a === null;
203
+ return ('' +
204
+ (_isNa(type) ? '' : '/' + encodeURIComponent(type)) +
205
+ (_isNa(type) || _isNa(id) ? '' : '/' + encodeURIComponent(id)) +
206
+ (_isNa(type) || _isNa(id) || _isNa(cmd) ? '' : '/' + encodeURI(cmd)) + //NOTE - cmd could have additional '/' char.
207
+ '');
208
+ };
209
+ this.asPath2 = (id, cmd) => {
210
+ const _isNa = (a) => a === undefined || a === null;
211
+ return ('' +
212
+ (_isNa(id) ? '' : encodeURIComponent(id)) +
213
+ (_isNa(id) || _isNa(cmd) ? '' : '/' + encodeURI(cmd)) + //NOTE - cmd could have additional '/' char.
214
+ '');
215
+ };
216
+ this.asHostPath = (id, cmd) => {
217
+ let host = this.base ? this.base : this.type;
218
+ let path = this.base ? this.asPath(id, cmd) : this.asPath2(id, cmd);
219
+ if (this.base) {
220
+ const url = (!host.startsWith('http') ? 'http://' : '') + `${host}${path || ''}`;
221
+ const $url = url_1.default.parse(url);
222
+ host = `${$url.protocol || 'http'}//${$url.hostname}`;
223
+ path = `${$url.path}`;
224
+ // console.info(`! asHostPath(${id}, ${cmd})@1 => `, { host, path });
225
+ }
226
+ else {
227
+ // console.info(`! asHostPath(${id}, ${cmd})@2 => `, { host, path });
228
+ }
229
+ return { host, path };
230
+ };
231
+ this.hello = () => `api-client:${this.proxy.hello()}`;
232
+ this.proxy = proxy;
233
+ this.base = base;
234
+ this.type = type;
235
+ }
236
+ doGet(id, cmd, param, body, hash) {
237
+ return __awaiter(this, void 0, void 0, function* () {
238
+ const { host, path } = this.asHostPath(id, cmd);
239
+ return this.proxy.doProxy('GET', host, path, param, body, null, hash);
240
+ });
241
+ }
242
+ doPut(id, cmd, param, body, hash) {
243
+ return __awaiter(this, void 0, void 0, function* () {
244
+ const { host, path } = this.asHostPath(id, cmd);
245
+ return this.proxy.doProxy('PUT', host, path, param, body, null, hash);
246
+ });
247
+ }
248
+ doPost(id, cmd, param, body, hash) {
249
+ return __awaiter(this, void 0, void 0, function* () {
250
+ const { host, path } = this.asHostPath(id, cmd);
251
+ return this.proxy.doProxy('POST', host, path, param, body, null, hash);
252
+ });
253
+ }
254
+ doPatch(id, cmd, param, body, hash) {
255
+ return __awaiter(this, void 0, void 0, function* () {
256
+ const { host, path } = this.asHostPath(id, cmd);
257
+ return this.proxy.doProxy('PATCH', host, path, param, body, null, hash);
258
+ });
259
+ }
260
+ doDelete(id, cmd, param, body, hash) {
261
+ return __awaiter(this, void 0, void 0, function* () {
262
+ const { host, path } = this.asHostPath(id, cmd);
263
+ return this.proxy.doProxy('DELETE', host, path, param, body, null, hash);
264
+ });
265
+ }
266
+ };
267
+ /**
268
+ * use sub-typed endpoint.
269
+ * - extends as endpoint := parent.endpoint + '/' + type
270
+ */
271
+ APIService.SubTypeClient = class {
272
+ constructor(parent, type) {
273
+ this.hello = () => `sub-typed:${this.parent.hello()}`;
274
+ this.asCmd = (id, cmd) => {
275
+ if (id === undefined || id === null)
276
+ return '';
277
+ if (id != encodeURI(id))
278
+ throw new Error(`@id (string) is not valid format.`);
279
+ return cmd !== undefined && cmd !== null ? `${id || ''}/${cmd}` : `${id || ''}`;
280
+ };
281
+ this.parent = parent;
282
+ this.type = `${type || ''}`;
283
+ }
284
+ doGet(id, cmd, param, body, hash) {
285
+ return __awaiter(this, void 0, void 0, function* () {
286
+ return this.parent.doGet(this.type, this.asCmd(id, cmd), param, body, hash);
287
+ });
288
+ }
289
+ doPut(id, cmd, param, body, hash) {
290
+ return __awaiter(this, void 0, void 0, function* () {
291
+ return this.parent.doPut(this.type, this.asCmd(id, cmd), param, body, hash);
292
+ });
293
+ }
294
+ doPost(id, cmd, param, body, hash) {
295
+ return __awaiter(this, void 0, void 0, function* () {
296
+ return this.parent.doPost(this.type, this.asCmd(id, cmd), param, body, hash);
297
+ });
298
+ }
299
+ doPatch(id, cmd, param, body, hash) {
300
+ return __awaiter(this, void 0, void 0, function* () {
301
+ return this.parent.doPatch(this.type, this.asCmd(id, cmd), param, body, hash);
302
+ });
303
+ }
304
+ doDelete(id, cmd, param, body, hash) {
305
+ return __awaiter(this, void 0, void 0, function* () {
306
+ return this.parent.doDelete(this.type, this.asCmd(id, cmd), param, body, hash);
307
+ });
308
+ }
309
+ };
310
+ /**
311
+ * recorder of api-http-proxy client.
312
+ */
313
+ APIService.ApiHttpProxyRecorder = (_a = class {
314
+ constructor(target, folder) {
315
+ this.hello = () => `recorder:${this.target.hello()}`;
316
+ this.target = target;
317
+ this.folder = `${folder || './logs'}`;
318
+ }
319
+ doProxy(method, host, path, param, body, context, hash) {
320
+ return __awaiter(this, void 0, void 0, function* () {
321
+ const endpoint = host.startsWith('http://') || host.startsWith('https://') ? `${host}${path}` : `http://${host}${path}`;
322
+ const index = APIService.ApiHttpProxyRecorder.next++;
323
+ const load = { method, endpoint, param, body, context };
324
+ return this.target
325
+ .doProxy(method, host, path, param, body, context, hash)
326
+ .then((data) => ({ index, load, data, error: null }))
327
+ .catch((error) => ({ index, load, data: null, error }))
328
+ .then(({ index, load, data, error }) => {
329
+ const baseDir = (() => {
330
+ // eslint-disable-next-line prettier/prettier
331
+ const ts = engine_1.$U.ts().substring(0, '1999-01-01'.length).replace(/\-/ig, '');
332
+ const fn = `${this.folder}/R${ts}`;
333
+ if (index <= 1 && !fs_1.default.existsSync(`${this.folder}`))
334
+ fs_1.default.mkdirSync(`${this.folder}`);
335
+ if (index <= 1 && !fs_1.default.existsSync(fn))
336
+ fs_1.default.mkdirSync(fn);
337
+ return fn;
338
+ })();
339
+ // eslint-disable-next-line prettier/prettier
340
+ const message = error instanceof Error ? `${error.message}` : typeof error != 'object' ? `${error}` : error ? JSON.stringify(error) : '';
341
+ const fn = (n) => {
342
+ const [S, s] = ['00000', `${n}`];
343
+ return n > 0 ? `${S.substring(s.length)}${s}` : s.startsWith('-') ? `N${s.substring(1)}` : s;
344
+ };
345
+ const file = `${baseDir}/P${fn(index)}.json`;
346
+ fs_1.default.writeFileSync(file, JSON.stringify({ param: load, data, error: message }, null, ' '), 'utf8');
347
+ if (error)
348
+ throw error;
349
+ else
350
+ return data;
351
+ });
352
+ });
353
+ }
354
+ },
355
+ _a.next = 1,
356
+ _a);
357
+ /**
358
+ * recorder of api-service client.
359
+ */
360
+ APIService.APIServiceClientRecorder = (_b = class {
361
+ constructor(target, endpoint, folder) {
362
+ this.hello = () => `recorder:${this.target.hello()}`;
363
+ this.target = target;
364
+ this.endpoint = `${endpoint || ''}`;
365
+ this.folder = `${folder || './logs'}`;
366
+ }
367
+ doRecord(method, id, cmd, param, body, hash) {
368
+ return __awaiter(this, void 0, void 0, function* () {
369
+ const index = APIService.APIServiceClientRecorder.next++;
370
+ const load = { method, endpoint: `${this.endpoint || ''}`, id, cmd, param, body };
371
+ const call = (method) => __awaiter(this, void 0, void 0, function* () {
372
+ if (method == 'GET')
373
+ return this.target.doGet(id, cmd, param, body, hash);
374
+ if (method == 'PUT')
375
+ return this.target.doPut(id, cmd, param, body, hash);
376
+ if (method == 'POST')
377
+ return this.target.doPost(id, cmd, param, body, hash);
378
+ if (method == 'PATCH')
379
+ return this.target.doPatch(id, cmd, param, body, hash);
380
+ if (method == 'DELETE')
381
+ return this.target.doDelete(id, cmd, param, body, hash);
382
+ throw new Error(`@method is not valid. method:${method}`);
383
+ });
384
+ return call(method)
385
+ .then((data) => ({ index, load, data, error: null }))
386
+ .catch((error) => ({ index, load, data: null, error }))
387
+ .then(({ index, load, data, error }) => {
388
+ const baseDir = (() => {
389
+ // eslint-disable-next-line prettier/prettier
390
+ const ts = engine_1.$U.ts().substring(0, '1999-01-01'.length).replace(/\-/ig, '');
391
+ const fn = `${this.folder}/R${ts}`;
392
+ if (index <= 1 && !fs_1.default.existsSync(`${this.folder}`))
393
+ fs_1.default.mkdirSync(`${this.folder}`);
394
+ if (index <= 1 && !fs_1.default.existsSync(fn))
395
+ fs_1.default.mkdirSync(fn);
396
+ return fn;
397
+ })();
398
+ // eslint-disable-next-line prettier/prettier
399
+ const message = error instanceof Error ? `${error.message}` : typeof error != 'object' ? `${error}` : error ? JSON.stringify(error) : '';
400
+ const fn = (n) => {
401
+ const [S, s] = ['00000', `${n}`];
402
+ return n > 0 ? `${S.substring(s.length)}${s}` : s.startsWith('-') ? `N${s.substring(1)}` : s;
403
+ };
404
+ const file = `${baseDir}/D${fn(index)}.json`;
405
+ fs_1.default.writeFileSync(file, JSON.stringify({ param: load, data, error: message }, null, ' '), 'utf8');
406
+ if (error)
407
+ throw error;
408
+ else
409
+ return data;
410
+ });
411
+ });
412
+ }
413
+ doGet(id, cmd, param, body, hash) {
414
+ return __awaiter(this, void 0, void 0, function* () {
415
+ return this.doRecord('GET', id, cmd, param, body, hash);
416
+ });
417
+ }
418
+ doPut(id, cmd, param, body, hash) {
419
+ return __awaiter(this, void 0, void 0, function* () {
420
+ return this.doRecord('PUT', id, cmd, param, body, hash);
421
+ });
422
+ }
423
+ doPost(id, cmd, param, body, hash) {
424
+ return __awaiter(this, void 0, void 0, function* () {
425
+ return this.doRecord('POST', id, cmd, param, body, hash);
426
+ });
427
+ }
428
+ doPatch(id, cmd, param, body, hash) {
429
+ return __awaiter(this, void 0, void 0, function* () {
430
+ return this.doRecord('PATCH', id, cmd, param, body, hash);
431
+ });
432
+ }
433
+ doDelete(id, cmd, param, body, hash) {
434
+ return __awaiter(this, void 0, void 0, function* () {
435
+ return this.doRecord('DELETE', id, cmd, param, body, hash);
436
+ });
437
+ }
438
+ },
439
+ _b.next = 1,
440
+ _b);
441
+ /** ********************************************************************************************************************
442
+ * BODY IMPLEMENTATION.
443
+ ** ********************************************************************************************************************/
444
+ const url_1 = __importDefault(require("url"));
445
+ const request_1 = __importDefault(require("request"));
446
+ const query_string_1 = __importDefault(require("query-string"));
447
+ /**
448
+ * create http-web-proxy agent which using endpoint as proxy server.
449
+ *
450
+ * # as cases.
451
+ * as proxy agent: GET <endpoint>/<host?>/<path?>
452
+ * as direct agent: GET <endpoint>/<id?>/<cmd?>
453
+ *
454
+ * @param name client-name
455
+ * @param endpoint service url (or backbone proxy-url)
456
+ * @param headers headers
457
+ * @param encoder path encoder (default encodeURIComponent)
458
+ * @param relayHeaderKey relay-key in headers for proxy.
459
+ * @param resultKey resultKey in response
460
+ */
461
+ const createHttpWebProxy = (name, endpoint, headers, encoder, relayHeaderKey, resultKey) => {
462
+ if (!endpoint)
463
+ throw new Error('@endpoint (url) is required!');
464
+ const NS = engine_1.$U.NS(`X${name}`, 'magenta'); // NAMESPACE TO BE PRINTED.
465
+ encoder = encoder !== undefined ? encoder : (name, path) => path;
466
+ relayHeaderKey = relayHeaderKey || '';
467
+ /**
468
+ * class: `ApiHttpProxy`
469
+ * - http proxy client via backbone's web.
470
+ */
471
+ return new (class {
472
+ constructor() {
473
+ this.hello = () => `http-web-proxy:${name}`;
474
+ }
475
+ doProxy(method, path1, path2, $param, $body, ctx) {
476
+ // const _log = console.info;
477
+ if (!method)
478
+ throw new Error('@method is required!');
479
+ (0, engine_1._log)(NS, `doProxy(${method})..`);
480
+ const _isNa = (a) => a === undefined || a === null;
481
+ (0, engine_1._log)(NS, '> endpoint =', endpoint);
482
+ _isNa(path1) && (0, engine_1._log)(NS, `> host(id) =`, typeof path1, path1);
483
+ _isNa(path2) && (0, engine_1._log)(NS, `> path(cmd) =`, typeof path2, path2);
484
+ //! prepare request parameters
485
+ // eslint-disable-next-line prettier/prettier
486
+ const query_string = _isNa($param) ? '' : (typeof $param == 'object' ? query_string_1.default.stringify($param) : `${$param}`);
487
+ const url = endpoint +
488
+ (_isNa(path1) ? '' : `/${encoder('host', path1)}`) +
489
+ (_isNa(path1) && _isNa(path2) ? '' : `/${encoder('path', path2)}`) +
490
+ (!query_string ? '' : '?' + query_string);
491
+ const request = request_1.default;
492
+ const options = {
493
+ method,
494
+ uri: url,
495
+ headers: {},
496
+ body: $body === null ? undefined : $body,
497
+ json: typeof $body === 'string' ? false : true,
498
+ };
499
+ //! relay HEADERS to `WEB-API`
500
+ if (headers) {
501
+ options.headers = Object.keys(headers).reduce((H, key) => {
502
+ const val = headers[key];
503
+ const name = `${relayHeaderKey}${key}`;
504
+ const text = `${val}`;
505
+ H[name] = text;
506
+ return H;
507
+ }, options.headers);
508
+ }
509
+ (0, engine_1._log)(NS, ' url :=', options.method, url);
510
+ (0, engine_1._log)(NS, '*', options.method, url, options.json ? 'json' : 'plain');
511
+ (0, engine_1._log)(NS, '> options =', engine_1.$U.json(options));
512
+ //! returns promise
513
+ return new Promise((resolve, reject) => {
514
+ //! start request..
515
+ request(options, function (error, response, body) {
516
+ error && (0, engine_1._err)(NS, '>>>>> requested! err=', error);
517
+ if (error)
518
+ return reject(error instanceof Error ? error : new Error((0, test_helper_1.GETERR)(error)));
519
+ //! detecte trouble.
520
+ const statusCode = response.statusCode;
521
+ const statusMessage = response.statusMessage;
522
+ //! if not in success
523
+ if (statusCode !== 200 && statusCode !== 201) {
524
+ const msg = body ? (0, test_helper_1.GETERR)(body) : `${statusMessage || ''}`;
525
+ if (statusCode === 400 || statusCode === 404) {
526
+ const title = `${(statusCode == 404 ? '' : statusMessage) || 'NOT FOUND'}`.toUpperCase();
527
+ const message = msg.startsWith('404 NOT FOUND') ? msg : `${statusCode} ${title} - ${msg}`;
528
+ return reject(new Error(message));
529
+ }
530
+ statusMessage && (0, engine_1._log)(NS, `> statusMessage[${statusCode}] =`, statusMessage);
531
+ body && (0, engine_1._log)(NS, `> body[${statusCode}] =`, engine_1.$U.json(body));
532
+ return reject(new Error(`${statusCode} ${statusMessage || 'FAILURE'} - ${msg}`));
533
+ }
534
+ //! try to parse body.
535
+ try {
536
+ if (body && typeof body == 'string' && body.startsWith('{') && body.endsWith('}')) {
537
+ body = JSON.parse(body);
538
+ }
539
+ else if (body && typeof body == 'string' && body.startsWith('[') && body.endsWith(']')) {
540
+ body = JSON.parse(body);
541
+ }
542
+ }
543
+ catch (e) {
544
+ (0, engine_1._err)(NS, '!WARN! parse(body) =', e instanceof Error ? e : engine_1.$U.json(e));
545
+ }
546
+ //! ok! successed.
547
+ resolve(body);
548
+ });
549
+ }).then((res) => {
550
+ if (resultKey && res && res[resultKey] !== undefined)
551
+ return res[resultKey];
552
+ return res;
553
+ });
554
+ }
555
+ })();
556
+ };
557
+ exports.createHttpWebProxy = createHttpWebProxy;
558
+ /** ********************************************************************************************************************
559
+ * MOCKS API-SERVICE
560
+ ** ********************************************************************************************************************/
561
+ /**
562
+ * class: `MocksAPIService`
563
+ * - use <mock>.json file in `./data/mocks/` instead of real http request.
564
+ * - it redirect to url like `endpoint/type/id/cmd`
565
+ *
566
+ * ```ts
567
+ * // json format
568
+ * {
569
+ * param: { // input format
570
+ * method: string;
571
+ * endpoint: string;
572
+ * id?: string;
573
+ * cmd?: string;
574
+ * },
575
+ * data: { // response data
576
+ * ...
577
+ * },
578
+ * error?: string; // in case of error.
579
+ * }
580
+ * ```
581
+ */
582
+ class MocksAPIService {
583
+ constructor(type, endpoint) {
584
+ this.asPath = (id, cmd) => {
585
+ const _isNa = (a) => a === undefined || a === null;
586
+ return (_isNa(id) ? '' : encodeURIComponent(id)) + (_isNa(id) || !cmd ? '' : '/' + encodeURI(cmd));
587
+ };
588
+ this.na = (a, x, y) => (a === undefined || a === null ? x : y);
589
+ this.hello = () => `mocks-api-service:${this.endpoint}${this.na(this.type, '', '/')}${this.type || ''}`;
590
+ this.type = type;
591
+ this.endpoint = endpoint;
592
+ }
593
+ loadSync() {
594
+ if (this.$map)
595
+ return;
596
+ const PATH = './data/mocks/';
597
+ const files = fs_1.default.readdirSync(PATH);
598
+ // console.log(NS, '> files =', files);
599
+ const $map = files
600
+ .sort()
601
+ .map(file => ({ file, json: (0, shared_1.loadJsonSync)(`${PATH}${file}`) }))
602
+ .reduce((M, F) => {
603
+ const file = F.file || '';
604
+ const data = F.json;
605
+ const param = data.param || {};
606
+ const { method, endpoint: endpoint0, id, cmd, param: $qs } = param;
607
+ const has = (a) => a !== undefined && a !== null;
608
+ const [endpoint, hash] = `${endpoint0}`.split('#', 2);
609
+ const qs = $qs ? engine_1.$U.qs.stringify($qs) : '';
610
+ const url = `${endpoint}` + (has(id) ? `/${id}` : '') + (has(id) && has(cmd) ? `/${cmd}` : '');
611
+ const key = `${method} ${url}`;
612
+ const key2 = qs ? `${key}${key.indexOf('?') > 0 ? '&' : '?'}${qs}` : key;
613
+ const key3 = hash ? `${key2}${hash ? '#' : ''}${hash || ''}` : key2;
614
+ // if (file.indexOf('#') > 0) console.info(`! file[${file}] =`, key3);
615
+ //! save by file & key.
616
+ M[file] = data;
617
+ M[key3] = data;
618
+ return M;
619
+ }, {});
620
+ // console.log(NS, '> $map =', $map);
621
+ this.$map = $map;
622
+ }
623
+ doProxy(method, type, path, param, body, ctx, hash) {
624
+ return __awaiter(this, void 0, void 0, function* () {
625
+ // console.info(`! mocks.proxy(${method},${type},${path})...`);
626
+ this.loadSync();
627
+ const file = path && path.endsWith('.json') ? path.split('/').pop() : '';
628
+ // eslint-disable-next-line prettier/prettier
629
+ const key = `${method} ${this.endpoint}${this.na(type, '', '/')}${type || ''}${!path || path.startsWith('/') ? '' : '/'}${path || ''}`;
630
+ const qs = param ? engine_1.$U.qs.stringify(param) : '';
631
+ const key2 = qs ? `${key}${path.indexOf('?') > 0 ? '&' : '?'}${qs}` : key;
632
+ const key3 = hash ? `${key2}${hash.startsWith('#') ? '' : '#'}${hash}` : key2;
633
+ // if (param) console.info('!key[] =', [key3, key2, key]);
634
+ // if (hash) console.info(`! hash[${hash}].keys =`, [key3, key2, key]);
635
+ const data = this.$map[file] || this.$map[key3] || this.$map[key2] || this.$map[key];
636
+ if (!data)
637
+ throw new Error(`404 NOT FOUND - ${key3}`);
638
+ const err = data.error;
639
+ if (err && typeof err == 'string') {
640
+ if (err.startsWith('{') && err.endsWith('}'))
641
+ throw JSON.parse(err);
642
+ else
643
+ throw new Error(err);
644
+ }
645
+ else if (err) {
646
+ throw err;
647
+ }
648
+ //! returns data.
649
+ return data.data ? JSON.parse(engine_1.$U.json(data.data)) : data.data;
650
+ });
651
+ }
652
+ doGet(id, cmd, param, body, hash) {
653
+ const path = this.asPath(id, cmd); // use mocks.type infor
654
+ return this.doProxy('GET', this.type, path, param, body, null, hash);
655
+ }
656
+ doPut(id, cmd, param, body, hash) {
657
+ const path = this.asPath(id, cmd); // use mocks.type infor
658
+ return this.doProxy('PUT', this.type, path, param, body, null, hash);
659
+ }
660
+ doPost(id, cmd, param, body, hash) {
661
+ const path = this.asPath(id, cmd); // use mocks.type infor
662
+ return this.doProxy('POST', this.type, path, param, body, null, hash);
663
+ }
664
+ doPatch(id, cmd, param, body, hash) {
665
+ const path = this.asPath(id, cmd); // use mocks.type infor
666
+ return this.doProxy('PATCH', this.type, path, param, body, null, hash);
667
+ }
668
+ doDelete(id, cmd, param, body, hash) {
669
+ const path = this.asPath(id, cmd); // use mocks.type infor
670
+ return this.doProxy('DELETE', this.type, path, param, body, null, hash);
671
+ }
672
+ }
673
+ exports.MocksAPIService = MocksAPIService;
674
+ //# sourceMappingURL=api-service.js.map