@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/LICENSE +4 -4
- package/README.md +319 -10
- package/{build → lib}/Service.d.ts +32 -1
- package/{build → lib}/Service.js +37 -0
- package/{build → lib}/constants.d.ts +1 -0
- package/{build → lib}/constants.js +1 -0
- package/{build → lib}/index.d.ts +17 -28
- package/{build → lib}/index.js +115 -129
- package/{build → lib}/regex.js +2 -2
- package/ouroboros-body-1.2.0.tgz +0 -0
- package/package.json +5 -8
- package/releases.md +12 -0
- package/src/Service.ts +43 -1
- package/src/constants.ts +5 -4
- package/src/index.ts +153 -157
- package/src/regex.ts +2 -2
- package/src/types/xhr2.d.ts +0 -3
- /package/{build → lib}/errors.d.ts +0 -0
- /package/{build → lib}/errors.js +0 -0
- /package/{build → lib}/regex.d.ts +0 -0
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
|
|
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
|
-
//
|
|
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
|
-
*
|
|
104
|
+
* Sets/Gets the domain
|
|
114
105
|
*
|
|
115
106
|
* @name domain
|
|
116
107
|
* @access public
|
|
117
|
-
* @param domain The
|
|
108
|
+
* @param @param domain The domain to set
|
|
109
|
+
* @returns the domain set
|
|
118
110
|
*/
|
|
119
|
-
domain(domain
|
|
120
|
-
|
|
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(
|
|
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
|
|
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
|
|
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
|
-
//
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
190
|
+
// If we have JSON
|
|
191
|
+
if(json) {
|
|
192
|
+
fetchInit.body = json;
|
|
193
|
+
}
|
|
181
194
|
|
|
182
|
-
|
|
183
|
-
|
|
195
|
+
// If we have a requesting callback, call it
|
|
196
|
+
if(this.requesting) {
|
|
197
|
+
this.requesting({ action, data, url });
|
|
198
|
+
}
|
|
184
199
|
|
|
185
|
-
|
|
186
|
-
|
|
200
|
+
// Make the call
|
|
201
|
+
fetch(url, fetchInit).then(response => {
|
|
187
202
|
|
|
188
|
-
|
|
189
|
-
|
|
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
|
-
//
|
|
197
|
-
|
|
198
|
-
|
|
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
|
-
|
|
203
|
-
|
|
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
|
-
//
|
|
209
|
-
|
|
218
|
+
// If it's 401
|
|
219
|
+
if(response.status === 401) {
|
|
210
220
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
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
|
-
|
|
217
|
-
if('error' in res && res.error) {
|
|
237
|
+
}).then(result => {
|
|
218
238
|
|
|
219
|
-
|
|
220
|
-
|
|
239
|
+
// Set res
|
|
240
|
+
res = result;
|
|
221
241
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
|
265
|
+
if('data' in result) {
|
|
231
266
|
|
|
232
267
|
// Resolve it
|
|
233
|
-
return resolve(
|
|
268
|
+
return resolve(result.data);
|
|
234
269
|
}
|
|
235
|
-
});
|
|
236
270
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
15
|
+
export const PHONE_NUMBER_NA = /^\+?1?[ -]?\(?(\d{3})\)?[ -]?(\d{3})[ -]?(\d{4})$/
|
package/src/types/xhr2.d.ts
DELETED
|
File without changes
|
/package/{build → lib}/errors.js
RENAMED
|
File without changes
|
|
File without changes
|