@ouroboros/body 1.1.2 → 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.
@@ -7,8 +7,6 @@
7
7
  * @copyright Ouroboros Coding Inc.
8
8
  * @created 2023-03-03
9
9
  */
10
- // NPM modules
11
- import XMLHttpRequest from 'xhr2';
12
10
  // Import const files
13
11
  import * as constants from './constants';
14
12
  import * as errors from './errors';
@@ -17,7 +15,7 @@ import * as regex from './regex';
17
15
  export { constants, errors, regex };
18
16
  export { default as Service } from './Service';
19
17
  // Actions to methods
20
- const ACTIONS_TO_METHODS = {
18
+ const METHODS = {
21
19
  create: 'POST',
22
20
  delete: 'DELETE',
23
21
  read: 'GET',
@@ -33,13 +31,13 @@ const ACTIONS_TO_METHODS = {
33
31
  */
34
32
  class Body {
35
33
  // The domain used to make requests to
36
- _domain = '';
34
+ _domain = 'localhost';
37
35
  // The function to call for http and related errors that need to be reported
38
36
  error = null;
39
37
  // The function to call if we get body errors
40
38
  errorCode = null;
41
39
  // The function to call when we get a status 401, or error code
42
- // REST_AUTHORIZATION
40
+ // REST_AUTHORIZATION
43
41
  noSession = null;
44
42
  // The function to call after any request is sent
45
43
  requested = null;
@@ -47,21 +45,27 @@ class Body {
47
45
  requesting = null;
48
46
  // The token associated with the current session
49
47
  token = null;
50
- // Flag for being verbose
51
- verbose = false;
52
48
  // The function to call if we get body warnings
53
49
  warning = null;
54
50
  /**
55
51
  * Domain
56
52
  *
57
- * Set the domain
53
+ * Sets/Gets the domain
58
54
  *
59
55
  * @name domain
60
56
  * @access public
61
- * @param domain The name of the domain to connect to
57
+ * @param @param domain The domain to set
58
+ * @returns the domain set
62
59
  */
63
60
  domain(domain) {
64
- this._domain = domain;
61
+ // If we are getting the token
62
+ if (domain === undefined) {
63
+ return this._domain;
64
+ }
65
+ // Else, we are setting the token
66
+ else {
67
+ this._domain = domain;
68
+ }
65
69
  }
66
70
  /**
67
71
  * Request
@@ -70,6 +74,7 @@ class Body {
70
74
  *
71
75
  * @name request
72
76
  * @access public
77
+ * @param action The action to take in the call
73
78
  * @param service The service to call
74
79
  * @param noun The noun to call on the service
75
80
  * @param data The data associated with the request
@@ -77,124 +82,107 @@ class Body {
77
82
  request(action, service, noun, data) {
78
83
  // Generate the URL for the request
79
84
  let url = `https://${this._domain}/${service}/${noun}`;
80
- // Init the response object
85
+ // Init the response and json variables
81
86
  let res;
87
+ let json;
88
+ // If we got data
89
+ if (data !== null) {
90
+ // If we're in GET mode, append the data as a param "d" after
91
+ // turning it into JSON
92
+ if (action === 'read') {
93
+ url += '?d=' + encodeURIComponent(JSON.stringify(data));
94
+ }
95
+ else {
96
+ json = JSON.stringify(data);
97
+ }
98
+ }
82
99
  // Set this
83
- const $this = this;
100
+ const _ = this;
101
+ // Handles an error based on whether an error handler is set
102
+ function handleError(message) {
103
+ if (_.error) {
104
+ _.error(message, { action, data, url });
105
+ }
106
+ else {
107
+ throw new Error(message);
108
+ }
109
+ }
84
110
  // Create a new Promise and return it
85
111
  return new Promise((resolve, reject) => {
86
- // Create a new XMLHttpRequest
87
- const xhr = new XMLHttpRequest();
88
- // Handles an error based on whether an error handler is set
89
- function handleError(message) {
90
- if ($this.error) {
91
- $this.error(message, { action, data, res, url, xhr });
92
- }
93
- else {
94
- throw new Error(message);
112
+ // Init the fetch init
113
+ const fetchInit = {
114
+ method: METHODS[action],
115
+ headers: {
116
+ 'Content-Type': 'application/json; charset=utf-8'
95
117
  }
118
+ };
119
+ // If we have a session token, add it as the Authorization header
120
+ if (_.token) {
121
+ fetchInit.headers.Authorization = _.token;
96
122
  }
97
- // Track abort
98
- xhr.addEventListener('abort', event => {
99
- if (this.verbose) {
100
- console.log(`xhr.abort:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
101
- }
102
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} was aborted`);
103
- });
104
- // Track errors
105
- xhr.addEventListener('error', event => {
106
- if (this.verbose) {
107
- console.log(`xhr.error:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
108
- }
109
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} failed to connect`);
110
- });
111
- // Handle successful request
112
- xhr.addEventListener('load', event => {
113
- if (this.verbose) {
114
- console.log(`xhr.load:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
123
+ // If we have JSON
124
+ if (json) {
125
+ fetchInit.body = json;
126
+ }
127
+ // If we have a requesting callback, call it
128
+ if (this.requesting) {
129
+ this.requesting({ action, data, url });
130
+ }
131
+ // Make the call
132
+ fetch(url, fetchInit).then(response => {
133
+ // If 2xx
134
+ if (response.ok) {
135
+ // If the Content-Type is missing or invalid
136
+ const ct = response.headers.get('Content-Type');
137
+ if (!ct || ct !== 'application/json; charset=utf-8') {
138
+ handleError(`${METHODS[action]} ${url} returned invalid Content-Type: ${ct}`);
139
+ }
140
+ // Return the JSON
141
+ return response.json();
115
142
  }
116
- // If we got anything other than 200
117
- if (xhr.status !== 200) {
118
- // If it's 401
119
- if (xhr.status === 401) {
120
- // If we have a no session callback
121
- if (this.noSession) {
122
- return this.noSession();
123
- }
124
- else {
125
- throw new Error(`${ACTIONS_TO_METHODS[action]} ${url} return 401 NOT AUTHORIZED`);
126
- }
143
+ // If it's 401
144
+ if (response.status === 401) {
145
+ // If we have a no session callback
146
+ if (_.noSession) {
147
+ return _.noSession();
127
148
  }
128
- // Else, invalid status
129
149
  else {
130
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid status: ${xhr.status}`);
150
+ throw new Error(`${METHODS[action]} ${url} return 401 NOT AUTHORIZED`);
131
151
  }
132
152
  }
133
- // If the Content-Type is missing or invalid
134
- const contentType = xhr.getResponseHeader('Content-Type');
135
- if (!contentType || contentType !== 'application/json; charset=utf-8') {
136
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid Content-Type: ${contentType}`);
137
- }
138
- // Convert the text from JSON
139
- res = JSON.parse(xhr.responseText);
140
- // If the JSON failed to parse
141
- if (!res) {
142
- handleError(`${ACTIONS_TO_METHODS[action]} ${url} returned invalid JSON: ${xhr.responseText}`);
153
+ // Else, invalid status
154
+ else {
155
+ handleError(`${METHODS[action]} ${url} returned invalid status: ${response.status}`);
143
156
  }
157
+ }).then(result => {
158
+ // Set res
159
+ res = result;
144
160
  // If we got an error
145
- if ('error' in res && res.error) {
146
- // Add the handle error function to it
147
- res.error.handle = handleError;
148
- // If we don't have an onErrorCode callback, or it we do and
149
- // calling it returns false
150
- if (!this.errorCode || this.errorCode(res.error, { action, data, res, url, xhr }) === false) {
151
- return reject(res.error);
161
+ if ('error' in result && result.error) {
162
+ // If we don't have an onErrorCode callback, or we do and
163
+ // calling it returns false
164
+ if (!_.errorCode ||
165
+ _.errorCode(result.error, { action, data, res, url }) === false) {
166
+ return reject(result.error);
152
167
  }
153
168
  }
169
+ // If we got a warning and we have an onWarning callback
170
+ if ('warning' in result && result.warning && _.warning) {
171
+ _.warning(result.warning, { action, data, res, url });
172
+ }
154
173
  // If we got data
155
- if ('data' in res) {
174
+ if ('data' in result) {
156
175
  // Resolve it
157
- return resolve(res.data);
158
- }
159
- });
160
- // Handle the request being finished
161
- xhr.addEventListener('loadend', event => {
162
- if (this.verbose) {
163
- console.log(`xhr.loadend:\n\t${ACTIONS_TO_METHODS[action]} ${url}\n\t`, event);
176
+ return resolve(result.data);
164
177
  }
178
+ }).catch(reason => {
179
+ handleError(`${METHODS[action]} ${url} failed because of "${reason}"`);
180
+ }).finally(() => {
165
181
  // If we have a requested callback
166
182
  if (this.requested) {
167
- this.requested({ action, data, res, url, xhr });
183
+ this.requested({ action, data, res, url });
168
184
  }
169
185
  });
170
- // Init the request body
171
- let xml = '';
172
- // If we got data
173
- if (data !== null) {
174
- // If we're in GET mode
175
- if (action === 'read') {
176
- // Append the data as a param
177
- url += '?d=' + encodeURIComponent(JSON.stringify(data));
178
- }
179
- // Else, DELETE, POST, PUT, just encode the data
180
- else {
181
- xml = JSON.stringify(data);
182
- }
183
- }
184
- // Open the request
185
- xhr.open(ACTIONS_TO_METHODS[action], url);
186
- // If we have a session token, add it as the Authorization header
187
- if (this.token) {
188
- xhr.setRequestHeader('Authorization', this.token);
189
- }
190
- // Set the Content-Type header
191
- xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8');
192
- // If we have a requesting callback, call it
193
- if (this.requesting) {
194
- this.requesting({ action, data, url, xhr });
195
- }
196
- // Send the request
197
- xhr.send(xml);
198
186
  });
199
187
  }
200
188
  /**
@@ -243,6 +231,9 @@ class Body {
243
231
  case 'errorCode':
244
232
  this.errorCode = callbacks.errorCode;
245
233
  continue;
234
+ case 'noSession':
235
+ this.noSession = callbacks.noSession;
236
+ continue;
246
237
  case 'requested':
247
238
  this.requested = callbacks.requested;
248
239
  continue;
@@ -277,7 +268,7 @@ class Body {
277
268
  *
278
269
  * Sets callback for whenever a request gets an error back
279
270
  *
280
- * @name onNoSession
271
+ * @name onErrorCode
281
272
  * @access public
282
273
  * @param callback The function to call if there's an error
283
274
  */
@@ -340,6 +331,23 @@ class Body {
340
331
  // Set the callback
341
332
  this.requesting = callback;
342
333
  }
334
+ /**
335
+ * On Warning
336
+ *
337
+ * Sets callback for whenever a request gets a warning back
338
+ *
339
+ * @name onWarning
340
+ * @access public
341
+ * @param callback The function to call if there's a warning
342
+ */
343
+ onWarning(callback) {
344
+ // Make sure the callback is function
345
+ if (typeof callback !== 'function') {
346
+ throw new Error('onWarning() called with an invalid callback');
347
+ }
348
+ // Set the callback
349
+ this.warning = callback;
350
+ }
343
351
  /**
344
352
  * Read
345
353
  *
@@ -388,28 +396,6 @@ class Body {
388
396
  update(service, noun, data = null) {
389
397
  return this.request('update', service, noun, data);
390
398
  }
391
- /**
392
- * Verbose Off
393
- *
394
- * Called to turn verbose mode off
395
- *
396
- * @name verbose_off
397
- * @access
398
- */
399
- verbose_off() {
400
- this.verbose = false;
401
- }
402
- /**
403
- * Verbose On
404
- *
405
- * Called to turn verbose mode on
406
- *
407
- * @name verbose_on
408
- * @access
409
- */
410
- verbose_on() {
411
- this.verbose = true;
412
- }
413
399
  }
414
400
  // Create an instance of Body
415
401
  const body = new Body();
@@ -8,6 +8,6 @@
8
8
  * @created 2023-03-05
9
9
  */
10
10
  // E-Mail address
11
- export const EMAIL_ADDRESS = /[^@\s]+@[^@\s]+\.[a-zA-Z0-9]{2,}$/;
11
+ export const EMAIL_ADDRESS = /^[^@\s]+@[^@\s]+\.[a-zA-Z0-9]{2,}$/;
12
12
  // North American Phone Number
13
- export const PHONE_NUMBER_NA = /\+?1?[ -]?\(?(\d{3})\)?[ -]?(\d{3})[ -]?(\d{4})/;
13
+ export const PHONE_NUMBER_NA = /^\+?1?[ -]?\(?(\d{3})\)?[ -]?(\d{3})[ -]?(\d{4})$/;
Binary file
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@ouroboros/body",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "Classes to communicate with Ouroboros Coding Inc. body services",
5
- "main": "build/index.js",
6
- "types": "build/index.d.ts",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
7
  "scripts": {
8
8
  "build": "tslint -p tsconfig.json && tsc",
9
- "clean": "rm build/*",
9
+ "clean": "rm lib/*",
10
10
  "for_local": "npm install; tslint -p tsconfig.json && tsc; rm -Rf node_modules",
11
11
  "test": "echo \"Error: no test specified.\" && exit 1"
12
12
  },
@@ -26,9 +26,6 @@
26
26
  "devDependencies": {
27
27
  "tslint": "^6.1.3",
28
28
  "tslint-config-prettier": "^1.18.0",
29
- "typescript": "^4.8.3"
30
- },
31
- "dependencies": {
32
- "xhr2": "^0.2.1"
29
+ "typescript": "^4.9.5"
33
30
  }
34
31
  }
package/releases.md ADDED
@@ -0,0 +1,12 @@
1
+ # @ouroboros/body releases
2
+
3
+ ## 1.2.0
4
+ - Moved generated .js and .d.ts files into lib/ instead of build/, this changes the "main" from "build/index.js" to "lib/index.js".
5
+ - Removed `xhr2` from the project and replaced `XMLHttpRequest` with `fetch`.
6
+ - Removed `xhr` from `onRequestedStruct` and `onRequestingStruct`.
7
+ - Removed `Body.verbose_on()` and `Body.verbose_off()` functions as well as all `console.log` calls.
8
+ - Added missing `Body.onWarning` function.
9
+ - Added "noSession" as a valid key to the `on` function's argument.
10
+ - Added check in `Body.request` to trigger `this.warning` if a warning is returned.
11
+ - Added `domain`, `on`, and `onWarning` functions to `Service` class, each passes their arguments to, and returns from, the `body` function of the same name.
12
+ - Changed `body.domain` to getter/setter instead of just setter.
package/src/Service.ts CHANGED
@@ -12,7 +12,9 @@
12
12
  import body from './';
13
13
 
14
14
  // Types
15
- import { onError, onErrorCode, onRequested, onRequesting } from './';
15
+ import {
16
+ onCallbacks, onError, onErrorCode, onRequested, onRequesting, onWarning
17
+ } from './';
16
18
 
17
19
  /**
18
20
  * Service
@@ -70,6 +72,33 @@ export default class Service {
70
72
  return body.request('delete', this.service, noun, data);
71
73
  }
72
74
 
75
+ /**
76
+ * Domain
77
+ *
78
+ * Set/Gets the current domain
79
+ *
80
+ * @name domain
81
+ * @access public
82
+ * @param domain The domain to make all calls to
83
+ * @returns void
84
+ */
85
+ domain(domain?: string): void | string {
86
+ return body.domain(domain);
87
+ }
88
+
89
+ /**
90
+ * On
91
+ *
92
+ * Called to set multiple events at once
93
+ *
94
+ * @name on
95
+ * @access public
96
+ * @param callbacks A name to callback object to set multiple events
97
+ */
98
+ on(callbacks: onCallbacks): void {
99
+ return body.on(callbacks);
100
+ }
101
+
73
102
  /**
74
103
  * On Error
75
104
  *
@@ -120,6 +149,19 @@ export default class Service {
120
149
  return body.onRequesting(callback);
121
150
  }
122
151
 
152
+ /**
153
+ * On Warning
154
+ *
155
+ * Sets callback for whenever a request gets a warning back
156
+ *
157
+ * @name onWarning
158
+ * @access public
159
+ * @param callback The function to call if there's a warning
160
+ */
161
+ onWarning(callback: onWarning): void {
162
+ return body.onWarning(callback);
163
+ }
164
+
123
165
  /**
124
166
  * Read
125
167
  *
package/src/constants.ts CHANGED
@@ -9,9 +9,10 @@
9
9
  */
10
10
 
11
11
  // Empty UUID
12
- export const EMPTY_UUID = '00000000-0000-4000-8000-000000000000'
12
+ export const EMPTY_TUUID = '00000000000040008000000000000000';
13
+ export const EMPTY_UUID = '00000000-0000-4000-8000-000000000000';
13
14
 
14
15
  // Seconds
15
- export const SECONDS_HOUR = 3600
16
- export const SECONDS_DAY = 86400
17
- export const SECONDS_WEEK = 604800
16
+ export const SECONDS_HOUR = 3600;
17
+ export const SECONDS_DAY = 86400;
18
+ export const SECONDS_WEEK = 604800;