@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
@@ -0,0 +1,136 @@
1
+ import { ResponseParser } from "./responseparser.js";
2
+ import { Response } from "./response.js";
3
+
4
+ /**
5
+ * ResponseTemplateManager Singleton Class
6
+ */
7
+ export class ResponseTemplateManager {
8
+ /**
9
+ * Get ResponseTemplateManager Instance
10
+ * @returns ResponseTemplateManager Instance
11
+ */
12
+ public static getInstance(): ResponseTemplateManager {
13
+ if (!ResponseTemplateManager.instance) {
14
+ ResponseTemplateManager.instance = new ResponseTemplateManager();
15
+ }
16
+ return ResponseTemplateManager.instance;
17
+ }
18
+ /**
19
+ * ResponseTemplateManager Instance
20
+ */
21
+ private static instance: ResponseTemplateManager;
22
+ /**
23
+ * template container
24
+ */
25
+ public templates: any;
26
+
27
+ private constructor() {
28
+ this.templates = {
29
+ 404: this.generateTemplate("421", "Page not found"),
30
+ 500: this.generateTemplate("500", "Internal server error"),
31
+ empty: this.generateTemplate(
32
+ "423",
33
+ "Empty API response. Probably unreachable API end point {CONNECTION_URL}",
34
+ ),
35
+ error: this.generateTemplate(
36
+ "421",
37
+ "Command failed due to server error. Client should try again",
38
+ ),
39
+ expired: this.generateTemplate("530", "SESSIONID NOT FOUND"),
40
+ httperror: this.generateTemplate(
41
+ "421",
42
+ "Command failed due to HTTP communication error",
43
+ ),
44
+ invalid: this.generateTemplate(
45
+ "423",
46
+ "Invalid API response. Contact Support",
47
+ ),
48
+ nocurl: this.generateTemplate(
49
+ "423",
50
+ "API access error: curl_init failed",
51
+ ),
52
+ notfound: this.generateTemplate("500", "Response Template not found"),
53
+ unauthorized: this.generateTemplate("500", "Unauthorized"),
54
+ };
55
+ }
56
+
57
+ /**
58
+ * Generate API response template string for given code and description
59
+ * @param code API response code
60
+ * @param description API response description
61
+ * @returns generate response template string
62
+ */
63
+ public generateTemplate(code: string, description: string): string {
64
+ return `[RESPONSE]\r\nCODE=${code}\r\nDESCRIPTION=${description}\r\nEOF\r\n`;
65
+ }
66
+
67
+ /**
68
+ * Add response template to template container
69
+ * @param id template id
70
+ * @param plain API plain response
71
+ * @returns ResponseTemplateManager instance for method chaining
72
+ */
73
+ public addTemplate(id: string, plain: string): ResponseTemplateManager {
74
+ this.templates[id] = plain;
75
+ return ResponseTemplateManager.instance;
76
+ }
77
+
78
+ /**
79
+ * Get response template instance from template container
80
+ * @param id template id
81
+ * @returns template instance
82
+ */
83
+ public getTemplate(id: string): Response {
84
+ if (this.hasTemplate(id)) {
85
+ return new Response(id);
86
+ }
87
+ console.log("template id " + id);
88
+ return new Response("notfound");
89
+ }
90
+
91
+ /**
92
+ * Return all available response templates
93
+ * @returns all available response template instances
94
+ */
95
+ public getTemplates(): any {
96
+ const tpls: any = {};
97
+ Object.keys(this.templates).forEach((key) => {
98
+ tpls[key] = new Response(key);
99
+ });
100
+ return tpls;
101
+ }
102
+
103
+ /**
104
+ * Check if given template exists in template container
105
+ * @param id template id
106
+ * @returns boolean result
107
+ */
108
+ public hasTemplate(id: string): boolean {
109
+ return Object.prototype.hasOwnProperty.call(this.templates, id);
110
+ }
111
+
112
+ /**
113
+ * Check if given API response hash matches a given template by code and description
114
+ * @param tpl2 api response hash
115
+ * @param id template id
116
+ * @returns boolean result
117
+ */
118
+ public isTemplateMatchHash(tpl2: any, id: string): boolean {
119
+ const h = this.getTemplate(id).getHash();
120
+ return h.CODE === tpl2.CODE && h.DESCRIPTION === tpl2.DESCRIPTION;
121
+ }
122
+
123
+ /**
124
+ * Check if given API plain response matches a given template by code and description
125
+ * @param plain API plain response
126
+ * @param id template id
127
+ * @returns boolean result
128
+ */
129
+ public isTemplateMatchPlain(plain: string, id: string): boolean {
130
+ const h = this.getTemplate(id).getHash();
131
+ const tpl2 = ResponseParser.parse(plain);
132
+ return h.CODE === tpl2.CODE && h.DESCRIPTION === tpl2.DESCRIPTION;
133
+ }
134
+ }
135
+
136
+ ResponseTemplateManager.getInstance();
@@ -0,0 +1,191 @@
1
+ import { ResponseTemplateManager as RTM } from "./responsetemplatemanager.js";
2
+
3
+ function preg_quote(str: string, delimiter: string = "") {
4
+ // MIT, from: https://locutus.io/php/preg_quote/
5
+ return (str + "").replace(
6
+ new RegExp("[.\\\\+*?\\[\\^\\]$(){}=!<>|:\\" + delimiter + "-]", "g"),
7
+ "\\$&",
8
+ );
9
+ }
10
+
11
+ /**
12
+ * ResponseTranslator class
13
+ */
14
+ export class ResponseTranslator {
15
+ /**
16
+ * Regular Expression Mapping for API DESCRIPTION Property translation
17
+ */
18
+ private static descriptionRegexMap: Object = {
19
+ // HX
20
+ "Authorization failed; Operation forbidden by ACL":
21
+ "Authorization failed; Used Command `{COMMAND}` not white-listed by your Access Control List",
22
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY STATUS (clientTransferProhibited)/WRONG AUTH":
23
+ "This Domain is locked and the given Authorization Code is wrong. Initiating a Transfer is therefore impossible.",
24
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY STATUS (clientTransferProhibited)":
25
+ "This Domain is locked. Initiating a Transfer is therefore impossible.",
26
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY STATUS (requested)":
27
+ "Registration of this Domain Name has not yet completed. Initiating a Transfer is therefore impossible.",
28
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY STATUS (requestedcreate)":
29
+ "Registration of this Domain Name has not yet completed. Initiating a Transfer is therefore impossible.",
30
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY STATUS (requesteddelete)":
31
+ "Deletion of this Domain Name has been requested. Initiating a Transfer is therefore impossible.",
32
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY STATUS (pendingdelete)":
33
+ "Deletion of this Domain Name is pending. Initiating a Transfer is therefore impossible.",
34
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY WRONG AUTH":
35
+ "The given Authorization Code is wrong. Initiating a Transfer is therefore impossible.",
36
+ "Request is not available; DOMAIN TRANSFER IS PROHIBITED BY AGE OF THE DOMAIN":
37
+ "This Domain Name is within 60 days of initial registration. Initiating a Transfer is therefore impossible.",
38
+ "Attribute value is not unique; DOMAIN is already assigned to your account":
39
+ "You cannot transfer a domain that is already on your account at the registrar's system.",
40
+ // CNR
41
+ "Missing required attribute; premium domain name. please provide required parameters":
42
+ "Confirm the Premium pricing by providing the necessary premium domain price data.",
43
+ SkipPregQuote: {
44
+ // HX
45
+ "Invalid attribute value syntax; resource record [(.+)]":
46
+ "Invalid Syntax for DNSZone Resource Record: $1",
47
+ "Missing required attribute; CLASS(?:=| [MUST BE )PREMIUM_([w+]+)[s]]":
48
+ "Confirm the Premium pricing by providing the parameter CLASS with the value PREMIUM_$1.",
49
+ "Syntax error in Parameter DOMAIN ((.+))":
50
+ "The Domain Name $1 is invalid.",
51
+ },
52
+ };
53
+
54
+ /**
55
+ * translate a raw api response
56
+ * @param raw API raw response
57
+ * @param cmd requested API command
58
+ * @param ph list of place holder vars
59
+ * @returns new translated raw response
60
+ */
61
+ public static translate(raw: string, cmd: any, ph: any = {}): string {
62
+ let httperror = "";
63
+ let newraw = raw || "empty";
64
+ // Hint: Empty API Response (replace {CONNECTION_URL} later)
65
+
66
+ // curl error handling
67
+ const isHTTPError = newraw.substring(0, 10) === "httperror|";
68
+ if (isHTTPError) {
69
+ [newraw, httperror] = newraw.split("|");
70
+ }
71
+
72
+ // Explicit call for a static template
73
+ if (RTM.getInstance().hasTemplate(newraw)) {
74
+ // don't use getTemplate as it leads to endless loop as of again
75
+ // creating a response instance
76
+ newraw = RTM.getInstance().templates[newraw];
77
+ if (isHTTPError && httperror.length) {
78
+ newraw = newraw.replace(/\{HTTPERROR\}/, " (" + httperror + ")");
79
+ }
80
+ }
81
+
82
+ // Missing CODE or DESCRIPTION in API Response
83
+ if (
84
+ (!/description[\s]*=/i.test(newraw) || // missing description
85
+ /description[\s]*=\r\n/i.test(newraw) || // empty description
86
+ !/code[\s]*=/i.test(newraw)) && // missing code
87
+ RTM.getInstance().hasTemplate("invalid")
88
+ ) {
89
+ newraw = RTM.getInstance().templates.invalid;
90
+ }
91
+
92
+ // Iterate through the description-to-regex mapping
93
+ // generic API response description rewrite
94
+ let data: string = "";
95
+ for (const [regex, val] of Object.entries(
96
+ ResponseTranslator.descriptionRegexMap,
97
+ )) {
98
+ // Check if regex should be treated as multiple patterns
99
+ if (regex === "SkipPregQuote") {
100
+ // Iterate through each temporary pattern in val
101
+ for (const [tmpregex, tmpval] of Object.entries(val)) {
102
+ // Attempt to find a match using the temporary pattern
103
+ data = ResponseTranslator.findMatch(
104
+ tmpregex,
105
+ newraw,
106
+ "" + tmpval,
107
+ cmd,
108
+ ph,
109
+ );
110
+
111
+ // If a match is found, exit the inner loop
112
+ if (data) {
113
+ newraw = data;
114
+ break;
115
+ }
116
+ }
117
+ } else {
118
+ // Escape the pattern and attempt to find a match for it
119
+ const escapedregex = preg_quote(regex);
120
+ console.log(newraw);
121
+ data = ResponseTranslator.findMatch(escapedregex, newraw, val, cmd, ph);
122
+ console.log(newraw);
123
+ }
124
+
125
+ // If a match is found, exit the outer loop
126
+ if (data) {
127
+ newraw = data;
128
+ break;
129
+ }
130
+ }
131
+
132
+ const cregex = /\{.+\}/;
133
+ if (cregex.test(newraw)) {
134
+ newraw = newraw.replace(cregex, "");
135
+ }
136
+
137
+ return newraw;
138
+ }
139
+
140
+ /**
141
+ * Finds a match in the given text and performs replacements based on patterns and placeholders.
142
+ *
143
+ * This function searches for a specified regular expression pattern in the provided text and
144
+ * performs replacements based on the matched pattern, command data, and placeholder values.
145
+ *
146
+ * @param regex The regular expression pattern to search for.
147
+ * @param newraw The input text where the match will be searched for.
148
+ * @param val The value to be used in replacement if a match is found.
149
+ * @param cmd The command data containing replacements, if applicable.
150
+ * @param ph An array of placeholder values for further replacements.
151
+ *
152
+ * @return Returns non-empty string if replacements were performed, empty string otherwise.
153
+ */
154
+ protected static findMatch(
155
+ regex: string,
156
+ newraw: string,
157
+ val: string,
158
+ cmd: any = {},
159
+ ph: any = {},
160
+ ): string {
161
+ // match the response for given description
162
+ // NOTE: we match if the description starts with the given description
163
+ // it would also match if it is followed by additional text
164
+ const qregex = new RegExp("/descriptions*=s*" + regex + "([^\\r\\n]+)?/i");
165
+ let ret = "";
166
+
167
+ if (qregex.test(newraw)) {
168
+ // If "COMMAND" exists in cmd, replace "{COMMAND}" in val
169
+ if (Object.prototype.hasOwnProperty.call(cmd, "COMMAND")) {
170
+ val = val.replace("{COMMAND}", cmd.COMMAND);
171
+ }
172
+
173
+ // If $newraw matches $qregex, replace with "description=" . $val
174
+ let tmp = newraw.replace(qregex, "description=" + val);
175
+ if (newraw !== tmp) {
176
+ ret = tmp;
177
+ }
178
+ }
179
+
180
+ // Generic replacing of placeholder vars
181
+ const vregex = /\{[^}]+\}/;
182
+ if (vregex.test(newraw)) {
183
+ for (const [tkey, tval] of Object.entries(ph)) {
184
+ newraw = newraw.replace("{" + tkey + "}", "" + tval);
185
+ }
186
+ newraw = newraw.replace(vregex, "");
187
+ ret = newraw;
188
+ }
189
+ return ret;
190
+ }
191
+ }
@@ -0,0 +1,116 @@
1
+ export const fixedURLEnc = (str: string): string => {
2
+ return encodeURIComponent(str).replace(/[!'()*]/g, (c) => {
3
+ return `%${c.charCodeAt(0).toString(16).toUpperCase()}`;
4
+ });
5
+ };
6
+
7
+ /**
8
+ * SocketConfig Class
9
+ */
10
+ export class SocketConfig {
11
+ /**
12
+ * account name
13
+ */
14
+ private login: string;
15
+ /**
16
+ * persistent for session request
17
+ */
18
+ private persistent: string;
19
+ /**
20
+ * account password
21
+ */
22
+ private pw: string;
23
+ /**
24
+ * API session id
25
+ */
26
+ private sessionid: string;
27
+
28
+ public constructor() {
29
+ this.login = "";
30
+ this.persistent = "";
31
+ this.pw = "";
32
+ this.sessionid = "";
33
+ }
34
+
35
+ /**
36
+ * Create POST data string out of connection data
37
+ * @returns POST data string
38
+ */
39
+ public getPOSTData(): string {
40
+ let data = "";
41
+ if (this.login !== "") {
42
+ data += `${fixedURLEnc("s_login")}=${fixedURLEnc(this.login)}&`;
43
+ }
44
+ if (this.persistent !== "") {
45
+ data += `${fixedURLEnc("persistent")}=${fixedURLEnc(this.persistent)}&`;
46
+ }
47
+ if (this.pw !== "") {
48
+ data += `${fixedURLEnc("s_pw")}=${fixedURLEnc(this.pw)}&`;
49
+ }
50
+ if (this.sessionid !== "") {
51
+ data += `${fixedURLEnc("s_sessionid")}=${fixedURLEnc(this.sessionid)}&`;
52
+ }
53
+ return data;
54
+ }
55
+
56
+ /**
57
+ * Get API Session ID in use
58
+ * @returns API Session ID
59
+ */
60
+ public getSession(): string {
61
+ return this.sessionid;
62
+ }
63
+
64
+ /**
65
+ * Set account login to use
66
+ * @param value account login
67
+ * @returns Current SocketConfig instance for method chaining
68
+ */
69
+ public setLogin(value: string): SocketConfig {
70
+ this.sessionid = "";
71
+ this.login = value;
72
+ return this;
73
+ }
74
+
75
+ /**
76
+ * Get account login to use
77
+ * @returns Current login
78
+ */
79
+ public getLogin(): string {
80
+ return this.login;
81
+ }
82
+
83
+ /**
84
+ * Set persistent to request session id
85
+ * @param value one time password
86
+ * @returns Current SocketConfig instance for method chaining
87
+ */
88
+ public setPersistent(): SocketConfig {
89
+ this.sessionid = "";
90
+ this.persistent = "1";
91
+ return this;
92
+ }
93
+
94
+ /**
95
+ * Set account password to use
96
+ * @param value account password
97
+ * @returns Current SocketConfig instance for method chaining
98
+ */
99
+ public setPassword(value: string): SocketConfig {
100
+ this.sessionid = "";
101
+ this.pw = value;
102
+ return this;
103
+ }
104
+
105
+ /**
106
+ * Set API Session ID to use
107
+ * @param value API Session ID
108
+ * @returns Current SocketConfig instance for method chaining
109
+ */
110
+ public setSession(value: string): SocketConfig {
111
+ this.sessionid = value;
112
+ this.pw = "";
113
+ this.persistent = "";
114
+ return this;
115
+ }
116
+ }