@optionfactory/ful 0.79.0 → 0.90.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/dist/ful.css +1 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.iife.js +398 -123
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +398 -118
- package/dist/ful.mjs.map +1 -1
- package/package.json +4 -4
package/dist/ful.mjs
CHANGED
|
@@ -70,171 +70,451 @@ class Hex {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
class
|
|
74
|
-
constructor() {
|
|
75
|
-
|
|
76
|
-
this.
|
|
73
|
+
class Failure extends Error {
|
|
74
|
+
constructor(name, problems, cause) {
|
|
75
|
+
super(JSON.stringify(problems), { cause });
|
|
76
|
+
this.name = name;
|
|
77
|
+
this.problems = problems;
|
|
77
78
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
class HttpClientError extends Failure {
|
|
82
|
+
constructor(status, problems, cause) {
|
|
83
|
+
super(`HttpClientError:${status}`, problems, cause);
|
|
84
|
+
this.status = status;
|
|
85
|
+
}
|
|
86
|
+
static of(type, cause) {
|
|
87
|
+
return new HttpClientError(0, [{
|
|
88
|
+
type,
|
|
89
|
+
context: null,
|
|
90
|
+
reason: cause.message,
|
|
91
|
+
details: null
|
|
92
|
+
}], cause);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Creates an HttpClientError from a Response.
|
|
96
|
+
* @param {Response} response
|
|
97
|
+
* @returns an HttpClientError
|
|
98
|
+
*/
|
|
99
|
+
static async fromResponse(response) {
|
|
100
|
+
const text = await response.text();
|
|
101
|
+
const def = [{
|
|
102
|
+
type: "GENERIC_PROBLEM",
|
|
103
|
+
context: null,
|
|
104
|
+
reason: `${response.status} ${response.statusText}: ${text}`,
|
|
105
|
+
details: null
|
|
106
|
+
}];
|
|
107
|
+
try {
|
|
108
|
+
return new HttpClientError(response.status, text ? JSON.parse(text) : def);
|
|
109
|
+
} catch (e) {
|
|
110
|
+
return new HttpClientError(response.status, def);
|
|
111
|
+
}
|
|
82
112
|
}
|
|
83
113
|
}
|
|
84
114
|
|
|
85
115
|
class CsrfTokenInterceptor {
|
|
116
|
+
#k; #v;
|
|
86
117
|
constructor() {
|
|
87
|
-
this
|
|
88
|
-
this
|
|
118
|
+
this.#k = document.querySelector("meta[name='_csrf_header']").getAttribute("content");
|
|
119
|
+
this.#v = document.querySelector("meta[name='_csrf']").getAttribute("content");
|
|
89
120
|
}
|
|
90
|
-
async intercept(request, chain){
|
|
91
|
-
|
|
92
|
-
headers.set(this.k, this.v);
|
|
93
|
-
request.options.headers = headers;
|
|
121
|
+
async intercept(request, chain) {
|
|
122
|
+
request.headers.set(this.#k, this.#v);
|
|
94
123
|
return await chain.proceed(request);
|
|
95
124
|
}
|
|
96
125
|
}
|
|
97
126
|
|
|
98
127
|
class RedirectOnUnauthorizedInterceptor {
|
|
128
|
+
#redirectUri;
|
|
99
129
|
constructor(redirectUri) {
|
|
100
|
-
this
|
|
130
|
+
this.#redirectUri = redirectUri;
|
|
101
131
|
}
|
|
102
|
-
async intercept(request, chain){
|
|
103
|
-
const response =
|
|
132
|
+
async intercept(request, chain) {
|
|
133
|
+
const response = await chain.proceed(request);
|
|
104
134
|
if (response.status !== 401) {
|
|
105
135
|
return response;
|
|
106
136
|
}
|
|
107
|
-
window.location.href = this
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
class Failure extends Error {
|
|
112
|
-
static parseProblems(status, text) {
|
|
113
|
-
const def = [{
|
|
114
|
-
type: "GENERIC_PROBLEM",
|
|
115
|
-
context: null,
|
|
116
|
-
reason: `${status}: ${text}`,
|
|
117
|
-
details: null
|
|
118
|
-
}];
|
|
119
|
-
try {
|
|
120
|
-
return text ? JSON.parse(text) : def;
|
|
121
|
-
} catch (e) {
|
|
122
|
-
return def;
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
static fromResponse(status, text) {
|
|
126
|
-
return new Failure(status, Failure.parseProblems(status, text));
|
|
127
|
-
}
|
|
128
|
-
constructor(status, problems) {
|
|
129
|
-
super(JSON.stringify(problems));
|
|
130
|
-
this.name = `Failure:${status}`;
|
|
131
|
-
this.status = status;
|
|
132
|
-
this.problems = problems;
|
|
137
|
+
window.location.href = this.#redirectUri;
|
|
133
138
|
}
|
|
134
139
|
}
|
|
135
140
|
|
|
136
141
|
class HttpClientBuilder {
|
|
142
|
+
#interceptors;
|
|
137
143
|
constructor() {
|
|
138
|
-
this
|
|
139
|
-
}
|
|
140
|
-
withContext() {
|
|
141
|
-
this.interceptors.push(new ContextInterceptor());
|
|
142
|
-
return this;
|
|
144
|
+
this.#interceptors = [];
|
|
143
145
|
}
|
|
144
146
|
withCsrfToken() {
|
|
145
|
-
this
|
|
147
|
+
this.#interceptors.push(new CsrfTokenInterceptor());
|
|
146
148
|
return this;
|
|
147
149
|
}
|
|
148
150
|
withRedirectOnUnauthorized(redirectUri) {
|
|
149
|
-
this
|
|
151
|
+
this.#interceptors.push(new RedirectOnUnauthorizedInterceptor(redirectUri));
|
|
150
152
|
return this;
|
|
151
153
|
}
|
|
152
154
|
withInterceptors(...interceptors) {
|
|
153
|
-
this
|
|
155
|
+
this.#interceptors.push(...interceptors);
|
|
154
156
|
return this;
|
|
155
157
|
}
|
|
156
158
|
build() {
|
|
157
|
-
|
|
158
|
-
return new HttpClient({interceptors});
|
|
159
|
+
return new HttpClient(this.#interceptors);
|
|
159
160
|
}
|
|
160
161
|
}
|
|
161
162
|
|
|
162
163
|
class HttpCall {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
/**
|
|
165
|
+
*
|
|
166
|
+
* @async
|
|
167
|
+
* @param {Request} request
|
|
168
|
+
* @param {HttpInterceptorChain} chain
|
|
169
|
+
* @returns {Promise<Response>} the response
|
|
170
|
+
*/
|
|
171
|
+
async intercept(request, chain) {
|
|
172
|
+
return await fetch(request);
|
|
173
|
+
}
|
|
166
174
|
}
|
|
167
175
|
|
|
168
176
|
class HttpInterceptorChain {
|
|
169
|
-
constructor(interceptors, current){
|
|
177
|
+
constructor(interceptors, current) {
|
|
170
178
|
this.interceptors = interceptors;
|
|
171
179
|
this.current = current;
|
|
172
180
|
}
|
|
173
|
-
async proceed(request){
|
|
181
|
+
async proceed(request) {
|
|
174
182
|
const interceptor = this.interceptors[this.current];
|
|
175
183
|
return await interceptor.intercept(request, new HttpInterceptorChain(this.interceptors, this.current + 1));
|
|
176
184
|
}
|
|
177
185
|
}
|
|
178
186
|
|
|
179
|
-
|
|
180
187
|
class HttpClient {
|
|
188
|
+
#interceptors;
|
|
189
|
+
/**
|
|
190
|
+
* Creates a builder for an HttpClient.
|
|
191
|
+
* @returns {HttpRequestBuilder} the client builder
|
|
192
|
+
*/
|
|
181
193
|
static builder() {
|
|
182
194
|
return new HttpClientBuilder();
|
|
183
195
|
}
|
|
184
|
-
|
|
185
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Creates an HttpClient.
|
|
198
|
+
* @returns {[HttpInterceptor]} interceptors - a list of interceptors to be registered for every request performed by the created client.
|
|
199
|
+
*/
|
|
200
|
+
constructor(interceptors) {
|
|
201
|
+
this.#interceptors = interceptors || [];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Performs an HTTP exchange.
|
|
205
|
+
* @async
|
|
206
|
+
* @param {string} uri - the (possibly relative) request url
|
|
207
|
+
* @param {RequestInit|undefined} options - fetch options
|
|
208
|
+
* @param {[any]|undefined} interceptors - the HttpInterceptors to be registered for this request.
|
|
209
|
+
* @returns {Promise<Response>} the response
|
|
210
|
+
*/
|
|
211
|
+
async exchange(uri, options, interceptors) {
|
|
212
|
+
const is = [...this.#interceptors, ...interceptors || [], new HttpCall()];
|
|
213
|
+
const chain = new HttpInterceptorChain(is, 0);
|
|
214
|
+
return await chain.proceed(new Request(uri, options));
|
|
186
215
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
216
|
+
/**
|
|
217
|
+
* Creates a request builder.
|
|
218
|
+
* @param {string} method - the HTTP method to be used
|
|
219
|
+
* @param {string} uri - the (possibly relative) request url
|
|
220
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
221
|
+
*/
|
|
222
|
+
request(method, uri) {
|
|
223
|
+
return HttpRequestBuilder.create(this, method, uri);
|
|
192
224
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
return
|
|
225
|
+
/**
|
|
226
|
+
* Creates a request builder.
|
|
227
|
+
* @param {string} uri - the (possibly relative) request url
|
|
228
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
229
|
+
*/
|
|
230
|
+
get(uri) {
|
|
231
|
+
return HttpRequestBuilder.create(this, 'GET', uri);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Creates a request builder.
|
|
235
|
+
* @param {string} uri - the (possibly relative) request url
|
|
236
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
237
|
+
*/
|
|
238
|
+
head(uri) {
|
|
239
|
+
return HttpRequestBuilder.create(this, 'HEAD', uri);
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Creates a request builder.
|
|
243
|
+
* @param {string} uri - the (possibly relative) request url
|
|
244
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
245
|
+
*/
|
|
246
|
+
post(uri) {
|
|
247
|
+
return HttpRequestBuilder.create(this, 'POST', uri);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Creates a request builder.
|
|
251
|
+
* @param {string} uri - the (possibly relative) request url
|
|
252
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
253
|
+
*/
|
|
254
|
+
put(uri) {
|
|
255
|
+
return HttpRequestBuilder.create(this, 'PUT', uri);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Creates a request builder.
|
|
259
|
+
* @param {string} uri - the (possibly relative) request url
|
|
260
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
261
|
+
*/
|
|
262
|
+
patch(uri) {
|
|
263
|
+
return HttpRequestBuilder.create(this, 'PATCH', uri);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Creates a request builder.
|
|
267
|
+
* @param {string} uri - the (possibly relative) request url
|
|
268
|
+
* @returns {HttpRequestBuilder} the request builder
|
|
269
|
+
*/
|
|
270
|
+
delete(uri) {
|
|
271
|
+
return HttpRequestBuilder.create(this, 'DELETE', uri);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
const unmarshal = async (response, type) => {
|
|
277
|
+
try {
|
|
278
|
+
return await response[type]();
|
|
279
|
+
} catch (e) {
|
|
280
|
+
throw HttpClientError.of("UNMARSHALING_PROBLEM", e);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
class HttpRequestBuilder {
|
|
286
|
+
#client;
|
|
287
|
+
#method;
|
|
288
|
+
#uri;
|
|
289
|
+
#params;
|
|
290
|
+
#headers;
|
|
291
|
+
#body;
|
|
292
|
+
#options;
|
|
293
|
+
#interceptors;
|
|
294
|
+
/**
|
|
295
|
+
* Creates an HttpRequestBuilder.
|
|
296
|
+
* @param {HttpClient} client
|
|
297
|
+
* @param {string} method - the HTTP method to be used
|
|
298
|
+
* @param {string} uri - the (possibly relative) request url
|
|
299
|
+
* @returns {HttpRequestBuilder} the builder
|
|
300
|
+
*/
|
|
301
|
+
static create(client, method, uri) {
|
|
302
|
+
return new HttpRequestBuilder(
|
|
303
|
+
client,
|
|
304
|
+
method,
|
|
305
|
+
uri,
|
|
306
|
+
new URLSearchParams(),
|
|
307
|
+
new Headers(),
|
|
308
|
+
undefined,
|
|
309
|
+
{},
|
|
310
|
+
[]
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Creates an HttpRequestBuilder.
|
|
315
|
+
* @param {HttpClient} client
|
|
316
|
+
* @param {string} method - the HTTP method to be used
|
|
317
|
+
* @param {string} uri - the (possibly relative) request url
|
|
318
|
+
* @param {URLSearchParams} params
|
|
319
|
+
* @param {Headers} headers
|
|
320
|
+
* @param {any} body
|
|
321
|
+
* @param {Omit<RequestInit,"headers"|"method"|"body">} options
|
|
322
|
+
* @param {[HttpInterceptor]} interceptors
|
|
323
|
+
*/
|
|
324
|
+
constructor(client, method, uri, params, headers, body, options, interceptors) {
|
|
325
|
+
this.#client = client;
|
|
326
|
+
this.#method = method;
|
|
327
|
+
this.#uri = uri;
|
|
328
|
+
this.#params = params;
|
|
329
|
+
this.#body = body;
|
|
330
|
+
this.#headers = headers;
|
|
331
|
+
this.#options = options;
|
|
332
|
+
this.#interceptors = interceptors;
|
|
200
333
|
}
|
|
201
|
-
|
|
334
|
+
/**
|
|
335
|
+
* Add all passed headers to the request, overriding existing ones if that key already exists.
|
|
336
|
+
* @param {headersInit} hs
|
|
337
|
+
* @returns {HttpRequestBuilder} this builder
|
|
338
|
+
*/
|
|
339
|
+
headers(hs) {
|
|
340
|
+
for (const [k, v] of new Headers(hs).entries()) {
|
|
341
|
+
this.#headers.set(k, v);
|
|
342
|
+
}
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Adds an header to the request, overriding it if it already exists.
|
|
347
|
+
* @param {string} k
|
|
348
|
+
* @param {string} v
|
|
349
|
+
* @returns {HttpRequestBuilder} this builder
|
|
350
|
+
*/
|
|
351
|
+
header(k, v) {
|
|
352
|
+
this.#headers.set(k, v);
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Add all query parameters to the request, overriding existing ones if that key already exists.
|
|
357
|
+
* @param {URLSearchParams|Record<string,string>|string[][]|string} ps
|
|
358
|
+
* @returns {HttpRequestBuilder} this builder
|
|
359
|
+
*/
|
|
360
|
+
params(ps) {
|
|
361
|
+
for (const [k, v] of new URLSearchParams(ps).entries()) {
|
|
362
|
+
this.#params.set(k, v);
|
|
363
|
+
}
|
|
364
|
+
return this;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Adds a query parameter to the request, overriding it if it already exists.
|
|
368
|
+
* @param {string} k
|
|
369
|
+
* @param {string} v
|
|
370
|
+
* @returns {HttpRequestBuilder} this builder
|
|
371
|
+
*/
|
|
372
|
+
param(k, v) {
|
|
373
|
+
this.#params.set(k, v);
|
|
374
|
+
return this;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Sets the request body.
|
|
378
|
+
* `Content-Type: multipart/form-data` header is automatically added by fetch when data is a FormData instance if not explicitly set.
|
|
379
|
+
* `Content-Type: application/x-www-form-urlencoded` header is automatically added by fetch when data is an URLSearchParams instance if not explicitly set.
|
|
380
|
+
* `Content-Type: text/plain` header is automatically added by fetch when data is a string instance if not explicitly set.
|
|
381
|
+
* @param {string|ArrayBuffer|Blob|DataView|File|FormData|TypedArray|URLSearchParams|ReadableStream} data
|
|
382
|
+
* @returns {HttpRequestBuilder} this builder
|
|
383
|
+
*/
|
|
384
|
+
body(data) {
|
|
385
|
+
this.#body = data;
|
|
386
|
+
return this;
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Sets the request body that will be serialized as json. Calling this method adds the `Content-Type application/json` header for the request.
|
|
390
|
+
* @param {any} body - the body to be serialized as json
|
|
391
|
+
* @returns {HttpRequestBuilder} this builder
|
|
392
|
+
*/
|
|
393
|
+
json(body) {
|
|
394
|
+
this.#headers.set("Content-Type", "application/json");
|
|
395
|
+
this.#body = JSON.stringify(body);
|
|
396
|
+
return this;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Sets a fetch options for the request.
|
|
400
|
+
* @param {Omit<RequestInit,"headers"|"method"|"body">} kvs
|
|
401
|
+
* @returns {HttpRequestBuilder} this builder
|
|
402
|
+
*/
|
|
403
|
+
options(kvs) {
|
|
404
|
+
for (const [k, v] of Object.entries(kvs)) {
|
|
405
|
+
this.#options[k] = v;
|
|
406
|
+
}
|
|
407
|
+
return this;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Sets a fetch option for the request.
|
|
411
|
+
* @param {keyof Omit<RequestInit,"headers"|"method"|"body">} k
|
|
412
|
+
* @param {*} v
|
|
413
|
+
* @returns {HttpRequestBuilder} this builder
|
|
414
|
+
*/
|
|
415
|
+
option(k, v) {
|
|
416
|
+
this.#options[k] = v;
|
|
417
|
+
return this;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Adds interceptors to the request.
|
|
421
|
+
* @param {[HttpInterceptor]} is - the interceptor to be regisered
|
|
422
|
+
* @returns {HttpRequestBuilder} this builder
|
|
423
|
+
*/
|
|
424
|
+
interceptors(is) {
|
|
425
|
+
for (const i of is) {
|
|
426
|
+
this.#interceptors.push(i);
|
|
427
|
+
}
|
|
428
|
+
return this;
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Adds an interceptor to the request.
|
|
432
|
+
* @param {HttpInterceptor} i - the interceptor to be regisered
|
|
433
|
+
* @returns {HttpRequestBuilder} this builder
|
|
434
|
+
*/
|
|
435
|
+
interceptor(i) {
|
|
436
|
+
this.#interceptors.push(i);
|
|
437
|
+
return this;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Performs an HTTP exchange using the configured client, request and interceptors.
|
|
441
|
+
* @returns {Promise<Response>} the response
|
|
442
|
+
*/
|
|
443
|
+
async exchange() {
|
|
444
|
+
const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;
|
|
445
|
+
const opts = {
|
|
446
|
+
...this.#options,
|
|
447
|
+
headers: this.#headers,
|
|
448
|
+
method: this.#method,
|
|
449
|
+
body: this.#body,
|
|
450
|
+
};
|
|
451
|
+
return await this.#client.exchange(uri, opts, this.#interceptors);
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
455
|
+
* @returns {Promise<Response>} the response
|
|
456
|
+
*/
|
|
457
|
+
async fetch() {
|
|
458
|
+
const uri = this.#params.size ? `${this.#uri}?${this.#params}` : this.#uri;
|
|
459
|
+
const opts = {
|
|
460
|
+
...this.#options,
|
|
461
|
+
headers: this.#headers,
|
|
462
|
+
method: this.#method,
|
|
463
|
+
body: this.#body,
|
|
464
|
+
};
|
|
202
465
|
try {
|
|
203
|
-
const response = await this.
|
|
204
|
-
|
|
205
|
-
|
|
466
|
+
const response = await this.#client.exchange(uri, opts, this.#interceptors);
|
|
467
|
+
if (!response.ok) {
|
|
468
|
+
throw await HttpClientError.fromResponse(response);
|
|
469
|
+
}
|
|
470
|
+
return response;
|
|
206
471
|
} catch (e) {
|
|
207
472
|
if (e instanceof Failure) {
|
|
208
473
|
throw e;
|
|
209
474
|
}
|
|
210
|
-
throw
|
|
211
|
-
type: "CONNECTION_PROBLEM",
|
|
212
|
-
context: null,
|
|
213
|
-
reason: e.message,
|
|
214
|
-
details: null
|
|
215
|
-
}]);
|
|
475
|
+
throw HttpClientError.of("CONNECTION_PROBLEM", e);
|
|
216
476
|
}
|
|
217
477
|
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
478
|
+
/**
|
|
479
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
480
|
+
* @returns {Promise<string>} the response body, as text
|
|
481
|
+
*/
|
|
482
|
+
async fetchText() {
|
|
483
|
+
const response = await this.fetch();
|
|
484
|
+
return await unmarshal(response, 'text');
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
488
|
+
* @returns {Promise<any>} the response body, deserialized as JSON
|
|
489
|
+
*/
|
|
490
|
+
async fetchJson() {
|
|
491
|
+
const response = await this.fetch();
|
|
492
|
+
return await unmarshal(response, 'json');
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
496
|
+
* @returns {Promise<Uint8Array>} the response body, as an Uint8Array
|
|
497
|
+
*/
|
|
498
|
+
async fetchBytes() {
|
|
499
|
+
const response = await this.fetch();
|
|
500
|
+
return await unmarshal(response, 'bytes');
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
504
|
+
* @returns {Promise<Blob>} the response body, as a Blob
|
|
505
|
+
*/
|
|
506
|
+
async fetchBlob() {
|
|
507
|
+
const response = await this.fetch();
|
|
508
|
+
return await unmarshal(response, 'blob');
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* Performs an HTTP exchange using the configured client request, and interceptos throwing a failure when response status is not in the 200-299 range.
|
|
512
|
+
* @returns {Promise<ArrayBuffer>} the response body, as an ArrayBuffer
|
|
513
|
+
*/
|
|
514
|
+
async fetchArrayBuffer() {
|
|
515
|
+
const response = await this.fetch();
|
|
516
|
+
return await unmarshal(response, 'arrayBuffer');
|
|
228
517
|
}
|
|
229
|
-
}
|
|
230
|
-
function jsonPost(body, headers){
|
|
231
|
-
return jsonRequest('POST', body, headers);
|
|
232
|
-
}
|
|
233
|
-
function jsonPut(body, headers){
|
|
234
|
-
return jsonRequest('PUT', body, headers);
|
|
235
|
-
}
|
|
236
|
-
function jsonPatch(body, headers){
|
|
237
|
-
return jsonRequest('PATCH', body, headers);
|
|
238
518
|
}
|
|
239
519
|
|
|
240
520
|
class Storage {
|
|
@@ -388,10 +668,10 @@ AuthorizationCodeFlow.PKCE_AND_STATE_KEY = "state-and-verifier";
|
|
|
388
668
|
class AuthorizationCodeFlowSession {
|
|
389
669
|
static parseToken(token) {
|
|
390
670
|
const [rawHeader, rawPayload, signature] = token.split(".");
|
|
391
|
-
const
|
|
671
|
+
const utf8decoder = new TextDecoder("utf-8");
|
|
392
672
|
return {
|
|
393
|
-
header: JSON.parse(
|
|
394
|
-
payload: JSON.parse(
|
|
673
|
+
header: JSON.parse(utf8decoder.decode(Base64.decode(rawHeader, Base64.STANDARD))),
|
|
674
|
+
payload: JSON.parse(utf8decoder.decode(Base64.decode(rawPayload, Base64.STANDARD))),
|
|
395
675
|
signature: signature
|
|
396
676
|
};
|
|
397
677
|
}
|
|
@@ -419,7 +699,8 @@ class AuthorizationCodeFlowSession {
|
|
|
419
699
|
])
|
|
420
700
|
});
|
|
421
701
|
if (!response.ok) {
|
|
422
|
-
|
|
702
|
+
const text = await response.text();
|
|
703
|
+
throw new Error("Error:" + response.status + ": " + text);
|
|
423
704
|
}
|
|
424
705
|
const token = await response.json();
|
|
425
706
|
this.token = token;
|
|
@@ -459,18 +740,19 @@ class AuthorizationCodeFlowSession {
|
|
|
459
740
|
}
|
|
460
741
|
|
|
461
742
|
class AuthorizationCodeFlowInterceptor {
|
|
743
|
+
#session;
|
|
744
|
+
#gracePeriodBefore;
|
|
745
|
+
#gracePeriodAfter;
|
|
462
746
|
constructor(session, gracePeriodBefore, gracePeriodAfter) {
|
|
463
|
-
this
|
|
464
|
-
this
|
|
465
|
-
this
|
|
747
|
+
this.#session = session;
|
|
748
|
+
this.#gracePeriodBefore = gracePeriodBefore || 2000;
|
|
749
|
+
this.#gracePeriodAfter = gracePeriodAfter || 30000;
|
|
466
750
|
}
|
|
467
751
|
async intercept(request, chain) {
|
|
468
|
-
await this
|
|
469
|
-
|
|
470
|
-
headers.set("Authorization", this.session.bearerToken());
|
|
471
|
-
request.options.headers = headers;
|
|
752
|
+
await this.#session.refreshIf(this.#gracePeriodBefore);
|
|
753
|
+
request.headers.set("Authorization", this.#session.bearerToken());
|
|
472
754
|
const response = await chain.proceed(request);
|
|
473
|
-
await this
|
|
755
|
+
await this.#session.refreshIf(this.#gracePeriodAfter);
|
|
474
756
|
return response;
|
|
475
757
|
}
|
|
476
758
|
}
|
|
@@ -922,8 +1204,6 @@ const ParsedElement = (conf) => {
|
|
|
922
1204
|
return k;
|
|
923
1205
|
};
|
|
924
1206
|
|
|
925
|
-
/* global Infinity, CSS */
|
|
926
|
-
|
|
927
1207
|
function flatten(obj, prefix) {
|
|
928
1208
|
return Object.keys(obj).reduce((acc, k) => {
|
|
929
1209
|
const pre = prefix.length ? prefix + '.' : '';
|
|
@@ -1081,7 +1361,7 @@ class Form extends ParsedElement() {
|
|
|
1081
1361
|
if (!this.hasAttribute('scroll-on-error')) {
|
|
1082
1362
|
return;
|
|
1083
1363
|
}
|
|
1084
|
-
const ys = Array.from(this.querySelectorAll(`[ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))
|
|
1364
|
+
const ys = Array.from(this.querySelectorAll(`ful-errors:not([hidden]), [ful-validated-field]:has(.${Form.INVALID_CLASS}) ful-field-error`))
|
|
1085
1365
|
.map(el => el.parentElement ? el.parentElement : el)
|
|
1086
1366
|
.map(el => el.getBoundingClientRect().y + window.scrollY);
|
|
1087
1367
|
const miny = Math.min(...ys);
|
|
@@ -1344,5 +1624,5 @@ class Spinner extends ParsedElement({
|
|
|
1344
1624
|
}
|
|
1345
1625
|
}
|
|
1346
1626
|
|
|
1347
|
-
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Deferred, ElementsRegistry, Failure, Form, Fragments, Hex, HttpClient, INPUT_TEMPLATE, Input, LightSlots, LocalStorage, Nodes, ParsedElement, RadioGroup, Select, SessionStorage, Spinner, TemplatesRegistry, VersionedStorage, elements,
|
|
1627
|
+
export { Attributes, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Deferred, ElementsRegistry, Failure, Form, Fragments, Hex, HttpClient, HttpClientError, INPUT_TEMPLATE, Input, LightSlots, LocalStorage, Nodes, ParsedElement, RadioGroup, Select, SessionStorage, Spinner, TemplatesRegistry, VersionedStorage, elements, makeInputFragment, timing };
|
|
1348
1628
|
//# sourceMappingURL=ful.mjs.map
|