@webqit/webflo 0.11.61-0 → 0.20.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 (274) hide show
  1. package/.github/FUNDING.yml +12 -0
  2. package/.github/workflows/publish.yml +48 -0
  3. package/.gitignore +9 -7
  4. package/LICENSE +21 -21
  5. package/README.md +100 -2074
  6. package/docker/Dockerfile +42 -42
  7. package/docker/README.md +91 -91
  8. package/docker/package.json +2 -2
  9. package/package.json +95 -81
  10. package/site/-/_.md +139 -0
  11. package/site/-/docs.old.md +2010 -0
  12. package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +93 -0
  13. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  14. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +7 -0
  15. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  16. package/site/.vitepress/cache/deps/_metadata 2.json +85 -0
  17. package/site/.vitepress/cache/deps/_metadata.json +85 -0
  18. package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +9 -0
  19. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  20. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +7 -0
  21. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  22. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +9719 -0
  23. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js +9719 -0
  24. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +7 -0
  25. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js.map +7 -0
  26. package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +12705 -0
  27. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js +12705 -0
  28. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +7 -0
  29. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js.map +7 -0
  30. package/site/.vitepress/cache/deps/cytoscape 2.js +30278 -0
  31. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +4710 -0
  32. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  33. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +7 -0
  34. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  35. package/site/.vitepress/cache/deps/cytoscape.js +30278 -0
  36. package/site/.vitepress/cache/deps/cytoscape.js 2.map +7 -0
  37. package/site/.vitepress/cache/deps/cytoscape.js.map +7 -0
  38. package/site/.vitepress/cache/deps/dayjs 2.js +285 -0
  39. package/site/.vitepress/cache/deps/dayjs.js +285 -0
  40. package/site/.vitepress/cache/deps/dayjs.js 2.map +7 -0
  41. package/site/.vitepress/cache/deps/dayjs.js.map +7 -0
  42. package/site/.vitepress/cache/deps/debug 2.js +453 -0
  43. package/site/.vitepress/cache/deps/debug.js +453 -0
  44. package/site/.vitepress/cache/deps/debug.js 2.map +7 -0
  45. package/site/.vitepress/cache/deps/debug.js.map +7 -0
  46. package/site/.vitepress/cache/deps/package 2.json +3 -0
  47. package/site/.vitepress/cache/deps/package.json +3 -0
  48. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +4507 -0
  49. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  50. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +7 -0
  51. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  52. package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +584 -0
  53. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  54. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +7 -0
  55. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  56. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +1166 -0
  57. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1166 -0
  58. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +7 -0
  59. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  60. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +1667 -0
  61. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  62. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +7 -0
  63. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  64. package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +1815 -0
  65. package/site/.vitepress/cache/deps/vitepress___minisearch.js +1815 -0
  66. package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +7 -0
  67. package/site/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  68. package/site/.vitepress/cache/deps/vue 2.js +344 -0
  69. package/site/.vitepress/cache/deps/vue.js +344 -0
  70. package/site/.vitepress/cache/deps/vue.js 2.map +7 -0
  71. package/site/.vitepress/cache/deps/vue.js.map +7 -0
  72. package/site/.vitepress/config.ts +147 -0
  73. package/site/.vitepress/theme/custom.css +50 -0
  74. package/site/.vitepress/theme/index.ts +6 -0
  75. package/site/api/webflo-fetch/FormData.md +0 -0
  76. package/site/api/webflo-fetch/Headers.md +0 -0
  77. package/site/api/webflo-fetch/LiveResponse.md +0 -0
  78. package/site/api/webflo-fetch/Request.md +0 -0
  79. package/site/api/webflo-fetch/Response.md +0 -0
  80. package/site/api/webflo-fetch/fetch.md +0 -0
  81. package/site/api/webflo-routing/HttpCookies.md +0 -0
  82. package/site/api/webflo-routing/HttpEvent/respondWith.md +1 -0
  83. package/site/api/webflo-routing/HttpEvent/waitUntil.md +1 -0
  84. package/site/api/webflo-routing/HttpEvent/waitUntilNavigate.md +1 -0
  85. package/site/api/webflo-routing/HttpEvent.md +30 -0
  86. package/site/api/webflo-routing/HttpSession.md +0 -0
  87. package/site/api/webflo-routing/HttpState.md +0 -0
  88. package/site/api/webflo-routing/HttpUser.md +0 -0
  89. package/site/api/webflo-routing/handler/fetch.md +42 -0
  90. package/site/api/webflo-routing/handler/next.md +54 -0
  91. package/site/api/webflo-routing/handler.md +119 -0
  92. package/site/api.md +26 -0
  93. package/site/contributing.md +16 -0
  94. package/site/docs/advanced/lifecycles.md +20 -0
  95. package/site/docs/advanced/redirects.md +0 -0
  96. package/site/docs/advanced/routing.md +1 -0
  97. package/site/docs/advanced.md +9 -0
  98. package/site/docs/concepts/realtime.md +637 -0
  99. package/site/docs/concepts/rendering.md +60 -0
  100. package/site/docs/concepts/request-response.md +47 -0
  101. package/site/docs/concepts/routing.md +656 -0
  102. package/site/docs/concepts/state.md +44 -0
  103. package/site/docs/concepts/templates.md +48 -0
  104. package/site/docs/concepts.md +97 -0
  105. package/site/docs/getting-started.md +378 -0
  106. package/site/docs/tech-stack.md +56 -0
  107. package/site/docs.md +100 -0
  108. package/site/examples/pwa.md +10 -0
  109. package/site/examples/web.md +11 -0
  110. package/site/examples.md +10 -0
  111. package/site/faq.md +13 -0
  112. package/site/guides/guide-auth.md +13 -0
  113. package/site/guides/guide-file-upload.md +11 -0
  114. package/site/guides/guide-service-worker.md +10 -0
  115. package/site/guides/tutorial-1-todo.md +24 -0
  116. package/site/guides.md +15 -0
  117. package/site/index.md +39 -0
  118. package/site/public/img/brand/logo-670x670.png +0 -0
  119. package/site/recipes/realtime.md +11 -0
  120. package/site/recipes/streaming.md +15 -0
  121. package/site/reference/cli.md +11 -0
  122. package/site/reference/config.md +13 -0
  123. package/site/reference/tools.md +9 -0
  124. package/src/Context.js +71 -79
  125. package/src/config-pi/deployment/Env.js +55 -68
  126. package/src/config-pi/deployment/Layout.js +71 -63
  127. package/src/config-pi/deployment/Origins.js +139 -139
  128. package/src/config-pi/deployment/Proxy.js +74 -74
  129. package/src/config-pi/deployment/index.js +17 -17
  130. package/src/config-pi/index.js +15 -15
  131. package/src/config-pi/runtime/Client.js +108 -98
  132. package/src/config-pi/runtime/Server.js +157 -125
  133. package/src/config-pi/runtime/client/Worker.js +111 -134
  134. package/src/config-pi/runtime/client/index.js +11 -11
  135. package/src/config-pi/runtime/index.js +17 -17
  136. package/src/config-pi/runtime/server/Headers.js +74 -74
  137. package/src/config-pi/runtime/server/Redirects.js +69 -69
  138. package/src/config-pi/runtime/server/index.js +13 -13
  139. package/src/config-pi/static/Init.js +57 -0
  140. package/src/config-pi/static/Manifest.js +319 -319
  141. package/src/config-pi/static/Ssg.js +49 -49
  142. package/src/config-pi/static/index.js +15 -13
  143. package/src/deployment-pi/index.js +10 -10
  144. package/src/deployment-pi/origins/index.js +216 -216
  145. package/src/deployment-pi/util.js +161 -0
  146. package/src/index.js +13 -19
  147. package/src/init-pi/index.js +117 -0
  148. package/src/init-pi/templates/pwa/app/handler.server.js +8 -0
  149. package/src/init-pi/templates/pwa/app/page.html +7 -0
  150. package/src/init-pi/templates/pwa/package.json +19 -0
  151. package/src/init-pi/templates/pwa/public/assets/app.css +16 -0
  152. package/src/init-pi/templates/pwa/public/index.html +39 -0
  153. package/src/init-pi/templates/pwa/public/manifest.json +29 -0
  154. package/src/init-pi/templates/web/app/handler.server.js +8 -0
  155. package/src/init-pi/templates/web/app/page.html +7 -0
  156. package/src/init-pi/templates/web/package.json +19 -0
  157. package/src/init-pi/templates/web/public/assets/app.css +16 -0
  158. package/src/init-pi/templates/web/public/index.html +39 -0
  159. package/src/runtime-pi/WebfloRuntime.js +350 -0
  160. package/src/runtime-pi/index.js +6 -13
  161. package/src/runtime-pi/webflo-client/ClientSideCookies.js +17 -0
  162. package/src/runtime-pi/webflo-client/ClientSideWorkport.js +63 -0
  163. package/src/runtime-pi/webflo-client/DeviceCapabilities.js +213 -0
  164. package/src/runtime-pi/webflo-client/WebfloClient.js +500 -0
  165. package/src/runtime-pi/webflo-client/WebfloRootClient1.js +206 -0
  166. package/src/runtime-pi/webflo-client/WebfloRootClient2.js +113 -0
  167. package/src/runtime-pi/webflo-client/WebfloSubClient.js +118 -0
  168. package/src/runtime-pi/webflo-client/index.js +17 -0
  169. package/src/runtime-pi/webflo-client/webflo-codegen.js +469 -0
  170. package/src/runtime-pi/webflo-client/webflo-devmode.js +243 -0
  171. package/src/runtime-pi/webflo-client/webflo-embedded.js +50 -0
  172. package/src/runtime-pi/webflo-fetch/LiveResponse.js +437 -0
  173. package/src/runtime-pi/webflo-fetch/cookies.js +10 -0
  174. package/src/runtime-pi/webflo-fetch/fetch.js +16 -0
  175. package/src/runtime-pi/webflo-fetch/formdata.js +54 -0
  176. package/src/runtime-pi/webflo-fetch/headers.js +151 -0
  177. package/src/runtime-pi/webflo-fetch/index.js +5 -0
  178. package/src/runtime-pi/webflo-fetch/message.js +49 -0
  179. package/src/runtime-pi/webflo-fetch/request.js +62 -0
  180. package/src/runtime-pi/webflo-fetch/response.js +110 -0
  181. package/src/runtime-pi/webflo-fetch/util.js +28 -0
  182. package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +10 -0
  183. package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +26 -0
  184. package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +87 -0
  185. package/src/runtime-pi/webflo-messaging/WQMessagePort.js +38 -0
  186. package/src/runtime-pi/webflo-messaging/WQRelayPort.js +47 -0
  187. package/src/runtime-pi/webflo-messaging/WQSockPort.js +113 -0
  188. package/src/runtime-pi/webflo-messaging/WQStarPort.js +104 -0
  189. package/src/runtime-pi/webflo-messaging/wq-message-port.js +404 -0
  190. package/src/runtime-pi/webflo-routing/HttpCookies.js +42 -0
  191. package/src/runtime-pi/webflo-routing/HttpEvent.js +112 -0
  192. package/src/runtime-pi/webflo-routing/HttpSession.js +11 -0
  193. package/src/runtime-pi/webflo-routing/HttpState.js +153 -0
  194. package/src/runtime-pi/webflo-routing/HttpUser.js +54 -0
  195. package/src/runtime-pi/webflo-routing/WebfloRouter.js +245 -0
  196. package/src/runtime-pi/webflo-server/ServerSideCookies.js +19 -0
  197. package/src/runtime-pi/webflo-server/ServerSideSession.js +38 -0
  198. package/src/runtime-pi/webflo-server/WebfloServer.js +937 -0
  199. package/src/runtime-pi/webflo-server/index.js +11 -0
  200. package/src/runtime-pi/webflo-server/messaging/Client.js +27 -0
  201. package/src/runtime-pi/webflo-server/messaging/ClientRequestRealtime.js +50 -0
  202. package/src/runtime-pi/webflo-server/messaging/Clients.js +25 -0
  203. package/src/runtime-pi/webflo-server/webflo-devmode.js +326 -0
  204. package/src/runtime-pi/{client → webflo-url}/Url.js +155 -205
  205. package/src/runtime-pi/webflo-url/index.js +1 -0
  206. package/src/runtime-pi/webflo-url/urlpattern.js +38 -0
  207. package/src/runtime-pi/{util-url.js → webflo-url/util.js} +109 -147
  208. package/src/runtime-pi/webflo-url/xURL.js +94 -0
  209. package/src/runtime-pi/webflo-worker/WebfloWorker.js +234 -0
  210. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +19 -0
  211. package/src/runtime-pi/webflo-worker/WorkerSideWorkport.js +18 -0
  212. package/src/runtime-pi/webflo-worker/index.js +11 -0
  213. package/src/services-pi/cert/http-auth-hook.js +22 -22
  214. package/src/services-pi/cert/http-cleanup-hook.js +22 -22
  215. package/src/services-pi/cert/index.js +79 -79
  216. package/src/services-pi/index.js +10 -8
  217. package/src/services-pi/push/index.js +23 -0
  218. package/src/util.js +10 -0
  219. package/src/{webflo.js → webflo-cli.js} +30 -30
  220. package/test/index.test.js +26 -26
  221. package/test/site/package.json +9 -9
  222. package/test/site/public/bundle.html +5 -5
  223. package/test/site/public/bundle.html.json +3 -3
  224. package/test/site/public/bundle.js +2 -2
  225. package/test/site/public/bundle.webflo.js +15 -15
  226. package/test/site/public/index.html +29 -29
  227. package/test/site/public/index1.html +34 -34
  228. package/test/site/public/page-2/bundle.html +4 -4
  229. package/test/site/public/page-2/bundle.js +2 -2
  230. package/test/site/public/page-2/index.html +45 -45
  231. package/test/site/public/page-2/main.html +2 -2
  232. package/test/site/public/page-4/subpage/bundle.js +2 -2
  233. package/test/site/public/page-4/subpage/index.html +30 -30
  234. package/test/site/public/sparoots.json +4 -4
  235. package/test/site/public/worker.js +3 -3
  236. package/test/site/server/index.js +15 -15
  237. package/src/runtime-pi/Application.js +0 -29
  238. package/src/runtime-pi/Cookies.js +0 -82
  239. package/src/runtime-pi/HttpEvent.js +0 -107
  240. package/src/runtime-pi/Router.js +0 -130
  241. package/src/runtime-pi/Runtime.js +0 -21
  242. package/src/runtime-pi/client/Application.js +0 -100
  243. package/src/runtime-pi/client/Context.js +0 -7
  244. package/src/runtime-pi/client/Router.js +0 -48
  245. package/src/runtime-pi/client/Runtime.js +0 -332
  246. package/src/runtime-pi/client/Workport.js +0 -178
  247. package/src/runtime-pi/client/createStorage.js +0 -57
  248. package/src/runtime-pi/client/generate.js +0 -472
  249. package/src/runtime-pi/client/index.js +0 -21
  250. package/src/runtime-pi/client/oohtml/full.js +0 -7
  251. package/src/runtime-pi/client/oohtml/namespacing.js +0 -7
  252. package/src/runtime-pi/client/oohtml/scripting.js +0 -8
  253. package/src/runtime-pi/client/oohtml/templating.js +0 -8
  254. package/src/runtime-pi/client/worker/Application.js +0 -44
  255. package/src/runtime-pi/client/worker/Context.js +0 -7
  256. package/src/runtime-pi/client/worker/Runtime.js +0 -269
  257. package/src/runtime-pi/client/worker/Workport.js +0 -86
  258. package/src/runtime-pi/client/worker/index.js +0 -21
  259. package/src/runtime-pi/server/Application.js +0 -116
  260. package/src/runtime-pi/server/Context.js +0 -16
  261. package/src/runtime-pi/server/Router.js +0 -159
  262. package/src/runtime-pi/server/Runtime.js +0 -557
  263. package/src/runtime-pi/server/index.js +0 -21
  264. package/src/runtime-pi/util-http.js +0 -86
  265. package/src/runtime-pi/xFormData.js +0 -24
  266. package/src/runtime-pi/xHeaders.js +0 -146
  267. package/src/runtime-pi/xRequest.js +0 -46
  268. package/src/runtime-pi/xRequestHeaders.js +0 -109
  269. package/src/runtime-pi/xResponse.js +0 -33
  270. package/src/runtime-pi/xResponseHeaders.js +0 -117
  271. package/src/runtime-pi/xURL.js +0 -105
  272. package/src/runtime-pi/xfetch.js +0 -23
  273. package/src/runtime-pi/xxHttpMessage.js +0 -102
  274. package/src/static-pi/index.js +0 -11
@@ -1,557 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import Fs from 'fs';
6
- import Path from 'path';
7
- import Http from 'http';
8
- import Https from 'https';
9
- import Sessions from 'client-sessions';
10
- import { Observer } from '@webqit/oohtml-ssr/apis.js';
11
- import { _each } from '@webqit/util/obj/index.js';
12
- import { _isEmpty } from '@webqit/util/js/index.js';
13
- import { _from as _arrFrom, _any } from '@webqit/util/arr/index.js';
14
- import { slice as _streamSlice } from 'stream-slice';
15
- import { Readable as _ReadableStream } from 'stream';
16
- import { pattern } from '../util-url.js';
17
- import xRequest from "../xRequest.js";
18
- import xResponse from "../xResponse.js";
19
- import xfetch from '../xfetch.js';
20
- import HttpEvent from '../HttpEvent.js';
21
- import _Runtime from '../Runtime.js';
22
-
23
- export {
24
- //fetch,
25
- HttpEvent,
26
- Observer,
27
- }
28
-
29
- export default class Runtime extends _Runtime {
30
-
31
- /**
32
- * Runtime
33
- *
34
- * @param Object cx
35
- * @param Function applicationInstance
36
- *
37
- * @return void
38
- */
39
- constructor(cx, applicationInstance) {
40
- super(cx, applicationInstance);
41
- // ---------------
42
- this.ready = (async () => {
43
- // ---------------
44
- const resolveContextObj = async (cx, force = false) => {
45
- if (_isEmpty(cx.layout) || force) { cx.layout = await (new cx.config.deployment.Layout(cx)).read(); }
46
- if (_isEmpty(cx.server) || force) { cx.server = await (new cx.config.runtime.Server(cx)).read(); }
47
- if (_isEmpty(cx.env) || force) { cx.env = await (new cx.config.deployment.Env(cx)).read(); }
48
- };
49
- await resolveContextObj(this.cx);
50
- if (this.cx.env.autoload !== false) {
51
- Object.keys(this.cx.env.entries).forEach(key => {
52
- if (!(key in process.env)) {
53
- process.env[key] = this.cx.env.entries[key];
54
- }
55
- });
56
- }
57
- // ---------------
58
- const parseDomains = domains => _arrFrom(domains).reduce((arr, str) => arr.concat(str.split(',')), []).map(str => str.trim()).filter(str => str);
59
- const selectDomains = (serverDefs, matchingPort = null) => serverDefs.reduce((doms, def) => doms.length ? doms : (((!matchingPort || def.port === matchingPort) && parseDomains(def.domains || def.hostnames)) || []), []);
60
- // ---------------
61
- this.proxied = new Map;
62
- if (this.cx.config.deployment.Proxy) {
63
- const proxied = await (new this.cx.config.deployment.Proxy(this.cx)).read();
64
- await Promise.all((proxied.entries || []).map(async vhost => {
65
- let cx, hostnames = parseDomains(vhost.hostnames), port = vhost.port, proto = vhost.proto;
66
- if (vhost.path) {
67
- cx = this.cx.constructor.create(this.cx, Path.join(this.cx.CWD, vhost.path));
68
- await resolveContextObj(cx, true);
69
- cx.dict.key = true;
70
- // From the server that's most likely to be active
71
- port || (port = cx.server.https.port || cx.server.port);
72
- // The domain list that corresponds to the specified resolved port
73
- hostnames.length || (hostnames = selectDomains([cx.server.https, cx.server], port));
74
- // Or anyone available... hoping that the remote configs can eventually be in sync
75
- hostnames.length || (hostnames = selectDomains([cx.server.https, cx.server]));
76
- // The corresponding proto
77
- proto || (proto = port === cx.server.https.port ? 'https' : 'http');
78
- }
79
- hostnames.length || (hostnames = ['*']);
80
- this.proxied.set(hostnames.sort().join('|'), { cx, hostnames, port, proto });
81
- }));
82
- }
83
- // ---------------
84
- this.servers = new Map;
85
- // ---------------
86
- if (!this.cx.flags['test-only'] && !this.cx.flags['https-only'] && this.cx.server.port) {
87
- const httpServer = Http.createServer((request, response) => handleRequest('http', request, response));
88
- httpServer.listen(this.cx.server.port);
89
- // -------
90
- let domains = parseDomains(this.cx.server.domains);
91
- if (!domains.length) { domains = ['*']; }
92
- this.servers.set('http', {
93
- instance: httpServer,
94
- port: this.cx.server.port,
95
- domains,
96
- });
97
- }
98
- // ---------------
99
- if (!this.cx.flags['test-only'] && !this.cx.flags['http-only'] && this.cx.server.https.port) {
100
- const httpsServer = Https.createServer((request, response) => handleRequest('https', request, response));
101
- httpsServer.listen(this.cx.server.https.port);
102
- // -------
103
- const addSSLContext = (serverConfig, domains) => {
104
- if (!Fs.existsSync(serverConfig.https.keyfile)) return;
105
- const cert = {
106
- key: Fs.readFileSync(serverConfig.https.keyfile),
107
- cert: Fs.readFileSync(serverConfig.https.certfile),
108
- };
109
- domains.forEach(domain => { httpsServer.addContext(domain, cert); });
110
- }
111
- // -------
112
- let domains = parseDomains(this.cx.server.https.domains);
113
- if (!domains.length) { domains = ['*']; }
114
- this.servers.set('https', {
115
- instance: httpsServer,
116
- port: this.cx.server.https.port,
117
- domains,
118
- });
119
- // -------
120
- addSSLContext(this.cx.server, domains);
121
- for (const [ /*id*/, vhost ] of this.proxied) {
122
- vhost.cx && addSSLContext(vhost.cx.server, vhost.hostnames);
123
- }
124
- }
125
- // ---------------
126
- const handleRequest = async (proto, request, response) => {
127
- request[Symbol.toStringTag] = 'ReadableStream';
128
- const [ fullUrl, requestInit ] = await this.parseNodeRequest(proto, request);
129
- let clientResponse = await this.go(fullUrl, requestInit, { request, response });
130
- if (response.headersSent) return;
131
- // --------
132
- _each(clientResponse.headers.json(), (name, value) => {
133
- response.setHeader(name, value);
134
- });
135
- // --------
136
- response.statusCode = clientResponse.status;
137
- response.statusMessage = clientResponse.statusText;
138
- if (clientResponse.headers.location) {
139
- return response.end();
140
- }
141
- if ((clientResponse.body instanceof _ReadableStream)) {
142
- return clientResponse.body.pipe(response);
143
- }
144
- if ((clientResponse.body instanceof ReadableStream)) {
145
- return _ReadableStream.from(clientResponse.body).pipe(response);
146
- }
147
- let body = clientResponse.body;
148
- if (clientResponse.headers.contentType === 'application/json') {
149
- body += '';
150
- }
151
- return response.end(body);
152
- };
153
- })();
154
-
155
- // ---------------
156
- Observer.set(this, 'location', {});
157
- Observer.set(this, 'network', {});
158
- // ---------------
159
-
160
- // -------------
161
- // Initialize
162
- (async () => {
163
- await this.ready;
164
- if (this.cx.logger) {
165
- if (this.servers.size) {
166
- this.cx.logger.info(`> Server running! (${this.cx.app.title || ''})`);
167
- for (let [ proto, def ] of this.servers) {
168
- this.cx.logger.info(`> ${ proto.toUpperCase() } / ${ def.domains.concat('').join(`:${ def.port } / `)}`);
169
- }
170
- } else {
171
- this.cx.logger.info(`> Server not running! No port specified.`);
172
- }
173
- if (this.proxied.size) {
174
- this.cx.logger.info(`> Reverse proxy active.`);
175
- for (let [ id, def ] of this.proxied) {
176
- this.cx.logger.info(`> ${ id } >>> ${ def.port }`);
177
- }
178
- }
179
- this.cx.logger.info(``);
180
- }
181
- if (this.app && this.app.init) {
182
- const request = this.generateRequest('http://localhost/');
183
- const httpEvent = new HttpEvent(request, { srcType: 'initialization' }, (id = 'session', options = { duration: 60 * 60 * 24, activeDuration: 60 * 60 * 24 }, callback = null) => {
184
- return this.getSession(this.cx, httpEvent, id, options, callback);
185
- });
186
- await this.app.init(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
187
- }
188
- })();
189
- // ---------------
190
-
191
- // ---------------
192
- this.mockSessionStore = {};
193
- // ---------------
194
-
195
- }
196
-
197
- /**
198
- * Parse Nodejs's IncomingMessage to WHATWAG request params.
199
- *
200
- * @param String proto
201
- * @param Http.IncomingMessage request
202
- *
203
- * @return Array
204
- */
205
- async parseNodeRequest(proto, request) {
206
- // Detected when using manual proxy setting in a browser
207
- if (request.url.startsWith(`http://${ request.headers.host }`) || request.url.startsWith(`https://${ request.headers.host }`)) {
208
- request.url = request.url.split(request.headers.host)[1];
209
- }
210
- const fullUrl = proto + '://' + request.headers.host + request.url;
211
- const requestInit = { method: request.method, headers: request.headers };
212
- if (!['GET', 'HEAD'].includes(request.method)) {
213
- requestInit.body = request;
214
- }
215
- return [ fullUrl, requestInit ];
216
- }
217
-
218
- /**
219
- * Performs a request.
220
- *
221
- * @param object|string url
222
- * @param object|Request init
223
- * @param object detail
224
- *
225
- * @return Response
226
- */
227
- async go(url, init = {}, detail = {}) {
228
- await this.ready;
229
-
230
- // ------------
231
- url = typeof url === 'string' ? new URL(url) : url;
232
- if (!(init instanceof Request) && !init.referrer) {
233
- init = { referrer: this.location.href, ...init };
234
- }
235
- // ------------
236
- const hosts = [];
237
- this.servers.forEach(server => hosts.push(...server.domains));
238
- // ------------
239
- for (const [ /*id*/, vhost ] of this.proxied) {
240
- if (vhost.hostnames.includes(url.hostname) || (vhost.hostnames.includes('*') && !hosts.includes('*'))) {
241
- return this.proxyGo(vhost, url, init);
242
- }
243
- }
244
- // ------------
245
- let exit, exitMessage;
246
- if (!hosts.includes(url.hostname) && !hosts.includes('*')) {
247
- exit = { status: 500 }, exitMessage = 'Unrecognized host';
248
- } else if (url.protocol === 'http:' && this.cx.server.https.force) {
249
- exit = { status: 302, headers: { Location: ( url.protocol = 'https:', url.href ) } };
250
- } else if (url.hostname.startsWith('www.') && this.cx.server.force_www === 'remove') {
251
- exit = { status: 302, headers: { Location: ( url.hostname = url.hostname.substr(4), url.href ) } };
252
- } else if (!url.hostname.startsWith('www.') && this.cx.server.force_www === 'add') {
253
- exit = { status: 302, headers: { Location: ( url.hostname = `www.${ url.hostname }`, url.href ) } };
254
- } else if (this.cx.config.runtime.server.Redirects) {
255
- exit = ((await (new this.cx.config.runtime.server.Redirects(this.cx)).read()).entries || []).reduce((_rdr, entry) => {
256
- return _rdr || ((_rdr = pattern(entry.from, url.origin).exec(url.href)) && { status: entry.code || 302, headers: { Location: _rdr.render(entry.to) } });
257
- }, null);
258
- }
259
- if (exit) { return new xResponse(exitMessage, exit); }
260
- // ------------
261
-
262
- // ------------
263
- Observer.set(this.location, url, { detail: { init, ...detail, } });
264
- Observer.set(this.network, 'redirecting', null);
265
- // ------------
266
-
267
- // ------------
268
- // Automatically-added headers
269
- const autoHeaders = this.cx.config.runtime.server.Headers
270
- ? ((await (new this.cx.config.runtime.server.Headers(this.cx)).read()).entries || []).filter(entry => pattern(entry.url, url.origin).exec(url.href))
271
- : [];
272
- // The request object
273
- const request = this.generateRequest(url.href, init, autoHeaders.filter(header => header.type === 'request'));
274
- // The navigation event
275
- const httpEvent = new HttpEvent(request, detail, (id = 'session', options = { duration: 60 * 60 * 24, activeDuration: 60 * 60 * 24 }, callback = null) => {
276
- return this.getSession(this.cx, httpEvent, id, options, callback);
277
- });
278
- // Response
279
- let response, finalResponse;
280
- try {
281
- response = await this.app.handle(httpEvent, ( ...args ) => this.remoteFetch( ...args ));
282
- finalResponse = await this.handleResponse(this.cx, httpEvent, response, autoHeaders.filter(header => header.type === 'response'));
283
- } catch(e) {
284
- finalResponse = new xResponse(e.message, { status: 500 });
285
- console.error(e);
286
- }
287
- // Logging
288
- if (this.cx.logger) {
289
- const log = this.generateLog(httpEvent.request, finalResponse);
290
- this.cx.logger.log(log);
291
- }
292
- // ------------
293
- // Return value
294
- return finalResponse;
295
- }
296
-
297
- // Fetch from proxied host
298
- async proxyGo(vhost, url, init) {
299
- // ---------
300
- const url2 = new URL(url);
301
- url2.port = vhost.port;
302
- if (vhost.proto) { url2.protocol = vhost.proto; }
303
- // ---------
304
- let init2;
305
- if (init instanceof Request) {
306
- init2 = init.clone();
307
- init.headers.set('Host', url2.host);
308
- } else {
309
- init2 = { ...init, decompress: false/* honoured in xfetch() */ };
310
- if (!init2.headers) init2.headers = {};
311
- init2.headers.host = url2.host;
312
- delete init2.headers.connection;
313
- }
314
- // ---------
315
- let response;
316
- try {
317
- response = await this.remoteFetch(url2, init2);
318
- } catch(e) {
319
- response = new xResponse(`Reverse Proxy Error: ${e.message}`, { status: 500 });
320
- console.error(e);
321
- }
322
- if (this.cx.logger) {
323
- const log = this.generateLog({ url: url2.href, ...init2 }, response, true);
324
- this.cx.logger.log(log);
325
- }
326
- return response;
327
-
328
- }
329
-
330
-
331
- // Generates request object
332
- generateRequest(href, init = {}, autoHeaders = []) {
333
- const request = new xRequest(href, init);
334
- this._autoHeaders(request.headers, autoHeaders);
335
- return request;
336
- }
337
-
338
- // Generates session object
339
- getSession(cx, e, id, options = {}, callback = null) {
340
- let baseObject;
341
- if (!(e.detail.request && e.detail.response)) {
342
- baseObject = this.mockSessionStore;
343
- let cookieAvailability = e.request.headers.cookies.get(id); // We just want to know availability... not validity, as this is understood to be for testing purposes only
344
- if (!(this.mockSessionStore[id] && cookieAvailability)) {
345
- let cookieObj = {};
346
- Object.defineProperty(this.mockSessionStore, id, {
347
- get: () => cookieObj,
348
- set: value => (cookieObj = value),
349
- });
350
- }
351
- } else {
352
- Sessions({
353
- duration: 0, // how long the session will stay valid in ms
354
- activeDuration: 0, // if expiresIn < activeDuration, the session will be extended by activeDuration milliseconds
355
- ...options,
356
- cookieName: id, // cookie name dictates the key name added to the request object
357
- secret: cx.env.SESSION_KEY, // should be a large unguessable string
358
- })(e.detail.request, e.detail.response, e => {
359
- if (e) {
360
- if (!callback) throw e;
361
- callback(e);
362
- }
363
- });
364
- baseObject = e.detail.request;
365
- }
366
- // Where theres no error, instance is available
367
- let instance = Object.getOwnPropertyDescriptor(baseObject, id);
368
- if (!callback) return instance;
369
- if (instance) callback(null, instance);
370
- }
371
-
372
- // Initiates remote fetch and sets the status
373
- remoteFetch(request, ...args) {
374
- let href = request;
375
- if (request instanceof Request) {
376
- href = request.url;
377
- } else if (request instanceof URL) {
378
- href = request.href;
379
- }
380
- Observer.set(this.network, 'remote', href);
381
- const _response = xfetch(request, ...args);
382
- // This catch() is NOT intended to handle failure of the fetch
383
- _response.catch(e => Observer.set(this.network, 'error', e.message));
384
- // Save a reference to this
385
- return _response.then(async response => {
386
- // Stop loading status
387
- Observer.set(this.network, 'remote', false);
388
- return xResponse.compat(response);
389
- });
390
- }
391
-
392
- // Handles response object
393
- async handleResponse(cx, e, response, autoHeaders = []) {
394
- if (!(response instanceof xResponse)) { response = xResponse.compat(response); }
395
- Observer.set(this.network, 'remote', false);
396
- Observer.set(this.network, 'error', null);
397
-
398
- // ----------------
399
- // Mock-Cookies?
400
- if (!(e.detail.request && e.detail.response)) {
401
- for (let cookieName of Object.getOwnPropertyNames(this.mockSessionStore)) {
402
- response.headers.append('Set-Cookie', `${cookieName}=1`); // We just want to know availability... not validity, as this is understood to be for testing purposes only
403
- }
404
- }
405
-
406
- // ----------------
407
- // Auto-Headers
408
- response.headers.set('Accept-Ranges', 'bytes');
409
- this._autoHeaders(response.headers, autoHeaders);
410
-
411
- // ----------------
412
- // Redirects
413
- if (response.headers.location) {
414
- const xRedirectPolicy = e.request.headers.get('X-Redirect-Policy');
415
- const xRedirectCode = e.request.headers.get('X-Redirect-Code') || 300;
416
- const destinationUrl = new URL(response.headers.location, e.url.origin);
417
- const isSameOriginRedirect = destinationUrl.origin === e.url.origin;
418
- let isSameSpaRedirect, sparootsFile = Path.join(cx.CWD, cx.layout.PUBLIC_DIR, 'sparoots.json');
419
- if (isSameOriginRedirect && xRedirectPolicy === 'manual-when-cross-spa' && Fs.existsSync(sparootsFile)) {
420
- // Longest-first sorting
421
- const sparoots = _arrFrom(JSON.parse(Fs.readFileSync(sparootsFile))).sort((a, b) => a.length > b.length ? -1 : 1);
422
- const matchRoot = path => sparoots.reduce((prev, root) => prev || (`${path}/`.startsWith(`${root}/`) && root), null);
423
- isSameSpaRedirect = matchRoot(destinationUrl.pathname) === matchRoot(e.url.pathname);
424
- }
425
- if (xRedirectPolicy === 'manual' || (!isSameOriginRedirect && xRedirectPolicy === 'manual-when-cross-origin') || (!isSameSpaRedirect && xRedirectPolicy === 'manual-when-cross-spa')) {
426
- response.headers.json({
427
- 'X-Redirect-Code': response.status,
428
- 'Access-Control-Allow-Origin': '*',
429
- 'Cache-Control': 'no-store',
430
- });
431
- response.attrs.status = xRedirectCode;
432
- }
433
- return response;
434
- }
435
-
436
- // ----------------
437
- // 404
438
- if (!response.meta.body && response.meta.body !== 0) {
439
- if (response.status === 200 || response.status === 0) {
440
- response = new xResponse(response.body, { status: 404, headers: response.headers });
441
- }
442
- return response;
443
- }
444
-
445
- // ----------------
446
- // Not acceptable
447
- if (e.request.headers.get('Accept') && !e.request.headers.accept.match(response.headers.contentType)) {
448
- response = new xResponse(response.body, { status: 406, headers: response.headers });
449
- return response;
450
- }
451
-
452
- // ----------------
453
- // Important no-caching
454
- // for non-"get" requests
455
- if (e.request.method !== 'GET' && !response.headers.get('Cache-Control')) {
456
- response.headers.set('Cache-Control', 'no-store');
457
- }
458
-
459
- // ----------------
460
- // Body
461
- let rangeRequest, body = response.body;
462
- if ((rangeRequest = e.request.headers.range) && !response.headers.get('Content-Range')
463
- && ((body instanceof ReadableStream) || (ArrayBuffer.isView(body) && (body = _ReadableStream.from(body))))) {
464
- // ...in partials
465
- const totalLength = response.headers.contentLength || 0;
466
- const ranges = await rangeRequest.reduce(async (_ranges, range) => {
467
- _ranges = await _ranges;
468
- if (range[0] < 0 || (totalLength && range[0] > totalLength)
469
- || (range[1] > -1 && (range[1] <= range[0] || (totalLength && range[1] >= totalLength)))) {
470
- // The range is beyond upper/lower limits
471
- _ranges.error = true;
472
- }
473
- if (!totalLength && range[0] === undefined) {
474
- // totalLength is unknown and we cant read the trailing size specified in range[1]
475
- _ranges.error = true;
476
- }
477
- if (_ranges.error) return _ranges;
478
- if (totalLength) { range.clamp(totalLength); }
479
- const partLength = range[1] - range[0] + 1;
480
- _ranges.parts.push({
481
- body: body.pipe(_streamSlice(range[0], range[1] + 1)),
482
- range: range = `bytes ${range[0]}-${range[1]}/${totalLength || '*'}`,
483
- length: partLength,
484
- });
485
- _ranges.totalLength += partLength;
486
- return _ranges;
487
- }, { parts: [], totalLength: 0 });
488
- if (ranges.error) {
489
- response.attrs.status = 416;
490
- response.headers.json({
491
- 'Content-Range': `bytes */${totalLength || '*'}`,
492
- 'Content-Length': 0,
493
- });
494
- } else {
495
- // TODO: of ranges.parts is more than one, return multipart/byteranges
496
- response = new xResponse(ranges.parts[0].body, {
497
- status: 206,
498
- statusText: response.statusText,
499
- headers: response.headers,
500
- });
501
- response.headers.json({
502
- 'Content-Range': ranges.parts[0].range,
503
- 'Content-Length': ranges.totalLength,
504
- });
505
- }
506
- }
507
-
508
- return response;
509
- }
510
-
511
- // Generates log
512
- generateLog(request, response, isproxy = false) {
513
- let log = [];
514
- // ---------------
515
- const style = this.cx.logger.style || { keyword: str => str, comment: str => str, url: str => str, val: str => str, err: str => str, };
516
- const errorCode = [ 404, 500 ].includes(response.status) ? response.status : 0;
517
- const xRedirectCode = response.headers.get('X-Redirect-Code');
518
- const redirectCode = xRedirectCode || ((response.status + '').startsWith('3') ? response.status : 0);
519
- const statusCode = xRedirectCode || response.status;
520
- // ---------------
521
- log.push(`[${style.comment((new Date).toUTCString())}]`);
522
- log.push(style.keyword(request.method));
523
- if (isproxy) log.push(style.keyword('>>'));
524
- log.push(style.url(request.url));
525
- if (response.attrs.hint) log.push(`(${style.comment(response.attrs.hint)})`);
526
- const contentInfo = [response.headers.contentType, response.headers.contentLength].filter(x => x);
527
- if (contentInfo.length) log.push(`(${style.comment(contentInfo.join('; '))})`);
528
- if (response.headers.get('Content-Encoding')) log.push(`(${style.comment(response.headers.get('Content-Encoding'))})`);
529
- if (errorCode) log.push(style.err(`${errorCode} ${response.statusText}`));
530
- else log.push(style.val(`${statusCode} ${response.statusText}`));
531
- if (redirectCode) log.push(`- ${style.url(response.headers.location)}`);
532
-
533
- return log.join(' ');
534
- }
535
-
536
- // Applies auto headers
537
- _autoHeaders(headers, autoHeaders) {
538
- autoHeaders.forEach(header => {
539
- var headerName = header.name.toLowerCase(),
540
- headerValue = header.value,
541
- isAppend = headerName.startsWith('+') ? (headerName = headerName.substr(1), true) : false,
542
- isPrepend = headerName.endsWith('+') ? (headerName = headerName.substr(0, headerName.length - 1), true) : false;
543
- if (isAppend || isPrepend) {
544
- headerValue = [ headers.get(headerName) || '' , headerValue].filter(v => v);
545
- headerValue = isPrepend ? headerValue.reverse().join(',') : headerValue.join(',');
546
- }
547
- headers.set(headerName, headerValue);
548
- });
549
- }
550
-
551
- }
552
-
553
- const _streamRead = stream => new Promise(res => {
554
- let data = '';
555
- stream.on('data', chunk => data += chunk);
556
- stream.on('end', () => res(data));
557
- });
@@ -1,21 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import Context from './Context.js';
6
- import Application from './Application.js';
7
- import Runtime from './Runtime.js';
8
-
9
- /**
10
- * @start
11
- */
12
- export async function start(applicationInstance = null) {
13
- const cx = this || {};
14
- const defaultApplicationInstance = _cx => new Application(_cx);
15
- return new Runtime(Context.create(cx), applicationInstance || defaultApplicationInstance);
16
- }
17
-
18
- /**
19
- * @APIS
20
- */
21
- export * as APIS from './Runtime.js';
@@ -1,86 +0,0 @@
1
-
2
- /**
3
- * @imports
4
- */
5
- import { _isString, _isNumeric, _isObject, _isPlainObject, _isArray, _isPlainArray, _isTypeObject, _isNumber, _isBoolean } from '@webqit/util/js/index.js';
6
- import { _before } from '@webqit/util/str/index.js';
7
- import { params } from './util-url.js';
8
-
9
- export function formatMessage(message) {
10
- const headers = (message.headers instanceof Headers) ? [...message.headers.keys()].reduce((_headers, name) => {
11
- return { ..._headers, [name/* lower-cased */]: message.headers.get(name) };
12
- }, {}) : Object.keys(message.headers || {}).reduce((_headers, name) => {
13
- return { ..._headers, [name.toLowerCase()]: message.headers[name] };
14
- }, {});
15
- let body = message.body, type = dataType(message.body);
16
- if ([ 'Blob', 'File' ].includes(type)) {
17
- !headers['content-type'] && (headers['content-type'] = body.type);
18
- !headers['content-length'] && (headers['content-length'] = body.size);
19
- } else if ([ 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer' ].includes(type)) {
20
- !headers['content-length'] && (headers['content-length'] = body.byteLength);
21
- } else if (type === 'json' && _isTypeObject(body)) {
22
- if (!headers['content-type']) {
23
- const [ _body, isJsonfiable ] = formDatarizeJson(body);
24
- if (isJsonfiable) {
25
- body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
26
- headers['content-type'] = 'application/json';
27
- headers['content-length'] = (new Blob([ body ])).size;
28
- } else {
29
- body = _body;
30
- type = 'FormData';
31
- }
32
- }
33
- } else if (type === 'json') {
34
- !headers['content-length'] && (headers['content-length'] = (body + '').length);
35
- }
36
- return [ body, headers, type ];
37
- }
38
-
39
- export function formDatarizeJson(data = {}, jsonfy = true) {
40
- const formData = new FormData;
41
- let isJsonfiable = true;
42
- params.reduceValue(data, '', (value, contextPath, suggestedKeys = undefined) => {
43
- if (suggestedKeys) {
44
- const isJson = dataType(value) === 'json';
45
- isJsonfiable = isJsonfiable && isJson;
46
- return isJson && suggestedKeys;
47
- }
48
- if (jsonfy && [true, false, null].includes(value)) {
49
- value = new Blob([value], { type: 'application/json' });
50
- }
51
- formData.append(contextPath, value);
52
- });
53
- return [ formData, isJsonfiable ];
54
- }
55
-
56
- export async function jsonfyFormData(formData, jsonfy = true) {
57
- let isJsonfiable = true;
58
- let json;
59
- for (let [ name, value ] of formData.entries()) {
60
- if (!json) { json = _isNumeric(_before(name, '[')) ? [] : {}; }
61
- let type = dataType(value);
62
- if (jsonfy && ['Blob', 'File'].includes(type) && value.type === 'application/json' && [4, 5].includes(value.size)) {
63
- let _value = await value.text();
64
- if (['true', 'false', 'null'].includes(_value)) {
65
- type = 'json';
66
- value = JSON.parse(_value);
67
- }
68
- }
69
- isJsonfiable = isJsonfiable && type === 'json';
70
- params.set(json, name, value);
71
- }
72
- return [ json, isJsonfiable ];
73
- }
74
-
75
- export function dataType(value) {
76
- if (_isString(value) || _isNumber(value) || _isBoolean(value)) return 'json';
77
- if (!_isTypeObject(value)) return;
78
- const toStringTag = value[Symbol.toStringTag];
79
- const type = [
80
- 'Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer', 'Blob', 'File', 'FormData', 'Stream', 'ReadableStream'
81
- ].reduce((_toStringTag, type) => _toStringTag || (toStringTag === type ? type : null), null);
82
- if (type) return type;
83
- if ((_isObject(value) && _isPlainObject(value)) || (_isArray(value) && _isPlainArray(value)) || 'toString' in value) {
84
- return 'json';
85
- }
86
- }