@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/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 +119 -128
- package/{build → lib}/regex.js +2 -2
- package/package.json +5 -8
- package/releases.md +15 -0
- package/src/Service.ts +43 -1
- package/src/constants.ts +5 -4
- package/src/index.ts +158 -156
- package/src/regex.ts +2 -2
- package/build/types/xhr2.d.ts +0 -3
- 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,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(
|
|
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
|
-
});
|
|
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
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
195
|
+
// If we have a requesting callback, call it
|
|
196
|
+
if(this.requesting) {
|
|
197
|
+
this.requesting({ action, data, url });
|
|
198
|
+
}
|
|
181
199
|
|
|
182
|
-
|
|
183
|
-
|
|
200
|
+
// Make the call
|
|
201
|
+
fetch(url, fetchInit).then(response => {
|
|
184
202
|
|
|
185
|
-
|
|
186
|
-
|
|
203
|
+
// If 2xx
|
|
204
|
+
if(response.ok) {
|
|
187
205
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
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
|
-
//
|
|
197
|
-
|
|
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
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
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
|
-
|
|
209
|
-
res = JSON.parse(xhr.responseText);
|
|
238
|
+
}).then(result => {
|
|
210
239
|
|
|
211
|
-
// If
|
|
212
|
-
if(!
|
|
213
|
-
|
|
240
|
+
// If there's no result, do nothing
|
|
241
|
+
if(!result) {
|
|
242
|
+
return;
|
|
214
243
|
}
|
|
215
244
|
|
|
216
|
-
//
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
// Add the handle error function to it
|
|
220
|
-
res.error.handle = handleError;
|
|
245
|
+
// Set res
|
|
246
|
+
res = result;
|
|
221
247
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
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
|
|
271
|
+
if('data' in result) {
|
|
231
272
|
|
|
232
273
|
// Resolve it
|
|
233
|
-
return resolve(
|
|
274
|
+
return resolve(result.data);
|
|
234
275
|
}
|
|
235
|
-
});
|
|
236
276
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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/build/types/xhr2.d.ts
DELETED
package/src/types/xhr2.d.ts
DELETED
|
File without changes
|
/package/{build → lib}/errors.js
RENAMED
|
File without changes
|
|
File without changes
|