@webqit/webflo 0.11.61 → 0.20.2-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/.github/FUNDING.yml +12 -0
  2. package/.github/workflows/publish.yml +48 -0
  3. package/.gitignore +2 -0
  4. package/LICENSE +2 -2
  5. package/README.md +71 -2050
  6. package/package.json +28 -13
  7. package/site/-/_.md +139 -0
  8. package/site/-/docs.old.md +2010 -0
  9. package/site/.vitepress/cache/deps/@braintree_sanitize-url 2.js +93 -0
  10. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js +93 -0
  11. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js 2.map +7 -0
  12. package/site/.vitepress/cache/deps/@braintree_sanitize-url.js.map +7 -0
  13. package/site/.vitepress/cache/deps/_metadata 2.json +85 -0
  14. package/site/.vitepress/cache/deps/_metadata.json +85 -0
  15. package/site/.vitepress/cache/deps/chunk-BUSYA2B4 2.js +9 -0
  16. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js +9 -0
  17. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js 2.map +7 -0
  18. package/site/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +7 -0
  19. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK 2.js +9719 -0
  20. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js +9719 -0
  21. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js 2.map +7 -0
  22. package/site/.vitepress/cache/deps/chunk-Q2AYPHVK.js.map +7 -0
  23. package/site/.vitepress/cache/deps/chunk-QAXAIFA7 2.js +12705 -0
  24. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js +12705 -0
  25. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js 2.map +7 -0
  26. package/site/.vitepress/cache/deps/chunk-QAXAIFA7.js.map +7 -0
  27. package/site/.vitepress/cache/deps/cytoscape 2.js +30278 -0
  28. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent 2.js +4710 -0
  29. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js +4710 -0
  30. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js 2.map +7 -0
  31. package/site/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +7 -0
  32. package/site/.vitepress/cache/deps/cytoscape.js +30278 -0
  33. package/site/.vitepress/cache/deps/cytoscape.js 2.map +7 -0
  34. package/site/.vitepress/cache/deps/cytoscape.js.map +7 -0
  35. package/site/.vitepress/cache/deps/dayjs 2.js +285 -0
  36. package/site/.vitepress/cache/deps/dayjs.js +285 -0
  37. package/site/.vitepress/cache/deps/dayjs.js 2.map +7 -0
  38. package/site/.vitepress/cache/deps/dayjs.js.map +7 -0
  39. package/site/.vitepress/cache/deps/debug 2.js +453 -0
  40. package/site/.vitepress/cache/deps/debug.js +453 -0
  41. package/site/.vitepress/cache/deps/debug.js 2.map +7 -0
  42. package/site/.vitepress/cache/deps/debug.js.map +7 -0
  43. package/site/.vitepress/cache/deps/package 2.json +3 -0
  44. package/site/.vitepress/cache/deps/package.json +3 -0
  45. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api 2.js +4507 -0
  46. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +4507 -0
  47. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js 2.map +7 -0
  48. package/site/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +7 -0
  49. package/site/.vitepress/cache/deps/vitepress___@vueuse_core 2.js +584 -0
  50. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js +584 -0
  51. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js 2.map +7 -0
  52. package/site/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +7 -0
  53. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap 2.js +1166 -0
  54. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +1166 -0
  55. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js 2.map +7 -0
  56. package/site/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +7 -0
  57. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js 2.js +1667 -0
  58. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +1667 -0
  59. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js 2.map +7 -0
  60. package/site/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +7 -0
  61. package/site/.vitepress/cache/deps/vitepress___minisearch 2.js +1815 -0
  62. package/site/.vitepress/cache/deps/vitepress___minisearch.js +1815 -0
  63. package/site/.vitepress/cache/deps/vitepress___minisearch.js 2.map +7 -0
  64. package/site/.vitepress/cache/deps/vitepress___minisearch.js.map +7 -0
  65. package/site/.vitepress/cache/deps/vue 2.js +344 -0
  66. package/site/.vitepress/cache/deps/vue.js +344 -0
  67. package/site/.vitepress/cache/deps/vue.js 2.map +7 -0
  68. package/site/.vitepress/cache/deps/vue.js.map +7 -0
  69. package/site/.vitepress/config.ts +147 -0
  70. package/site/.vitepress/theme/custom.css +50 -0
  71. package/site/.vitepress/theme/index.ts +6 -0
  72. package/site/api/webflo-fetch/FormData.md +0 -0
  73. package/site/api/webflo-fetch/Headers.md +0 -0
  74. package/site/api/webflo-fetch/LiveResponse.md +0 -0
  75. package/site/api/webflo-fetch/Request.md +0 -0
  76. package/site/api/webflo-fetch/Response.md +0 -0
  77. package/site/api/webflo-fetch/fetch.md +0 -0
  78. package/site/api/webflo-routing/HttpCookies.md +0 -0
  79. package/site/api/webflo-routing/HttpEvent/respondWith.md +1 -0
  80. package/site/api/webflo-routing/HttpEvent/waitUntil.md +1 -0
  81. package/site/api/webflo-routing/HttpEvent/waitUntilNavigate.md +1 -0
  82. package/site/api/webflo-routing/HttpEvent.md +30 -0
  83. package/site/api/webflo-routing/HttpSession.md +0 -0
  84. package/site/api/webflo-routing/HttpState.md +0 -0
  85. package/site/api/webflo-routing/HttpUser.md +0 -0
  86. package/site/api/webflo-routing/handler/fetch.md +42 -0
  87. package/site/api/webflo-routing/handler/next.md +54 -0
  88. package/site/api/webflo-routing/handler.md +119 -0
  89. package/site/api.md +26 -0
  90. package/site/contributing.md +16 -0
  91. package/site/docs/advanced/lifecycles.md +20 -0
  92. package/site/docs/advanced/redirects.md +0 -0
  93. package/site/docs/advanced/routing.md +1 -0
  94. package/site/docs/advanced.md +9 -0
  95. package/site/docs/concepts/realtime.md +637 -0
  96. package/site/docs/concepts/rendering.md +60 -0
  97. package/site/docs/concepts/request-response.md +47 -0
  98. package/site/docs/concepts/routing.md +656 -0
  99. package/site/docs/concepts/state.md +44 -0
  100. package/site/docs/concepts/templates.md +48 -0
  101. package/site/docs/concepts.md +97 -0
  102. package/site/docs/getting-started.md +378 -0
  103. package/site/docs/tech-stack.md +56 -0
  104. package/site/docs.md +100 -0
  105. package/site/examples/pwa.md +10 -0
  106. package/site/examples/web.md +11 -0
  107. package/site/examples.md +10 -0
  108. package/site/faq.md +13 -0
  109. package/site/guides/guide-auth.md +13 -0
  110. package/site/guides/guide-file-upload.md +11 -0
  111. package/site/guides/guide-service-worker.md +10 -0
  112. package/site/guides/tutorial-1-todo.md +24 -0
  113. package/site/guides.md +15 -0
  114. package/site/index.md +39 -0
  115. package/site/public/img/brand/logo-670x670.png +0 -0
  116. package/site/recipes/realtime.md +11 -0
  117. package/site/recipes/streaming.md +15 -0
  118. package/site/reference/cli.md +11 -0
  119. package/site/reference/config.md +13 -0
  120. package/site/reference/tools.md +9 -0
  121. package/src/Context.js +3 -11
  122. package/src/config-pi/deployment/Env.js +6 -19
  123. package/src/config-pi/deployment/Layout.js +11 -3
  124. package/src/config-pi/runtime/Client.js +40 -48
  125. package/src/config-pi/runtime/Server.js +52 -20
  126. package/src/config-pi/runtime/client/Worker.js +22 -20
  127. package/src/config-pi/static/Init.js +57 -0
  128. package/src/config-pi/static/index.js +2 -0
  129. package/src/deployment-pi/origins/index.js +1 -1
  130. package/src/deployment-pi/util.js +161 -0
  131. package/src/index.js +3 -9
  132. package/src/init-pi/index.js +117 -0
  133. package/src/init-pi/templates/pwa/app/handler.server.js +8 -0
  134. package/src/init-pi/templates/pwa/app/page.html +7 -0
  135. package/src/init-pi/templates/pwa/package.json +19 -0
  136. package/src/init-pi/templates/pwa/public/assets/app.css +16 -0
  137. package/src/init-pi/templates/pwa/public/index.html +39 -0
  138. package/src/init-pi/templates/pwa/public/manifest.json +29 -0
  139. package/src/init-pi/templates/web/app/handler.server.js +8 -0
  140. package/src/init-pi/templates/web/app/page.html +7 -0
  141. package/src/init-pi/templates/web/package.json +19 -0
  142. package/src/init-pi/templates/web/public/assets/app.css +16 -0
  143. package/src/init-pi/templates/web/public/index.html +39 -0
  144. package/src/runtime-pi/WebfloRuntime.js +350 -0
  145. package/src/runtime-pi/index.js +3 -10
  146. package/src/runtime-pi/webflo-client/ClientSideCookies.js +17 -0
  147. package/src/runtime-pi/webflo-client/ClientSideWorkport.js +63 -0
  148. package/src/runtime-pi/webflo-client/DeviceCapabilities.js +213 -0
  149. package/src/runtime-pi/webflo-client/WebfloClient.js +500 -0
  150. package/src/runtime-pi/webflo-client/WebfloRootClient1.js +206 -0
  151. package/src/runtime-pi/webflo-client/WebfloRootClient2.js +113 -0
  152. package/src/runtime-pi/webflo-client/WebfloSubClient.js +118 -0
  153. package/src/runtime-pi/webflo-client/index.js +17 -0
  154. package/src/runtime-pi/webflo-client/webflo-codegen.js +469 -0
  155. package/src/runtime-pi/webflo-client/webflo-devmode.js +243 -0
  156. package/src/runtime-pi/webflo-client/webflo-embedded.js +50 -0
  157. package/src/runtime-pi/webflo-fetch/LiveResponse.js +437 -0
  158. package/src/runtime-pi/webflo-fetch/cookies.js +10 -0
  159. package/src/runtime-pi/webflo-fetch/fetch.js +16 -0
  160. package/src/runtime-pi/webflo-fetch/formdata.js +54 -0
  161. package/src/runtime-pi/webflo-fetch/headers.js +151 -0
  162. package/src/runtime-pi/webflo-fetch/index.js +5 -0
  163. package/src/runtime-pi/webflo-fetch/message.js +49 -0
  164. package/src/runtime-pi/webflo-fetch/request.js +62 -0
  165. package/src/runtime-pi/webflo-fetch/response.js +110 -0
  166. package/src/runtime-pi/webflo-fetch/util.js +28 -0
  167. package/src/runtime-pi/webflo-messaging/WQBroadcastChannel.js +10 -0
  168. package/src/runtime-pi/webflo-messaging/WQMessageChannel.js +26 -0
  169. package/src/runtime-pi/webflo-messaging/WQMessageEvent.js +87 -0
  170. package/src/runtime-pi/webflo-messaging/WQMessagePort.js +38 -0
  171. package/src/runtime-pi/webflo-messaging/WQRelayPort.js +47 -0
  172. package/src/runtime-pi/webflo-messaging/WQSockPort.js +113 -0
  173. package/src/runtime-pi/webflo-messaging/WQStarPort.js +104 -0
  174. package/src/runtime-pi/webflo-messaging/wq-message-port.js +404 -0
  175. package/src/runtime-pi/webflo-routing/HttpCookies.js +42 -0
  176. package/src/runtime-pi/webflo-routing/HttpEvent.js +112 -0
  177. package/src/runtime-pi/webflo-routing/HttpSession.js +11 -0
  178. package/src/runtime-pi/webflo-routing/HttpState.js +153 -0
  179. package/src/runtime-pi/webflo-routing/HttpUser.js +54 -0
  180. package/src/runtime-pi/webflo-routing/WebfloRouter.js +245 -0
  181. package/src/runtime-pi/webflo-server/ServerSideCookies.js +19 -0
  182. package/src/runtime-pi/webflo-server/ServerSideSession.js +38 -0
  183. package/src/runtime-pi/webflo-server/WebfloServer.js +937 -0
  184. package/src/runtime-pi/webflo-server/index.js +11 -0
  185. package/src/runtime-pi/webflo-server/messaging/Client.js +27 -0
  186. package/src/runtime-pi/webflo-server/messaging/ClientRequestRealtime.js +50 -0
  187. package/src/runtime-pi/webflo-server/messaging/Clients.js +25 -0
  188. package/src/runtime-pi/webflo-server/webflo-devmode.js +326 -0
  189. package/src/runtime-pi/{client → webflo-url}/Url.js +27 -76
  190. package/src/runtime-pi/webflo-url/index.js +1 -0
  191. package/src/runtime-pi/webflo-url/urlpattern.js +38 -0
  192. package/src/runtime-pi/{util-url.js → webflo-url/util.js} +5 -43
  193. package/src/runtime-pi/webflo-url/xURL.js +94 -0
  194. package/src/runtime-pi/webflo-worker/WebfloWorker.js +234 -0
  195. package/src/runtime-pi/webflo-worker/WorkerSideCookies.js +19 -0
  196. package/src/runtime-pi/webflo-worker/WorkerSideWorkport.js +18 -0
  197. package/src/runtime-pi/webflo-worker/index.js +11 -0
  198. package/src/services-pi/index.js +2 -0
  199. package/src/services-pi/push/index.js +23 -0
  200. package/src/util.js +10 -0
  201. package/src/{webflo.js → webflo-cli.js} +4 -4
  202. package/src/runtime-pi/Application.js +0 -29
  203. package/src/runtime-pi/Cookies.js +0 -82
  204. package/src/runtime-pi/HttpEvent.js +0 -107
  205. package/src/runtime-pi/Router.js +0 -130
  206. package/src/runtime-pi/Runtime.js +0 -21
  207. package/src/runtime-pi/client/Application.js +0 -76
  208. package/src/runtime-pi/client/Context.js +0 -7
  209. package/src/runtime-pi/client/Router.js +0 -48
  210. package/src/runtime-pi/client/Runtime.js +0 -525
  211. package/src/runtime-pi/client/Workport.js +0 -190
  212. package/src/runtime-pi/client/createStorage.js +0 -58
  213. package/src/runtime-pi/client/generate.js +0 -481
  214. package/src/runtime-pi/client/index.js +0 -21
  215. package/src/runtime-pi/client/worker/Application.js +0 -44
  216. package/src/runtime-pi/client/worker/Context.js +0 -7
  217. package/src/runtime-pi/client/worker/Runtime.js +0 -275
  218. package/src/runtime-pi/client/worker/Workport.js +0 -78
  219. package/src/runtime-pi/client/worker/index.js +0 -21
  220. package/src/runtime-pi/server/Application.js +0 -101
  221. package/src/runtime-pi/server/Context.js +0 -16
  222. package/src/runtime-pi/server/Router.js +0 -159
  223. package/src/runtime-pi/server/Runtime.js +0 -558
  224. package/src/runtime-pi/server/index.js +0 -21
  225. package/src/runtime-pi/util-http.js +0 -86
  226. package/src/runtime-pi/xFormData.js +0 -24
  227. package/src/runtime-pi/xHeaders.js +0 -146
  228. package/src/runtime-pi/xRequest.js +0 -46
  229. package/src/runtime-pi/xRequestHeaders.js +0 -109
  230. package/src/runtime-pi/xResponse.js +0 -33
  231. package/src/runtime-pi/xResponseHeaders.js +0 -117
  232. package/src/runtime-pi/xURL.js +0 -105
  233. package/src/runtime-pi/xfetch.js +0 -23
  234. package/src/runtime-pi/xxHttpMessage.js +0 -102
  235. package/src/static-pi/index.js +0 -11
@@ -0,0 +1,243 @@
1
+ export class WebfloHMR {
2
+
3
+ static manage(app, options = {}) {
4
+ return new this(app, options);
5
+ }
6
+
7
+ #app;
8
+
9
+ #options;
10
+ get options() { return this.#options; }
11
+
12
+ #socket;
13
+ get socket() { return this.#socket; }
14
+
15
+ #selectors = {
16
+ remoteStyleSheet: 'link[rel="stylesheet"][href]',
17
+ remoteHtmlModule: 'template[def][src]',
18
+ inlineHtmlModule: 'template[def]:not([src])'
19
+ };
20
+
21
+ #removedCSS = new Set;
22
+ #removedHTML = new Map;
23
+
24
+ constructor(app, options = {}) {
25
+ this.#app = app;
26
+ this.#options = options;
27
+ this.#socket = new WebSocket('/?rel=hmr');
28
+ this.#socket.onmessage = async (msg) => {
29
+ const events = JSON.parse(msg.data);
30
+ await this.fire(events);
31
+ };
32
+ }
33
+
34
+ async fire(events) {
35
+ const statuses = {
36
+ numCSSAffected: 0,
37
+ numHTMLAffected: 0,
38
+ routesAffected: new Set,
39
+ currentRouteAffected: false,
40
+ serviceWorkerAffected: false,
41
+ };
42
+ for (const { ...event } of events) {
43
+ if (event.affectedRoute) {
44
+ if (event.realm === 'client') {
45
+ if (event.actionableEffect === 'unlink') {
46
+ delete this.#app.routes[event.affectedRoute];
47
+ } else {
48
+ this.#app.routes[event.affectedRoute] = `/@dev?src=${event.affectedHandler}&t=${Date.now()}`;
49
+ }
50
+ statuses.routesAffected.add(event.affectedRoute);
51
+ } else if (event.realm === 'worker') {
52
+ statuses.serviceWorkerAffected = true;
53
+ }
54
+ // Now both for realm === client | worker | server
55
+ if (this.#app.location.pathname.startsWith(event.affectedRoute)) {
56
+ statuses.currentRouteAffected = true;
57
+ }
58
+ } else {
59
+ const parts = event.target.split('/');
60
+ const upCount = parts.filter((p) => p === '..').length;
61
+ const remaining = parts.filter((p) => p !== '..' && p !== '.');
62
+ const $target = '/' + remaining.slice(upCount).join('/');
63
+ event.$target = new URL($target, window.location.origin/*not href*/);
64
+ if (event.fileType === 'css') {
65
+ statuses.numCSSAffected += await this.handleAffectedStyleSheets(event);
66
+ } else if (event.fileType === 'html' || /Dir$/.test(event.type)) {
67
+ statuses.numHTMLAffected += await this.handleAffectedHTMLModules(event);
68
+ }
69
+ }
70
+ }
71
+ let serviceWorkerUpdateDone;
72
+ if (statuses.serviceWorkerAffected && 'serviceWorker' in navigator) {
73
+ // Must run before any reload below
74
+ serviceWorkerUpdateDone = this.updateServiceWorker().then(async (status) => {
75
+ console.log('[HMR] Service Worker Update:', status);
76
+ });
77
+ }
78
+ if (statuses.currentRouteAffected) {
79
+ Promise.resolve(serviceWorkerUpdateDone).then(async () => {
80
+ await this.#app.navigate(this.#app.location.href);
81
+ });
82
+ }
83
+ }
84
+
85
+ async updateServiceWorker() {
86
+ const registration = await navigator.serviceWorker.getRegistration();
87
+ if (!registration) return 0;
88
+ registration.update();
89
+ return await new Promise((resolve) => {
90
+ navigator.serviceWorker.addEventListener('controllerchange', () => resolve(1));
91
+ registration.addEventListener('updatefound', () => {
92
+ const newWorker = registration.installing;
93
+ if (!newWorker) return resolve(0);
94
+ });
95
+ });
96
+ }
97
+
98
+ async handleAffectedStyleSheets(event) {
99
+ const sheets = document.querySelectorAll(this.#selectors.remoteStyleSheet);
100
+ let _count = 0;
101
+ for (const node of [...sheets, ...this.#removedCSS]) {
102
+ if (!node.$url) {
103
+ Object.defineProperty(node, '$url', {
104
+ value: new URL(node.getAttribute('href'), window.location.href/*not origin*/)
105
+ });
106
+ }
107
+ if (_matchUrl(event, node.$url.pathname)) {
108
+ _count += await this.mutateNode(event, node, this.#removedCSS);
109
+ }
110
+ }
111
+ return _count;
112
+ }
113
+
114
+ async handleAffectedHTMLModules(event) {
115
+ const topLevelModules = document.querySelectorAll(this.#selectors.remoteHtmlModule);
116
+ return await (async function eat(contextNode, $contextPath, modules, level = 0) {
117
+ if (!this.#removedHTML.has($contextPath)) {
118
+ this.#removedHTML.set($contextPath, new Set);
119
+ }
120
+ const removedHTML = this.#removedHTML.get($contextPath);
121
+ let _count = 0;
122
+ for (const node of [...modules, ...removedHTML]) {
123
+ const $def = node.getAttribute('def');
124
+ const $defPath = $contextPath ? `${$contextPath === '/' ? '' : $contextPath}/${$def}` : null;
125
+
126
+ // Match remote modules
127
+ if (node.matches(this.#selectors.remoteHtmlModule)) {
128
+ if (!node.$url) {
129
+ Object.defineProperty(node, '$url', {
130
+ value: new URL(node.getAttribute('src'), window.location.href/*not origin*/)
131
+ });
132
+ }
133
+ if (node.$url.pathname === event.$target.pathname) {
134
+ // The referenced bundle file has been directly mutated
135
+ _count += await this.mutateNode(event, node, removedHTML, true);
136
+ continue;
137
+ }
138
+ /*
139
+ const srcDir = _dirname(node.$url.pathname);
140
+ if (srcDir === '/' || event.$target.pathname.startsWith(`${srcDir}/`)) {
141
+ // Target is a file within current bundle. So we recurse
142
+ _count += await eat.call(this, node, srcDir, [...node.content.children], level + 1);
143
+ continue;
144
+ }*/
145
+ _count += await eat.call(this, node, $defPath || '/', [...node.content.children], level + 1);
146
+ continue;
147
+ }
148
+ if ($defPath === event.$target.pathname) {
149
+ // Target (file or directory) exactly matches DEF
150
+ _count += await this.mutateNode(event, node, removedHTML, async () => {
151
+ const replacementNode = await this.loadHTMLModule(event.target/*!IMPORTANT*/);
152
+ if (!replacementNode) return 0;
153
+ replacementNode.setAttribute?.('def', $def);
154
+ node.replaceWith(replacementNode);
155
+ return 1;
156
+ });
157
+ continue;
158
+ }
159
+ // Recurse along DEF tree
160
+ if (node.matches(this.#selectors.inlineHtmlModule)) {
161
+ // Target is a file within current module. So we recurse
162
+ _count += await eat.call(this, node, $defPath, [...node.content.children], level + 1);
163
+ continue;
164
+ }
165
+ }
166
+ // Handle module add event
167
+ if (!_count/*no existing node matched*/ && /^add/.test(event.type)/* (addDir | add) */ && (
168
+ contextNode && $contextPath === _dirname(event.$target.pathname)
169
+ )) {
170
+ const newNode = event.type === 'addDir'
171
+ ? document.createElement('template')
172
+ : await this.loadHTMLModule(event.target/*!IMPORTANT*/);
173
+ if (newNode) {
174
+ newNode.setAttribute?.('def', _basename(event.$target.pathname));
175
+ contextNode.content.appendChild(newNode);
176
+ _count++;
177
+ }
178
+ }
179
+ return _count;
180
+ }).call(this, [...topLevelModules][0], '', topLevelModules);
181
+ }
182
+
183
+ async mutateNode(event, node, removedNodes, customRefresh = null) {
184
+ // (unlink | unlinkDir)
185
+ if (/^unlink/.test(event.type)) {
186
+ node.$previousSibling = node.previousSibling;
187
+ removedNodes.add(node);
188
+ node.remove();
189
+ return 1;
190
+ }
191
+ // (add | addDir)
192
+ if (/^add/.test(event.type)) {
193
+ if (node.$previousSibling) {
194
+ node.$previousSibling.after(node);
195
+ removedNodes.delete(node);
196
+ return 1;
197
+ }
198
+ return 0;
199
+ }
200
+ // (change)
201
+ if (!node.$url) {
202
+ return await customRefresh(node);
203
+ }
204
+ const $url = node.$url;
205
+ const url = encodeURIComponent($url.href.replace(`${$url.origin}/`, '')); // preserving origin query strings
206
+ const urlRewrite = `/@dev?src=${url}&t=${Date.now()}`;
207
+ if (node.matches(this.#selectors.remoteStyleSheet)) {
208
+ node.setAttribute('href', urlRewrite);
209
+ return 1;
210
+ }
211
+ if (node.matches(this.#selectors.remoteHtmlModule)) {
212
+ node.setAttribute('src', urlRewrite);
213
+ return 1;
214
+ }
215
+ return 0
216
+ }
217
+
218
+ async loadHTMLModule(url) {
219
+ const urlRewrite = `/@dev?src=${url}?t=${Date.now()}`;
220
+ const fileContents = await fetch(urlRewrite).then((res) => res.text()).catch(() => null);
221
+ if (fileContents === null) return null;
222
+ const temp = document.createElement('template');
223
+ temp.innerHTML = fileContents.trim(); // IMPORTANT: .trim()
224
+ return temp.content.firstElementChild;
225
+ }
226
+ }
227
+
228
+ const _dirname = (path) => {
229
+ const dname = path.replace(/\/[^\/]+$/, '');
230
+ return !dname ? '/' : dname;
231
+ };
232
+
233
+ const _basename = (path) => {
234
+ const bname = path.match(/\/([^\/]+)$/)[1];
235
+ return !bname ? path : bname;
236
+ };
237
+
238
+ const _matchUrl = (event, pathname) => {
239
+ if (/Dir$/.test(event.type)) {
240
+ return pathname.startsWith(`${event.$target.pathname}/`);
241
+ }
242
+ return pathname === event.$target.pathname;
243
+ };
@@ -0,0 +1,50 @@
1
+ export function defineElement(WebfloSubClient, embedTagNames = 'webflo-embedded') {
2
+ window.customElements.define(embedTagNames, class extends HTMLElement {
3
+
4
+ #superRuntime;
5
+ #lifecycleController;
6
+ #location;
7
+ #reflectAction;
8
+
9
+ static get observedAttributes() { return ['location']; }
10
+
11
+ get location() {
12
+ if (!this.#location) {
13
+ this.#location = new URL(this.getAttribute('location') || '', window.location.origin);
14
+ }
15
+ return this.#location;
16
+ }
17
+
18
+ set location(value) {
19
+ if (!(value instanceof URL)) {
20
+ value = new URL(value, window.location.origin);
21
+ }
22
+ if (value.href === this.location.href) return;
23
+ this.#location = value;
24
+ this.setAttribute('location', value.href.replace(value.origin, ''));
25
+ if (!this.#reflectAction) {
26
+ this.webfloRuntime.navigate(value);
27
+ }
28
+ }
29
+
30
+ reflectLocation(location) {
31
+ this.#reflectAction = true;
32
+ this.location = location;
33
+ this.#reflectAction = false;
34
+ }
35
+
36
+ attributeChangedCallback(name, oldValue, newValue) {
37
+ if (oldValue === newValue) return;
38
+ this.location = newValue;
39
+ }
40
+
41
+ async connectedCallback() {
42
+ this.#superRuntime = (this.parentNode?.closest(embedTagNames) || document).webfloRuntime;
43
+ this.#lifecycleController = await WebfloSubClient.create(this.#superRuntime, this).initialize();
44
+ }
45
+
46
+ disconnectedCallback() {
47
+ this.#lifecycleController.abort();
48
+ }
49
+ });
50
+ }