plgg-bundle 0.0.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 (235) hide show
  1. package/README.md +68 -0
  2. package/bin/appAliasHook.mjs +89 -0
  3. package/bin/hook.mjs +94 -0
  4. package/bin/plgg-bundle.mjs +16 -0
  5. package/dist/Dev/fixtures/devPoc.spec.d.ts +2 -0
  6. package/dist/Dev/fixtures/devPoc.spec.d.ts.map +1 -0
  7. package/dist/Dev/fixtures/devPoc.spec.js +145 -0
  8. package/dist/Dev/fixtures/devPoc.spec.js.map +1 -0
  9. package/dist/Dev/model/Fetch.d.ts +20 -0
  10. package/dist/Dev/model/Fetch.d.ts.map +1 -0
  11. package/dist/Dev/model/Fetch.js +8 -0
  12. package/dist/Dev/model/Fetch.js.map +1 -0
  13. package/dist/Dev/model/ModuleGraph.d.ts +27 -0
  14. package/dist/Dev/model/ModuleGraph.d.ts.map +1 -0
  15. package/dist/Dev/model/ModuleGraph.js +2 -0
  16. package/dist/Dev/model/ModuleGraph.js.map +1 -0
  17. package/dist/Dev/model/Protocol.d.ts +22 -0
  18. package/dist/Dev/model/Protocol.d.ts.map +1 -0
  19. package/dist/Dev/model/Protocol.js +31 -0
  20. package/dist/Dev/model/Protocol.js.map +1 -0
  21. package/dist/Dev/node/devServer.d.ts +21 -0
  22. package/dist/Dev/node/devServer.d.ts.map +1 -0
  23. package/dist/Dev/node/devServer.js +298 -0
  24. package/dist/Dev/node/devServer.js.map +1 -0
  25. package/dist/Dev/node/httpAdapter.d.ts +19 -0
  26. package/dist/Dev/node/httpAdapter.d.ts.map +1 -0
  27. package/dist/Dev/node/httpAdapter.js +76 -0
  28. package/dist/Dev/node/httpAdapter.js.map +1 -0
  29. package/dist/Dev/node/scanGraph.d.ts +21 -0
  30. package/dist/Dev/node/scanGraph.d.ts.map +1 -0
  31. package/dist/Dev/node/scanGraph.js +145 -0
  32. package/dist/Dev/node/scanGraph.js.map +1 -0
  33. package/dist/Dev/node/watch.d.ts +10 -0
  34. package/dist/Dev/node/watch.d.ts.map +1 -0
  35. package/dist/Dev/node/watch.js +44 -0
  36. package/dist/Dev/node/watch.js.map +1 -0
  37. package/dist/Dev/usecase/allowedHost.d.ts +16 -0
  38. package/dist/Dev/usecase/allowedHost.d.ts.map +1 -0
  39. package/dist/Dev/usecase/allowedHost.js +33 -0
  40. package/dist/Dev/usecase/allowedHost.js.map +1 -0
  41. package/dist/Dev/usecase/allowedHost.spec.d.ts +2 -0
  42. package/dist/Dev/usecase/allowedHost.spec.d.ts.map +1 -0
  43. package/dist/Dev/usecase/allowedHost.spec.js +13 -0
  44. package/dist/Dev/usecase/allowedHost.spec.js.map +1 -0
  45. package/dist/Dev/usecase/buildGraph.d.ts +12 -0
  46. package/dist/Dev/usecase/buildGraph.d.ts.map +1 -0
  47. package/dist/Dev/usecase/buildGraph.js +24 -0
  48. package/dist/Dev/usecase/buildGraph.js.map +1 -0
  49. package/dist/Dev/usecase/buildGraph.spec.d.ts +2 -0
  50. package/dist/Dev/usecase/buildGraph.spec.d.ts.map +1 -0
  51. package/dist/Dev/usecase/buildGraph.spec.js +16 -0
  52. package/dist/Dev/usecase/buildGraph.spec.js.map +1 -0
  53. package/dist/Dev/usecase/decorateDevHtml.d.ts +12 -0
  54. package/dist/Dev/usecase/decorateDevHtml.d.ts.map +1 -0
  55. package/dist/Dev/usecase/decorateDevHtml.js +15 -0
  56. package/dist/Dev/usecase/decorateDevHtml.js.map +1 -0
  57. package/dist/Dev/usecase/decorateDevHtml.spec.d.ts +2 -0
  58. package/dist/Dev/usecase/decorateDevHtml.spec.d.ts.map +1 -0
  59. package/dist/Dev/usecase/decorateDevHtml.spec.js +19 -0
  60. package/dist/Dev/usecase/decorateDevHtml.spec.js.map +1 -0
  61. package/dist/Dev/usecase/invalidate.d.ts +17 -0
  62. package/dist/Dev/usecase/invalidate.d.ts.map +1 -0
  63. package/dist/Dev/usecase/invalidate.js +57 -0
  64. package/dist/Dev/usecase/invalidate.js.map +1 -0
  65. package/dist/Dev/usecase/invalidate.spec.d.ts +2 -0
  66. package/dist/Dev/usecase/invalidate.spec.d.ts.map +1 -0
  67. package/dist/Dev/usecase/invalidate.spec.js +64 -0
  68. package/dist/Dev/usecase/invalidate.spec.js.map +1 -0
  69. package/dist/Dev/usecase/parseImports.d.ts +24 -0
  70. package/dist/Dev/usecase/parseImports.d.ts.map +1 -0
  71. package/dist/Dev/usecase/parseImports.js +40 -0
  72. package/dist/Dev/usecase/parseImports.js.map +1 -0
  73. package/dist/Dev/usecase/parseImports.spec.d.ts +2 -0
  74. package/dist/Dev/usecase/parseImports.spec.d.ts.map +1 -0
  75. package/dist/Dev/usecase/parseImports.spec.js +24 -0
  76. package/dist/Dev/usecase/parseImports.spec.js.map +1 -0
  77. package/dist/Dev/usecase/reloadDecision.d.ts +20 -0
  78. package/dist/Dev/usecase/reloadDecision.d.ts.map +1 -0
  79. package/dist/Dev/usecase/reloadDecision.js +52 -0
  80. package/dist/Dev/usecase/reloadDecision.js.map +1 -0
  81. package/dist/Dev/usecase/reloadDecision.spec.d.ts +2 -0
  82. package/dist/Dev/usecase/reloadDecision.spec.d.ts.map +1 -0
  83. package/dist/Dev/usecase/reloadDecision.spec.js +17 -0
  84. package/dist/Dev/usecase/reloadDecision.spec.js.map +1 -0
  85. package/dist/domain/model/BundleConfig.d.ts +136 -0
  86. package/dist/domain/model/BundleConfig.d.ts.map +1 -0
  87. package/dist/domain/model/BundleConfig.js +18 -0
  88. package/dist/domain/model/BundleConfig.js.map +1 -0
  89. package/dist/domain/model/BundleConfig.spec.d.ts +2 -0
  90. package/dist/domain/model/BundleConfig.spec.d.ts.map +1 -0
  91. package/dist/domain/model/BundleConfig.spec.js +8 -0
  92. package/dist/domain/model/BundleConfig.spec.js.map +1 -0
  93. package/dist/domain/usecase/asBundleConfig.d.ts +17 -0
  94. package/dist/domain/usecase/asBundleConfig.d.ts.map +1 -0
  95. package/dist/domain/usecase/asBundleConfig.js +179 -0
  96. package/dist/domain/usecase/asBundleConfig.js.map +1 -0
  97. package/dist/domain/usecase/asBundleConfig.spec.d.ts +2 -0
  98. package/dist/domain/usecase/asBundleConfig.spec.d.ts.map +1 -0
  99. package/dist/domain/usecase/asBundleConfig.spec.js +119 -0
  100. package/dist/domain/usecase/asBundleConfig.spec.js.map +1 -0
  101. package/dist/domain/usecase/build.d.ts +14 -0
  102. package/dist/domain/usecase/build.d.ts.map +1 -0
  103. package/dist/domain/usecase/build.js +177 -0
  104. package/dist/domain/usecase/build.js.map +1 -0
  105. package/dist/domain/usecase/collectModules.d.ts +53 -0
  106. package/dist/domain/usecase/collectModules.d.ts.map +1 -0
  107. package/dist/domain/usecase/collectModules.js +118 -0
  108. package/dist/domain/usecase/collectModules.js.map +1 -0
  109. package/dist/domain/usecase/deriveExternal.d.ts +25 -0
  110. package/dist/domain/usecase/deriveExternal.d.ts.map +1 -0
  111. package/dist/domain/usecase/deriveExternal.js +79 -0
  112. package/dist/domain/usecase/deriveExternal.js.map +1 -0
  113. package/dist/domain/usecase/deriveExternal.spec.d.ts +2 -0
  114. package/dist/domain/usecase/deriveExternal.spec.d.ts.map +1 -0
  115. package/dist/domain/usecase/deriveExternal.spec.js +56 -0
  116. package/dist/domain/usecase/deriveExternal.spec.js.map +1 -0
  117. package/dist/domain/usecase/discoverWorkspace.d.ts +27 -0
  118. package/dist/domain/usecase/discoverWorkspace.d.ts.map +1 -0
  119. package/dist/domain/usecase/discoverWorkspace.js +116 -0
  120. package/dist/domain/usecase/discoverWorkspace.js.map +1 -0
  121. package/dist/domain/usecase/discoverWorkspace.spec.d.ts +2 -0
  122. package/dist/domain/usecase/discoverWorkspace.spec.d.ts.map +1 -0
  123. package/dist/domain/usecase/discoverWorkspace.spec.js +23 -0
  124. package/dist/domain/usecase/discoverWorkspace.spec.js.map +1 -0
  125. package/dist/domain/usecase/emitBundle.d.ts +43 -0
  126. package/dist/domain/usecase/emitBundle.d.ts.map +1 -0
  127. package/dist/domain/usecase/emitBundle.js +157 -0
  128. package/dist/domain/usecase/emitBundle.js.map +1 -0
  129. package/dist/domain/usecase/emitBundle.spec.d.ts +2 -0
  130. package/dist/domain/usecase/emitBundle.spec.d.ts.map +1 -0
  131. package/dist/domain/usecase/emitBundle.spec.js +80 -0
  132. package/dist/domain/usecase/emitBundle.spec.js.map +1 -0
  133. package/dist/domain/usecase/emitDts.d.ts +32 -0
  134. package/dist/domain/usecase/emitDts.d.ts.map +1 -0
  135. package/dist/domain/usecase/emitDts.js +99 -0
  136. package/dist/domain/usecase/emitDts.js.map +1 -0
  137. package/dist/domain/usecase/isExternal.d.ts +12 -0
  138. package/dist/domain/usecase/isExternal.d.ts.map +1 -0
  139. package/dist/domain/usecase/isExternal.js +16 -0
  140. package/dist/domain/usecase/isExternal.js.map +1 -0
  141. package/dist/domain/usecase/isExternal.spec.d.ts +2 -0
  142. package/dist/domain/usecase/isExternal.spec.d.ts.map +1 -0
  143. package/dist/domain/usecase/isExternal.spec.js +16 -0
  144. package/dist/domain/usecase/isExternal.spec.js.map +1 -0
  145. package/dist/domain/usecase/resolveSpecifier.d.ts +35 -0
  146. package/dist/domain/usecase/resolveSpecifier.d.ts.map +1 -0
  147. package/dist/domain/usecase/resolveSpecifier.js +83 -0
  148. package/dist/domain/usecase/resolveSpecifier.js.map +1 -0
  149. package/dist/domain/usecase/resolveSpecifier.spec.d.ts +2 -0
  150. package/dist/domain/usecase/resolveSpecifier.spec.d.ts.map +1 -0
  151. package/dist/domain/usecase/resolveSpecifier.spec.js +44 -0
  152. package/dist/domain/usecase/resolveSpecifier.spec.js.map +1 -0
  153. package/dist/domain/usecase/resolveWorkspaceSpecifier.d.ts +29 -0
  154. package/dist/domain/usecase/resolveWorkspaceSpecifier.d.ts.map +1 -0
  155. package/dist/domain/usecase/resolveWorkspaceSpecifier.js +89 -0
  156. package/dist/domain/usecase/resolveWorkspaceSpecifier.js.map +1 -0
  157. package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.d.ts +2 -0
  158. package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.d.ts.map +1 -0
  159. package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.js +27 -0
  160. package/dist/domain/usecase/resolveWorkspaceSpecifier.spec.js.map +1 -0
  161. package/dist/domain/usecase/rewriteDtsAliases.d.ts +25 -0
  162. package/dist/domain/usecase/rewriteDtsAliases.d.ts.map +1 -0
  163. package/dist/domain/usecase/rewriteDtsAliases.js +71 -0
  164. package/dist/domain/usecase/rewriteDtsAliases.js.map +1 -0
  165. package/dist/domain/usecase/rewriteDtsAliases.spec.d.ts +2 -0
  166. package/dist/domain/usecase/rewriteDtsAliases.spec.d.ts.map +1 -0
  167. package/dist/domain/usecase/rewriteDtsAliases.spec.js +35 -0
  168. package/dist/domain/usecase/rewriteDtsAliases.spec.js.map +1 -0
  169. package/dist/entrypoints/cli.d.ts +2 -0
  170. package/dist/entrypoints/cli.d.ts.map +1 -0
  171. package/dist/entrypoints/cli.js +79 -0
  172. package/dist/entrypoints/cli.js.map +1 -0
  173. package/dist/index.d.ts +21 -0
  174. package/dist/index.d.ts.map +1 -0
  175. package/dist/index.js +28 -0
  176. package/dist/index.js.map +1 -0
  177. package/dist/vendors/runner.d.ts +20 -0
  178. package/dist/vendors/runner.d.ts.map +1 -0
  179. package/dist/vendors/runner.js +60 -0
  180. package/dist/vendors/runner.js.map +1 -0
  181. package/dist/vendors/runner.spec.d.ts +2 -0
  182. package/dist/vendors/runner.spec.d.ts.map +1 -0
  183. package/dist/vendors/runner.spec.js +20 -0
  184. package/dist/vendors/runner.spec.js.map +1 -0
  185. package/dist/vendors/transpiler.d.ts +19 -0
  186. package/dist/vendors/transpiler.d.ts.map +1 -0
  187. package/dist/vendors/transpiler.js +42 -0
  188. package/dist/vendors/transpiler.js.map +1 -0
  189. package/package.json +31 -0
  190. package/src/Dev/fixtures/devPoc.spec.ts +235 -0
  191. package/src/Dev/model/Fetch.ts +31 -0
  192. package/src/Dev/model/ModuleGraph.ts +30 -0
  193. package/src/Dev/model/Protocol.ts +35 -0
  194. package/src/Dev/node/devServer.ts +503 -0
  195. package/src/Dev/node/httpAdapter.ts +162 -0
  196. package/src/Dev/node/scanGraph.ts +203 -0
  197. package/src/Dev/node/watch.ts +54 -0
  198. package/src/Dev/usecase/allowedHost.spec.ts +50 -0
  199. package/src/Dev/usecase/allowedHost.ts +39 -0
  200. package/src/Dev/usecase/buildGraph.spec.ts +30 -0
  201. package/src/Dev/usecase/buildGraph.ts +31 -0
  202. package/src/Dev/usecase/decorateDevHtml.spec.ts +39 -0
  203. package/src/Dev/usecase/decorateDevHtml.ts +21 -0
  204. package/src/Dev/usecase/invalidate.spec.ts +88 -0
  205. package/src/Dev/usecase/invalidate.ts +67 -0
  206. package/src/Dev/usecase/parseImports.spec.ts +58 -0
  207. package/src/Dev/usecase/parseImports.ts +50 -0
  208. package/src/Dev/usecase/reloadDecision.spec.ts +50 -0
  209. package/src/Dev/usecase/reloadDecision.ts +65 -0
  210. package/src/domain/model/BundleConfig.spec.ts +35 -0
  211. package/src/domain/model/BundleConfig.ts +162 -0
  212. package/src/domain/usecase/asBundleConfig.spec.ts +230 -0
  213. package/src/domain/usecase/asBundleConfig.ts +257 -0
  214. package/src/domain/usecase/build.ts +259 -0
  215. package/src/domain/usecase/collectModules.ts +226 -0
  216. package/src/domain/usecase/deriveExternal.spec.ts +125 -0
  217. package/src/domain/usecase/deriveExternal.ts +108 -0
  218. package/src/domain/usecase/discoverWorkspace.spec.ts +63 -0
  219. package/src/domain/usecase/discoverWorkspace.ts +183 -0
  220. package/src/domain/usecase/emitBundle.spec.ts +162 -0
  221. package/src/domain/usecase/emitBundle.ts +215 -0
  222. package/src/domain/usecase/emitDts.ts +156 -0
  223. package/src/domain/usecase/isExternal.spec.ts +53 -0
  224. package/src/domain/usecase/isExternal.ts +20 -0
  225. package/src/domain/usecase/resolveSpecifier.spec.ts +112 -0
  226. package/src/domain/usecase/resolveSpecifier.ts +127 -0
  227. package/src/domain/usecase/resolveWorkspaceSpecifier.spec.ts +79 -0
  228. package/src/domain/usecase/resolveWorkspaceSpecifier.ts +120 -0
  229. package/src/domain/usecase/rewriteDtsAliases.spec.ts +123 -0
  230. package/src/domain/usecase/rewriteDtsAliases.ts +133 -0
  231. package/src/entrypoints/cli.ts +105 -0
  232. package/src/index.ts +28 -0
  233. package/src/vendors/runner.spec.ts +50 -0
  234. package/src/vendors/runner.ts +78 -0
  235. package/src/vendors/transpiler.ts +48 -0
@@ -0,0 +1,298 @@
1
+ import { resolve, isAbsolute, join, } from "node:path";
2
+ import { existsSync } from "node:fs";
3
+ import { pathToFileURL } from "node:url";
4
+ import { register } from "node:module";
5
+ import {} from "node:http";
6
+ import {} from "plgg-bundle/Dev/model/Fetch";
7
+ import {} from "plgg-bundle/Dev/model/ModuleGraph";
8
+ import { RELOAD_PATH, SSE_PRELUDE, RELOAD_FRAME, } from "plgg-bundle/Dev/model/Protocol";
9
+ import { isAllowedHost } from "plgg-bundle/Dev/usecase/allowedHost";
10
+ import { shouldReload } from "plgg-bundle/Dev/usecase/reloadDecision";
11
+ import { decorateDevHtml } from "plgg-bundle/Dev/usecase/decorateDevHtml";
12
+ import {} from "plgg-bundle/domain/model/BundleConfig";
13
+ import { serveFetch, } from "plgg-bundle/Dev/node/httpAdapter";
14
+ import { watchRoots } from "plgg-bundle/Dev/node/watch";
15
+ import { scanGraph, } from "plgg-bundle/Dev/node/scanGraph";
16
+ /** UTF-8 encode at call time (never at module top level). */
17
+ const encodeUtf8 = (text) => new TextEncoder().encode(text);
18
+ /** Whether a value is a non-null object. */
19
+ const isRecord = (v) => typeof v === "object" && v !== null;
20
+ /**
21
+ * The dev-entry factory to invoke: the module's `default`
22
+ * export, or the module itself when it has none. Stays
23
+ * `unknown` — {@link callFactory} does the callable check.
24
+ */
25
+ const defaultExport = (mod) => isRecord(mod) && "default" in mod
26
+ ? mod["default"]
27
+ : mod;
28
+ /**
29
+ * Invoke a dev-entry factory and normalise its result to a
30
+ * {@link Fetch}. The imported value is `unknown`, so the
31
+ * boundary is validated at runtime (`typeof`/`instanceof`)
32
+ * and wrapped into a correctly-typed `Fetch` — no `as`, no
33
+ * `any` annotation. Calling a value narrowed only to
34
+ * `Function` yields `any`; feeding it through the
35
+ * `unknown`-typed {@link normalizeFetch} re-establishes
36
+ * the type at the seam.
37
+ */
38
+ const callFactory = (factory) => {
39
+ if (typeof factory !== "function") {
40
+ throw new Error("dev entry must default-export a () => Fetch factory");
41
+ }
42
+ return Promise.resolve(factory()).then(normalizeFetch);
43
+ };
44
+ /**
45
+ * Validate that a factory's result is a callable and wrap
46
+ * it as a {@link Fetch} that checks each answer is a
47
+ * `Response`.
48
+ */
49
+ const normalizeFetch = (value) => {
50
+ if (typeof value !== "function") {
51
+ throw new Error("dev entry factory must return a Fetch (a function)");
52
+ }
53
+ return (request) => Promise.resolve(value(request)).then(asResponse);
54
+ };
55
+ /** Assert a Fetch answer is a Web `Response`. */
56
+ const asResponse = (value) => {
57
+ if (value instanceof Response) {
58
+ return value;
59
+ }
60
+ throw new Error("dev entry Fetch must resolve to a Response");
61
+ };
62
+ /** An Error's message, or a stringified non-Error. */
63
+ const msg = (e) => e instanceof Error ? e.message : String(e);
64
+ /** dev-server console output — a deliberate side effect. */
65
+ const log = (message) => {
66
+ process.stdout.write(`${message}\n`);
67
+ };
68
+ /**
69
+ * Cache-busting re-import of the dev entry at `version`,
70
+ * then run its factory to get a fresh {@link Fetch}. The
71
+ * loader hook propagates `?v=<version>` down the local
72
+ * import graph, so the whole affected subgraph
73
+ * re-evaluates — real code hot-reload.
74
+ */
75
+ const load = async (entryUrl, version) => {
76
+ const mod = await import(`${entryUrl}?v=${version}`);
77
+ return callFactory(defaultExport(mod));
78
+ };
79
+ /** The 403 a disallowed Host gets. */
80
+ const forbidden = () => new Response("Forbidden", {
81
+ status: 403,
82
+ headers: {
83
+ "content-type": "text/plain; charset=utf-8",
84
+ },
85
+ });
86
+ /**
87
+ * The DEV-ONLY SSE endpoint: an open `text/event-stream`
88
+ * whose controller joins the client registry and is
89
+ * removed on disconnect; a reload enqueues a frame onto it.
90
+ */
91
+ const sseResponse = (clients) => {
92
+ // Bridge seam: capture the controller so `start` can
93
+ // register it and `cancel` can remove the same one.
94
+ let registered;
95
+ return new Response(new ReadableStream({
96
+ start: (controller) => {
97
+ registered = controller;
98
+ clients.add(controller);
99
+ controller.enqueue(encodeUtf8(SSE_PRELUDE));
100
+ },
101
+ cancel: () => {
102
+ if (registered !== undefined) {
103
+ clients.delete(registered);
104
+ }
105
+ },
106
+ }), {
107
+ status: 200,
108
+ headers: {
109
+ "content-type": "text/event-stream",
110
+ "cache-control": "no-cache",
111
+ connection: "keep-alive",
112
+ },
113
+ });
114
+ };
115
+ /** Push a reload frame to every open live-reload stream. */
116
+ const notifyReload = (clients) => clients.forEach((controller) => controller.enqueue(encodeUtf8(RELOAD_FRAME)));
117
+ /** Whether a response carries an HTML body. */
118
+ const isHtml = (response) => {
119
+ const ct = response.headers.get("content-type");
120
+ return ct !== null && ct.includes("text/html");
121
+ };
122
+ /**
123
+ * Dev HTML headers: drop `content-length` (the appended
124
+ * script grew the body) and force `no-store` so a tunnel/
125
+ * CDN never serves stale inlined styles after an edit.
126
+ */
127
+ const devHtmlHeaders = (headers) => {
128
+ const next = new Headers([...headers].filter(([key]) => {
129
+ const lower = key.toLowerCase();
130
+ return (lower !== "content-length" &&
131
+ lower !== "cache-control");
132
+ }));
133
+ next.set("cache-control", "no-store");
134
+ return next;
135
+ };
136
+ /** Append the live-reload script to an HTML response. */
137
+ const decorateHtmlResponse = (response) => isHtml(response)
138
+ ? response
139
+ .text()
140
+ .then((html) => new Response(decorateDevHtml(html), {
141
+ status: response.status,
142
+ headers: devHtmlHeaders(response.headers),
143
+ }))
144
+ : Promise.resolve(response);
145
+ /**
146
+ * The wrapping dev handler: 403 a disallowed Host, answer
147
+ * the SSE route, otherwise run the live app Fetch and
148
+ * append the live-reload script to its HTML.
149
+ */
150
+ const devHandler = (state, allowedHosts) => (request) => {
151
+ const url = new URL(request.url);
152
+ if (!isAllowedHost(allowedHosts)(url.host)) {
153
+ return Promise.resolve(forbidden());
154
+ }
155
+ if (url.pathname === RELOAD_PATH) {
156
+ return Promise.resolve(sseResponse(state.clients));
157
+ }
158
+ return state
159
+ .appFetch(request)
160
+ .then(decorateHtmlResponse);
161
+ };
162
+ /** Resolve a config value that may be absolute or root-relative. */
163
+ const under = (root, path) => isAbsolute(path)
164
+ ? path
165
+ : resolve(root, path);
166
+ /**
167
+ * Register the dev-only cross-package source resolver
168
+ * (`bin/appAliasHook.mjs`) with the alias rules, so a
169
+ * dependency's `<prefix>/*` imports load from source and
170
+ * hot-reload. Registered later than the package's own hook
171
+ * so it runs first and short-circuits on an alias hit.
172
+ */
173
+ const registerSourceAliases = (aliases) => {
174
+ const hookUrl = new URL("../../../bin/appAliasHook.mjs", import.meta.url).href;
175
+ register(hookUrl, import.meta.url, {
176
+ data: {
177
+ aliases: aliases.map((a) => ({
178
+ prefix: a.prefix,
179
+ srcDir: a.srcDir,
180
+ })),
181
+ },
182
+ });
183
+ };
184
+ /**
185
+ * Map an fs.watch filename (relative to some watched root)
186
+ * to an absolute path by probing each root, or null when
187
+ * it matches none (a deletion) — the reload decision then
188
+ * reloads conservatively.
189
+ */
190
+ const toChanged = (roots, filename) => {
191
+ for (const root of roots) {
192
+ const abs = resolve(root, filename);
193
+ if (existsSync(abs)) {
194
+ return abs;
195
+ }
196
+ }
197
+ return null;
198
+ };
199
+ /**
200
+ * A single hot-reload cycle: refresh the graph, decide
201
+ * whether the change is relevant, then bump the version,
202
+ * re-import the entry (re-evaluating the changed
203
+ * subgraph), swap the live Fetch, and notify browsers. A
204
+ * failed re-import keeps the last good Fetch so a
205
+ * mid-edit save never crashes the loop.
206
+ */
207
+ const reload = async (state, entryUrl, watchAbs, aliases, filename) => {
208
+ state.graph = scanGraph(watchAbs, aliases);
209
+ const changed = toChanged(watchAbs, filename);
210
+ if (changed !== null &&
211
+ !shouldReload(state.graph, changed)) {
212
+ return;
213
+ }
214
+ state.version += 1;
215
+ try {
216
+ state.appFetch = await load(entryUrl, state.version);
217
+ }
218
+ catch (e) {
219
+ log(`plgg-bundle dev: reload failed (${msg(e)}) — keeping last good build`);
220
+ return;
221
+ }
222
+ notifyReload(state.clients);
223
+ log(`plgg-bundle dev: hot-reloaded (${filename})`);
224
+ };
225
+ /** The URL the dev server is reachable at. */
226
+ const devUrl = (port) => `http://localhost:${port}/`;
227
+ /** The port a listening server actually bound (honours port 0). */
228
+ const boundPort = (server, fallback) => {
229
+ const addr = server.address();
230
+ return typeof addr === "object" &&
231
+ addr !== null &&
232
+ typeof addr.port === "number"
233
+ ? addr.port
234
+ : fallback;
235
+ };
236
+ /**
237
+ * Start the dev server for a config's `dev` section: load
238
+ * the app Fetch, serve it over node:http, watch the source
239
+ * roots, and hot-reload on every relevant code/content
240
+ * edit. Resolves once the listener is up, with the
241
+ * reachable URL and a `close` handle.
242
+ */
243
+ export const runDevServer = async (config) => {
244
+ const dev = config.dev;
245
+ if (dev === undefined) {
246
+ throw new Error("plgg-bundle dev: config has no `dev` section");
247
+ }
248
+ const entryUrl = pathToFileURL(under(config.root, dev.entry)).href;
249
+ const watchAbs = dev.watch.map((w) => under(config.root, w));
250
+ // The app's own self-alias (source), plus any
251
+ // cross-package `sourceAliases` — the resolution rules for
252
+ // both the module graph AND the loader hook.
253
+ const aliases = [
254
+ {
255
+ prefix: config.alias.prefix,
256
+ srcDir: join(config.root, config.alias.srcRoot),
257
+ },
258
+ ...dev.sourceAliases.map((a) => ({
259
+ prefix: a.prefix,
260
+ srcDir: under(config.root, a.srcDir),
261
+ })),
262
+ ];
263
+ // Register the cross-package source resolver BEFORE the
264
+ // first entry import, so a dependency's `<prefix>/*`
265
+ // loads from source and hot-reloads. Only needed when the
266
+ // app pulls another package's source (a self-contained
267
+ // app resolves everything relatively / via its own hook).
268
+ if (dev.sourceAliases.length > 0) {
269
+ registerSourceAliases(aliases);
270
+ }
271
+ const state = {
272
+ version: 1,
273
+ appFetch: await load(entryUrl, 1),
274
+ graph: scanGraph(watchAbs, aliases),
275
+ clients: new Set(),
276
+ };
277
+ const handler = devHandler(state, dev.allowedHosts);
278
+ const options = {
279
+ port: dev.port,
280
+ };
281
+ const server = await new Promise((ready) => {
282
+ const s = serveFetch(options, () => handler, () => ready(s))();
283
+ });
284
+ const url = devUrl(boundPort(server, dev.port));
285
+ log(`plgg-bundle dev on ${url}`);
286
+ const watchers = watchRoots(watchAbs, (filename) => {
287
+ void reload(state, entryUrl, watchAbs, aliases, filename);
288
+ });
289
+ return {
290
+ url,
291
+ close: () => {
292
+ server.closeAllConnections();
293
+ server.close();
294
+ watchers.forEach((w) => w.close());
295
+ },
296
+ };
297
+ };
298
+ //# sourceMappingURL=devServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devServer.js","sourceRoot":"","sources":["../../../src/Dev/node/devServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type IncomingMessage, type ServerResponse, type Server } from "node:http";
2
+ import { type Fetch } from "plgg-bundle/Dev/model/Fetch";
3
+ /** How the dev server binds its node:http listener. */
4
+ export type ServeOptions = Readonly<{
5
+ port: number;
6
+ hostname?: string;
7
+ }>;
8
+ /** Convert a Node request (+ buffered body) into a Request. */
9
+ export declare const toRequest: (req: IncomingMessage, body: ArrayBuffer) => Request;
10
+ /** Write a Web Response back onto a Node ServerResponse. */
11
+ export declare const writeResponse: (res: ServerResponse, response: Response) => Promise<void>;
12
+ /**
13
+ * Serve a {@link Fetch} over a node:http server
14
+ * (data-last). The handler is read fresh from `current()`
15
+ * per request, so the dev loop can hot-swap the live
16
+ * `Fetch` without rebinding the listener.
17
+ */
18
+ export declare const serveFetch: (options: ServeOptions, current: () => Fetch, onListen?: () => void) => () => Server;
19
+ //# sourceMappingURL=httpAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpAdapter.d.ts","sourceRoot":"","sources":["../../../src/Dev/node/httpAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,MAAM,EACZ,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,KAAK,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAUzD,uDAAuD;AACvD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC,CAAC;AA4CH,+DAA+D;AAC/D,eAAO,MAAM,SAAS,GACpB,KAAK,eAAe,EACpB,MAAM,WAAW,KAChB,OAgBF,CAAC;AAqBF,4DAA4D;AAC5D,eAAO,MAAM,aAAa,GACxB,KAAK,cAAc,EACnB,UAAU,QAAQ,KACjB,OAAO,CAAC,IAAI,CAUd,CAAC;AAUF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAEnB,SAAS,YAAY,EACrB,SAAS,MAAM,KAAK,EACpB,WAAW,MAAM,IAAI,WAEnB,MAoBH,CAAC"}
@@ -0,0 +1,76 @@
1
+ import { createServer, } from "node:http";
2
+ import {} from "plgg-bundle/Dev/model/Fetch";
3
+ /** Buffer a request body into an ArrayBuffer. */
4
+ const collectBody = (req) => new Promise((resolve, reject) => {
5
+ const chunks = [];
6
+ req.on("data", (chunk) => {
7
+ chunks.push(chunk);
8
+ });
9
+ req.on("end", () => {
10
+ const merged = Buffer.concat(chunks);
11
+ const copy = new ArrayBuffer(merged.byteLength);
12
+ new Uint8Array(copy).set(merged);
13
+ resolve(copy);
14
+ });
15
+ req.on("error", reject);
16
+ });
17
+ /** Copy Node's incoming headers into Web Headers. */
18
+ const buildHeaders = (raw) => new Headers(Object.entries(raw).flatMap(([key, value]) => value === undefined
19
+ ? []
20
+ : typeof value === "string"
21
+ ? [[key, value]]
22
+ : value.map((v) => [
23
+ key,
24
+ v,
25
+ ])));
26
+ /** Convert a Node request (+ buffered body) into a Request. */
27
+ export const toRequest = (req, body) => {
28
+ const method = req.method ?? "GET";
29
+ const host = req.headers.host ?? "localhost";
30
+ const url = `http://${host}${req.url ?? "/"}`;
31
+ return method !== "GET" &&
32
+ method !== "HEAD" &&
33
+ body.byteLength > 0
34
+ ? new Request(url, {
35
+ method,
36
+ headers: buildHeaders(req.headers),
37
+ body,
38
+ })
39
+ : new Request(url, {
40
+ method,
41
+ headers: buildHeaders(req.headers),
42
+ });
43
+ };
44
+ /** Stream a Web ReadableStream of bytes onto the Node response. */
45
+ const pump = (reader, res) => reader.read().then((chunk) => chunk.done
46
+ ? new Promise((resolve) => res.end(() => resolve()))
47
+ : new Promise((resolve, reject) => res.write(Buffer.from(chunk.value), (e) => e ? reject(e) : resolve())).then(() => pump(reader, res)));
48
+ /** Write a Web Response back onto a Node ServerResponse. */
49
+ export const writeResponse = (res, response) => {
50
+ res.statusCode = response.status;
51
+ response.headers.forEach((value, key) => res.setHeader(key, value));
52
+ return response.body === null
53
+ ? new Promise((resolve) => res.end(() => resolve()))
54
+ : pump(response.body.getReader(), res);
55
+ };
56
+ /** Last-resort 500 when the adapter itself throws. */
57
+ const writeError = (res) => {
58
+ res.statusCode = 500;
59
+ res.end("Internal Server Error");
60
+ };
61
+ /**
62
+ * Serve a {@link Fetch} over a node:http server
63
+ * (data-last). The handler is read fresh from `current()`
64
+ * per request, so the dev loop can hot-swap the live
65
+ * `Fetch` without rebinding the listener.
66
+ */
67
+ export const serveFetch = (options, current, onListen) => () => {
68
+ const server = createServer((req, res) => collectBody(req)
69
+ .then((body) => current()(toRequest(req, body)))
70
+ .then((response) => writeResponse(res, response))
71
+ .catch(() => writeError(res)));
72
+ return options.hostname === undefined
73
+ ? server.listen(options.port, () => onListen?.())
74
+ : server.listen(options.port, options.hostname, () => onListen?.());
75
+ };
76
+ //# sourceMappingURL=httpAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"httpAdapter.js","sourceRoot":"","sources":["../../../src/Dev/node/httpAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { type ModuleGraph } from "plgg-bundle/Dev/model/ModuleGraph";
2
+ /**
3
+ * A self-alias resolution rule: `<prefix>`/`<prefix>/<sub>`
4
+ * → `<srcDir>`/`<srcDir>/<sub>`. One per package whose
5
+ * source participates in dev (the app's own, plus any
6
+ * cross-package `sourceAliases`).
7
+ */
8
+ export type Alias = Readonly<{
9
+ prefix: string;
10
+ srcDir: string;
11
+ }>;
12
+ /**
13
+ * Scan the watch roots and build the local
14
+ * {@link ModuleGraph}, resolving relative AND aliased
15
+ * imports (every rule in `aliases`) so cross-package source
16
+ * edges are captured. Unreadable roots/files are skipped (a
17
+ * scan is best-effort — the reload decision falls back to
18
+ * reloading when the graph is empty).
19
+ */
20
+ export declare const scanGraph: (roots: ReadonlyArray<string>, aliases: ReadonlyArray<Alias>) => ModuleGraph;
21
+ //# sourceMappingURL=scanGraph.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanGraph.d.ts","sourceRoot":"","sources":["../../../src/Dev/node/scanGraph.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAkBrE;;;;;GAKG;AACH,MAAM,MAAM,KAAK,GAAG,QAAQ,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,GACpB,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,SAAS,aAAa,CAAC,KAAK,CAAC,KAC5B,WAKA,CAAC"}
@@ -0,0 +1,145 @@
1
+ import { readdirSync, readFileSync, statSync, } from "node:fs";
2
+ import { resolve, dirname, join, } from "node:path";
3
+ import { parseImports } from "plgg-bundle/Dev/usecase/parseImports";
4
+ import { buildGraph } from "plgg-bundle/Dev/usecase/buildGraph";
5
+ import {} from "plgg-bundle/Dev/model/ModuleGraph";
6
+ // The effectful graph scan: walk the watch roots, read
7
+ // each source file, and resolve its LOCAL import edges
8
+ // (relative specifiers + the app's own self-alias) to
9
+ // absolute paths. Feeds the pure `buildGraph` /
10
+ // reload-decision. In `Dev/node/` (fs seam), excluded from
11
+ // the coverage threshold and exercised by the fixture PoC.
12
+ /** Source extensions whose imports are scanned. */
13
+ const SOURCE_EXT = [
14
+ ".ts",
15
+ ".tsx",
16
+ ".mts",
17
+ ".js",
18
+ ".mjs",
19
+ ];
20
+ /**
21
+ * Scan the watch roots and build the local
22
+ * {@link ModuleGraph}, resolving relative AND aliased
23
+ * imports (every rule in `aliases`) so cross-package source
24
+ * edges are captured. Unreadable roots/files are skipped (a
25
+ * scan is best-effort — the reload decision falls back to
26
+ * reloading when the graph is empty).
27
+ */
28
+ export const scanGraph = (roots, aliases) => buildGraph(sourceFiles(roots).flatMap((file) => edgesOf(file, aliases)));
29
+ /** Every source file under the roots (recursive, de-duped). */
30
+ const sourceFiles = (roots) => {
31
+ const seen = new Set();
32
+ for (const root of roots) {
33
+ for (const abs of walk(root)) {
34
+ seen.add(abs);
35
+ }
36
+ }
37
+ return [...seen];
38
+ };
39
+ /**
40
+ * Directories never descended into during the graph scan —
41
+ * dependency trees, build output, VCS. A watch root of `.`
42
+ * (a package dir) would otherwise pull thousands of
43
+ * `node_modules` files into the graph.
44
+ */
45
+ const SKIP_DIRS = [
46
+ "node_modules",
47
+ "dist",
48
+ ".git",
49
+ ];
50
+ /**
51
+ * Recursively list source files under a directory, pruning
52
+ * {@link SKIP_DIRS}. A manual walk (not `readdirSync`'s
53
+ * `recursive`) so a huge `node_modules` is never read.
54
+ */
55
+ const walk = (root) => {
56
+ let entries;
57
+ try {
58
+ entries = readdirSync(root, {
59
+ withFileTypes: true,
60
+ });
61
+ }
62
+ catch {
63
+ return [];
64
+ }
65
+ return entries.flatMap((entry) => {
66
+ const abs = join(root, entry.name);
67
+ if (entry.isDirectory()) {
68
+ return SKIP_DIRS.includes(entry.name)
69
+ ? []
70
+ : walk(abs);
71
+ }
72
+ return entry.isFile() &&
73
+ SOURCE_EXT.some((e) => entry.name.endsWith(e))
74
+ ? [abs]
75
+ : [];
76
+ });
77
+ };
78
+ /** The resolved local edges a single file imports. */
79
+ const edgesOf = (file, aliases) => {
80
+ const source = read(file);
81
+ if (source === null) {
82
+ return [];
83
+ }
84
+ return parseImports(source).flatMap((spec) => {
85
+ const to = resolveLocal(file, spec, aliases);
86
+ return to === null
87
+ ? []
88
+ : [{ from: file, to }];
89
+ });
90
+ };
91
+ /** Read a file, or null when it cannot be read. */
92
+ const read = (file) => {
93
+ try {
94
+ return readFileSync(file, "utf8");
95
+ }
96
+ catch {
97
+ return null;
98
+ }
99
+ };
100
+ /**
101
+ * Resolve a specifier to an absolute local file, or null
102
+ * for a package / `node:` specifier. Handles relative
103
+ * paths and every alias rule (`prefix` / `prefix/…`); tries
104
+ * the path itself, `.ts`, and `/index.ts`.
105
+ */
106
+ const resolveLocal = (from, spec, aliases) => {
107
+ const base = baseOf(from, spec, aliases);
108
+ if (base === null) {
109
+ return null;
110
+ }
111
+ const candidates = [
112
+ base,
113
+ `${base}.ts`,
114
+ join(base, "index.ts"),
115
+ ];
116
+ // A FILE, never a directory: a bare `<prefix>` base is
117
+ // the src dir (which exists) — prefer its `index.ts`.
118
+ return (candidates.find(isFile) ?? null);
119
+ };
120
+ /** Whether a path exists and is a regular file. */
121
+ const isFile = (path) => {
122
+ try {
123
+ return statSync(path).isFile();
124
+ }
125
+ catch {
126
+ return false;
127
+ }
128
+ };
129
+ /** The pre-extension base path a specifier points at. */
130
+ const baseOf = (from, spec, aliases) => {
131
+ if (spec.startsWith("./") ||
132
+ spec.startsWith("../")) {
133
+ return resolve(dirname(from), spec);
134
+ }
135
+ for (const alias of aliases) {
136
+ if (spec === alias.prefix) {
137
+ return alias.srcDir;
138
+ }
139
+ if (spec.startsWith(`${alias.prefix}/`)) {
140
+ return join(alias.srcDir, spec.slice(alias.prefix.length + 1));
141
+ }
142
+ }
143
+ return null;
144
+ };
145
+ //# sourceMappingURL=scanGraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanGraph.js","sourceRoot":"","sources":["../../../src/Dev/node/scanGraph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type FSWatcher } from "node:fs";
2
+ /**
3
+ * Watch each root recursively; coalesce bursts onto a
4
+ * single `onChange` carrying the last changed filename.
5
+ * Returns the watchers so the caller owns their lifecycle.
6
+ * A root that cannot be watched is skipped rather than
7
+ * crashing the dev loop.
8
+ */
9
+ export declare const watchRoots: (roots: ReadonlyArray<string>, onChange: (filename: string) => void) => ReadonlyArray<FSWatcher>;
10
+ //# sourceMappingURL=watch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watch.d.ts","sourceRoot":"","sources":["../../../src/Dev/node/watch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AAYhD;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,GACrB,OAAO,aAAa,CAAC,MAAM,CAAC,EAC5B,UAAU,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,KACnC,aAAa,CAAC,SAAS,CA+BzB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { watch } from "node:fs";
2
+ // The fs.watch seam: a debounced, recursive watcher over
3
+ // several source roots. One save can emit multiple events,
4
+ // so an imperative timer coalesces them onto a single
5
+ // `onChange(path)`. Kept in `Dev/node/` (effectful,
6
+ // excluded from the coverage threshold) — the pure reload
7
+ // decision it feeds is unit-tested separately.
8
+ /** fs.watch debounce window in ms. */
9
+ const DEBOUNCE_MS = 80;
10
+ /**
11
+ * Watch each root recursively; coalesce bursts onto a
12
+ * single `onChange` carrying the last changed filename.
13
+ * Returns the watchers so the caller owns their lifecycle.
14
+ * A root that cannot be watched is skipped rather than
15
+ * crashing the dev loop.
16
+ */
17
+ export const watchRoots = (roots, onChange) => {
18
+ // Debounce seam: one shared timer + the latest filename
19
+ // across all roots.
20
+ let pending;
21
+ let latest = "";
22
+ const fire = (filename) => {
23
+ latest = filename;
24
+ clearTimeout(pending);
25
+ pending = setTimeout(() => {
26
+ onChange(latest);
27
+ }, DEBOUNCE_MS);
28
+ };
29
+ return roots.flatMap((root) => {
30
+ try {
31
+ return [
32
+ watch(root, { recursive: true }, (_event, filename) => {
33
+ if (filename !== null) {
34
+ fire(filename);
35
+ }
36
+ }),
37
+ ];
38
+ }
39
+ catch {
40
+ return [];
41
+ }
42
+ });
43
+ };
44
+ //# sourceMappingURL=watch.js.map