@webqit/webflo 1.0.14 → 1.0.16
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
CHANGED
|
@@ -10,7 +10,6 @@ export class HttpEvent {
|
|
|
10
10
|
#parentEvent;
|
|
11
11
|
#init;
|
|
12
12
|
#url;
|
|
13
|
-
#requestCloneCallback;
|
|
14
13
|
|
|
15
14
|
constructor(parentEvent, init = {}) {
|
|
16
15
|
this.#parentEvent = parentEvent;
|
|
@@ -32,56 +31,48 @@ export class HttpEvent {
|
|
|
32
31
|
|
|
33
32
|
get client() { return this.#init.client; }
|
|
34
33
|
|
|
34
|
+
#requestCloneCallback;
|
|
35
35
|
set onRequestClone(callback) {
|
|
36
36
|
this.#requestCloneCallback = callback;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
#responseHandler;
|
|
40
|
+
set onRespondWith(callback) {
|
|
41
|
+
this.#responseHandler = callback;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
get onRespondWith() {
|
|
45
|
+
return this.#responseHandler;
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
clone() {
|
|
40
49
|
const request = this.#requestCloneCallback?.() || this.request;
|
|
41
50
|
const init = { ...this.#init, request };
|
|
42
|
-
const instance = this.constructor.create(init);
|
|
51
|
+
const instance = this.constructor.create(this.#parentEvent, init);
|
|
43
52
|
instance.#requestCloneCallback = this.#requestCloneCallback;
|
|
44
53
|
return instance;
|
|
45
54
|
}
|
|
46
55
|
|
|
56
|
+
waitUntil(promise) {
|
|
57
|
+
if (this.#parentEvent) {
|
|
58
|
+
this.#parentEvent.waitUntil(promise);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
47
62
|
#response = null;
|
|
48
63
|
get response() { return this.#response; }
|
|
49
64
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
async #respondWith(response) {
|
|
53
|
-
/*
|
|
54
|
-
if (this.#response) {
|
|
55
|
-
throw new Error(`Event has already been responded to! (${this.#responseOrigin})`);
|
|
56
|
-
}
|
|
57
|
-
*/
|
|
65
|
+
async respondWith(response) {
|
|
58
66
|
this.#response = response;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const stackLines = stack.split('\n');
|
|
63
|
-
this.#responseOrigin = stackLines[3].trim();
|
|
64
|
-
}
|
|
65
|
-
*/
|
|
66
|
-
if (this.#parentEvent instanceof HttpEvent) {
|
|
67
|
-
/*
|
|
68
|
-
// Set responseOrigin first to prevent parent from repeating the work
|
|
69
|
-
this.#parentEvent.#responseOrigin = this.#responseOrigin;
|
|
70
|
-
*/
|
|
71
|
-
// Ensure the respondWith() method is how we propagate response
|
|
67
|
+
if (this.#responseHandler) {
|
|
68
|
+
await this.#responseHandler(this.#response);
|
|
69
|
+
} else if (this.#parentEvent) {
|
|
72
70
|
await this.#parentEvent.respondWith(this.#response);
|
|
73
|
-
} else {
|
|
74
|
-
// The callback passed at root
|
|
75
|
-
await this.#parentEvent?.(response);
|
|
76
71
|
}
|
|
77
72
|
}
|
|
78
73
|
|
|
79
|
-
async respondWith(response) {
|
|
80
|
-
await this.#respondWith(response);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
74
|
async defer() {
|
|
84
|
-
await this
|
|
75
|
+
await this.respondWith(new Response(null, { status: 202/*Accepted*/ }));
|
|
85
76
|
}
|
|
86
77
|
|
|
87
78
|
deferred() {
|
|
@@ -89,7 +80,7 @@ export class HttpEvent {
|
|
|
89
80
|
}
|
|
90
81
|
|
|
91
82
|
async redirect(url, status = 302) {
|
|
92
|
-
await this
|
|
83
|
+
await this.respondWith(new Response(null, { status, headers: {
|
|
93
84
|
Location: url
|
|
94
85
|
} }));
|
|
95
86
|
}
|
|
@@ -111,7 +102,7 @@ export class HttpEvent {
|
|
|
111
102
|
|
|
112
103
|
async with(url, init = {}) {
|
|
113
104
|
if (!this.request) {
|
|
114
|
-
return new HttpEvent(this, { ...this.#init, url
|
|
105
|
+
return new HttpEvent(this, { ...this.#init, url });
|
|
115
106
|
}
|
|
116
107
|
let request, _;
|
|
117
108
|
if (url instanceof Request) {
|
|
@@ -122,6 +113,6 @@ export class HttpEvent {
|
|
|
122
113
|
init = await Request.copy(this.request, init);
|
|
123
114
|
request = new Request(url, { ...init, referrer: this.request.url });
|
|
124
115
|
}
|
|
125
|
-
return new HttpEvent(this, { ...this.#init, request
|
|
116
|
+
return new HttpEvent(this, { ...this.#init, request });
|
|
126
117
|
}
|
|
127
118
|
}
|
|
@@ -63,6 +63,8 @@ export class WebfloRouter {
|
|
|
63
63
|
nextTick.destination = newDestination.split('?').shift().split('/').map(a => a.trim()).filter(a => a);
|
|
64
64
|
nextTick.trail = _args[1].startsWith('/') ? [] : thisTick.trail.reduce((_commonRoot, _seg, i) => _commonRoot.length === i && _seg === nextTick.destination[i] ? _commonRoot.concat(_seg) : _commonRoot, []);
|
|
65
65
|
nextTick.trailOnFile = thisTick.trailOnFile.slice(0, nextTick.trail.length);
|
|
66
|
+
} else {
|
|
67
|
+
nextTick.event = thisTick.event.clone();
|
|
66
68
|
}
|
|
67
69
|
return next(nextTick);
|
|
68
70
|
};
|
|
@@ -71,7 +73,21 @@ export class WebfloRouter {
|
|
|
71
73
|
_next.pathname = nextPathname.join('/');
|
|
72
74
|
_next.stepname = nextPathname[0];
|
|
73
75
|
// -------------
|
|
74
|
-
return
|
|
76
|
+
return new Promise(async (res) => {
|
|
77
|
+
thisTick.event.onRespondWith = (response) => {
|
|
78
|
+
thisTick.event.onRespondWith = null;
|
|
79
|
+
res(response);
|
|
80
|
+
};
|
|
81
|
+
const $returnValue = handler.call(thisContext, thisTick.event, thisTick.arg, _next/*next*/, remoteFetch);
|
|
82
|
+
thisTick.event.waitUntil($returnValue);
|
|
83
|
+
const returnValue = await $returnValue;
|
|
84
|
+
if (thisTick.event.onRespondWith) {
|
|
85
|
+
thisTick.event.onRespondWith = null;
|
|
86
|
+
res(returnValue);
|
|
87
|
+
} else if (typeof returnValue !== 'undefined') {
|
|
88
|
+
await thisTick.event.respondWith(returnValue);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
75
91
|
}
|
|
76
92
|
// Handler not found but exports found
|
|
77
93
|
return next(thisTick);
|
|
@@ -313,83 +313,100 @@ export class WebfloClient extends WebfloRuntime {
|
|
|
313
313
|
if (typeof scope.url === 'string') {
|
|
314
314
|
scope.url = new URL(scope.url, self.location.origin);
|
|
315
315
|
}
|
|
316
|
-
//
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
scope.
|
|
320
|
-
|
|
321
|
-
|
|
316
|
+
// ---------------
|
|
317
|
+
// Event lifecycle
|
|
318
|
+
scope.eventLifecyclePromises = new Set;
|
|
319
|
+
scope.eventLifecycleHooks = {
|
|
320
|
+
waitUntil: (promise) => {
|
|
321
|
+
promise = Promise.resolve(promise);
|
|
322
|
+
scope.eventLifecyclePromises.add(promise);
|
|
323
|
+
scope.eventLifecyclePromises.dirty = true;
|
|
324
|
+
promise.then(() => scope.eventLifecyclePromises.delete(promise));
|
|
325
|
+
},
|
|
326
|
+
respondWith: async (response) => {
|
|
327
|
+
if (scope.eventLifecyclePromises.dirty && !scope.eventLifecyclePromises.size) {
|
|
322
328
|
throw new Error('Final response already sent');
|
|
323
329
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
scope.
|
|
337
|
-
scope.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
330
|
+
return await this.execPush(scope.clientMessaging, response);
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
// Create and route request
|
|
334
|
+
scope.request = this.createRequest(scope.url, scope.init);
|
|
335
|
+
scope.cookies = this.constructor.CookieStorage.create(scope.request);
|
|
336
|
+
scope.session = this.constructor.SessionStorage.create(scope.request);
|
|
337
|
+
const messageChannel = new MessageChannel;
|
|
338
|
+
this.backgroundMessaging.add(new MessagingOverChannel(null, messageChannel.port1));
|
|
339
|
+
scope.clientMessaging = new ClientMessaging(this, messageChannel.port2);
|
|
340
|
+
scope.user = this.constructor.HttpUser.create(
|
|
341
|
+
scope.request,
|
|
342
|
+
scope.session,
|
|
343
|
+
scope.clientMessaging
|
|
344
|
+
);
|
|
345
|
+
scope.httpEvent = this.constructor.HttpEvent.create(scope.eventLifecycleHooks, {
|
|
346
|
+
request: scope.request,
|
|
347
|
+
detail: scope.detail,
|
|
348
|
+
cookies: scope.cookies,
|
|
349
|
+
session: scope.session,
|
|
350
|
+
user: scope.user,
|
|
351
|
+
client: scope.clientMessaging
|
|
352
|
+
});
|
|
353
|
+
scope.httpEvent.onRequestClone = () => this.createRequest(scope.url, scope.init);
|
|
354
|
+
// Ste pre-request states
|
|
355
|
+
Observer.set(this.navigator, {
|
|
356
|
+
requesting: new Url/*NOT URL*/(scope.url),
|
|
357
|
+
origins: scope.detail.navigationOrigins || [],
|
|
358
|
+
method: scope.request.method,
|
|
359
|
+
error: null
|
|
360
|
+
});
|
|
361
|
+
scope.resetStates = () => {
|
|
352
362
|
Observer.set(this.navigator, {
|
|
353
|
-
requesting:
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
363
|
+
requesting: null,
|
|
364
|
+
remotely: false,
|
|
365
|
+
origins: [],
|
|
366
|
+
method: null
|
|
357
367
|
});
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
368
|
+
};
|
|
369
|
+
scope.context = {};
|
|
370
|
+
if (window.webqit?.oohtml?.configs) {
|
|
371
|
+
const { BINDINGS_API: { api: bindingsConfig } = {}, } = window.webqit.oohtml.configs;
|
|
372
|
+
scope.context = this.host[bindingsConfig.bindings].data || {};
|
|
373
|
+
}
|
|
374
|
+
if (scope.request.method === 'GET') {
|
|
375
|
+
// Ping any existing background process
|
|
376
|
+
this.#backgroundMessaging.postMessage('navigation');
|
|
377
|
+
}
|
|
378
|
+
// Dispatch for response
|
|
379
|
+
scope.response = await this.dispatch(scope.httpEvent, scope.context, async (event) => {
|
|
380
|
+
// Was this nexted()? Tell the next layer we're in JSON mode by default
|
|
381
|
+
if (event !== scope.httpEvent && !event.request.headers.has('Accept')) {
|
|
382
|
+
event.request.headers.set('Accept', 'application/json');
|
|
370
383
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
scope.finalResponseSeen = true;
|
|
381
|
-
if (scope.initialResponseSeen) {
|
|
382
|
-
// Send via background port
|
|
383
|
-
if (typeof scope.$response !== 'undefined') {
|
|
384
|
-
await this.execPush(scope.clientMessaging, scope.$response);
|
|
385
|
-
}
|
|
386
|
-
return;
|
|
384
|
+
return await this.remoteFetch(event.request);
|
|
385
|
+
});
|
|
386
|
+
// ---------------
|
|
387
|
+
// Response processing
|
|
388
|
+
scope.hasBackgroundActivity = scope.eventLifecyclePromises.size || (scope.redirectMessage && !(scope.response instanceof Response && scope.response.headers.get('Location')));
|
|
389
|
+
scope.response = await this.normalizeResponse(scope.httpEvent, scope.response);
|
|
390
|
+
if (scope.response.headers.get('Location')) {
|
|
391
|
+
if (scope.redirectMessage) {
|
|
392
|
+
scope.session.set(`redirect-message:${scope.redirectMessageID}`, scope.redirectMessage);
|
|
387
393
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
394
|
+
} else {
|
|
395
|
+
if (scope.redirectMessage) {
|
|
396
|
+
scope.eventLifecycleHooks.respondWith(scope.redirectMessage);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
Promise.all([...scope.eventLifecyclePromises]).then(() => {
|
|
400
|
+
if (scope.clientMessaging.isMessaging()) {
|
|
401
|
+
scope.clientMessaging.on('connected', () => {
|
|
402
|
+
setTimeout(() => {
|
|
403
|
+
scope.clientMessaging.close();
|
|
404
|
+
}, 100);
|
|
405
|
+
});
|
|
406
|
+
} else scope.clientMessaging.close();
|
|
391
407
|
});
|
|
392
|
-
|
|
408
|
+
// ---------------
|
|
409
|
+
// Decode response
|
|
393
410
|
scope.finalUrl = scope.response.url || scope.request.url;
|
|
394
411
|
if (scope.response.redirected || scope.detail.navigationType === 'rdr' || scope.detail.isHoisted) {
|
|
395
412
|
const stateData = { ...(this.currentEntry()?.getState() || {}), redirected: true, };
|
|
@@ -131,84 +131,81 @@ export class WebfloWorker extends WebfloRuntime {
|
|
|
131
131
|
if (typeof scope.url === 'string') {
|
|
132
132
|
scope.url = new URL(scope.url, self.location.origin);
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
// ---------------
|
|
135
|
+
// Event lifecycle
|
|
136
|
+
scope.eventLifecyclePromises = new Set;
|
|
137
|
+
scope.eventLifecycleHooks = {
|
|
138
|
+
waitUntil: (promise) => {
|
|
139
|
+
promise = Promise.resolve(promise);
|
|
140
|
+
scope.eventLifecyclePromises.add(promise);
|
|
141
|
+
scope.eventLifecyclePromises.dirty = true;
|
|
142
|
+
promise.then(() => scope.eventLifecyclePromises.delete(promise));
|
|
143
|
+
},
|
|
144
|
+
respondWith: async (response) => {
|
|
145
|
+
if (scope.eventLifecyclePromises.dirty && !scope.eventLifecyclePromises.size) {
|
|
137
146
|
throw new Error('Final response already sent');
|
|
138
147
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
scope.
|
|
150
|
-
scope.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
148
|
+
return await this.execPush(scope.clientMessaging, response);
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
// Create and route request
|
|
152
|
+
scope.request = this.createRequest(scope.url, scope.init);
|
|
153
|
+
scope.cookies = this.constructor.CookieStorage.create(scope.request);
|
|
154
|
+
scope.session = this.constructor.SessionStorage.create(scope.request);
|
|
155
|
+
const portID = crypto.randomUUID();
|
|
156
|
+
scope.clientMessaging = new ClientMessaging(this, portID, { isPrimary: true });
|
|
157
|
+
scope.user = this.constructor.HttpUser.create(
|
|
158
|
+
scope.request,
|
|
159
|
+
scope.session,
|
|
160
|
+
scope.clientMessaging
|
|
161
|
+
);
|
|
162
|
+
scope.httpEvent = this.constructor.HttpEvent.create(scope.eventLifecycleHooks, {
|
|
163
|
+
request: scope.request,
|
|
164
|
+
detail: scope.detail,
|
|
165
|
+
cookies: scope.cookies,
|
|
166
|
+
session: scope.session,
|
|
167
|
+
user: scope.user,
|
|
168
|
+
client: scope.clientMessaging
|
|
169
|
+
});
|
|
170
|
+
// Restore session before dispatching
|
|
171
|
+
if (scope.request.method === 'GET'
|
|
172
|
+
&& (scope.redirectMessageID = scope.httpEvent.url.query['redirect-message'])
|
|
173
|
+
&& (scope.redirectMessage = scope.session.get(`redirect-message:${scope.redirectMessageID}`))) {
|
|
174
|
+
scope.session.delete(`redirect-message:${scope.redirectMessageID}`);
|
|
175
|
+
}
|
|
176
|
+
// Dispatch for response
|
|
177
|
+
scope.response = await this.dispatch(scope.httpEvent, {}, async (event) => {
|
|
178
|
+
// Was this nexted()? Tell the next layer we're in JSON mode by default
|
|
179
|
+
if (event !== scope.httpEvent && !event.request.headers.has('Accept')) {
|
|
180
|
+
event.request.headers.set('Accept', 'application/json');
|
|
168
181
|
}
|
|
169
|
-
|
|
170
|
-
scope.$response = await this.dispatch(scope.httpEvent, {}, async (event) => {
|
|
171
|
-
// Was this nexted()? Tell the next layer we're in JSON mode by default
|
|
172
|
-
if (event !== scope.httpEvent && !event.request.headers.has('Accept')) {
|
|
173
|
-
event.request.headers.set('Accept', 'application/json');
|
|
174
|
-
}
|
|
175
|
-
return await this.remoteFetch(event.request);
|
|
176
|
-
});
|
|
177
|
-
// Final reponse!!!
|
|
178
|
-
scope.finalResponseSeen = true;
|
|
179
|
-
if (scope.initialResponseSeen) {
|
|
180
|
-
// Send via background port
|
|
181
|
-
if (typeof scope.$response !== 'undefined') {
|
|
182
|
-
await this.execPush(scope.clientMessaging, scope.$response);
|
|
183
|
-
}
|
|
184
|
-
scope.clientMessaging.close();
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
// Send normally
|
|
188
|
-
resolveResponse(scope.$response);
|
|
182
|
+
return await this.remoteFetch(event.request);
|
|
189
183
|
});
|
|
190
|
-
|
|
191
|
-
|
|
184
|
+
// ---------------
|
|
185
|
+
// Response processing
|
|
186
|
+
scope.hasBackgroundActivity = scope.eventLifecyclePromises.size || (scope.redirectMessage && !(scope.response instanceof Response && scope.response.headers.get('Location')));
|
|
192
187
|
scope.response = await this.normalizeResponse(scope.httpEvent, scope.response, scope.hasBackgroundActivity);
|
|
193
188
|
if (scope.hasBackgroundActivity) {
|
|
194
189
|
scope.response.headers.set('X-Background-Messaging', `ch:${scope.clientMessaging.port.name}`);
|
|
195
190
|
}
|
|
196
|
-
if (scope.response
|
|
191
|
+
if (scope.response.headers.get('Location')) {
|
|
197
192
|
if (scope.redirectMessage) {
|
|
198
193
|
scope.session.set(`redirect-message:${scope.redirectMessageID}`, scope.redirectMessage);
|
|
199
194
|
}
|
|
200
195
|
} else {
|
|
201
196
|
if (scope.redirectMessage) {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
if (scope.finalResponseSeen) {
|
|
205
|
-
scope.clientMessaging.close();
|
|
206
|
-
}
|
|
207
|
-
}, 500);
|
|
208
|
-
} else if (scope.finalResponseSeen) {
|
|
209
|
-
scope.clientMessaging.close();
|
|
210
|
-
}
|
|
197
|
+
scope.eventLifecycleHooks.respondWith(scope.redirectMessage);
|
|
198
|
+
}
|
|
211
199
|
}
|
|
200
|
+
Promise.all([...scope.eventLifecyclePromises]).then(() => {
|
|
201
|
+
if (scope.clientMessaging.isMessaging()) {
|
|
202
|
+
scope.clientMessaging.on('connected', () => {
|
|
203
|
+
setTimeout(() => {
|
|
204
|
+
scope.clientMessaging.close();
|
|
205
|
+
}, 100);
|
|
206
|
+
});
|
|
207
|
+
} else scope.clientMessaging.close();
|
|
208
|
+
});
|
|
212
209
|
return scope.response;
|
|
213
210
|
}
|
|
214
211
|
|
|
@@ -477,98 +477,93 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
477
477
|
if (typeof scope.url === 'string') {
|
|
478
478
|
scope.url = new URL(scope.url, 'http://localhost');
|
|
479
479
|
}
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
480
|
+
// ---------------
|
|
481
|
+
// Event lifecycle
|
|
482
|
+
scope.eventLifecyclePromises = new Set;
|
|
483
|
+
scope.eventLifecycleHooks = {
|
|
484
|
+
waitUntil: (promise) => {
|
|
485
|
+
promise = Promise.resolve(promise);
|
|
486
|
+
scope.eventLifecyclePromises.add(promise);
|
|
487
|
+
scope.eventLifecyclePromises.dirty = true;
|
|
488
|
+
promise.then(() => scope.eventLifecyclePromises.delete(promise));
|
|
489
|
+
},
|
|
490
|
+
respondWith: async (response, isRedirectMessage = false) => {
|
|
491
|
+
if (!isRedirectMessage && scope.eventLifecyclePromises.dirty && !scope.eventLifecyclePromises.size) {
|
|
483
492
|
throw new Error('Final response already sent');
|
|
484
493
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
scope.
|
|
504
|
-
scope.
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
user: scope.user,
|
|
515
|
-
client: scope.clientMessaging
|
|
516
|
-
});
|
|
517
|
-
// Restore session before dispatching
|
|
518
|
-
if (scope.request.method === 'GET'
|
|
519
|
-
&& (scope.redirectMessageID = scope.httpEvent.url.query['redirect-message'])
|
|
520
|
-
&& (scope.redirectMessage = scope.session.get(`redirect-message:${scope.redirectMessageID}`))) {
|
|
521
|
-
scope.session.delete(`redirect-message:${scope.redirectMessageID}`);
|
|
522
|
-
}
|
|
523
|
-
// Dispatch for response
|
|
524
|
-
scope.$response = await this.dispatch(scope.httpEvent, {}, async (event) => {
|
|
525
|
-
return await this.localFetch(event);
|
|
526
|
-
});
|
|
527
|
-
// Final reponse!!!
|
|
528
|
-
scope.finalResponseSeen = true;
|
|
529
|
-
if (scope.initialResponseSeen) {
|
|
530
|
-
// Send via background port
|
|
531
|
-
if (typeof scope.$response !== 'undefined') {
|
|
532
|
-
await this.execPush(scope.clientMessaging, scope.$response);
|
|
533
|
-
}
|
|
534
|
-
scope.clientMessaging.close();
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
537
|
-
// Send normally
|
|
538
|
-
resolveResponse(scope.$response);
|
|
494
|
+
return await this.execPush(scope.clientMessaging, response);
|
|
495
|
+
},
|
|
496
|
+
};
|
|
497
|
+
// ---------------
|
|
498
|
+
// Request processing
|
|
499
|
+
scope.autoHeaders = this.#cx.config.runtime.server.Headers
|
|
500
|
+
? ((await (new this.#cx.config.runtime.server.Headers(this.#cx)).read()).entries || []).filter(entry => pattern(entry.url, url.origin).exec(url.href))
|
|
501
|
+
: [];
|
|
502
|
+
scope.request = this.createRequest(scope.url.href, scope.init, scope.autoHeaders.filter((header) => header.type === 'request'));
|
|
503
|
+
scope.cookies = this.constructor.CookieStorage.create(scope.request);
|
|
504
|
+
scope.session = this.constructor.SessionStorage.create(scope.request, { secret: this.#cx.env.entries.SESSION_KEY });
|
|
505
|
+
const sessionID = scope.session.sessionID;
|
|
506
|
+
if (!this.#globalMessagingRegistry.has(sessionID)) {
|
|
507
|
+
this.#globalMessagingRegistry.set(sessionID, new ClientMessagingRegistry(this, sessionID));
|
|
508
|
+
}
|
|
509
|
+
scope.clientMessagingRegistry = this.#globalMessagingRegistry.get(sessionID);
|
|
510
|
+
scope.clientMessaging = scope.clientMessagingRegistry.createPort();
|
|
511
|
+
scope.user = this.constructor.HttpUser.create(
|
|
512
|
+
scope.request,
|
|
513
|
+
scope.session,
|
|
514
|
+
scope.clientMessaging
|
|
515
|
+
);
|
|
516
|
+
scope.httpEvent = this.constructor.HttpEvent.create(scope.eventLifecycleHooks, {
|
|
517
|
+
request: scope.request,
|
|
518
|
+
detail: scope.detail,
|
|
519
|
+
cookies: scope.cookies,
|
|
520
|
+
session: scope.session,
|
|
521
|
+
user: scope.user,
|
|
522
|
+
client: scope.clientMessaging
|
|
539
523
|
});
|
|
540
|
-
|
|
541
|
-
|
|
524
|
+
// Restore session before dispatching
|
|
525
|
+
if (scope.request.method === 'GET'
|
|
526
|
+
&& (scope.redirectMessageID = scope.httpEvent.url.query['redirect-message'])
|
|
527
|
+
&& (scope.redirectMessage = scope.session.get(`redirect-message:${scope.redirectMessageID}`))) {
|
|
528
|
+
scope.session.delete(`redirect-message:${scope.redirectMessageID}`);
|
|
529
|
+
}
|
|
530
|
+
// Dispatch for response
|
|
531
|
+
scope.response = await this.dispatch(scope.httpEvent, {}, async (event) => {
|
|
532
|
+
return await this.localFetch(event);
|
|
533
|
+
});
|
|
534
|
+
// ---------------
|
|
535
|
+
// Response processing
|
|
536
|
+
scope.hasBackgroundActivity = scope.eventLifecyclePromises.size || (scope.redirectMessage && !(scope.response instanceof Response && scope.response.headers.get('Location')));
|
|
542
537
|
scope.response = await this.normalizeResponse(scope.httpEvent, scope.response, scope.hasBackgroundActivity);
|
|
543
538
|
if (scope.hasBackgroundActivity) {
|
|
544
539
|
scope.response.headers.set('X-Background-Messaging', `ws:${scope.clientMessaging.portID}`);
|
|
545
540
|
}
|
|
546
541
|
// Reponse handlers
|
|
547
|
-
if (scope.response
|
|
548
|
-
this.writeRedirectHeaders(scope.httpEvent, scope.response);
|
|
542
|
+
if (scope.response.headers.get('Location')) {
|
|
549
543
|
if (scope.redirectMessage) {
|
|
550
544
|
scope.session.set(`redirect-message:${scope.redirectMessageID}`, scope.redirectMessage);
|
|
551
545
|
}
|
|
546
|
+
this.writeRedirectHeaders(scope.httpEvent, scope.response);
|
|
552
547
|
} else {
|
|
548
|
+
if (scope.redirectMessage) {
|
|
549
|
+
scope.eventLifecycleHooks.respondWith(scope.redirectMessage, true);
|
|
550
|
+
}
|
|
553
551
|
this.writeAutoHeaders(scope.response.headers, scope.autoHeaders.filter((header) => header.type === 'response'));
|
|
554
552
|
if (scope.httpEvent.request.method !== 'GET' && !scope.response.headers.get('Cache-Control')) {
|
|
555
553
|
scope.response.headers.set('Cache-Control', 'no-store');
|
|
556
554
|
}
|
|
557
555
|
scope.response.headers.set('Accept-Ranges', 'bytes');
|
|
558
556
|
scope.response = await this.satisfyRequestFormat(scope.httpEvent, scope.response);
|
|
559
|
-
if (scope.redirectMessage) {
|
|
560
|
-
this.execPush(scope.clientMessaging, scope.redirectMessage);
|
|
561
|
-
if (scope.finalResponseSeen) {
|
|
562
|
-
scope.clientMessaging.on('connected', () => {
|
|
563
|
-
setTimeout(() => {
|
|
564
|
-
scope.clientMessaging.close();
|
|
565
|
-
}, 100);
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
} else if (scope.finalResponseSeen) {
|
|
569
|
-
scope.clientMessaging.close();
|
|
570
|
-
}
|
|
571
557
|
}
|
|
558
|
+
Promise.all([...scope.eventLifecyclePromises]).then(() => {
|
|
559
|
+
if (scope.clientMessaging.isMessaging()) {
|
|
560
|
+
scope.clientMessaging.on('connected', () => {
|
|
561
|
+
setTimeout(() => {
|
|
562
|
+
scope.clientMessaging.close();
|
|
563
|
+
}, 100);
|
|
564
|
+
});
|
|
565
|
+
} else scope.clientMessaging.close();
|
|
566
|
+
});
|
|
572
567
|
return scope.response;
|
|
573
568
|
}
|
|
574
569
|
|