@webqit/webflo 0.20.16 → 0.20.18
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/package.json +1 -1
- package/src/runtime-pi/WebfloRuntime.js +18 -14
- package/src/runtime-pi/webflo-client/WebfloClient.js +89 -49
- package/src/runtime-pi/webflo-client/WebfloRootClient2.js +7 -9
- package/src/runtime-pi/webflo-client/WebfloSubClient.js +8 -4
- package/src/runtime-pi/webflo-fetch/LiveResponse.js +2 -1
- package/src/runtime-pi/webflo-fetch/index.js +0 -6
- package/src/runtime-pi/webflo-routing/HttpEvent.js +3 -4
- package/src/runtime-pi/webflo-routing/HttpState.js +1 -1
- package/src/runtime-pi/webflo-routing/HttpThread.js +6 -1
- package/src/runtime-pi/webflo-routing/WebfloRouter.js +2 -2
package/package.json
CHANGED
|
@@ -15,13 +15,13 @@ export class WebfloRuntime {
|
|
|
15
15
|
|
|
16
16
|
static get Router() { return WebfloRouter; }
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
static get HttpEvent() { return HttpEvent; }
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
static get HttpThread() { return HttpThread; }
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
static get HttpSession() { return HttpSession; }
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
static get HttpUser() { return HttpUser; }
|
|
25
25
|
|
|
26
26
|
static create(bootstrap) { return new this(bootstrap); }
|
|
27
27
|
|
|
@@ -109,7 +109,7 @@ export class WebfloRuntime {
|
|
|
109
109
|
|
|
110
110
|
// Dispatch event
|
|
111
111
|
const router = new this.constructor.Router(this, httpEvent.url.pathname);
|
|
112
|
-
await router.route(['SETUP'], httpEvent.
|
|
112
|
+
await router.route(['SETUP'], httpEvent.spawn());
|
|
113
113
|
|
|
114
114
|
// Do proper routing for respone
|
|
115
115
|
const response = await new Promise(async (resolve) => {
|
|
@@ -141,8 +141,8 @@ export class WebfloRuntime {
|
|
|
141
141
|
: responseShim.from.value(response);
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
// Any "
|
|
145
|
-
await this.
|
|
144
|
+
// Any "status" in thread?
|
|
145
|
+
await this.handleThreadStatus(httpEvent, response);
|
|
146
146
|
|
|
147
147
|
// Resolve now...
|
|
148
148
|
if (autoLiveResponse) {
|
|
@@ -192,8 +192,11 @@ export class WebfloRuntime {
|
|
|
192
192
|
|
|
193
193
|
// On ROOT event complete:
|
|
194
194
|
// Close httpEvent.client
|
|
195
|
-
httpEvent.lifeCycleComplete(true).then(() => {
|
|
195
|
+
httpEvent.lifeCycleComplete(true).then(async () => {
|
|
196
196
|
httpEvent.client.close();
|
|
197
|
+
if (!httpEvent.thread.extended) {
|
|
198
|
+
await httpEvent.thread.clear();
|
|
199
|
+
}
|
|
197
200
|
});
|
|
198
201
|
}
|
|
199
202
|
|
|
@@ -205,16 +208,17 @@ export class WebfloRuntime {
|
|
|
205
208
|
return response;
|
|
206
209
|
}
|
|
207
210
|
|
|
208
|
-
async
|
|
211
|
+
async handleThreadStatus(httpEvent, response) {
|
|
209
212
|
if (!response.headers.get('Location')) {
|
|
210
|
-
const status = await httpEvent.thread.consume('status');
|
|
211
|
-
|
|
212
|
-
if (!status) return;
|
|
213
|
+
const status = await httpEvent.thread.consume('status', true);
|
|
214
|
+
if (!status.length) return;
|
|
213
215
|
// Fire redirect message?
|
|
214
216
|
httpEvent.waitUntil(new Promise((resolve) => {
|
|
215
217
|
httpEvent.client.wqLifecycle.open.then(async () => {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
+
setTimeout(() => {
|
|
219
|
+
httpEvent.client.postMessage(status, { wqEventOptions: { type: 'alert' } });
|
|
220
|
+
resolve();
|
|
221
|
+
}, 500); // half a sec
|
|
218
222
|
}, { once: true });
|
|
219
223
|
}));
|
|
220
224
|
}
|
|
@@ -58,20 +58,24 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
58
58
|
const instanceController = await super.initialize();
|
|
59
59
|
// Bind prompt handlers
|
|
60
60
|
const promptsHandler = (e) => {
|
|
61
|
-
|
|
62
|
-
? e.data.message
|
|
63
|
-
: e.data;
|
|
64
|
-
const execPromp = () => {
|
|
61
|
+
window.queueMicrotask(() => {
|
|
65
62
|
if (e.defaultPrevented) return;
|
|
66
63
|
if (e.type === 'confirm') {
|
|
67
|
-
e.
|
|
64
|
+
if (e.data?.message) {
|
|
65
|
+
e.wqRespondWith(confirm(e.data.message));
|
|
66
|
+
}
|
|
68
67
|
} else if (e.type === 'prompt') {
|
|
69
|
-
e.
|
|
68
|
+
if (e.data?.message) {
|
|
69
|
+
e.wqRespondWith(prompt(e.data.message));
|
|
70
|
+
}
|
|
70
71
|
} else if (e.type === 'alert') {
|
|
71
|
-
|
|
72
|
+
for (const item of [].concat(e.data)) {
|
|
73
|
+
if (item?.message) {
|
|
74
|
+
alert(item.message);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
72
77
|
}
|
|
73
|
-
};
|
|
74
|
-
window.queueMicrotask(execPromp);
|
|
78
|
+
});
|
|
75
79
|
};
|
|
76
80
|
this.background.addEventListener('confirm', promptsHandler, { signal: instanceController.signal });
|
|
77
81
|
this.background.addEventListener('prompt', promptsHandler, { signal: instanceController.signal });
|
|
@@ -318,6 +322,7 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
318
322
|
method: null
|
|
319
323
|
});
|
|
320
324
|
};
|
|
325
|
+
|
|
321
326
|
// Ping existing background processes
|
|
322
327
|
// !IMPORTANT: Posting to the group when empty will keep the event until next addition
|
|
323
328
|
// and we don't want that
|
|
@@ -325,6 +330,9 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
325
330
|
const url = { ...Url.copy(scopeObj.url), method: scopeObj.request.method };
|
|
326
331
|
this.#background.postMessage(url, { wqEventOptions: { type: 'navigate' } });
|
|
327
332
|
}
|
|
333
|
+
|
|
334
|
+
console.log('_______,', scopeObj.detail.navigationType);
|
|
335
|
+
|
|
328
336
|
// Dispatch for response
|
|
329
337
|
scopeObj.response = await this.dispatchNavigationEvent({
|
|
330
338
|
httpEvent: scopeObj.httpEvent,
|
|
@@ -338,20 +346,15 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
338
346
|
clientPortB: wqMessageChannel.port2,
|
|
339
347
|
originalRequestInit: scopeObj.init
|
|
340
348
|
});
|
|
349
|
+
|
|
341
350
|
// Decode response
|
|
342
351
|
scopeObj.finalUrl = scopeObj.response.url || scopeObj.request.url;
|
|
343
352
|
if (scopeObj.response.redirected || scopeObj.detail.navigationType === 'rdr' || scopeObj.detail.isHoisted) {
|
|
344
353
|
const stateData = { ...(this.currentEntry()?.getState() || {}), redirected: true, };
|
|
345
354
|
await this.updateCurrentEntry({ state: stateData }, scopeObj.finalUrl);
|
|
346
355
|
}
|
|
356
|
+
|
|
347
357
|
// Transition UI
|
|
348
|
-
Observer.set(this.transition.from, Url.copy(this.location));
|
|
349
|
-
Observer.set(this.transition.to, 'href', scopeObj.finalUrl);
|
|
350
|
-
Observer.set(this.transition, 'rel', this.transition.from.pathname === this.transition.to.pathname ? 'unchanged' : (
|
|
351
|
-
`${this.transition.from.pathname}/`.startsWith(`${this.transition.to.pathname}/`) ? 'parent' : (
|
|
352
|
-
`${this.transition.to.pathname}/`.startsWith(`${this.transition.from.pathname}/`) ? 'child' : 'unrelated'
|
|
353
|
-
)
|
|
354
|
-
));
|
|
355
358
|
await this.transitionUI(async () => {
|
|
356
359
|
// Set post-request states
|
|
357
360
|
Observer.set(this.location, 'href', scopeObj.finalUrl);
|
|
@@ -370,26 +373,45 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
370
373
|
!(['GET'].includes(scopeObj.request.method) || scopeObj.response.redirected || scopeObj.detail.navigationType === 'rdr')
|
|
371
374
|
);
|
|
372
375
|
await this.applyPostRenderState(scopeObj.httpEvent);
|
|
373
|
-
});
|
|
376
|
+
}, scopeObj.finalUrl, scopeObj.detail);
|
|
374
377
|
}
|
|
375
378
|
|
|
376
379
|
async dispatchNavigationEvent({ httpEvent, crossLayerFetch, clientPortB, originalRequestInit, processObj = {} }) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
380
|
+
let response = await super.dispatchNavigationEvent({ httpEvent, crossLayerFetch, clientPortB });
|
|
381
|
+
|
|
382
|
+
// Extract interactive. mode handling
|
|
383
|
+
const handleInteractiveMode = async (resolve) => {
|
|
384
|
+
const liveResponse = await LiveResponse.from(response);
|
|
385
|
+
this.background.addPort(liveResponse.background);
|
|
386
|
+
liveResponse.addEventListener('replace', () => {
|
|
387
|
+
if (liveResponse.headers.get('Location')) {
|
|
388
|
+
this.processRedirect(liveResponse);
|
|
389
|
+
} else {
|
|
390
|
+
resolve?.(liveResponse);
|
|
391
|
+
}
|
|
392
|
+
}, { signal: httpEvent.signal });
|
|
393
|
+
return liveResponse;
|
|
394
|
+
};
|
|
395
|
+
|
|
383
396
|
// Await a response with an "Accepted" or redirect status
|
|
384
397
|
const statusCode = responseShim.prototype.status.get.call(response);
|
|
385
|
-
if (statusCode === 202
|
|
398
|
+
if (statusCode === 202 && LiveResponse.hasBackground(response)) {
|
|
399
|
+
return new Promise(handleInteractiveMode);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Handle redirects
|
|
403
|
+
if (response.headers.get('Location')) {
|
|
404
|
+
// Never resolves...
|
|
386
405
|
return new Promise(async (resolve) => {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
406
|
+
const redirectHandlingMode = this.processRedirect(response);
|
|
407
|
+
// ...except processRedirect() says keep-alive
|
|
408
|
+
if (redirectHandlingMode === 3/* keep-alive */
|
|
409
|
+
&& LiveResponse.hasBackground(response)) {
|
|
410
|
+
await handleInteractiveMode(resolve);
|
|
411
|
+
}
|
|
391
412
|
});
|
|
392
413
|
}
|
|
414
|
+
|
|
393
415
|
// Handle "retry" directives
|
|
394
416
|
if (response.headers.has('Retry-After')) {
|
|
395
417
|
if (!processObj.recurseController) {
|
|
@@ -400,13 +422,21 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
400
422
|
// Ensure a previous recursion hasn't aborted the process
|
|
401
423
|
if (!processObj.recurseController.signal.aborted) {
|
|
402
424
|
await new Promise((res) => setTimeout(res, parseInt(response.headers.get('Retry-After')) * 1000));
|
|
403
|
-
const eventClone = httpEvent.
|
|
425
|
+
const eventClone = httpEvent.clone({ request: this.createRequest(httpEvent.url, originalRequestInit) });
|
|
404
426
|
return await this.dispatchNavigationEvent({ httpEvent: eventClone, crossLayerFetch, clientPortB, originalRequestInit, processObj });
|
|
405
427
|
}
|
|
406
|
-
} else
|
|
407
|
-
|
|
408
|
-
|
|
428
|
+
} else {
|
|
429
|
+
if (processObj.recurseController) {
|
|
430
|
+
// Abort the signal. This is the end of the loop
|
|
431
|
+
processObj.recurseController.abort();
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// Obtain and connect clientPortB as first thing
|
|
435
|
+
if (LiveResponse.hasBackground(response)) {
|
|
436
|
+
response = await handleInteractiveMode();
|
|
437
|
+
}
|
|
409
438
|
}
|
|
439
|
+
|
|
410
440
|
return response;
|
|
411
441
|
}
|
|
412
442
|
|
|
@@ -419,39 +449,48 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
419
449
|
responseMeta.set('status', xActualRedirectCode); // @NOTE 1
|
|
420
450
|
statusCode = xActualRedirectCode;
|
|
421
451
|
}
|
|
452
|
+
|
|
422
453
|
// Trigger redirect
|
|
423
454
|
if ([302, 301].includes(statusCode)) {
|
|
424
455
|
const location = new URL(response.headers.get('Location'), this.location.origin);
|
|
425
456
|
if (this.isSpaRoute(location)) {
|
|
426
457
|
this.navigate(location, {}, { navigationType: 'rdr' });
|
|
427
|
-
|
|
428
|
-
this.redirect(location, LiveResponse.getBackground(response));
|
|
458
|
+
return 1;
|
|
429
459
|
}
|
|
430
|
-
return
|
|
460
|
+
return this.redirect(location, response);
|
|
431
461
|
}
|
|
462
|
+
|
|
463
|
+
return 0; // No actual redirect
|
|
432
464
|
}
|
|
433
465
|
|
|
434
|
-
redirect(location
|
|
435
|
-
if (responseBackground) {
|
|
436
|
-
// Redundant as this is a window reload anyways
|
|
437
|
-
responseBackground.close();
|
|
438
|
-
}
|
|
466
|
+
redirect(location) {
|
|
439
467
|
window.location = location;
|
|
468
|
+
return 2; // Window reload
|
|
440
469
|
}
|
|
441
470
|
|
|
442
|
-
async transitionUI(updateCallback) {
|
|
443
|
-
|
|
471
|
+
async transitionUI(updateCallback, finalUrl, detail) {
|
|
472
|
+
// Set initial states
|
|
473
|
+
Observer.set(this.transition.from, Url.copy(this.location));
|
|
474
|
+
Observer.set(this.transition.to, 'href', finalUrl);
|
|
475
|
+
const viewTransitionRel = this.transition.from.pathname === this.transition.to.pathname ? 'same' : (
|
|
476
|
+
`${this.transition.from.pathname}/`.startsWith(`${this.transition.to.pathname}/`) ? 'out' : (
|
|
477
|
+
`${this.transition.to.pathname}/`.startsWith(`${this.transition.from.pathname}/`) ? 'in' : 'other'
|
|
478
|
+
)
|
|
479
|
+
);
|
|
480
|
+
Observer.set(this.transition, 'rel', viewTransitionRel);
|
|
481
|
+
// Trigger transition
|
|
482
|
+
if (document.startViewTransition && this.withViewTransitions && !detail.hasUAVisualTransition) {
|
|
444
483
|
const synthesizeWhile = window.webqit?.realdom?.synthesizeWhile || ((callback) => callback());
|
|
445
484
|
return new Promise(async (resolve) => {
|
|
446
485
|
await synthesizeWhile(async () => {
|
|
447
|
-
Observer.set(this.transition, 'phase',
|
|
448
|
-
const viewTransition = document.startViewTransition(updateCallback);
|
|
486
|
+
Observer.set(this.transition, 'phase', 'old');
|
|
487
|
+
const viewTransition = document.startViewTransition({ update: updateCallback, styles: ['navigation', viewTransitionRel] });
|
|
449
488
|
try { await viewTransition.updateCallbackDone; } catch (e) { console.log(e); }
|
|
450
|
-
Observer.set(this.transition, 'phase',
|
|
489
|
+
Observer.set(this.transition, 'phase', 'new');
|
|
451
490
|
try { await viewTransition.ready; } catch (e) { console.log(e); }
|
|
452
|
-
Observer.set(this.transition, 'phase',
|
|
491
|
+
Observer.set(this.transition, 'phase', 'start');
|
|
453
492
|
try { await viewTransition.finished; } catch (e) { console.log(e); }
|
|
454
|
-
Observer.set(this.transition, 'phase',
|
|
493
|
+
Observer.set(this.transition, 'phase', 'end');
|
|
455
494
|
resolve();
|
|
456
495
|
});
|
|
457
496
|
});
|
|
@@ -482,8 +521,9 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
482
521
|
transition: this.transition,
|
|
483
522
|
}, { diff: true, merge });
|
|
484
523
|
$response.addEventListener('replace', (e) => {
|
|
485
|
-
if (
|
|
486
|
-
|
|
524
|
+
if (!$response.headers.get('Location')) {
|
|
525
|
+
this.host[bindingsConfig.bindings].data = $response.body;
|
|
526
|
+
}
|
|
487
527
|
});
|
|
488
528
|
}
|
|
489
529
|
if (modulesContextAttrs) {
|
|
@@ -24,12 +24,16 @@ export class WebfloRootClient2 extends WebfloRootClient1 {
|
|
|
24
24
|
if (!e.canIntercept
|
|
25
25
|
|| e.downloadRequest !== null
|
|
26
26
|
|| !this.isSpaRoute(e.destination.url)
|
|
27
|
-
|| e.navigationType
|
|
27
|
+
|| ['reload'].includes(e.navigationType)) return;
|
|
28
28
|
if (e.hashChange) {
|
|
29
29
|
Observer.set(this.location, 'href', e.destination.url);
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
if (e.navigationType === 'replace') {
|
|
33
|
+
e.intercept({});
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const { navigationType, destination, signal, formData, info, userInitiated, hasUAVisualTransition } = e;
|
|
33
37
|
if (formData && navigationOrigins[1]?.hasAttribute('webflo-no-intercept')) return;
|
|
34
38
|
if (formData && (navigationOrigins[0] || {}).name) { formData.set(navigationOrigins[0].name, navigationOrigins[0].value); }
|
|
35
39
|
// Navigation details
|
|
@@ -39,6 +43,7 @@ export class WebfloRootClient2 extends WebfloRootClient1 {
|
|
|
39
43
|
destination,
|
|
40
44
|
source: this.currentEntry(),
|
|
41
45
|
userInitiated,
|
|
46
|
+
hasUAVisualTransition,
|
|
42
47
|
info
|
|
43
48
|
};
|
|
44
49
|
navigationOrigins = [];
|
|
@@ -50,18 +55,11 @@ export class WebfloRootClient2 extends WebfloRootClient1 {
|
|
|
50
55
|
body: formData,
|
|
51
56
|
//signal TODO: auto-aborts on a redirect response which thus fails to parse
|
|
52
57
|
};
|
|
53
|
-
this.updateCurrentEntry({
|
|
54
|
-
state: {
|
|
55
|
-
...(this.currentEntry().getState() || {}),
|
|
56
|
-
scrollPosition: [window.scrollX, window.scrollY],
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
58
|
const runtime = this;
|
|
60
59
|
e.intercept({
|
|
61
60
|
scroll: 'after-transition',
|
|
62
61
|
focusReset: 'after-transition',
|
|
63
62
|
async handler() {
|
|
64
|
-
if (navigationType === 'replace') return;
|
|
65
63
|
await runtime.navigate(url, init, detail);
|
|
66
64
|
},
|
|
67
65
|
});
|
|
@@ -90,16 +90,18 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
90
90
|
(this.host.querySelector('[autofocus]') || this.host).focus();
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
redirect(location,
|
|
93
|
+
redirect(location, response = null) {
|
|
94
94
|
location = typeof location === 'string' ? new URL(location, this.location.origin) : location;
|
|
95
95
|
const width = Math.min(800, window.innerWidth);
|
|
96
96
|
const height = Math.min(600, window.innerHeight);
|
|
97
97
|
const left = (window.outerWidth - width) / 2;
|
|
98
98
|
const top = (window.outerHeight - height) / 2;
|
|
99
99
|
const popup = window.open(location, '_blank', `popup=true,width=${width},height=${height},left=${left},top=${top}`);
|
|
100
|
-
if (
|
|
100
|
+
if (response && LiveResponse.hasBackground(response)) {
|
|
101
101
|
Observer.set(this.navigator, 'redirecting', new Url/*NOT URL*/(location), { diff: true });
|
|
102
|
-
|
|
102
|
+
const backgroundPort = LiveResponse.getBackground(response);
|
|
103
|
+
backgroundPort.postMessage(true, { wqEventOptions: { type: 'keep-alive' } });
|
|
104
|
+
backgroundPort.addEventListener('close', (e) => {
|
|
103
105
|
window.removeEventListener('message', windowMessageHandler);
|
|
104
106
|
Observer.set(this.navigator, 'redirecting', null);
|
|
105
107
|
popup.postMessage('timeout:5');
|
|
@@ -109,10 +111,12 @@ export class WebfloSubClient extends WebfloClient {
|
|
|
109
111
|
}, { once: true });
|
|
110
112
|
const windowMessageHandler = (e) => {
|
|
111
113
|
if (e.source === popup && e.data === 'close') {
|
|
112
|
-
|
|
114
|
+
backgroundPort.close();
|
|
113
115
|
}
|
|
114
116
|
};
|
|
115
117
|
window.addEventListener('message', windowMessageHandler);
|
|
116
118
|
}
|
|
119
|
+
|
|
120
|
+
return 3; // keep-alive
|
|
117
121
|
}
|
|
118
122
|
}
|
|
@@ -50,7 +50,8 @@ export class LiveResponse extends EventTarget {
|
|
|
50
50
|
throw new Error('Argument must be a Response instance.');
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
let body = null;
|
|
54
|
+
try { body = await responseShim.prototype.parse.value.call(response); } catch(e) {}
|
|
54
55
|
|
|
55
56
|
// Instance
|
|
56
57
|
const instance = new this(body, {
|
|
@@ -87,11 +87,6 @@ export const request = {
|
|
|
87
87
|
}
|
|
88
88
|
},
|
|
89
89
|
prototype: {
|
|
90
|
-
carries: {
|
|
91
|
-
get: function () {
|
|
92
|
-
return _wq(this, 'meta').get('carries') || [];
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
90
|
parse: { value: async function () { return await parseHttpMessage(this); } },
|
|
96
91
|
clone: {
|
|
97
92
|
value: function (init = {}) {
|
|
@@ -149,7 +144,6 @@ export const response = {
|
|
|
149
144
|
: this.status);
|
|
150
145
|
}
|
|
151
146
|
},
|
|
152
|
-
carry: { get: function () { return _wq(this, 'meta').get('carry'); } },
|
|
153
147
|
parse: { value: async function () { return await parseHttpMessage(this); } },
|
|
154
148
|
clone: {
|
|
155
149
|
value: function (init = {}) {
|
|
@@ -132,7 +132,7 @@ export class HttpEvent {
|
|
|
132
132
|
}
|
|
133
133
|
//-----
|
|
134
134
|
const urlRewrite = new URL(url, this.request.url);
|
|
135
|
-
const newThread = this.thread.
|
|
135
|
+
const newThread = this.thread.spawn(urlRewrite.searchParams.get('_thread'));
|
|
136
136
|
urlRewrite.searchParams.set('_thread', newThread.threadID);
|
|
137
137
|
await newThread.append('back', this.request.url.replace(urlRewrite.origin, ''));
|
|
138
138
|
for (const [key, value] of Object.entries(data)) {
|
|
@@ -146,9 +146,8 @@ export class HttpEvent {
|
|
|
146
146
|
return this.constructor.create(this.#parentEvent, { ...this.#init, ...init });
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
return instance;
|
|
149
|
+
spawn(init = {}) {
|
|
150
|
+
return this.constructor.create(this/*Main difference from clone*/, { ...this.#init, ...(init || {}) });
|
|
152
151
|
}
|
|
153
152
|
|
|
154
153
|
abort() {
|
|
@@ -140,7 +140,7 @@ export class HttpState {
|
|
|
140
140
|
return new Promise(() => { });
|
|
141
141
|
}
|
|
142
142
|
const urlRewrite = new URL(handler.url, this.#request.url);
|
|
143
|
-
const newThread = this.#thread.
|
|
143
|
+
const newThread = this.#thread.spawn(urlRewrite.searchParams.get('_thread')/* show */);
|
|
144
144
|
urlRewrite.searchParams.set('_thread', newThread.threadID);
|
|
145
145
|
await newThread.append('back', this.#request.url.replace(urlRewrite.origin, ''));
|
|
146
146
|
if (handler.with) {
|
|
@@ -10,6 +10,7 @@ export class HttpThread {
|
|
|
10
10
|
#store;
|
|
11
11
|
#threadID;
|
|
12
12
|
#realm;
|
|
13
|
+
#extended = false;
|
|
13
14
|
|
|
14
15
|
get threadID() { return this.#threadID; }
|
|
15
16
|
|
|
@@ -19,7 +20,7 @@ export class HttpThread {
|
|
|
19
20
|
this.#realm = realm;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
spawn(_threadID = null) {
|
|
23
24
|
return this.constructor.create({
|
|
24
25
|
store: this.#store,
|
|
25
26
|
threadID: _threadID,
|
|
@@ -78,4 +79,8 @@ export class HttpThread {
|
|
|
78
79
|
await this.#store.delete(this.#threadID);
|
|
79
80
|
return this;
|
|
80
81
|
}
|
|
82
|
+
|
|
83
|
+
get extended() { return this.#extended; }
|
|
84
|
+
|
|
85
|
+
extend(set = true) { this.#extended = !!set; }
|
|
81
86
|
}
|
|
@@ -132,7 +132,7 @@ export class WebfloRouter {
|
|
|
132
132
|
|
|
133
133
|
// Set context parameters
|
|
134
134
|
nextTick.method = request.method;
|
|
135
|
-
nextTick.event = await thisTick.event.
|
|
135
|
+
nextTick.event = await thisTick.event.spawn({ request });
|
|
136
136
|
nextTick.source = thisTick.destination.join('/');
|
|
137
137
|
nextTick.destination = url.pathname.split('/').map((a) => a.trim()).filter((a) => a);
|
|
138
138
|
nextTick.trail = !urlStr_isRelative ? [] : thisTick.trail.reduce((_commonRoot, _seg, i) => _commonRoot.length === i && _seg === nextTick.destination[i] ? _commonRoot.concat(_seg) : _commonRoot, []);
|
|
@@ -141,7 +141,7 @@ export class WebfloRouter {
|
|
|
141
141
|
if (isFetch) {
|
|
142
142
|
throw new Error('fetch() cannot be called without arguments!');
|
|
143
143
|
}
|
|
144
|
-
nextTick.event = thisTick.event.
|
|
144
|
+
nextTick.event = thisTick.event.spawn();
|
|
145
145
|
}
|
|
146
146
|
const result = await next(nextTick);
|
|
147
147
|
if (asResponse) {
|