tungsten 0.3.1 → 0.3.3

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 (291) hide show
  1. package/dist/.build-complete +1 -0
  2. package/dist/Components.d.ts +2 -1
  3. package/dist/Components.d.ts.map +1 -1
  4. package/dist/Components.js +10 -1
  5. package/dist/DomRegion.js +1 -1
  6. package/dist/Framework.d.ts +2 -0
  7. package/dist/Framework.d.ts.map +1 -1
  8. package/dist/Framework.js +68 -57
  9. package/dist/FrameworkConfig.d.ts +6 -0
  10. package/dist/FrameworkConfig.d.ts.map +1 -1
  11. package/dist/FunctionComponentStandIn.d.ts +2 -0
  12. package/dist/FunctionComponentStandIn.d.ts.map +1 -1
  13. package/dist/FunctionComponentStandIn.js +10 -1
  14. package/dist/Instance/Instance.d.ts.map +1 -1
  15. package/dist/Instance/Instance.js +18 -1
  16. package/dist/Instance/InstanceConfig.d.ts +1 -0
  17. package/dist/Instance/InstanceConfig.d.ts.map +1 -1
  18. package/dist/PopMessage.type.d.ts +6 -0
  19. package/dist/PopMessage.type.d.ts.map +1 -0
  20. package/dist/PopMessage.type.js +1 -0
  21. package/dist/Servers/DevServer.d.ts +4 -0
  22. package/dist/Servers/DevServer.d.ts.map +1 -1
  23. package/dist/Servers/DevServer.js +116 -13
  24. package/dist/Servers/MatchedRouteInfo.d.ts +1 -1
  25. package/dist/Servers/MatchedRouteInfo.d.ts.map +1 -1
  26. package/dist/Servers/ProdServer.d.ts +1 -0
  27. package/dist/Servers/ProdServer.d.ts.map +1 -1
  28. package/dist/Servers/ProdServer.js +79 -5
  29. package/dist/Servers/devErrorPageAutoRetry.d.ts +4 -0
  30. package/dist/Servers/devErrorPageAutoRetry.d.ts.map +1 -0
  31. package/dist/Servers/devErrorPageAutoRetry.js +26 -0
  32. package/dist/Servers/hono/DevServerHono.js +25 -29
  33. package/dist/Servers/hono/ProdServerHono.js +49 -142
  34. package/dist/Servers/hono/TungstenServerHono.d.ts +1 -1
  35. package/dist/Servers/hono/TungstenServerHono.d.ts.map +1 -1
  36. package/dist/Servers/hono/TungstenServerHono.js +12 -29
  37. package/dist/Servers/routing.d.ts.map +1 -1
  38. package/dist/Servers/routing.js +10 -6
  39. package/dist/Servers/tungstenCorePrivateEnvSchema.d.ts +0 -3
  40. package/dist/Servers/tungstenCorePrivateEnvSchema.d.ts.map +1 -1
  41. package/dist/Servers/tungstenCorePrivateEnvSchema.js +3 -3
  42. package/dist/Servers/tungstenCorePublicEnvSchema.d.ts +8 -0
  43. package/dist/Servers/tungstenCorePublicEnvSchema.d.ts.map +1 -0
  44. package/dist/Servers/tungstenCorePublicEnvSchema.js +14 -0
  45. package/dist/Store/InternalStoreSchema.d.ts +2 -0
  46. package/dist/Store/InternalStoreSchema.d.ts.map +1 -1
  47. package/dist/Store/InternalStoreSchema.js +1 -0
  48. package/dist/api/Request.d.ts +1 -1
  49. package/dist/api/Request.d.ts.map +1 -1
  50. package/dist/api/Response.d.ts +1 -1
  51. package/dist/api/Response.d.ts.map +1 -1
  52. package/dist/api/getExport.d.ts.map +1 -1
  53. package/dist/api/getExport.js +2 -1
  54. package/dist/babelPlugins/BabelAddDevCacheBust.d.ts +11 -0
  55. package/dist/babelPlugins/BabelAddDevCacheBust.d.ts.map +1 -0
  56. package/dist/babelPlugins/BabelAddDevCacheBust.js +68 -0
  57. package/dist/babelPlugins/BabelTypes.d.ts +2 -2
  58. package/dist/babelPlugins/BabelTypes.d.ts.map +1 -1
  59. package/dist/babelPlugins/BabelTypes.js +0 -1
  60. package/dist/bin/commands/build.d.ts.map +1 -1
  61. package/dist/bin/commands/build.js +3 -0
  62. package/dist/bin/commands/dev.d.ts.map +1 -1
  63. package/dist/bin/commands/dev.js +16 -3
  64. package/dist/bin/commands/devmon.d.ts +2 -0
  65. package/dist/bin/commands/devmon.d.ts.map +1 -0
  66. package/dist/bin/commands/devmon.js +66 -0
  67. package/dist/bin/index.d.ts.map +1 -1
  68. package/dist/bin/index.js +6 -0
  69. package/dist/booleanAttributeValue.d.ts +21 -0
  70. package/dist/booleanAttributeValue.d.ts.map +1 -0
  71. package/dist/booleanAttributeValue.js +23 -0
  72. package/dist/build/compileJavascript.js +1 -1
  73. package/dist/build/compileUserApp.d.ts +2 -1
  74. package/dist/build/compileUserApp.d.ts.map +1 -1
  75. package/dist/build/compileUserApp.js +10 -9
  76. package/dist/build/createInstanceConfigFile.js +1 -1
  77. package/dist/build/makeBabelUserDevConfig.d.ts.map +1 -1
  78. package/dist/build/makeBabelUserDevConfig.js +6 -1
  79. package/dist/compat/types.d.ts +1 -1
  80. package/dist/compat/types.d.ts.map +1 -1
  81. package/dist/components/PopMessages.d.ts +12 -0
  82. package/dist/components/PopMessages.d.ts.map +1 -0
  83. package/dist/components/PopMessages.js +45 -0
  84. package/dist/defaultConfig.d.ts +3 -0
  85. package/dist/defaultConfig.d.ts.map +1 -1
  86. package/dist/defaultConfig.js +4 -1
  87. package/dist/env/Interfaces.d.ts +2 -1
  88. package/dist/env/Interfaces.d.ts.map +1 -1
  89. package/dist/env/getEnvSchemas.d.ts +1 -1
  90. package/dist/env/getEnvSchemas.d.ts.map +1 -1
  91. package/dist/env/getEnvSchemas.js +2 -1
  92. package/dist/env/publicEnv.d.ts.map +1 -1
  93. package/dist/env/publicEnv.js +4 -1
  94. package/dist/frameworkConfigSchema.d.ts +4 -0
  95. package/dist/frameworkConfigSchema.d.ts.map +1 -1
  96. package/dist/frameworkConfigSchema.js +2 -1
  97. package/dist/getComponent.d.ts.map +1 -1
  98. package/dist/getComponent.js +2 -1
  99. package/dist/getRoutes.d.ts.map +1 -1
  100. package/dist/getRoutes.js +2 -1
  101. package/dist/hmr/applyHmrModule.d.ts +11 -0
  102. package/dist/hmr/applyHmrModule.d.ts.map +1 -0
  103. package/dist/hmr/applyHmrModule.js +78 -0
  104. package/dist/hmr/componentIdentity.d.ts +9 -0
  105. package/dist/hmr/componentIdentity.d.ts.map +1 -0
  106. package/dist/hmr/componentIdentity.js +17 -0
  107. package/dist/hmr/instanceRegistry.d.ts +4 -0
  108. package/dist/hmr/instanceRegistry.d.ts.map +1 -0
  109. package/dist/hmr/instanceRegistry.js +6 -0
  110. package/dist/hmr/liveReloadHub.d.ts +10 -0
  111. package/dist/hmr/liveReloadHub.d.ts.map +1 -0
  112. package/dist/{dev → hmr}/liveReloadHub.js +8 -2
  113. package/dist/hmr/refreshStylesheets.d.ts +2 -0
  114. package/dist/hmr/refreshStylesheets.d.ts.map +1 -0
  115. package/dist/hmr/refreshStylesheets.js +26 -0
  116. package/dist/hooks/index.d.ts +1 -0
  117. package/dist/hooks/index.d.ts.map +1 -1
  118. package/dist/hooks/index.js +1 -0
  119. package/dist/hooks/useInstance.d.ts +3 -0
  120. package/dist/hooks/useInstance.d.ts.map +1 -0
  121. package/dist/hooks/useInstance.js +4 -0
  122. package/dist/hydrate/hydrate.d.ts +10 -0
  123. package/dist/hydrate/hydrate.d.ts.map +1 -1
  124. package/dist/hydrate/hydrate.js +81 -19
  125. package/dist/hydrate/reconcileHydratedAttributes.d.ts.map +1 -1
  126. package/dist/hydrate/reconcileHydratedAttributes.js +14 -5
  127. package/dist/hydrate/renderHydrationMismatchBanner.d.ts +7 -0
  128. package/dist/hydrate/renderHydrationMismatchBanner.d.ts.map +1 -0
  129. package/dist/hydrate/renderHydrationMismatchBanner.js +69 -0
  130. package/dist/importDevModuleWithRetry.d.ts +3 -0
  131. package/dist/importDevModuleWithRetry.d.ts.map +1 -0
  132. package/dist/importDevModuleWithRetry.js +46 -0
  133. package/dist/indexInner.d.ts +8 -0
  134. package/dist/indexInner.d.ts.map +1 -1
  135. package/dist/indexInner.js +7 -1
  136. package/dist/makeInstanceConfigFromFrameworkConfig.d.ts.map +1 -1
  137. package/dist/makeInstanceConfigFromFrameworkConfig.js +2 -1
  138. package/dist/pop.d.ts +10 -0
  139. package/dist/pop.d.ts.map +1 -0
  140. package/dist/pop.js +49 -0
  141. package/dist/rawHtml/filterContentNode.d.ts +20 -0
  142. package/dist/rawHtml/filterContentNode.d.ts.map +1 -0
  143. package/dist/rawHtml/filterContentNode.js +96 -0
  144. package/dist/rawHtml/parseHtml.d.ts +14 -0
  145. package/dist/rawHtml/parseHtml.d.ts.map +1 -1
  146. package/dist/rawHtml/parseHtml.js +4 -4
  147. package/dist/rawHtml/sanitizeHtml.d.ts +17 -0
  148. package/dist/rawHtml/sanitizeHtml.d.ts.map +1 -0
  149. package/dist/rawHtml/sanitizeHtml.js +19 -0
  150. package/dist/render/HeadData.d.ts +2 -0
  151. package/dist/render/HeadData.d.ts.map +1 -1
  152. package/dist/render/contentNodeToHtml.d.ts +18 -0
  153. package/dist/render/contentNodeToHtml.d.ts.map +1 -0
  154. package/dist/render/contentNodeToHtml.js +66 -0
  155. package/dist/render/contentToHtml.d.ts.map +1 -1
  156. package/dist/render/contentToHtml.js +3 -1
  157. package/dist/render/processHead.d.ts.map +1 -1
  158. package/dist/render/processHead.js +53 -6
  159. package/dist/render/renderingTreeToHtml.d.ts.map +1 -1
  160. package/dist/render/renderingTreeToHtml.js +8 -1
  161. package/dist/routing/ErrorRouteType.d.ts +6 -0
  162. package/dist/routing/ErrorRouteType.d.ts.map +1 -0
  163. package/dist/routing/ErrorRouteType.js +1 -0
  164. package/dist/routing/RouteTypes.d.ts +2 -1
  165. package/dist/routing/RouteTypes.d.ts.map +1 -1
  166. package/dist/routing/Routes.d.ts +5 -0
  167. package/dist/routing/Routes.d.ts.map +1 -1
  168. package/dist/routing/TungstenErrorInfo.d.ts +6 -0
  169. package/dist/routing/TungstenErrorInfo.d.ts.map +1 -0
  170. package/dist/routing/TungstenErrorInfo.js +6 -0
  171. package/dist/style/styleContentSxy.js +21 -0
  172. package/dist/testing/hydrateTestApp.d.ts +38 -0
  173. package/dist/testing/hydrateTestApp.d.ts.map +1 -0
  174. package/dist/testing/hydrateTestApp.js +242 -0
  175. package/dist/testing/index.d.ts +4 -3
  176. package/dist/testing/index.d.ts.map +1 -1
  177. package/dist/testing/index.js +16 -2
  178. package/dist/timeProfiler.d.ts +6 -0
  179. package/dist/timeProfiler.d.ts.map +1 -0
  180. package/dist/timeProfiler.js +31 -0
  181. package/dist/update/integrateUpdateVdom.d.ts +16 -1
  182. package/dist/update/integrateUpdateVdom.d.ts.map +1 -1
  183. package/dist/update/integrateUpdateVdom.js +116 -7
  184. package/dist/warnOnFrameworkChange.d.ts +2 -0
  185. package/dist/warnOnFrameworkChange.d.ts.map +1 -0
  186. package/dist/warnOnFrameworkChange.js +27 -0
  187. package/package.json +18 -16
  188. package/dist/Instance/gotoRedirect.sxyt.d.ts +0 -2
  189. package/dist/Instance/gotoRedirect.sxyt.d.ts.map +0 -1
  190. package/dist/Instance/gotoRedirect.sxyt.js +0 -148
  191. package/dist/Instance/runTrackedWork.sxyt.d.ts +0 -2
  192. package/dist/Instance/runTrackedWork.sxyt.d.ts.map +0 -1
  193. package/dist/Instance/runTrackedWork.sxyt.js +0 -35
  194. package/dist/_client/cjsHelpers.sxyt.d.ts +0 -2
  195. package/dist/_client/cjsHelpers.sxyt.d.ts.map +0 -1
  196. package/dist/_client/cjsHelpers.sxyt.js +0 -45
  197. package/dist/auth/passwordHashing.sxyt.d.ts +0 -2
  198. package/dist/auth/passwordHashing.sxyt.d.ts.map +0 -1
  199. package/dist/auth/passwordHashing.sxyt.js +0 -46
  200. package/dist/auth/ref/checkPasswordResetToken.sxyt.d.ts +0 -2
  201. package/dist/auth/ref/checkPasswordResetToken.sxyt.d.ts.map +0 -1
  202. package/dist/auth/ref/checkPasswordResetToken.sxyt.js +0 -40
  203. package/dist/auth/ref/createPasswordResetToken.sxyt.d.ts +0 -2
  204. package/dist/auth/ref/createPasswordResetToken.sxyt.d.ts.map +0 -1
  205. package/dist/auth/ref/createPasswordResetToken.sxyt.js +0 -10
  206. package/dist/babelPlugins/fixImportsInSassErrorMessage.sxyt.d.ts +0 -2
  207. package/dist/babelPlugins/fixImportsInSassErrorMessage.sxyt.d.ts.map +0 -1
  208. package/dist/babelPlugins/fixImportsInSassErrorMessage.sxyt.js +0 -108
  209. package/dist/babelPlugins/transformPackageImports/resolveBareImport.sxyt.d.ts +0 -2
  210. package/dist/babelPlugins/transformPackageImports/resolveBareImport.sxyt.d.ts.map +0 -1
  211. package/dist/babelPlugins/transformPackageImports/resolveBareImport.sxyt.js +0 -104
  212. package/dist/bin/commands/compile.sxyt.d.ts +0 -2
  213. package/dist/bin/commands/compile.sxyt.d.ts.map +0 -1
  214. package/dist/bin/commands/compile.sxyt.js +0 -255
  215. package/dist/build/modifySassImports.sxyt.d.ts +0 -2
  216. package/dist/build/modifySassImports.sxyt.d.ts.map +0 -1
  217. package/dist/build/modifySassImports.sxyt.js +0 -55
  218. package/dist/build/sassImportParser.sxyt.d.ts +0 -2
  219. package/dist/build/sassImportParser.sxyt.d.ts.map +0 -1
  220. package/dist/build/sassImportParser.sxyt.js +0 -110
  221. package/dist/build/scssImportParserChatgpt.sxyt.d.ts +0 -2
  222. package/dist/build/scssImportParserChatgpt.sxyt.d.ts.map +0 -1
  223. package/dist/build/scssImportParserChatgpt.sxyt.js +0 -120
  224. package/dist/clone.sxyt.d.ts +0 -2
  225. package/dist/clone.sxyt.d.ts.map +0 -1
  226. package/dist/clone.sxyt.js +0 -24
  227. package/dist/componentProxyHandlers.sxyt.d.ts +0 -2
  228. package/dist/componentProxyHandlers.sxyt.d.ts.map +0 -1
  229. package/dist/componentProxyHandlers.sxyt.js +0 -130
  230. package/dist/components/RawHtml.sxyt.d.ts +0 -2
  231. package/dist/components/RawHtml.sxyt.d.ts.map +0 -1
  232. package/dist/components/RawHtml.sxyt.js +0 -104
  233. package/dist/components/bindable/BindableSelect.sxyt.d.ts +0 -2
  234. package/dist/components/bindable/BindableSelect.sxyt.d.ts.map +0 -1
  235. package/dist/components/bindable/BindableSelect.sxyt.js +0 -186
  236. package/dist/dev/liveReloadHub.d.ts +0 -6
  237. package/dist/dev/liveReloadHub.d.ts.map +0 -1
  238. package/dist/env/injectEnv.sxyt.d.ts +0 -2
  239. package/dist/env/injectEnv.sxyt.d.ts.map +0 -1
  240. package/dist/env/injectEnv.sxyt.js +0 -20
  241. package/dist/env/parseEnv.sxyt.d.ts +0 -2
  242. package/dist/env/parseEnv.sxyt.d.ts.map +0 -1
  243. package/dist/env/parseEnv.sxyt.js +0 -11
  244. package/dist/findProjectDir.sxyt.d.ts +0 -2
  245. package/dist/findProjectDir.sxyt.d.ts.map +0 -1
  246. package/dist/findProjectDir.sxyt.js +0 -82
  247. package/dist/hydrate/reconcileHydratedAttributes.sxyt.d.ts +0 -2
  248. package/dist/hydrate/reconcileHydratedAttributes.sxyt.d.ts.map +0 -1
  249. package/dist/hydrate/reconcileHydratedAttributes.sxyt.js +0 -173
  250. package/dist/innerHtmlFromProps.sxyt.d.ts +0 -2
  251. package/dist/innerHtmlFromProps.sxyt.d.ts.map +0 -1
  252. package/dist/innerHtmlFromProps.sxyt.js +0 -99
  253. package/dist/postcssPlugins/parseSelectors.sxyt.d.ts +0 -2
  254. package/dist/postcssPlugins/parseSelectors.sxyt.d.ts.map +0 -1
  255. package/dist/postcssPlugins/parseSelectors.sxyt.js +0 -62
  256. package/dist/postcssPlugins/parseSelectorsRich.sxyt.d.ts +0 -2
  257. package/dist/postcssPlugins/parseSelectorsRich.sxyt.d.ts.map +0 -1
  258. package/dist/postcssPlugins/parseSelectorsRich.sxyt.js +0 -155
  259. package/dist/rawHtml/parseHtml.sxyt.d.ts +0 -2
  260. package/dist/rawHtml/parseHtml.sxyt.d.ts.map +0 -1
  261. package/dist/rawHtml/parseHtml.sxyt.js +0 -239
  262. package/dist/render/getFunctionBodyAsString.sxyt.d.ts +0 -2
  263. package/dist/render/getFunctionBodyAsString.sxyt.d.ts.map +0 -1
  264. package/dist/render/getFunctionBodyAsString.sxyt.js +0 -37
  265. package/dist/render/processProps.sxyt.d.ts +0 -2
  266. package/dist/render/processProps.sxyt.d.ts.map +0 -1
  267. package/dist/render/processProps.sxyt.js +0 -90
  268. package/dist/routing/compareRequestToRegex.sxyt.d.ts +0 -2
  269. package/dist/routing/compareRequestToRegex.sxyt.d.ts.map +0 -1
  270. package/dist/routing/compareRequestToRegex.sxyt.js +0 -65
  271. package/dist/routing/getPathPriority.sxyt.d.ts +0 -2
  272. package/dist/routing/getPathPriority.sxyt.d.ts.map +0 -1
  273. package/dist/routing/getPathPriority.sxyt.js +0 -24
  274. package/dist/routing/matchPath.sxyt.d.ts +0 -2
  275. package/dist/routing/matchPath.sxyt.d.ts.map +0 -1
  276. package/dist/routing/matchPath.sxyt.js +0 -41
  277. package/dist/routing/patternToRegex.sxyt.d.ts +0 -2
  278. package/dist/routing/patternToRegex.sxyt.d.ts.map +0 -1
  279. package/dist/routing/patternToRegex.sxyt.js +0 -69
  280. package/dist/routing/splitRequest.sxyt.d.ts +0 -2
  281. package/dist/routing/splitRequest.sxyt.d.ts.map +0 -1
  282. package/dist/routing/splitRequest.sxyt.js +0 -47
  283. package/dist/style/jssToCss.sxyt.d.ts +0 -2
  284. package/dist/style/jssToCss.sxyt.d.ts.map +0 -1
  285. package/dist/style/jssToCss.sxyt.js +0 -17
  286. package/dist/testing/createTestApp.sxyt.d.ts +0 -2
  287. package/dist/testing/createTestApp.sxyt.d.ts.map +0 -1
  288. package/dist/testing/createTestApp.sxyt.js +0 -470
  289. package/dist/testing/ensureTestEnvLoaded.sxyt.d.ts +0 -2
  290. package/dist/testing/ensureTestEnvLoaded.sxyt.d.ts.map +0 -1
  291. package/dist/testing/ensureTestEnvLoaded.sxyt.js +0 -20
@@ -2,7 +2,8 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
2
2
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
3
3
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
4
4
  import express from 'express';
5
- import { join } from 'path';
5
+ import { join, relative } from 'path';
6
+ import slash from 'slash';
6
7
  import "../moduleReloader.js"; // V important ES module cache control
7
8
  import { allObj as promiseAllObj } from 'sxy-lib/promises.js';
8
9
  import { staticFolder, assetsFolder, publicFolder, packagesFolder, clientFolder, componentCssFolder } from "../settings.js";
@@ -24,9 +25,12 @@ import { TungstenServer } from "./TungstenServer.js";
24
25
  import { portError } from "./portError.js";
25
26
  import { loadEnvsDev } from "./loadEnvsDev.js";
26
27
  import { initStores } from "./initStores.js";
28
+ import { makeTungstenErrorInfo } from "../routing/TungstenErrorInfo.js";
27
29
  import { MatchedRoute } from "../routing/MatchedRoute.js";
28
30
  import { iterationQueryString } from "../iterationQueryString.js";
29
- import { onReloadEvent } from "../dev/liveReloadHub.js";
31
+ import { onReloadEvent } from "../hmr/liveReloadHub.js";
32
+ import { importDevModuleWithRetry } from "../importDevModuleWithRetry.js";
33
+ import { devErrorPageAutoRetryScript } from "./devErrorPageAutoRetry.js";
30
34
  //import cookieParser from 'cookie-parser'
31
35
  function debug(...texts) {
32
36
  // console.log(...texts)
@@ -51,6 +55,10 @@ export class DevServer extends TungstenServer {
51
55
  _defineProperty(this, "serverIterationCount", 0);
52
56
  _defineProperty(this, "liveReloadClients", new Set());
53
57
  _defineProperty(this, "unsubscribeReload", null);
58
+ // Sent as the first event on every live-reload connection (see handleLiveReloadStream), so
59
+ // the client can tell a fresh reconnect (server process restarted, e.g. by tungsten devmon)
60
+ // apart from its first-ever connection, and reload only in the former case.
61
+ _defineProperty(this, "bootId", `${Date.now()}-${Math.random()}`);
54
62
  _defineProperty(this, "addServerMiddleware", serverMiddleware => {
55
63
  //console.log('addServerMiddleware')
56
64
  const [middlewareFile, middlewareExportName, middlewarePath] = serverMiddleware;
@@ -83,7 +91,7 @@ export class DevServer extends TungstenServer {
83
91
  //const load = await createLoad(import.meta.url, sxyLoaderConfig)
84
92
  const fullFilePath = 'file://' + join(this.compilationInfo.codeLocation, middlewareFile);
85
93
  //const middlewareModule = await load(fullFilePath)
86
- const middlewareModule = await import(iterationQueryString(fullFilePath, this.serverIterationCount++, 'middleware'));
94
+ const middlewareModule = await importDevModuleWithRetry(iterationQueryString(fullFilePath, this.serverIterationCount++, 'middleware'));
87
95
  if (!(middlewareExportName in middlewareModule)) {
88
96
  throwError('DevServer', `export ${middlewareExportName} not found in ${middlewareFile}` + ` when trying to load server middleware`);
89
97
  }
@@ -121,6 +129,9 @@ export class DevServer extends TungstenServer {
121
129
  res.setHeader('Cache-Control', 'no-cache');
122
130
  res.setHeader('Connection', 'keep-alive');
123
131
  res.flushHeaders();
132
+ res.write(`event: boot\ndata: ${JSON.stringify({
133
+ bootId: this.bootId
134
+ })}\n\n`);
124
135
  this.liveReloadClients.add(res);
125
136
  req.on('close', () => {
126
137
  this.liveReloadClients.delete(res);
@@ -128,21 +139,43 @@ export class DevServer extends TungstenServer {
128
139
  });
129
140
  _defineProperty(this, "reloadDebounceTimer", null);
130
141
  _defineProperty(this, "pendingReloadKind", null);
131
- _defineProperty(this, "broadcastReloadEvent", kind => {
142
+ _defineProperty(this, "pendingReloadFiles", new Set());
143
+ _defineProperty(this, "broadcastReloadEvent", ({
144
+ kind,
145
+ file
146
+ }) => {
132
147
  // A single save can fire several filesystem events in quick succession -
133
148
  // tsc's writer often truncates a file before writing its new contents, and each
134
149
  // of those steps runs back through this framework's own watch -> transform -> write
135
150
  // cycle. Reloading on the first signal can land the browser on a momentarily
136
151
  // half-written file, so wait for the burst to go quiet before actually reloading.
137
152
  this.pendingReloadKind = this.pendingReloadKind === 'js' || kind === 'js' ? 'js' : kind;
153
+ if (file !== undefined) this.pendingReloadFiles.add(file);
138
154
  if (this.reloadDebounceTimer !== null) clearTimeout(this.reloadDebounceTimer);
139
155
  this.reloadDebounceTimer = setTimeout(() => {
140
156
  const finalKind = this.pendingReloadKind ?? kind;
141
- for (const client of this.liveReloadClients) client.write(`event: ${finalKind}\ndata: reload\n\n`);
157
+ // 'files' carries the compiled-URL path of every changed component file, so the
158
+ // browser can attempt an in-place HMR swap instead of a full reload. Left empty for
159
+ // css events, or if a js event arrived with no known source file - the client falls
160
+ // back to a full reload in both cases.
161
+ const files = finalKind === 'js' ? [...this.pendingReloadFiles].map(this.sourceFileToUrlPath) : [];
162
+ const payload = JSON.stringify({
163
+ files
164
+ });
165
+ for (const client of this.liveReloadClients) client.write(`event: ${finalKind}\ndata: ${payload}\n\n`);
142
166
  this.reloadDebounceTimer = null;
143
167
  this.pendingReloadKind = null;
168
+ this.pendingReloadFiles.clear();
144
169
  }, DevServer.reloadDebounceMs);
145
170
  });
171
+ _defineProperty(this, "sourceFileToUrlPath", file => {
172
+ let rel = slash(relative(this.compilationInfo.codeLocation, file));
173
+ // compileJavascript strips the trailing 'x' off '.jsx' when writing the compiled
174
+ // output (the file no longer contains literal JSX after the babel transform) - match
175
+ // that here so the URL points at the file that's actually served.
176
+ if (rel.endsWith('.jsx')) rel = rel.slice(0, -1);
177
+ return `/${this.compilationInfo.codeSubPath}/${rel}`;
178
+ });
146
179
  _defineProperty(this, "handleRequestApi", async (req, res, next) => {
147
180
  req.params.foo;
148
181
  this.apiRoutes = await getApiRoutes(this.config, this.compilationInfo, 'dev');
@@ -168,7 +201,19 @@ export class DevServer extends TungstenServer {
168
201
  res.status(404).end();
169
202
  return;
170
203
  }
204
+ cliLog('handling ' + req.url);
171
205
  const errorTrack = [];
206
+ // Captured as soon as each resolves, independent of the promiseAllObj combinators
207
+ // below - those are all-or-nothing, so if routing/data-fetching/rendering fails
208
+ // afterwards, the destructured `routes`/`RootComponentClass` locals never get
209
+ // assigned even though resolving them didn't fail. The catch block below uses these
210
+ // to tell "app routes resolved fine, something later failed" apart from "routes
211
+ // themselves couldn't be resolved" - only the former can show the app's 'error' route.
212
+ let capturedRoutes;
213
+ let capturedRootComponentClass = null;
214
+ // Defaults to {} to match the "no global data function registered" branch below,
215
+ // which resolves synchronously to {} and is never itself a failure case.
216
+ let capturedGlobalData = {};
172
217
  try {
173
218
  const _firstRender = this.firstRender;
174
219
  this.firstRender = false;
@@ -205,11 +250,15 @@ export class DevServer extends TungstenServer {
205
250
  //const routingPromise = getRoutesDev(this.compilationInfo, this.config, load).then(
206
251
  const routingPromise = getRoutesDev(this.compilationInfo, this.config, iteration).then(async appRoutes => {
207
252
  const routes = typeof appRoutes === 'function' ? appRoutes(reqRes) : appRoutes;
253
+ capturedRoutes = routes;
208
254
  // load data, and do routing
209
255
  return promiseAllObj({
210
256
  appRoutes,
211
257
  routes,
212
- globalData: globalDataFunc.value !== undefined ? this.getGlobalData(globalDataFunc.value, reqRes).catch(e => {
258
+ globalData: globalDataFunc.value !== undefined ? this.getGlobalData(globalDataFunc.value, reqRes).then(globalData => {
259
+ capturedGlobalData = globalData;
260
+ return globalData;
261
+ }).catch(e => {
213
262
  const msg = 'Error getting global data';
214
263
  cliError(msg);
215
264
  errorTrack.push(msg);
@@ -253,7 +302,10 @@ export class DevServer extends TungstenServer {
253
302
  } = await promiseAllObj({
254
303
  routing: routingPromise,
255
304
  //RootComponentClass: getComponentDev(rootComponentFileFull, this.config.rootComponent, load)
256
- RootComponentClass: getComponentDev(rootComponentFileFull, this.config.rootComponent, iteration)
305
+ RootComponentClass: getComponentDev(rootComponentFileFull, this.config.rootComponent, iteration).then(c => {
306
+ capturedRootComponentClass = c;
307
+ return c;
308
+ })
257
309
  })
258
310
  // .catch(e => {
259
311
  // cliError('ROUTING AND ROOT ERR')
@@ -315,11 +367,60 @@ export class DevServer extends TungstenServer {
315
367
  res.send(html);
316
368
  } catch (e) {
317
369
  cliLog('error in TungstenServer handleRequest', e);
318
- res.setHeader('Content-Type', 'text/html');
319
- res.status(500);
320
370
  this.errorLog(e);
321
371
  cliLog('');
322
- res.send(this.errorPage(e, errorTrack));
372
+ const errorRouteHtml = await this.tryRenderErrorRoute(req, res, capturedRoutes, capturedRootComponentClass, capturedGlobalData, e);
373
+ res.setHeader('Content-Type', 'text/html');
374
+ res.status(500);
375
+ res.send(errorRouteHtml ?? this.errorPage(e, errorTrack));
376
+ }
377
+ });
378
+ // Attempts to render the app's own 'error' route instead of the dev server's generic
379
+ // error dump, using whatever `routes`/`RootComponentClass`/`globalData` handleRequest
380
+ // above managed to capture before it failed. Global data and route data are independent
381
+ // tRPC calls (batched together, but batching doesn't couple their success/failure - see
382
+ // resolveResponse.ts in @trpc/server), so global data commonly did resolve even when
383
+ // route data or rendering is what actually failed; passing the real value through here
384
+ // (rather than defaulting to {}) lets the error route render with it, e.g. the real theme
385
+ // colour or username instead of framework defaults. Only succeeds when routes actually
386
+ // resolved (so `routes` is defined) and the app defines an 'error' route. Never throws -
387
+ // falls back to null (the caller's default error page) on any failure, since we're
388
+ // already handling one error and can't risk a second, unhandled one taking the dev
389
+ // server down.
390
+ _defineProperty(this, "tryRenderErrorRoute", async (req, res, routes, RootComponentClass, globalData, error) => {
391
+ try {
392
+ if (routes === undefined) return null;
393
+ const errorRouteDef = routes.error;
394
+ if (errorRouteDef === undefined) return null;
395
+ if (this.framework.clientImportAliases === undefined) {
396
+ throwError('DevServer.tryRenderErrorRoute()', 'framework.clientImportAliases is undefined');
397
+ }
398
+ const reqRes = {
399
+ req,
400
+ res
401
+ };
402
+ const instanceConfig = makeInstanceConfigFromFrameworkConfig(this.config, true);
403
+ const matchedRouteInfo = {
404
+ key: 'error',
405
+ params: {},
406
+ content: errorRouteDef.content,
407
+ data: makeTungstenErrorInfo(error)
408
+ };
409
+ const serverDataLoading = {
410
+ value: false
411
+ };
412
+ const {
413
+ internalStore,
414
+ stores,
415
+ storeSubscriptions
416
+ } = initStores(req.url, reqRes, globalData, matchedRouteInfo, serverDataLoading);
417
+ const instance = new Instance(req.url, instanceConfig, reqRes, routes, routes, internalStore, stores, storeSubscriptions, globalData, matchedRouteInfo);
418
+ return await renderRootToHtmlDev(this.compilationInfo, this.framework.clientImportAliases, RootComponentClass ?? MatchedRoute, instance, this.config, global.tungstenPublicEnv, '' // siteBasePathOverride
419
+ );
420
+ } catch (renderError) {
421
+ cliError('Error rendering app error route, falling back to default error page');
422
+ cliLog(renderError);
423
+ return null;
323
424
  }
324
425
  });
325
426
  // private async handlePost(req: express.Request, res: express.Response): Promise<void> {
@@ -340,11 +441,13 @@ export class DevServer extends TungstenServer {
340
441
  log('end error log');
341
442
  });
342
443
  _defineProperty(this, "errorPage", (error, errorTrack) => {
444
+ const autoRetryScript = devErrorPageAutoRetryScript(error);
343
445
  return `<!DOCTYPE html>
344
- </html>
446
+ <html>
345
447
  <head>
346
448
  <title>Error</title>
347
449
  <style>html { font-family: arial }</style>
450
+ ${autoRetryScript ? `<script>${autoRetryScript}</script>` : ''}
348
451
  </head>
349
452
  <body>
350
453
  <h1>Application Error</h1>
@@ -381,8 +484,8 @@ export class DevServer extends TungstenServer {
381
484
  // + '\n Ensure that you have an env schema with this field, and a matching env file'
382
485
  // )
383
486
  // }
384
- const proto = tungstenPrivateEnv.FRONTEND_PROTO ?? 'http';
385
- const host = tungstenPrivateEnv.FRONTEND_HOST ?? 'localhost';
487
+ const proto = tungstenPublicEnv.FRONTEND_PROTO ?? 'http';
488
+ const host = tungstenPublicEnv.FRONTEND_HOST ?? 'localhost';
386
489
  const port = tungstenPrivateEnv.TUNGSTEN_SERVER_PORT ?? 3000;
387
490
  if (isNaN(port) || port === 0) throwError('DevServer', portError(port));
388
491
  this.port = port;
@@ -5,7 +5,7 @@ import type { RouteContentFunction } from '../routing/RouteContentFunction.js';
5
5
  export type MatchedRouteInfo = {
6
6
  key: RouteKey | null;
7
7
  params: Record<string, string>;
8
- content: ContentNode | RouteContentFunction;
8
+ content: ContentNode | RouteContentFunction<any, any>;
9
9
  data?: unknown | RoutingRedirect;
10
10
  };
11
11
  //# sourceMappingURL=MatchedRouteInfo.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MatchedRouteInfo.d.ts","sourceRoot":"","sources":["../../src/Servers/MatchedRouteInfo.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC3B,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,OAAO,EAAE,WAAW,GAAG,oBAAoB,CAAA;IAC3C,IAAI,CAAC,EAAE,OAAO,GAAG,eAAe,CAAA;CACnC,CAAA"}
1
+ {"version":3,"file":"MatchedRouteInfo.d.ts","sourceRoot":"","sources":["../../src/Servers/MatchedRouteInfo.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAA;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AACvD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAA;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC3B,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;IAErB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAK9B,OAAO,EAAE,WAAW,GAAG,oBAAoB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;IACrD,IAAI,CAAC,EAAE,OAAO,GAAG,eAAe,CAAA;CACnC,CAAA"}
@@ -22,6 +22,7 @@ export declare class ProdServer extends TungstenServer {
22
22
  constructor(framework: Framework, config: FrameworkConfigComplete, compilationInfo: CompilationInfo, appRoutes: AppRoutes, RootComponentOrNull: AnyComponentType | null, serverMiddleware: ServerMiddleware | null);
23
23
  private handleRequestApi;
24
24
  handleRequest: (req: express.Request, res: express.Response) => Promise<void>;
25
+ private tryRenderErrorRoute;
25
26
  errorPage: () => string;
26
27
  start(portOverride?: number | null, mute?: boolean): Promise<string>;
27
28
  stop(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ProdServer.d.ts","sourceRoot":"","sources":["../../src/Servers/ProdServer.ts"],"names":[],"mappings":"AAEA,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAI7B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQpD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAM3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAKnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AASrD,qBAAa,UAAW,SAAQ,cAAc;IAC1C,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,uBAAuB,CAAA;IAC/B,eAAe,EAAE,eAAe,CAAA;IAChC,SAAS,EAAE,SAAS,CAAA;IACpB,mBAAmB,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAK5C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAO;IAC9B,GAAG,EAAE,OAAO,CAAC,WAAW,CAAA;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IACrC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;gBAEX,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,uBAAuB,EAC/B,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,SAAS,EACpB,mBAAmB,EAAE,gBAAgB,GAAG,IAAI,EAC5C,gBAAgB,EAAE,gBAAgB,GAAG,IAAI;IA8H7C,OAAO,CAAC,gBAAgB,CAgBvB;IACD,aAAa,GAAU,KAAK,OAAO,CAAC,OAAO,EAAE,KAAK,OAAO,CAAC,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CA6GjF;IACD,SAAS,eASR;IAMD,KAAK,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBlE,IAAI;CAKP"}
1
+ {"version":3,"file":"ProdServer.d.ts","sourceRoot":"","sources":["../../src/Servers/ProdServer.ts"],"names":[],"mappings":"AAEA,OAAO,OAAO,MAAM,SAAS,CAAA;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAA;AAI7B,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAClE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQpD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAM3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AAKnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAWrD,qBAAa,UAAW,SAAQ,cAAc;IAC1C,SAAS,EAAE,SAAS,CAAA;IACpB,MAAM,EAAE,uBAAuB,CAAA;IAC/B,eAAe,EAAE,eAAe,CAAA;IAChC,SAAS,EAAE,SAAS,CAAA;IACpB,mBAAmB,EAAE,gBAAgB,GAAG,IAAI,CAAA;IAK5C,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAO;IAC9B,GAAG,EAAE,OAAO,CAAC,WAAW,CAAA;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IACrC,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;gBAEX,SAAS,EAAE,SAAS,EACpB,MAAM,EAAE,uBAAuB,EAC/B,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,SAAS,EACpB,mBAAmB,EAAE,gBAAgB,GAAG,IAAI,EAC5C,gBAAgB,EAAE,gBAAgB,GAAG,IAAI;IA8H7C,OAAO,CAAC,gBAAgB,CAgBvB;IACD,aAAa,GAAU,KAAK,OAAO,CAAC,OAAO,EAAE,KAAK,OAAO,CAAC,QAAQ,KAAG,OAAO,CAAC,IAAI,CAAC,CA2HjF;IASD,OAAO,CAAC,mBAAmB,CA+C1B;IACD,SAAS,eASR;IAMD,KAAK,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC;IAwBlE,IAAI;CAKP"}
@@ -19,6 +19,7 @@ import { globalDataFunc } from "../routing/registerGlobalData.js";
19
19
  import { TungstenServer } from "./TungstenServer.js";
20
20
  import { portError } from "./portError.js";
21
21
  import { initStores } from "./initStores.js";
22
+ import { makeTungstenErrorInfo } from "../routing/TungstenErrorInfo.js";
22
23
  function debug(...texts) {
23
24
  // console.log(...texts)
24
25
  }
@@ -83,6 +84,14 @@ export class ProdServer extends TungstenServer {
83
84
  res.status(404).end();
84
85
  return;
85
86
  }
87
+ // Captured as soon as it resolves, independent of the Promise.all below - that's
88
+ // all-or-nothing, so if routing/route-data-fetching fails afterwards, `globalData`
89
+ // never gets assigned even though fetching it didn't fail (global data and route data
90
+ // are independent tRPC calls, batched together but not coupled - see
91
+ // resolveResponse.ts in @trpc/server). tryRenderErrorRoute uses this to render the
92
+ // app's error route with the real global data (theme colour, username, ...) rather
93
+ // than framework defaults, when it did resolve.
94
+ let capturedGlobalData = {};
86
95
  try {
87
96
  const location = req.url;
88
97
  const instanceConfig = makeInstanceConfigFromFrameworkConfig(this.config);
@@ -115,7 +124,10 @@ export class ProdServer extends TungstenServer {
115
124
  value: false
116
125
  };
117
126
  const routes = typeof appRoutes === 'function' ? appRoutes(reqRes) : appRoutes;
118
- const [globalData, matchedRouteInfo] = await Promise.all([globalDataFunc.value !== undefined ? globalDataFunc.value(reqRes) : {}, routing(location, routes, serverDataLoading)]);
127
+ const [globalData, matchedRouteInfo] = await Promise.all([globalDataFunc.value !== undefined ? globalDataFunc.value(reqRes).then(globalData => {
128
+ capturedGlobalData = globalData;
129
+ return globalData;
130
+ }) : {}, routing(location, routes, serverDataLoading)]);
119
131
  //instance.matchedRouteInfo =
120
132
  //cliTodo('Can we move redirect handling to base class?')
121
133
  // // 2025-03-14 copied this code here from Dev server,
@@ -165,14 +177,76 @@ export class ProdServer extends TungstenServer {
165
177
  res.send(html);
166
178
  } catch (e) {
167
179
  cliLog('handleRequest() error', e);
180
+ const errorRouteHtml = await this.tryRenderErrorRoute(req, res, capturedGlobalData, e);
168
181
  res.setHeader('Content-Type', 'text/html');
169
182
  res.status(500);
170
- res.send(this.errorPage());
183
+ res.send(errorRouteHtml ?? this.errorPage());
184
+ }
185
+ });
186
+ // Attempts to render the app's own 'error' route in place of the framework's generic
187
+ // error page, using whatever `globalData` handleRequest above managed to capture before
188
+ // it failed (see the capturedGlobalData comment there for why that's not always {}). Only
189
+ // usable when the app routes themselves could be resolved (this runs from the catch block
190
+ // of handleRequest, so anything from route resolution onward may have failed) and the app
191
+ // actually defines an 'error' route. Never throws - falls back to null (the caller's
192
+ // default error page) on any failure, since we're already handling one error and can't
193
+ // risk a second, unhandled one taking the server down.
194
+ _defineProperty(this, "tryRenderErrorRoute", async (req, res, globalData, error) => {
195
+ try {
196
+ if (this.framework.clientImportAliases === undefined) {
197
+ throwError('ProdServer.tryRenderErrorRoute()', 'framework.clientImportAliases is undefined');
198
+ }
199
+ const {
200
+ config,
201
+ appRoutes,
202
+ RootComponentOrNull
203
+ } = this;
204
+ const reqRes = {
205
+ req,
206
+ res
207
+ };
208
+ const routes = typeof appRoutes === 'function' ? appRoutes(reqRes) : appRoutes;
209
+ const errorRouteDef = routes.error;
210
+ if (errorRouteDef === undefined) return null;
211
+ const location = req.url;
212
+ const instanceConfig = makeInstanceConfigFromFrameworkConfig(this.config);
213
+ const matchedRouteInfo = {
214
+ key: 'error',
215
+ params: {},
216
+ content: errorRouteDef.content,
217
+ data: makeTungstenErrorInfo(error)
218
+ };
219
+ const serverDataLoading = {
220
+ value: false
221
+ };
222
+ const {
223
+ internalStore,
224
+ stores,
225
+ storeSubscriptions
226
+ } = initStores(location, reqRes, globalData, matchedRouteInfo, serverDataLoading);
227
+ const instance = new Instance(location, instanceConfig, reqRes, appRoutes, routes, internalStore, stores, storeSubscriptions, globalData, matchedRouteInfo);
228
+ if (RootComponentOrNull !== null) {
229
+ return await renderRootToHtml(this.compilationInfo, this.framework.clientImportAliases, RootComponentOrNull, instance, config, this.config.siteBasePath);
230
+ }
231
+ const {
232
+ params,
233
+ data
234
+ } = matchedRouteInfo;
235
+ let {
236
+ content
237
+ } = matchedRouteInfo;
238
+ if (typeof content === 'function') {
239
+ content = content(data, params, {} /* props */, globalData, location);
240
+ }
241
+ return await renderContentToHtml(this.compilationInfo, this.framework.clientImportAliases, content, instance, config, this.config.siteBasePath);
242
+ } catch (renderError) {
243
+ cliLog('Error rendering app error route, falling back to default error page', renderError);
244
+ return null;
171
245
  }
172
246
  });
173
247
  _defineProperty(this, "errorPage", () => {
174
248
  return `<!DOCTYPE html>
175
- </html>
249
+ <html>
176
250
  <head><title>Error</title></head>
177
251
  <body>
178
252
  <h1>Internal error</h1>
@@ -263,8 +337,8 @@ export class ProdServer extends TungstenServer {
263
337
  // I don't think we ever override the port, not sure why
264
338
  start(portOverride, mute = false) {
265
339
  return new Promise(resolve => {
266
- const proto = tungstenPrivateEnv.FRONTEND_PROTO ?? 'http';
267
- const host = tungstenPrivateEnv.FRONTEND_HOST ?? 'localhost';
340
+ const proto = tungstenPublicEnv.FRONTEND_PROTO ?? 'http';
341
+ const host = tungstenPublicEnv.FRONTEND_HOST ?? 'localhost';
268
342
  let port;
269
343
  if (portOverride !== undefined) {
270
344
  port = portOverride;
@@ -0,0 +1,4 @@
1
+ export declare const maxAutoRetryAttempts = 8;
2
+ export declare function devErrorPageAutoRetryScript(error: unknown): string;
3
+ export declare const devErrorPageClearRetryScript = "try{sessionStorage.removeItem('tungstenDevErrorRetryCount')}catch(e){}";
4
+ //# sourceMappingURL=devErrorPageAutoRetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devErrorPageAutoRetry.d.ts","sourceRoot":"","sources":["../../src/Servers/devErrorPageAutoRetry.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,oBAAoB,IAAI,CAAA;AAGrC,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAqBlE;AAKD,eAAO,MAAM,4BAA4B,2EAC6B,CAAA"}
@@ -0,0 +1,26 @@
1
+ // devErrorPageAutoRetry
2
+ // exports devErrorPageAutoRetryScript, devErrorPageClearRetryScript, maxAutoRetryAttempts
3
+ //
4
+ // Dev-only. importDevModuleWithRetry.ts already rides out the common case of a transient,
5
+ // self-resolving module-shape error from a multi-file edit landing mid-compile - but under heavy
6
+ // load its bounded retry budget can still be exhausted before the underlying tsc/babel pipeline
7
+ // settles (see docs/hmr.md), leaving the developer looking at a dead dev error page for what's
8
+ // still, in fact, a self-resolving situation. If the error that reached the error page still
9
+ // looks like that same transient shape, embed a tiny script that auto-reloads a few times before
10
+ // giving up - capped via sessionStorage so a genuine, permanent error doesn't loop forever.
11
+ import { isTransientDevModuleError } from "../importDevModuleWithRetry.js";
12
+ const sessionStorageKey = 'tungstenDevErrorRetryCount';
13
+ export const maxAutoRetryAttempts = 8;
14
+ const retryDelayMs = 500;
15
+ export function devErrorPageAutoRetryScript(error) {
16
+ if (!isTransientDevModuleError(error)) return '';
17
+ // Wrapped in try/catch: sessionStorage can throw (some private-browsing modes, restrictive
18
+ // embedding contexts) rather than just being absent. Without a working store there's no way
19
+ // to safely cap attempts, so degrade to doing nothing rather than risk retrying unbounded -
20
+ // same as if this feature didn't exist, not worse.
21
+ return `(function(){` + `try{` + `var key='${sessionStorageKey}';` + `var count=parseInt(sessionStorage.getItem(key)||'0',10);` + `if(count<${maxAutoRetryAttempts}){` + `sessionStorage.setItem(key,String(count+1));` + `setTimeout(function(){location.reload()},${retryDelayMs})` + `}else{` + `console.error('[tungsten-dev] gave up auto-retrying a transient-looking error after ` + `${maxAutoRetryAttempts} attempts - this may be a real error, not a transient compile race')` + `}` + `}catch(e){` + `console.error('[tungsten-dev] could not auto-retry - sessionStorage unavailable',e)` + `}` + `})();`;
22
+ }
23
+ // Injected into every successfully-rendered dev page (see processHead.ts), so a later, unrelated
24
+ // transient error starts its own retry budget from zero rather than inheriting a stale count.
25
+ // Same try/catch reasoning as above - a successful render should never itself error out over this.
26
+ export const devErrorPageClearRetryScript = `try{sessionStorage.removeItem('${sessionStorageKey}')}catch(e){}`;
@@ -1,8 +1,7 @@
1
- // import type { Server } from 'http'
2
- // //import express, { Request, Response, NextFunction, RequestHandler } from 'express'
1
+ // Status/known gaps: see ./README.md
3
2
  // import { Context, Hono } from 'hono'
4
3
  // import type { BlankEnv, BlankSchema, Handler, Next } from 'hono/types'
5
- // import { serve } from '@hono/node-server'
4
+ // import { serve, type ServerType } from '@hono/node-server'
6
5
  // import { serveStatic } from '@hono/node-server/serve-static'
7
6
  // import { join } from 'path'
8
7
  // import { allObj as promiseAllObj } from 'sxy-lib/promises.js'
@@ -35,7 +34,6 @@
35
34
  // import { ServerDataLoading } from '../../Store/ServerDataLoading.js'
36
35
  // import { TungstenServer } from '../TungstenServer.jsx'
37
36
  // import { Routes } from '../../routing/Routes.js'
38
- // import { RedirectCode, RoutingRedirect } from '../../routing/RoutingRedirect.js'
39
37
  // import { portError } from '../portError.js'
40
38
  // import { loadEnvsDev } from '../loadEnvsDev.js'
41
39
  // import { initStores } from '../initStores.js'
@@ -45,7 +43,6 @@
45
43
  // import { MatchedRoute } from '../../routing/MatchedRoute.js'
46
44
  // import { ContentNodeIsClassComponent } from '../../ContentNode.js'
47
45
  // import { $props, $type } from '../../contentNodeSymbols.js'
48
- // import { RedirectComponent } from '../../components/RedirectComponent.js'
49
46
  // import { Path } from '../../routing/RouteTypes.js'
50
47
  // import type { ApiRoutesHono } from '../../api/ApiRoutesHono.js'
51
48
  // import { TungstenServerHono } from './TungstenServerHono.jsx'
@@ -64,9 +61,10 @@ export {};
64
61
  // app: Hono<BlankEnv, BlankSchema, '/'>
65
62
  // apiRoutes?: ApiRoutesHono
66
63
  // apiPath?: string
67
- // server?: Server
64
+ // server?: ServerType
68
65
  // reqId: number
69
66
  // firstRender: boolean = true
67
+ // iterationCount: number = 0
70
68
  // constructor(
71
69
  // framework: Framework, config: FrameworkConfigComplete, compilationInfo: CompilationInfo,
72
70
  // initialProcessEnv: Record<string, string> = {}/* FIX ME */
@@ -83,8 +81,8 @@ export {};
83
81
  // // + '\n Ensure that you have an env schema with this field, and a matching env file'
84
82
  // // )
85
83
  // // }
86
- // const proto = tungstenPrivateEnv.FRONTEND_PROTO ?? 'http'
87
- // const host = tungstenPrivateEnv.FRONTEND_HOST ?? 'localhost'
84
+ // const proto = tungstenPublicEnv.FRONTEND_PROTO ?? 'http'
85
+ // const host = tungstenPublicEnv.FRONTEND_HOST ?? 'localhost'
88
86
  // const port = tungstenPrivateEnv.TUNGSTEN_SERVER_PORT ?? 3000
89
87
  // if (isNaN(port) || port === 0) throwError('DevServer', portError(port))
90
88
  // this.port = port
@@ -301,21 +299,24 @@ export {};
301
299
  // )
302
300
  // }
303
301
  // globalDataFunc.value = undefined
304
- // const load = await createLoad(import.meta.url, sxyLoaderConfig)
305
- // await loadEnvsDev(this.config, load, this.initialProcessEnv, false)
306
- // // we are delaying instance creation until after we load the app code, to lets things initialise?
307
- // //const reqRes: ReqRes = { req, res }
308
- // //const honoContext = c
302
+ // const iteration = this.iterationCount++
303
+ // await loadEnvsDev(this.config, iteration, this.initialProcessEnv, false)
304
+ // // ReqRes is Express-shaped ({req, res}) and Hono's Context isn't - this cast is a
305
+ // // type-only bridge so the (Express-only) Instance/initStores/routing plumbing below
306
+ // // still compiles. Not behaviorally correct; fine since this dev server isn't wired
307
+ // // up anywhere live (see Framework.createDevServer, which only builds DevServer).
308
+ // // eslint-disable-next-line no-type-assertion/no-type-assertion -- see comment above
309
+ // const reqRes = c as unknown as ReqRes
309
310
  // // Save some state. I think this is a placeholder for later
310
311
  // const serverDataLoading: ServerDataLoading = { value: false }
311
- // const routingPromise = getRoutesDev(this.compilationInfo, this.config, load).then(
312
+ // const routingPromise = getRoutesDev(this.compilationInfo, this.config, iteration).then(
312
313
  // async (appRoutes) => {
313
- // const routes = (typeof appRoutes === 'function') ? appRoutes(c) : appRoutes
314
+ // const routes = (typeof appRoutes === 'function') ? appRoutes(reqRes) : appRoutes
314
315
  // // load data, and do routing
315
316
  // return promiseAllObj({
316
317
  // appRoutes,
317
318
  // routes,
318
- // globalData: (globalDataFunc.value !== undefined) ? globalDataFunc.value(c) : {},
319
+ // globalData: (globalDataFunc.value !== undefined) ? globalDataFunc.value(reqRes) : {},
319
320
  // matchedRouteInfo: routing(location, routes, serverDataLoading)
320
321
  // })
321
322
  // }
@@ -330,7 +331,7 @@ export {};
330
331
  // ;({ routing: { appRoutes, routes, globalData, matchedRouteInfo }, RootComponentClass }
331
332
  // = await promiseAllObj({
332
333
  // routing: routingPromise,
333
- // RootComponentClass: getComponentDev(rootComponentFileFull, this.config.rootComponent, load)
334
+ // RootComponentClass: getComponentDev(rootComponentFileFull, this.config.rootComponent, iteration)
334
335
  // }))
335
336
  // } else {
336
337
  // ({ appRoutes, routes, globalData, matchedRouteInfo } = await routingPromise)
@@ -344,13 +345,13 @@ export {};
344
345
  // // routing(location, routes, serverDataLoading)
345
346
  // // ])
346
347
  // const redirected = this.handleRedirects(c, matchedRouteInfo)
347
- // if (redirected) return // end early
348
+ // if (redirected !== false) return redirected // end early
348
349
  // // make stores
349
350
  // const { internalStore, stores, storeSubscriptions }
350
- // = initStores(location, c, globalData, matchedRouteInfo, serverDataLoading)
351
+ // = initStores(location, reqRes, globalData, matchedRouteInfo, serverDataLoading)
351
352
  // // create the instance
352
- // const instance = new Instance(
353
- // location, instanceConfig, c, appRoutes, routes, internalStore,
353
+ // const instance = new Instance(
354
+ // location, instanceConfig, reqRes, appRoutes, routes, internalStore,
354
355
  // stores, storeSubscriptions, globalData, matchedRouteInfo
355
356
  // )
356
357
  // let html: string
@@ -379,16 +380,11 @@ export {};
379
380
  // // '' // siteBasePathOverride
380
381
  // // )
381
382
  // }
382
- // //debug('html', html)
383
- // res.setHeader('Content-Type', 'text/html')
384
- // res.status((instance.matchedRouteInfo.key === '404') ? 404 : 200)
385
- // res.send(html)
383
+ // return c.html(html, (instance.matchedRouteInfo.key === '404') ? 404 : 200)
386
384
  // } catch(e) {
387
385
  // cliLog('error', e)
388
- // res.setHeader('Content-Type', 'text/html')
389
- // res.status(500)
390
386
  // this.errorLog(e)
391
- // res.send(this.errorPage(e))
387
+ // return c.html(this.errorPage(e), 500)
392
388
  // }
393
389
  // }
394
390
  // // private async handlePost(req: express.Request, res: express.Response): Promise<void> {
@@ -414,7 +410,7 @@ export {};
414
410
  // }
415
411
  // start = (): Promise<string> => {
416
412
  // return new Promise( resolve => {
417
- // this.server = this.app.listen(this.port, () => {
413
+ // this.server = serve({ fetch: this.app.fetch, port: this.port }, () => {
418
414
  // cliNews(`Dev server ready at ${this.location}`)
419
415
  // resolve(this.location ?? '')
420
416
  // })