@ouroboros/body 1.1.1 → 1.2.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.
package/src/index.ts CHANGED
@@ -8,9 +8,6 @@
8
8
  * @created 2023-03-03
9
9
  */
10
10
 
11
- // NPM modules
12
- import XMLHttpRequest from 'xhr2';
13
-
14
11
  // Import const files
15
12
  import * as constants from './constants';
16
13
  import * as errors from './errors';
@@ -22,10 +19,10 @@ export { default as Service } from './Service';
22
19
 
23
20
  // Types
24
21
  export type actionOptions = 'create' | 'delete' | 'read' | 'update';
25
- export type callbackOptions = 'error' | 'errorCode' | 'requested' | 'requesting' | 'warning';
26
22
  export type onCallbacks = {
27
23
  error?: onError,
28
24
  errorCode?: onErrorCode,
25
+ noSession?: () => void
29
26
  requested?: onRequested,
30
27
  requesting?: onRequesting,
31
28
  warning?: onWarning
@@ -37,15 +34,13 @@ export type onRequestedStruct = {
37
34
  action: actionOptions,
38
35
  data: any,
39
36
  res?: responseStruct,
40
- url: string,
41
- xhr: XMLHttpRequest
37
+ url: string
42
38
  };
43
39
  export type onRequesting = (info: onRequestingStruct) => void;
44
40
  export type onRequestingStruct = {
45
41
  action: actionOptions,
46
42
  data: any,
47
- url: string,
48
- xhr: XMLHttpRequest
43
+ url: string
49
44
  };
50
45
  export type onWarning = (warning: any, info: onRequestedStruct) => void;
51
46
  export type responseStruct = {
@@ -55,14 +50,13 @@ export type responseStruct = {
55
50
  };
56
51
  export type responseErrorStruct = {
57
52
  code: number,
58
- msg?: any,
59
- handle?: (message: string) => void
53
+ msg?: any
60
54
  }
61
55
  export type responseResolve = (res: responseStruct) => void;
62
56
  export type responseReject = (error: responseErrorStruct) => boolean;
63
57
 
64
58
  // Actions to methods
65
- const ACTIONS_TO_METHODS = {
59
+ const METHODS = {
66
60
  create: 'POST',
67
61
  delete: 'DELETE',
68
62
  read: 'GET',
@@ -80,7 +74,7 @@ const ACTIONS_TO_METHODS = {
80
74
  class Body {
81
75
 
82
76
  // The domain used to make requests to
83
- private _domain: string = '';
77
+ private _domain: string = 'localhost';
84
78
 
85
79
  // The function to call for http and related errors that need to be reported
86
80
  private error: onError | null = null;
@@ -89,7 +83,7 @@ class Body {
89
83
  private errorCode: onErrorCode | null = null;
90
84
 
91
85
  // The function to call when we get a status 401, or error code
92
- // REST_AUTHORIZATION
86
+ // REST_AUTHORIZATION
93
87
  private noSession: (() => void) | null = null;
94
88
 
95
89
  // The function to call after any request is sent
@@ -101,23 +95,30 @@ class Body {
101
95
  // The token associated with the current session
102
96
  private token: string | null = null;
103
97
 
104
- // Flag for being verbose
105
- private verbose: boolean = false;
106
-
107
98
  // The function to call if we get body warnings
108
99
  private warning: onWarning | null = null;
109
100
 
110
101
  /**
111
102
  * Domain
112
103
  *
113
- * Set the domain
104
+ * Sets/Gets the domain
114
105
  *
115
106
  * @name domain
116
107
  * @access public
117
- * @param domain The name of the domain to connect to
108
+ * @param @param domain The domain to set
109
+ * @returns the domain set
118
110
  */
119
- domain(domain: string): void {
120
- this._domain = domain;
111
+ domain(domain?: string): string | void {
112
+
113
+ // If we are getting the token
114
+ if(domain === undefined) {
115
+ return this._domain;
116
+ }
117
+
118
+ // Else, we are setting the token
119
+ else {
120
+ this._domain = domain;
121
+ }
121
122
  }
122
123
 
123
124
  /**
@@ -127,162 +128,158 @@ class Body {
127
128
  *
128
129
  * @name request
129
130
  * @access public
131
+ * @param action The action to take in the call
130
132
  * @param service The service to call
131
133
  * @param noun The noun to call on the service
132
134
  * @param data The data associated with the request
133
135
  */
134
- request(action: actionOptions, service: string, noun: string, data: any): Promise<any> {
136
+ request(
137
+ action: actionOptions,
138
+ service: string,
139
+ noun: string,
140
+ data: any
141
+ ): Promise<any> {
135
142
 
136
143
  // Generate the URL for the request
137
144
  let url = `https://${this._domain}/${service}/${noun}`;
138
145
 
139
- // Init the response object
146
+ // Init the response and json variables
140
147
  let res: responseStruct;
148
+ let json: string;
149
+
150
+ // If we got data
151
+ if(data !== null) {
152
+
153
+ // If we're in GET mode, append the data as a param "d" after
154
+ // turning it into JSON
155
+ if(action === 'read') {
156
+ url += '?d=' + encodeURIComponent(JSON.stringify(data));
157
+ } else {
158
+ json = JSON.stringify(data);
159
+ }
160
+ }
141
161
 
142
162
  // Set this
143
- const $this = this;
163
+ const _ = this;
164
+
165
+ // Handles an error based on whether an error handler is set
166
+ function handleError(message: string): void {
167
+ if(_.error) {
168
+ _.error(message, { action, data, url });
169
+ } else {
170
+ throw new Error(message);
171
+ }
172
+ }
144
173
 
145
174
  // Create a new Promise and return it
146
175
  return new Promise((resolve: responseResolve, reject) => {
147
176
 
148
- // Create a new XMLHttpRequest
149
- const xhr: XMLHttpRequest = new XMLHttpRequest();
150
-
151
- // Handles an error based on whether an error handler is set
152
- function handleError(message: string): void {
153
- if($this.error) {
154
- $this.error(message, { action, data, res, url, xhr });
155
- } else {
156
- throw new Error(message);
177
+ // Init the fetch init
178
+ const fetchInit: any = {
179
+ method: METHODS[action],
180
+ headers: {
181
+ 'Content-Type': 'application/json; charset=utf-8'
157
182
  }
158
183
  }
159
184
 
160
- // Track abort
161
- xhr.addEventListener('abort', event => {
162
- if(this.verbose) {
163
- console.log(`xhr.abort:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
164
- }
165
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} was aborted`)
166
- });
167
-
168
- // Track errors
169
- xhr.addEventListener('error', event => {
170
- if(this.verbose) {
171
- console.log(`xhr.error:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
172
- }
173
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} failed to connect`);
174
- });
185
+ // If we have a session token, add it as the Authorization header
186
+ if(_.token) {
187
+ fetchInit.headers.Authorization = _.token;
188
+ }
175
189
 
176
- // Handle successful request
177
- xhr.addEventListener('load', event => {
178
- if(this.verbose) {
179
- console.log(`xhr.load:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
180
- }
190
+ // If we have JSON
191
+ if(json) {
192
+ fetchInit.body = json;
193
+ }
181
194
 
182
- // If we got anything other than 200
183
- if(xhr.status !== 200) {
195
+ // If we have a requesting callback, call it
196
+ if(this.requesting) {
197
+ this.requesting({ action, data, url });
198
+ }
184
199
 
185
- // If it's 401
186
- if(xhr.status === 401) {
200
+ // Make the call
201
+ fetch(url, fetchInit).then(response => {
187
202
 
188
- // If we have a no session callback
189
- if(this.noSession) {
190
- return this.noSession();
191
- } else {
192
- throw new Error(`${ACTIONS_TO_METHODS[action]} ${url} return 401 NOT AUTHORIZED`);
193
- }
194
- }
203
+ // If 2xx
204
+ if(response.ok) {
195
205
 
196
- // Else, invalid status
197
- else {
198
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid status: ${xhr.status}`);
206
+ // If the Content-Type is missing or invalid
207
+ const ct = response.headers.get('Content-Type');
208
+ if(!ct || ct !== 'application/json; charset=utf-8') {
209
+ handleError(
210
+ `${METHODS[action]} ${url} returned invalid Content-Type: ${ct}`
211
+ );
199
212
  }
200
- }
201
213
 
202
- // If the Content-Type is missing or invalid
203
- const contentType = xhr.getResponseHeader('Content-Type');
204
- if(!contentType || contentType !== 'application/json; charset=utf-8') {
205
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid Content-Type: ${contentType}`);
214
+ // Return the JSON
215
+ return response.json();
206
216
  }
207
217
 
208
- // Convert the text from JSON
209
- res = JSON.parse(xhr.responseText);
218
+ // If it's 401
219
+ if(response.status === 401) {
210
220
 
211
- // If the JSON failed to parse
212
- if(!res) {
213
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid JSON: ${xhr.responseText}`);
221
+ // If we have a no session callback
222
+ if(_.noSession) {
223
+ return _.noSession();
224
+ } else {
225
+ throw new Error(
226
+ `${METHODS[action]} ${url} return 401 NOT AUTHORIZED`
227
+ );
228
+ }
229
+ }
230
+ // Else, invalid status
231
+ else {
232
+ handleError(
233
+ `${METHODS[action]} ${url} returned invalid status: ${response.status}`
234
+ );
214
235
  }
215
236
 
216
- // If we got an error
217
- if('error' in res && res.error) {
237
+ }).then(result => {
218
238
 
219
- // Add the handle error function to it
220
- res.error.handle = handleError;
239
+ // Set res
240
+ res = result;
221
241
 
222
- // If we don't have an onErrorCode callback, or it we do and
223
- // calling it returns false
224
- if(!this.errorCode || this.errorCode(res.error as responseErrorStruct, { action, data, res, url, xhr }) === false) {
225
- return reject(res.error);
242
+ // If we got an error
243
+ if('error' in result && result.error) {
244
+
245
+ // If we don't have an onErrorCode callback, or we do and
246
+ // calling it returns false
247
+ if(!_.errorCode ||
248
+ _.errorCode(
249
+ result.error as responseErrorStruct,
250
+ { action, data, res, url }
251
+ ) === false
252
+ ) {
253
+ return reject(result.error);
226
254
  }
227
255
  }
228
256
 
257
+ // If we got a warning and we have an onWarning callback
258
+ if('warning' in result && result.warning && _.warning) {
259
+ _.warning(
260
+ result.warning, { action, data, res, url }
261
+ );
262
+ }
263
+
229
264
  // If we got data
230
- if('data' in res) {
265
+ if('data' in result) {
231
266
 
232
267
  // Resolve it
233
- return resolve(res.data);
268
+ return resolve(result.data);
234
269
  }
235
- });
236
270
 
237
- // Handle the request being finished
238
- xhr.addEventListener('loadend', event => {
239
- if(this.verbose) {
240
- console.log(`xhr.loadend:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
241
- }
271
+ }).catch(reason => {
272
+ handleError(
273
+ `${METHODS[action]} ${url} failed because of "${reason}"`
274
+ )
275
+
276
+ }).finally(() => {
242
277
 
243
278
  // If we have a requested callback
244
279
  if(this.requested) {
245
- this.requested({ action, data, res, url, xhr });
246
- }
247
- });
248
-
249
- // Init the request body
250
- let xml = '';
251
-
252
- // If we got data
253
- if(data !== null) {
254
-
255
- // If we're in GET mode
256
- if(action === 'read') {
257
-
258
- // Append the data as a param
259
- url += '?d=' + encodeURIComponent(JSON.stringify(data));
280
+ this.requested({ action, data, res, url });
260
281
  }
261
-
262
- // Else, DELETE, POST, PUT, just encode the data
263
- else {
264
- xml = JSON.stringify(data);
265
- }
266
- }
267
-
268
- // Open the request
269
- xhr.open(ACTIONS_TO_METHODS[action], url);
270
-
271
- // If we have a session token, add it as the Authorization header
272
- if(this.token) {
273
- xhr.setRequestHeader('Authorization', this.token);
274
- }
275
-
276
- // Set the Content-Type header
277
- xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
278
-
279
- // If we have a requesting callback, call it
280
- if(this.requesting) {
281
- this.requesting({ action, data, url, xhr });
282
- }
283
-
284
- // Send the request
285
- xhr.send(xml);
282
+ })
286
283
  });
287
284
  }
288
285
 
@@ -334,6 +331,9 @@ class Body {
334
331
  case 'errorCode':
335
332
  this.errorCode = callbacks.errorCode as onErrorCode;
336
333
  continue;
334
+ case 'noSession':
335
+ this.noSession = callbacks.noSession as () => void;
336
+ continue;
337
337
  case 'requested':
338
338
  this.requested = callbacks.requested as onRequested;
339
339
  continue;
@@ -372,7 +372,7 @@ class Body {
372
372
  *
373
373
  * Sets callback for whenever a request gets an error back
374
374
  *
375
- * @name onNoSession
375
+ * @name onErrorCode
376
376
  * @access public
377
377
  * @param callback The function to call if there's an error
378
378
  */
@@ -447,6 +447,26 @@ class Body {
447
447
  this.requesting = callback;
448
448
  }
449
449
 
450
+ /**
451
+ * On Warning
452
+ *
453
+ * Sets callback for whenever a request gets a warning back
454
+ *
455
+ * @name onWarning
456
+ * @access public
457
+ * @param callback The function to call if there's a warning
458
+ */
459
+ onWarning(callback: onWarning): void {
460
+
461
+ // Make sure the callback is function
462
+ if(typeof callback !== 'function') {
463
+ throw new Error('onWarning() called with an invalid callback');
464
+ }
465
+
466
+ // Set the callback
467
+ this.warning = callback;
468
+ }
469
+
450
470
  /**
451
471
  * Read
452
472
  *
@@ -499,30 +519,6 @@ class Body {
499
519
  update(service: string, noun: string, data: any = null): Promise<any> {
500
520
  return this.request('update', service, noun, data);
501
521
  }
502
-
503
- /**
504
- * Verbose Off
505
- *
506
- * Called to turn verbose mode off
507
- *
508
- * @name verbose_off
509
- * @access
510
- */
511
- verbose_off(): void {
512
- this.verbose = false;
513
- }
514
-
515
- /**
516
- * Verbose On
517
- *
518
- * Called to turn verbose mode on
519
- *
520
- * @name verbose_on
521
- * @access
522
- */
523
- verbose_on(): void {
524
- this.verbose = true;
525
- }
526
522
  }
527
523
 
528
524
  // Create an instance of Body
package/src/regex.ts CHANGED
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  // E-Mail address
12
- export const EMAIL_ADDRESS = /[^@\s]+@[^@\s]+\.[a-zA-Z0-9]{2,}$/
12
+ export const EMAIL_ADDRESS = /^[^@\s]+@[^@\s]+\.[a-zA-Z0-9]{2,}$/
13
13
 
14
14
  // North American Phone Number
15
- export const PHONE_NUMBER_NA = /\+?1?[ -]?\(?(\d{3})\)?[ -]?(\d{3})[ -]?(\d{4})/
15
+ export const PHONE_NUMBER_NA = /^\+?1?[ -]?\(?(\d{3})\)?[ -]?(\d{3})[ -]?(\d{4})$/
@@ -1,3 +0,0 @@
1
- declare module "xhr2" {
2
- export default XMLHttpRequest;
3
- }
File without changes
File without changes
File without changes