@ouroboros/body 1.1.2 → 1.2.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.
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,164 @@ 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
- });
185
+ // If we have a session token, add it as the Authorization header
186
+ if(_.token) {
187
+ fetchInit.headers.Authorization = _.token;
188
+ }
167
189
 
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
- });
190
+ // If we have JSON
191
+ if(json) {
192
+ fetchInit.body = json;
193
+ }
175
194
 
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
- }
195
+ // If we have a requesting callback, call it
196
+ if(this.requesting) {
197
+ this.requesting({ action, data, url });
198
+ }
181
199
 
182
- // If we got anything other than 200
183
- if(xhr.status !== 200) {
200
+ // Make the call
201
+ fetch(url, fetchInit).then(response => {
184
202
 
185
- // If it's 401
186
- if(xhr.status === 401) {
203
+ // If 2xx
204
+ if(response.ok) {
187
205
 
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
- }
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
+ );
194
212
  }
195
213
 
196
- // Else, invalid status
197
- else {
198
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid status: ${xhr.status}`);
199
- }
214
+ // Return the JSON
215
+ return response.json();
200
216
  }
201
217
 
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}`);
218
+ // If it's 401
219
+ if(response.status === 401) {
220
+
221
+ // If we have a no session callback
222
+ if(_.noSession) {
223
+ _.noSession();
224
+ return Promise.resolve();
225
+ } else {
226
+ throw new Error(
227
+ `${METHODS[action]} ${url} return 401 NOT AUTHORIZED`
228
+ );
229
+ }
230
+ }
231
+ // Else, invalid status
232
+ else {
233
+ handleError(
234
+ `${METHODS[action]} ${url} returned invalid status: ${response.status}`
235
+ );
206
236
  }
207
237
 
208
- // Convert the text from JSON
209
- res = JSON.parse(xhr.responseText);
238
+ }).then(result => {
210
239
 
211
- // If the JSON failed to parse
212
- if(!res) {
213
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid JSON: ${xhr.responseText}`);
240
+ // If there's no result, do nothing
241
+ if(!result) {
242
+ return;
214
243
  }
215
244
 
216
- // If we got an error
217
- if('error' in res && res.error) {
218
-
219
- // Add the handle error function to it
220
- res.error.handle = handleError;
245
+ // Set res
246
+ res = result;
221
247
 
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);
248
+ // If we got an error
249
+ if('error' in result && result.error) {
250
+
251
+ // If we don't have an onErrorCode callback, or we do and
252
+ // calling it returns false
253
+ if(!_.errorCode ||
254
+ _.errorCode(
255
+ result.error as responseErrorStruct,
256
+ { action, data, res, url }
257
+ ) === false
258
+ ) {
259
+ return reject(result.error);
226
260
  }
227
261
  }
228
262
 
263
+ // If we got a warning and we have an onWarning callback
264
+ if('warning' in result && result.warning && _.warning) {
265
+ _.warning(
266
+ result.warning, { action, data, res, url }
267
+ );
268
+ }
269
+
229
270
  // If we got data
230
- if('data' in res) {
271
+ if('data' in result) {
231
272
 
232
273
  // Resolve it
233
- return resolve(res.data);
274
+ return resolve(result.data);
234
275
  }
235
- });
236
276
 
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
- }
277
+ }).catch(reason => {
278
+ handleError(
279
+ `${METHODS[action]} ${url} failed because of "${reason}"`
280
+ )
281
+
282
+ }).finally(() => {
242
283
 
243
284
  // If we have a requested callback
244
285
  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));
286
+ this.requested({ action, data, res, url });
260
287
  }
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);
288
+ })
286
289
  });
287
290
  }
288
291
 
@@ -334,6 +337,9 @@ class Body {
334
337
  case 'errorCode':
335
338
  this.errorCode = callbacks.errorCode as onErrorCode;
336
339
  continue;
340
+ case 'noSession':
341
+ this.noSession = callbacks.noSession as () => void;
342
+ continue;
337
343
  case 'requested':
338
344
  this.requested = callbacks.requested as onRequested;
339
345
  continue;
@@ -372,7 +378,7 @@ class Body {
372
378
  *
373
379
  * Sets callback for whenever a request gets an error back
374
380
  *
375
- * @name onNoSession
381
+ * @name onErrorCode
376
382
  * @access public
377
383
  * @param callback The function to call if there's an error
378
384
  */
@@ -447,6 +453,26 @@ class Body {
447
453
  this.requesting = callback;
448
454
  }
449
455
 
456
+ /**
457
+ * On Warning
458
+ *
459
+ * Sets callback for whenever a request gets a warning back
460
+ *
461
+ * @name onWarning
462
+ * @access public
463
+ * @param callback The function to call if there's a warning
464
+ */
465
+ onWarning(callback: onWarning): void {
466
+
467
+ // Make sure the callback is function
468
+ if(typeof callback !== 'function') {
469
+ throw new Error('onWarning() called with an invalid callback');
470
+ }
471
+
472
+ // Set the callback
473
+ this.warning = callback;
474
+ }
475
+
450
476
  /**
451
477
  * Read
452
478
  *
@@ -499,30 +525,6 @@ class Body {
499
525
  update(service: string, noun: string, data: any = null): Promise<any> {
500
526
  return this.request('update', service, noun, data);
501
527
  }
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
528
  }
527
529
 
528
530
  // 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
- }
@@ -1,3 +0,0 @@
1
- declare module "xhr2" {
2
- export default XMLHttpRequest;
3
- }
File without changes
File without changes
File without changes