@team-internet/apiconnector 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.devcontainer/Dockerfile +66 -0
  2. package/.devcontainer/devcontainer.json +30 -0
  3. package/.devcontainer/docker-compose.yml +11 -0
  4. package/.devcontainer/supporting_files/configuration/.czrc +1 -0
  5. package/.devcontainer/supporting_files/configuration/.p10k.zsh +1735 -0
  6. package/.devcontainer/supporting_files/configuration/.zshrc +23 -0
  7. package/.devcontainer/supporting_files/configuration/p10k-instant-prompt-vscode.zsh +323 -0
  8. package/.devcontainer/supporting_files/scripts/post-create.sh +11 -0
  9. package/.nycrc +6 -0
  10. package/CHANGELOG.md +582 -0
  11. package/CONTRIBUTING.md +132 -0
  12. package/LICENSE +21 -0
  13. package/README.md +56 -0
  14. package/dist/apiclient.d.ts +233 -0
  15. package/dist/apiclient.js +517 -0
  16. package/dist/column.d.ts +40 -0
  17. package/dist/column.js +52 -0
  18. package/dist/customlogger.d.ts +15 -0
  19. package/dist/customlogger.js +23 -0
  20. package/dist/index.d.ts +16 -0
  21. package/dist/index.js +16 -0
  22. package/dist/logger.d.ts +14 -0
  23. package/dist/logger.js +21 -0
  24. package/dist/record.d.ts +31 -0
  25. package/dist/record.js +42 -0
  26. package/dist/response.d.ts +264 -0
  27. package/dist/response.js +512 -0
  28. package/dist/responseparser.d.ts +1 -0
  29. package/dist/responseparser.js +36 -0
  30. package/dist/responsetemplatemanager.d.ts +65 -0
  31. package/dist/responsetemplatemanager.js +111 -0
  32. package/dist/responsetranslator.d.ts +32 -0
  33. package/dist/responsetranslator.js +144 -0
  34. package/dist/socketconfig.d.ts +62 -0
  35. package/dist/socketconfig.js +107 -0
  36. package/package.json +86 -0
  37. package/src/apiclient.ts +579 -0
  38. package/src/column.ts +57 -0
  39. package/src/customlogger.ts +29 -0
  40. package/src/index.ts +18 -0
  41. package/src/logger.ts +23 -0
  42. package/src/record.ts +46 -0
  43. package/src/response.ts +562 -0
  44. package/src/responseparser.ts +35 -0
  45. package/src/responsetemplatemanager.ts +136 -0
  46. package/src/responsetranslator.ts +191 -0
  47. package/src/socketconfig.ts +116 -0
  48. package/tests/apiclient.spec.ts +610 -0
  49. package/tests/app.js +47 -0
  50. package/tests/column.spec.ts +23 -0
  51. package/tests/index.spec.ts +22 -0
  52. package/tests/record.spec.ts +31 -0
  53. package/tests/response.spec.ts +341 -0
  54. package/tests/responseparser.spec.ts +13 -0
  55. package/tests/responsetemplatemanager.spec.ts +52 -0
  56. package/tests/socketconfig.spec.ts +14 -0
  57. package/tsconfig.json +7 -0
  58. package/typedoc.json +7 -0
package/src/record.ts ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Record class
3
+ */
4
+ export class Record {
5
+ /**
6
+ * row data container
7
+ */
8
+ private data: any;
9
+
10
+ /**
11
+ * Constructor
12
+ * @param data data object (use column names as object keys)
13
+ */
14
+ public constructor(data: any) {
15
+ this.data = data;
16
+ }
17
+
18
+ /**
19
+ * get row data
20
+ * @returns row data
21
+ */
22
+ public getData(): any {
23
+ return this.data;
24
+ }
25
+
26
+ /**
27
+ * get row data for given column
28
+ * @param key column name
29
+ * @returns row data for given column or null if column does not exist
30
+ */
31
+ public getDataByKey(key: string): string | null {
32
+ if (this.hasData(key)) {
33
+ return this.data[key];
34
+ }
35
+ return null;
36
+ }
37
+
38
+ /**
39
+ * check if record has data for given column
40
+ * @param key column name
41
+ * @returns boolean result
42
+ */
43
+ private hasData(key: string): boolean {
44
+ return Object.prototype.hasOwnProperty.call(this.data, key);
45
+ }
46
+ }
@@ -0,0 +1,562 @@
1
+ import { Column } from "./column.js";
2
+ import { Record } from "./record.js";
3
+ import { ResponseTranslator as RT } from "./responsetranslator.js";
4
+ import { ResponseParser as RP } from "./responseparser.js";
5
+
6
+ /**
7
+ * Response Class
8
+ */
9
+ export class Response {
10
+ /**
11
+ * plain API response
12
+ */
13
+ protected raw: string;
14
+ /**
15
+ * hash representation of plain API response
16
+ */
17
+ protected hash: any;
18
+ /**
19
+ * The API Command used within this request
20
+ */
21
+ private command: any;
22
+ /**
23
+ * Column names available in this responsse
24
+ * NOTE: this includes also FIRST, LAST, LIMIT, COUNT, TOTAL
25
+ * and maybe further specific columns in case of a list query
26
+ */
27
+ private columnkeys: string[];
28
+ /**
29
+ * Container of Column Instances
30
+ */
31
+ private columns: Column[];
32
+ /**
33
+ * Record Index we currently point to in record list
34
+ */
35
+ private recordIndex: number;
36
+ /**
37
+ * Record List (List of rows)
38
+ */
39
+ private records: Record[];
40
+
41
+ /**
42
+ * Constructor
43
+ * @param raw API plain response
44
+ * @param cmd API command used within this request
45
+ * @param ph placeholder array to get vars in response description dynamically replaced
46
+ */
47
+ public constructor(raw: string, cmd: any = {}, ph: any = {}) {
48
+ this.command = cmd;
49
+ if (
50
+ this.command &&
51
+ Object.prototype.hasOwnProperty.call(this.command, "PASSWORD")
52
+ ) {
53
+ // make password no longer accessible
54
+ this.command.PASSWORD = "***";
55
+ }
56
+
57
+ this.raw = RT.translate(raw, cmd, ph);
58
+ console.log(this.raw);
59
+ console.log("-----------------------------------------");
60
+ this.hash = RP.parse(this.raw);
61
+ this.columnkeys = [];
62
+ this.columns = [];
63
+ this.recordIndex = 0;
64
+ this.records = [];
65
+
66
+ if (Object.prototype.hasOwnProperty.call(this.hash, "PROPERTY")) {
67
+ const colKeys = Object.keys(this.hash.PROPERTY);
68
+ let count = 0;
69
+ colKeys.forEach((c: string) => {
70
+ const d = this.hash.PROPERTY[c];
71
+ this.addColumn(c, d);
72
+ if (d.length > count) {
73
+ count = d.length;
74
+ }
75
+ });
76
+ for (let i = 0; i < count; i++) {
77
+ const d: any = {};
78
+ colKeys.forEach((k: string) => {
79
+ const col = this.getColumn(k);
80
+ if (col) {
81
+ const v = col.getDataByIndex(i);
82
+ if (v !== null) {
83
+ d[k] = v;
84
+ }
85
+ }
86
+ });
87
+ this.addRecord(d);
88
+ }
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Get API response code
94
+ * @returns API response code
95
+ */
96
+ public getCode(): number {
97
+ return parseInt(this.hash.CODE, 10);
98
+ }
99
+
100
+ /**
101
+ * Get API response description
102
+ * @returns API response description
103
+ */
104
+ public getDescription(): string {
105
+ return this.hash.DESCRIPTION;
106
+ }
107
+
108
+ /**
109
+ * Get Plain API response
110
+ * @returns Plain API response
111
+ */
112
+ public getPlain(): string {
113
+ return this.raw;
114
+ }
115
+
116
+ /**
117
+ * Get Queuetime of API response
118
+ * @returns Queuetime of API response
119
+ */
120
+ public getQueuetime(): number {
121
+ if (Object.prototype.hasOwnProperty.call(this.hash, "QUEUETIME")) {
122
+ return parseFloat(this.hash.QUEUETIME);
123
+ }
124
+ return 0.0;
125
+ }
126
+
127
+ /**
128
+ * Get API response as Hash
129
+ * @returns API response hash
130
+ */
131
+ public getHash(): any {
132
+ return this.hash;
133
+ }
134
+
135
+ /**
136
+ * Get Runtime of API response
137
+ * @returns Runtime of API response
138
+ */
139
+ public getRuntime(): number {
140
+ if (Object.prototype.hasOwnProperty.call(this.hash, "RUNTIME")) {
141
+ return parseFloat(this.hash.RUNTIME);
142
+ }
143
+ return 0.0;
144
+ }
145
+
146
+ /**
147
+ * Check if current API response represents an error case
148
+ * API response code is an 5xx code
149
+ * @returns boolean result
150
+ */
151
+ public isError(): boolean {
152
+ return this.hash.CODE.charAt(0) === "5";
153
+ }
154
+
155
+ /**
156
+ * Check if current API response represents a success case
157
+ * API response code is an 2xx code
158
+ * @returns boolean result
159
+ */
160
+ public isSuccess(): boolean {
161
+ return this.hash.CODE.charAt(0) === "2";
162
+ }
163
+
164
+ /**
165
+ * Check if current API response represents a temporary error case
166
+ * API response code is an 4xx code
167
+ * @returns boolean result
168
+ */
169
+ public isTmpError(): boolean {
170
+ return this.hash.CODE.charAt(0) === "4";
171
+ }
172
+
173
+ /**
174
+ * Check if current operation is returned as pending
175
+ * @returns boolean result
176
+ */
177
+ public isPending(): boolean {
178
+ const cmd = this.getCommand();
179
+
180
+ // Check if the COMMAND is AddDomain (case-insensitive)
181
+ if (!cmd.COMMAND || cmd.COMMAND.toLowerCase() !== "adddomain") {
182
+ return false;
183
+ }
184
+
185
+ // Retrieve the STATUS column and check if its data equals REQUESTED (case-insensitive)
186
+ const status = this.getColumn("STATUS");
187
+ if (status) {
188
+ const statusData = status.getDataByIndex(0);
189
+ if (statusData && statusData.toLowerCase() === "requested") {
190
+ return true;
191
+ }
192
+ }
193
+
194
+ return false;
195
+ }
196
+
197
+ /**
198
+ * Add a column to the column list
199
+ * @param key column name
200
+ * @param data array of column data
201
+ * @returns Current Response Instance for method chaining
202
+ */
203
+ public addColumn(key: string, data: string[]): Response {
204
+ const col = new Column(key, data);
205
+ this.columns.push(col);
206
+ this.columnkeys.push(key);
207
+ return this;
208
+ }
209
+
210
+ /**
211
+ * Add a record to the record list
212
+ * @param h row hash data
213
+ * @returns Current Response Instance for method chaining
214
+ */
215
+ public addRecord(h: any): Response {
216
+ this.records.push(new Record(h));
217
+ return this;
218
+ }
219
+
220
+ /**
221
+ * Get column by column name
222
+ * @param key column name
223
+ * @returns column instance or null if column does not exist
224
+ */
225
+ public getColumn(key: string): Column | null {
226
+ return this.hasColumn(key)
227
+ ? this.columns[this.columnkeys.indexOf(key)]
228
+ : null;
229
+ }
230
+
231
+ /**
232
+ * Get Data by Column Name and Index
233
+ * @param colkey column name
234
+ * @param index column data index
235
+ * @returns column data at index or null if not found
236
+ */
237
+ public getColumnIndex(colkey: string, index: number): string | null {
238
+ const col = this.getColumn(colkey);
239
+ return col ? col.getDataByIndex(index) : null;
240
+ }
241
+
242
+ /**
243
+ * Get Column Names
244
+ * @returns Array of Column Names
245
+ */
246
+ public getColumnKeys(): string[] {
247
+ return this.columnkeys;
248
+ }
249
+
250
+ /**
251
+ * Get List of Columns
252
+ * @returns Array of Columns
253
+ */
254
+ public getColumns(): Column[] {
255
+ return this.columns;
256
+ }
257
+
258
+ /**
259
+ * Get Command used in this request
260
+ * @returns command
261
+ */
262
+ public getCommand(): any {
263
+ return this.command;
264
+ }
265
+
266
+ /**
267
+ * Get Command used in this request in plain text format
268
+ * @return command as plain text
269
+ */
270
+ public getCommandPlain(): string {
271
+ let tmp = "";
272
+ Object.keys(this.command).forEach((key: string) => {
273
+ tmp += `${key} = ${this.command[key]}\n`;
274
+ });
275
+ return tmp;
276
+ }
277
+
278
+ /**
279
+ * Get Page Number of current List Query
280
+ * @returns page number or null in case of a non-list response
281
+ */
282
+ public getCurrentPageNumber(): number | null {
283
+ const first = this.getFirstRecordIndex();
284
+ const limit = this.getRecordsLimitation();
285
+ if (first !== null && limit) {
286
+ return Math.floor(first / limit) + 1;
287
+ }
288
+ return null;
289
+ }
290
+
291
+ /**
292
+ * Get Record of current record index
293
+ * @returns Record or null in case of a non-list response
294
+ */
295
+ public getCurrentRecord(): Record | null {
296
+ return this.hasCurrentRecord() ? this.records[this.recordIndex] : null;
297
+ }
298
+
299
+ /**
300
+ * Get Index of first row in this response
301
+ * @returns first row index
302
+ */
303
+ public getFirstRecordIndex(): number | null {
304
+ const col = this.getColumn("FIRST");
305
+ if (col) {
306
+ const f = col.getDataByIndex(0);
307
+ if (f !== null) {
308
+ return parseInt(f, 10);
309
+ }
310
+ }
311
+ if (this.records.length) {
312
+ return 0;
313
+ }
314
+ return null;
315
+ }
316
+
317
+ /**
318
+ * Get last record index of the current list query
319
+ * @returns record index or null for a non-list response
320
+ */
321
+ public getLastRecordIndex(): number | null {
322
+ const col = this.getColumn("LAST");
323
+ if (col) {
324
+ const l = col.getDataByIndex(0);
325
+ if (l !== null) {
326
+ return parseInt(l, 10);
327
+ }
328
+ }
329
+ const len = this.getRecordsCount();
330
+ if (len) {
331
+ return len - 1;
332
+ }
333
+ return null;
334
+ }
335
+
336
+ /**
337
+ * Get Response as List Hash including useful meta data for tables
338
+ * @returns hash including list meta data and array of rows in hash notation
339
+ */
340
+ public getListHash(): any {
341
+ const lh: any[] = [];
342
+ this.getRecords().forEach((rec) => {
343
+ lh.push(rec.getData());
344
+ });
345
+ return {
346
+ LIST: lh,
347
+ meta: {
348
+ columns: this.getColumnKeys(),
349
+ pg: this.getPagination(),
350
+ },
351
+ };
352
+ }
353
+
354
+ /**
355
+ * Get next record in record list
356
+ * @returns Record or null in case there's no further record
357
+ */
358
+ public getNextRecord(): Record | null {
359
+ if (this.hasNextRecord()) {
360
+ return this.records[++this.recordIndex];
361
+ }
362
+ return null;
363
+ }
364
+
365
+ /**
366
+ * Get Page Number of next list query
367
+ * @returns page number or null if there's no next page
368
+ */
369
+ public getNextPageNumber(): number | null {
370
+ const cp = this.getCurrentPageNumber();
371
+ if (cp === null) {
372
+ return null;
373
+ }
374
+ const page = cp + 1;
375
+ const pages = this.getNumberOfPages();
376
+ return page <= pages ? page : pages;
377
+ }
378
+
379
+ /**
380
+ * Get the number of pages available for this list query
381
+ * @returns number of pages
382
+ */
383
+ public getNumberOfPages(): number {
384
+ const t = this.getRecordsTotalCount();
385
+ const limit = this.getRecordsLimitation();
386
+ if (t && limit) {
387
+ return Math.ceil(t / this.getRecordsLimitation());
388
+ }
389
+ return 0;
390
+ }
391
+
392
+ /**
393
+ * Get object containing all paging data
394
+ * @returns paginator data
395
+ */
396
+ public getPagination(): any {
397
+ return {
398
+ COUNT: this.getRecordsCount(),
399
+ CURRENTPAGE: this.getCurrentPageNumber(),
400
+ FIRST: this.getFirstRecordIndex(),
401
+ LAST: this.getLastRecordIndex(),
402
+ LIMIT: this.getRecordsLimitation(),
403
+ NEXTPAGE: this.getNextPageNumber(),
404
+ PAGES: this.getNumberOfPages(),
405
+ PREVIOUSPAGE: this.getPreviousPageNumber(),
406
+ TOTAL: this.getRecordsTotalCount(),
407
+ };
408
+ }
409
+
410
+ /**
411
+ * Get Page Number of previous list query
412
+ * @returns page number or null if there's no previous page
413
+ */
414
+ public getPreviousPageNumber(): number | null {
415
+ const cp = this.getCurrentPageNumber();
416
+ if (cp === null) {
417
+ return null;
418
+ }
419
+ return cp - 1 || null;
420
+ }
421
+
422
+ /**
423
+ * Get previous record in record list
424
+ * @returns Record or null if there's no previous record
425
+ */
426
+ public getPreviousRecord(): Record | null {
427
+ if (this.hasPreviousRecord()) {
428
+ return this.records[--this.recordIndex];
429
+ }
430
+ return null;
431
+ }
432
+
433
+ /**
434
+ * Get Record at given index
435
+ * @param idx record index
436
+ * @returns Record or null if index does not exist
437
+ */
438
+ public getRecord(idx: number): Record | null {
439
+ if (idx >= 0 && this.records.length > idx) {
440
+ return this.records[idx];
441
+ }
442
+ return null;
443
+ }
444
+
445
+ /**
446
+ * Get all Records
447
+ * @returns array of records
448
+ */
449
+ public getRecords(): Record[] {
450
+ return this.records;
451
+ }
452
+
453
+ /**
454
+ * Get count of rows in this response
455
+ * @returns count of rows
456
+ */
457
+ public getRecordsCount(): number {
458
+ return this.records.length;
459
+ }
460
+
461
+ /**
462
+ * Get total count of records available for the list query
463
+ * @returns total count of records or count of records for a non-list response
464
+ */
465
+ public getRecordsTotalCount(): number {
466
+ const col = this.getColumn("TOTAL");
467
+ if (col) {
468
+ const t = col.getDataByIndex(0);
469
+ if (t !== null) {
470
+ return parseInt(t, 10);
471
+ }
472
+ }
473
+ return this.getRecordsCount();
474
+ }
475
+
476
+ /**
477
+ * Get limit(ation) setting of the current list query
478
+ * This is the count of requested rows
479
+ * @returns limit setting or count requested rows
480
+ */
481
+ public getRecordsLimitation(): number {
482
+ const col = this.getColumn("LIMIT");
483
+ if (col) {
484
+ const l = col.getDataByIndex(0);
485
+ if (l !== null) {
486
+ return parseInt(l, 10);
487
+ }
488
+ }
489
+ return this.getRecordsCount();
490
+ }
491
+
492
+ /**
493
+ * Check if this list query has a next page
494
+ * @returns boolean result
495
+ */
496
+ public hasNextPage(): boolean {
497
+ const cp = this.getCurrentPageNumber();
498
+ if (cp === null) {
499
+ return false;
500
+ }
501
+ return cp + 1 <= this.getNumberOfPages();
502
+ }
503
+
504
+ /**
505
+ * Check if this list query has a previous page
506
+ * @returns boolean result
507
+ */
508
+ public hasPreviousPage(): boolean {
509
+ const cp = this.getCurrentPageNumber();
510
+ if (cp === null) {
511
+ return false;
512
+ }
513
+ return cp - 1 > 0;
514
+ }
515
+
516
+ /**
517
+ * Reset index in record list back to zero
518
+ * @returns Current Response Instance for method chaining
519
+ */
520
+ public rewindRecordList(): Response {
521
+ this.recordIndex = 0;
522
+ return this;
523
+ }
524
+
525
+ /**
526
+ * Check if column exists in response
527
+ * @param key column name
528
+ * @returns boolean result
529
+ */
530
+ private hasColumn(key: string): boolean {
531
+ return this.columnkeys.indexOf(key) !== -1;
532
+ }
533
+
534
+ /**
535
+ * Check if the record list contains a record for the
536
+ * current record index in use
537
+ * @returns boolean result
538
+ */
539
+ private hasCurrentRecord(): boolean {
540
+ const len = this.records.length;
541
+ return len > 0 && this.recordIndex >= 0 && this.recordIndex < len;
542
+ }
543
+
544
+ /**
545
+ * Check if the record list contains a next record for the
546
+ * current record index in use
547
+ * @returns boolean result
548
+ */
549
+ private hasNextRecord(): boolean {
550
+ const next = this.recordIndex + 1;
551
+ return this.hasCurrentRecord() && next < this.records.length;
552
+ }
553
+
554
+ /**
555
+ * Check if the record list contains a previous record for the
556
+ * current record index in use
557
+ * @returns boolean result
558
+ */
559
+ private hasPreviousRecord(): boolean {
560
+ return this.recordIndex > 0 && this.hasCurrentRecord();
561
+ }
562
+ }
@@ -0,0 +1,35 @@
1
+ export const ResponseParser: any = {
2
+ /**
3
+ * Method to parse plain API response into js object
4
+ * @param raw API plain response
5
+ * @returns API response as JS Object (hash)
6
+ */
7
+ parse: (raw: string): any => {
8
+ const hash: any = {};
9
+ const regexp = /^([^=]*[^\t= ])[\t ]*=[\t ]*(.*)$/;
10
+ const r = raw.replace(/\r\n/g, "\n").split("\n");
11
+ while (r.length) {
12
+ const row = r.shift();
13
+ let m;
14
+ if (row) {
15
+ m = row.match(regexp);
16
+ if (m) {
17
+ const mm = m[1].match(/^property\[([^\]]*)\]/i);
18
+ if (mm) {
19
+ if (!Object.prototype.hasOwnProperty.call(hash, "PROPERTY")) {
20
+ hash.PROPERTY = {};
21
+ }
22
+ mm[1] = mm[1].toUpperCase().replace(/\s/g, "");
23
+ if (!Object.prototype.hasOwnProperty.call(hash.PROPERTY, mm[1])) {
24
+ hash.PROPERTY[mm[1]] = [];
25
+ }
26
+ hash.PROPERTY[mm[1]].push(m[2].replace(/[\t ]*$/, ""));
27
+ } else {
28
+ hash[m[1].toUpperCase()] = m[2].replace(/[\t ]*$/, "");
29
+ }
30
+ }
31
+ }
32
+ }
33
+ return hash;
34
+ },
35
+ };