@webqit/webflo 0.8.77 → 0.9.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.
Files changed (97) hide show
  1. package/package.json +5 -12
  2. package/src/Cli.js +131 -0
  3. package/src/Configurator.js +97 -0
  4. package/src/Context.js +76 -0
  5. package/src/config-pi/deployment/Env.js +69 -0
  6. package/src/config-pi/deployment/Layout.js +65 -0
  7. package/src/config-pi/deployment/Origins.js +133 -0
  8. package/src/config-pi/deployment/Virtualization.js +65 -0
  9. package/src/config-pi/deployment/index.js +18 -0
  10. package/src/config-pi/index.js +16 -0
  11. package/src/config-pi/runtime/Client.js +59 -0
  12. package/src/config-pi/runtime/Server.js +174 -0
  13. package/src/config-pi/runtime/client/Worker.js +117 -0
  14. package/src/config-pi/runtime/client/index.js +12 -0
  15. package/src/config-pi/runtime/index.js +18 -0
  16. package/src/config-pi/runtime/server/Headers.js +90 -0
  17. package/src/config-pi/runtime/server/Redirects.js +108 -0
  18. package/src/config-pi/runtime/server/index.js +14 -0
  19. package/src/config-pi/static/Manifest.js +321 -0
  20. package/src/config-pi/static/Ssg.js +72 -0
  21. package/src/config-pi/static/index.js +14 -0
  22. package/src/deployment-pi/index.js +10 -0
  23. package/src/{services → deployment-pi}/origins/index.js +88 -58
  24. package/src/index.js +14 -147
  25. package/src/{runtime → runtime-pi}/Router.js +19 -19
  26. package/src/runtime-pi/client/Context.js +7 -0
  27. package/src/{runtime → runtime-pi}/client/Router.js +2 -2
  28. package/src/{runtime/client/Navigator.js → runtime-pi/client/Runtime.js} +148 -103
  29. package/src/runtime-pi/client/RuntimeClient.js +114 -0
  30. package/src/{runtime → runtime-pi}/client/Storage.js +1 -1
  31. package/src/{runtime → runtime-pi}/client/Url.js +2 -6
  32. package/src/{runtime/client/WorkerClient.js → runtime-pi/client/WorkerComm.js} +2 -2
  33. package/src/runtime-pi/client/generate.js +242 -0
  34. package/src/runtime-pi/client/generate.oohtml.js +7 -0
  35. package/src/runtime-pi/client/index.js +18 -0
  36. package/src/runtime-pi/client/whatwag.js +27 -0
  37. package/src/runtime-pi/client/worker/Context.js +7 -0
  38. package/src/runtime-pi/client/worker/Worker.js +243 -0
  39. package/src/runtime-pi/client/worker/WorkerClient.js +46 -0
  40. package/src/runtime-pi/client/worker/index.js +18 -0
  41. package/src/runtime-pi/index.js +14 -0
  42. package/src/runtime-pi/server/Context.js +16 -0
  43. package/src/{runtime → runtime-pi}/server/Router.js +6 -6
  44. package/src/runtime-pi/server/Runtime.js +531 -0
  45. package/src/runtime-pi/server/RuntimeClient.js +103 -0
  46. package/src/runtime-pi/server/index.js +41 -0
  47. package/src/runtime-pi/server/whatwag.js +35 -0
  48. package/src/{runtime → runtime-pi}/util.js +0 -0
  49. package/src/{runtime/_FormData.js → runtime-pi/xFormData.js} +2 -2
  50. package/src/{runtime/_Headers.js → runtime-pi/xHeaders.js} +4 -4
  51. package/src/runtime-pi/xHttpEvent.js +93 -0
  52. package/src/runtime-pi/xHttpMessage.js +179 -0
  53. package/src/runtime-pi/xRequest.js +67 -0
  54. package/src/runtime-pi/xRequestHeaders.js +95 -0
  55. package/src/runtime-pi/xResponse.js +62 -0
  56. package/src/{runtime/_ResponseHeaders.js → runtime-pi/xResponseHeaders.js} +38 -18
  57. package/src/{runtime/_URL.js → runtime-pi/xURL.js} +4 -4
  58. package/src/runtime-pi/xfetch.js +7 -0
  59. package/src/{services → services-pi}/certbot/http-auth-hook.js +0 -0
  60. package/src/{services → services-pi}/certbot/http-cleanup-hook.js +0 -0
  61. package/src/{services → services-pi}/certbot/index.js +21 -15
  62. package/src/services-pi/index.js +9 -0
  63. package/src/static-pi/index.js +11 -0
  64. package/src/webflo.js +33 -0
  65. package/test/index.test.js +26 -0
  66. package/src/build/client/index.js +0 -261
  67. package/src/build/index.js +0 -5
  68. package/src/config/client.js +0 -191
  69. package/src/config/headers.js +0 -121
  70. package/src/config/index.js +0 -14
  71. package/src/config/layout.js +0 -83
  72. package/src/config/manifest.js +0 -341
  73. package/src/config/origins.js +0 -165
  74. package/src/config/prerendering.js +0 -100
  75. package/src/config/redirects.js +0 -137
  76. package/src/config/server.js +0 -201
  77. package/src/config/variables.js +0 -102
  78. package/src/config/vhosts.js +0 -93
  79. package/src/runtime/_MessageStream.js +0 -195
  80. package/src/runtime/_NavigationEvent.js +0 -91
  81. package/src/runtime/_Request.js +0 -59
  82. package/src/runtime/_RequestHeaders.js +0 -72
  83. package/src/runtime/_Response.js +0 -56
  84. package/src/runtime/client/NavigationEvent.js +0 -21
  85. package/src/runtime/client/Runtime.js +0 -126
  86. package/src/runtime/client/Worker.js +0 -317
  87. package/src/runtime/client/archive/Cache.js +0 -38
  88. package/src/runtime/client/archive/Http.js +0 -225
  89. package/src/runtime/client/archive/StdRequest.js +0 -74
  90. package/src/runtime/client/archive/WorkerComm.js +0 -183
  91. package/src/runtime/client/effects/sounds.js +0 -64
  92. package/src/runtime/index.js +0 -5
  93. package/src/runtime/server/NavigationEvent.js +0 -39
  94. package/src/runtime/server/Runtime.js +0 -593
  95. package/src/runtime/server/index.js +0 -183
  96. package/src/runtime/server/index.mjs +0 -10
  97. package/src/services/index.js +0 -6
@@ -0,0 +1,243 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import _isGlobe from 'is-glob';
6
+ import Minimatch from 'minimatch';
7
+ import { _any } from '@webqit/util/arr/index.js';
8
+ import { _after, _afterLast } from '@webqit/util/str/index.js';
9
+ import { HttpEvent, Request, Response } from '../Runtime.js';
10
+ import { Observer } from '../Runtime.js';
11
+
12
+ /**
13
+ * ---------------------------
14
+ * The Worker Initializer
15
+ * ---------------------------
16
+ */
17
+
18
+ export default class Worker {
19
+
20
+ /**
21
+ * Runtime
22
+ *
23
+ * @param Object cx
24
+ * @param Function clientCallback
25
+ *
26
+ * @return void
27
+ */
28
+ constructor(cx, clientCallback) {
29
+
30
+ // ---------------
31
+ this.cx = cx;
32
+ this.clients = new Map;
33
+ this.mockSessionStore = {};
34
+ // ---------------
35
+ this.cx.runtime = this;
36
+ let client = clientCallback(this.cx, '*');
37
+ if (!client || !client.handle) throw new Error(`Application instance must define a ".handle()" method.`);
38
+ this.clients.set('*', client);
39
+
40
+ // -------------
41
+ // ONINSTALL
42
+ self.addEventListener('install', evt => {
43
+ if (this.cx.params.skip_waiting) { self.skipWaiting(); }
44
+ // Manage CACHE
45
+ if (this.cx.params.cache_name && (this.cx.params.cache_only_urls || []).length) {
46
+ // Add files to cache
47
+ evt.waitUntil( self.caches.open(this.cx.params.cache_name).then(cache => {
48
+ if (this.cx.logger) { this.cx.logger.log('[ServiceWorker] Pre-caching resources.'); }
49
+ const cache_only_urls = (this.cx.params.cache_only_urls || []).map(c => c.trim()).filter(c => c);
50
+ return cache.addAll(cache_only_urls.filter(url => !_isGlobe(url) && !_afterLast(url, '.').includes('/')));
51
+ }) );
52
+ }
53
+ });
54
+
55
+ // -------------
56
+ // ONACTIVATE
57
+ self.addEventListener('activate', evt => {
58
+ evt.waitUntil( new Promise(async resolve => {
59
+ if (this.cx.params.skip_waiting) { await self.clients.claim(); }
60
+ // Manage CACHE
61
+ if (this.cx.params.cache_name) {
62
+ // Clear outdated CACHES
63
+ await self.caches.keys().then(keyList => {
64
+ return Promise.all(keyList.map(key => {
65
+ if (key !== this.cx.params.cache_name && key !== this.cx.params.cache_name + '_json') {
66
+ if (this.cx.logger) { this.cx.logger.log('[ServiceWorker] Removing old cache:', key); }
67
+ return self.caches.delete(key);
68
+ }
69
+ }));
70
+ })
71
+ }
72
+ resolve();
73
+ }) );
74
+ });
75
+
76
+ // -------------
77
+ // ONFETCH
78
+ self.addEventListener('fetch', async evt => {
79
+ // URL schemes that might arrive here but not supported; e.g.: chrome-extension://
80
+ if (!evt.request.url.startsWith('http')) return;
81
+ const requestInit = [
82
+ 'method', 'headers', 'body', 'mode', 'credentials', 'cache', 'redirect', 'referrer', 'integrity',
83
+ ].reduce((init, prop) => ({ [prop]: evt.request[prop], ...init }), {});
84
+ evt.respondWith(this.go(evt.request.url, requestInit, { event: evt }));
85
+ });
86
+
87
+ // ---------------
88
+ Observer.set(this, 'location', {});
89
+ Observer.set(this, 'network', {});
90
+ // ---------------
91
+ }
92
+
93
+ /**
94
+ * Performs a request.
95
+ *
96
+ * @param object|string url
97
+ * @param object init
98
+ * @param object detail
99
+ *
100
+ * @return Response
101
+ */
102
+ async go(url, init = {}, detail = {}) {
103
+ // ------------
104
+ url = typeof url === 'string' ? new URL(url) : url;
105
+ init = { referrer: this.location.href, ...init };
106
+ // ------------
107
+ // The request object
108
+ let request = this.generateRequest(url.href, init);
109
+ // The navigation event
110
+ let httpEvent = new HttpEvent(request, detail, (id = null, persistent = false) => this.getSession(httpEvent, id, persistent));
111
+ httpEvent.port.listen(message => {
112
+ if (message.$type === 'handler:hints' && message.session) {
113
+ // TODO: Sync sesseion data from client
114
+ return Promise.resolve();
115
+ }
116
+ });
117
+ // Response
118
+ let response;
119
+ if (httpEvent.request.url.startsWith(self.origin)/* && httpEvent.request.mode === 'navigate'*/) {
120
+ response = await this.clients.get('*').handle(httpEvent, (...args) => this.remoteFetch(...args));
121
+ } else {
122
+ response = await this.remoteFetch(httpEvent.request);
123
+ }
124
+ let finalResponse = this.handleResponse(httpEvent, response);
125
+ // Return value
126
+ return finalResponse;
127
+ }
128
+
129
+ // Generates request object
130
+ generateRequest(href, init) {
131
+ // Now, the following is key:
132
+ // The browser likes to use "force-cache" for "navigate" requests
133
+ // when, for example, the back button was used.
134
+ // Thus the origin server would still not be contacted by the self.fetch() below, leading to inconsistencies in responses.
135
+ // So, we detect this scenerio and avoid it.
136
+ if (init.mode === 'navigate' && init.cache === 'force-cache') {
137
+ init = { ...init, cache: 'default' };
138
+ }
139
+ let request = new Request(href, init);
140
+ return request;
141
+ }
142
+
143
+ // Generates session object
144
+ getSession(e, id = null, persistent = false) {
145
+ return {
146
+ get: () => this.mockSessionStore,
147
+ set: value => { this.mockSessionStore = value },
148
+ };
149
+ }
150
+
151
+ // Initiates remote fetch and sets the status
152
+ remoteFetch(request) {
153
+ const execFetch = () => {
154
+ if (_any((this.cx.params.cache_only_urls || []).map(c => c.trim()).filter(c => c), pattern => Minimatch.Minimatch(request.url, pattern))) {
155
+ Observer.set(this.network, 'strategy', 'cache-only');
156
+ return this.cacheFetch(request, { networkFallback: false, cacheRefresh: false });
157
+ }
158
+ // network_only_urls
159
+ if (_any((this.cx.params.network_only_urls || []).map(c => c.trim()).filter(c => c), pattern => Minimatch.Minimatch(request.url, pattern))) {
160
+ Observer.set(this.network, 'strategy', 'network-only');
161
+ return this.networkFetch(request, { cacheFallback: false, cacheRefresh: false });
162
+ }
163
+ // cache_first_urls
164
+ if (_any((this.cx.params.cache_first_urls || []).map(c => c.trim()).filter(c => c), pattern => Minimatch.Minimatch(request.url, pattern))) {
165
+ Observer.set(this.network, 'strategy', 'cache-first');
166
+ return this.cacheFetch(request, { networkFallback: true, cacheRefresh: true });
167
+ }
168
+ Observer.set(this.network, 'strategy', 'network-first');
169
+ return this.networkFetch(request, { cacheFallback: true, cacheRefresh: true });
170
+ };
171
+ let response = execFetch(request);
172
+ // This catch() is NOT intended to handle failure of the fetch
173
+ response.catch(e => Observer.set(this.network, 'error', e.message));
174
+ // Return xResponse
175
+ return response.then(_response => new Response(_response));
176
+ }
177
+
178
+ // Caching strategy: cache_first
179
+ cacheFetch(request, params = {}) {
180
+ return this.getRequestCache(request).then(cache => cache.match(request).then(response => {
181
+ // Nothing cache, use network
182
+ if (!response && params.networkFallback) return this.networkFetch(request, { ...params, cacheFallback: false });
183
+ // Note: fetch, but for refreshing purposes only... not the returned response
184
+ if (response && params.cacheRefresh) this.networkFetch(request, { ...params, justRefreshing: true });
185
+ Observer.set(this.network, 'cache', true);
186
+ return response;
187
+ }));
188
+ }
189
+
190
+ // Caching strategy: network_first
191
+ networkFetch(request, params = {}) {
192
+ if (params.forceNetwork) {
193
+ let url = new URL(request.url);
194
+ url.searchParams.set('$force-cache', '1');
195
+ request.attr.url = url.toString();
196
+ }
197
+ if (!params.cacheFallback) {
198
+ Observer.set(this.network, 'remote', true);
199
+ return self.fetch(request);
200
+ }
201
+ return self.fetch(request).then(response => {
202
+ if (params.cacheRefresh) this.refreshCache(request, response);
203
+ Observer.set(this.network, 'remote', true);
204
+ return response;
205
+ }).catch(() => this.getRequestCache(request).then(cache => {
206
+ Observer.set(this.network, 'cache', true);
207
+ return cache.match(request);
208
+ }));
209
+ }
210
+
211
+ // Caches response
212
+ refreshCache(request, response) {
213
+ // Check if we received a valid response
214
+ if (request.method !== 'GET' || !response || response.status !== 200 || (response.type !== 'basic' && response.type !== 'cors')) {
215
+ return response;
216
+ }
217
+ // IMPORTANT: Clone the response. A response is a stream
218
+ // and because we want the browser to consume the response
219
+ // as well as the cache consuming the response, we need
220
+ // to clone it so we have two streams.
221
+ var responseToCache = response.clone();
222
+ this.getRequestCache(request).then(cache => {
223
+ Observer.set(this.network, 'cacheRefresh', true);
224
+ cache.put(request, responseToCache);
225
+ });
226
+ return response;
227
+ }
228
+
229
+ // Returns either the regular cache or a json-specific cache
230
+ getRequestCache(request) {
231
+ let cacheName = request.headers.get('Accept') === 'application/json'
232
+ ? this.cx.params.cache_name + '_json'
233
+ : this.cx.params.cache_name;
234
+ return self.caches.open(cacheName);
235
+ }
236
+
237
+ // Handles response object
238
+ handleResponse(e, response) {
239
+ if (!(response instanceof Response)) { response = new Response(response); }
240
+ return response;
241
+ }
242
+
243
+ }
@@ -0,0 +1,46 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import Router from '../Router.js';
6
+
7
+ export default class WorkerClient {
8
+
9
+ /**
10
+ * WorkerClient
11
+ *
12
+ * @param Context cx
13
+ */
14
+ constructor(cx) {
15
+ this.cx = cx;
16
+ }
17
+
18
+ /**
19
+ * Handles HTTP events.
20
+ *
21
+ * @param HttpEvent httpEvent
22
+ * @param Function remoteFetch
23
+ *
24
+ * @return Response
25
+ */
26
+ async handle(httpEvent, remoteFetch) {
27
+ // The app router
28
+ const router = new Router(this.cx, httpEvent.url.pathname);
29
+ const handle = async () => {
30
+ // --------
31
+ // ROUTE FOR DATA
32
+ // --------
33
+ let httpMethodName = httpEvent.request.method.toLowerCase();
34
+ let response = await router.route([httpMethodName === 'delete' ? 'del' : httpMethodName, 'default'], httpEvent, {}, async event => {
35
+ return remoteFetch(event.request);
36
+ }, remoteFetch);
37
+ if (!(response instanceof httpEvent.Response)) {
38
+ response = new httpEvent.Response(response);
39
+ }
40
+ return response;
41
+ };
42
+ return handle();
43
+ }
44
+
45
+ }
46
+
@@ -0,0 +1,18 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import Context from './Context.js';
6
+ import WorkerClient from './WorkerClient.js';
7
+ import Worker from './Worker.js';
8
+
9
+ /**
10
+ * @start
11
+ */
12
+ export async function start(clientCallback = null) {
13
+ const cx = this || {};
14
+ const defaultClientCallback = _cx => new WorkerClient(_cx);
15
+ return new Worker(Context.create(cx), ( ...args ) => {
16
+ return clientCallback ? clientCallback( ...args.concat( defaultClientCallback ) ) : defaultClientCallback( ...args );
17
+ });
18
+ }
@@ -0,0 +1,14 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import * as server from './server/index.js';
6
+ import * as client from './client/generate.js';
7
+
8
+ /**
9
+ * @exports
10
+ */
11
+ export {
12
+ server,
13
+ client,
14
+ }
@@ -0,0 +1,16 @@
1
+
2
+ /**
3
+ * @imports
4
+ */
5
+ import _Contex from '../../Context.js';
6
+
7
+ export default class Context extends _Contex {
8
+ // env
9
+ get env() {
10
+ return this.dict.env || {};
11
+ }
12
+
13
+ set env(value) {
14
+ this.dict.env = value;
15
+ }
16
+ }
@@ -23,8 +23,8 @@ export default class Router extends _Router {
23
23
  if (_segmentOnFile.index) return _segmentOnFile;
24
24
  var _currentPath = thisTick.trailOnFile.concat(_seg).join('/'),
25
25
  routeHandlerFile;
26
- return Fs.existsSync(routeHandlerFile = Path.join(this.layout.ROOT, this.layout.SERVER_DIR, _currentPath, 'index.js')) ? { seg: _seg, index: routeHandlerFile } : (
27
- Fs.existsSync(Path.join(this.layout.ROOT, this.layout.SERVER_DIR, _currentPath)) ? { seg: _seg, dirExists: true } : _segmentOnFile
26
+ return Fs.existsSync(routeHandlerFile = Path.join(this.cx.CWD, this.cx.layout.SERVER_DIR, _currentPath, 'index.js')) ? { seg: _seg, index: routeHandlerFile } : (
27
+ Fs.existsSync(Path.join(this.cx.CWD, this.cx.layout.SERVER_DIR, _currentPath)) ? { seg: _seg, dirExists: true } : _segmentOnFile
28
28
  );
29
29
  }, { seg: null });
30
30
  thisTick.trail.push(thisTick.currentSegment);
@@ -33,7 +33,7 @@ export default class Router extends _Router {
33
33
  } else {
34
34
  thisTick.trail = [];
35
35
  thisTick.trailOnFile = [];
36
- thisTick.currentSegmentOnFile = { index: Path.join(this.layout.ROOT, this.layout.SERVER_DIR, 'index.js') };
36
+ thisTick.currentSegmentOnFile = { index: Path.join(this.cx.CWD, this.cx.layout.SERVER_DIR, 'index.js') };
37
37
  thisTick.exports = Fs.existsSync(thisTick.currentSegmentOnFile.index)
38
38
  ? await import(Url.pathToFileURL(thisTick.currentSegmentOnFile.index))
39
39
  : null;
@@ -58,9 +58,9 @@ export default class Router extends _Router {
58
58
  *
59
59
  * @return Promise
60
60
  */
61
- fetch(event) {
61
+ file(event) {
62
62
  var filename = event.url.pathname;
63
- var _filename = Path.join(this.layout.ROOT, this.layout.PUBLIC_DIR, decodeURIComponent(filename));
63
+ var _filename = Path.join(this.cx.CWD, this.cx.layout.PUBLIC_DIR, decodeURIComponent(filename));
64
64
  var autoIndex;
65
65
  if (Fs.existsSync(_filename)) {
66
66
  // based on the URL path, extract the file extention. e.g. .js, .doc, ...
@@ -115,7 +115,7 @@ export default class Router extends _Router {
115
115
  * @return bool
116
116
  */
117
117
  putPreRendered(filename, content) {
118
- var _filename = Path.join(this.layout.PUBLIC_DIR, '.', filename);
118
+ var _filename = Path.join(this.cx.layout.PUBLIC_DIR, '.', filename);
119
119
  if (!Path.parse(filename).ext && filename.lastIndexOf('.') < filename.lastIndexOf('/')) {
120
120
  _filename = Path.join(_filename, '/index.html');
121
121
  }