@askrjs/askr 0.0.50 → 0.0.51

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 (227) hide show
  1. package/dist/bench/components/benchmark-table.js.map +1 -1
  2. package/dist/benchmark.js +5 -4
  3. package/dist/benchmark.js.map +1 -1
  4. package/dist/bin/askr-ssg.d.ts.map +1 -1
  5. package/dist/bin/askr-ssg.js.map +1 -1
  6. package/dist/boot/hydration.js.map +1 -1
  7. package/dist/boot/index.js +2 -1
  8. package/dist/boot/index.js.map +1 -1
  9. package/dist/boot/root-lifecycle.d.ts.map +1 -1
  10. package/dist/boot/root-lifecycle.js +4 -4
  11. package/dist/boot/root-lifecycle.js.map +1 -1
  12. package/dist/boot/route-startup.js.map +1 -1
  13. package/dist/common/error-boundary.d.ts +16 -0
  14. package/dist/common/error-boundary.d.ts.map +1 -0
  15. package/dist/common/invariant.js +17 -0
  16. package/dist/common/invariant.js.map +1 -0
  17. package/dist/{dev → common}/logger.js +5 -6
  18. package/dist/common/logger.js.map +1 -0
  19. package/dist/common/vnode.js.map +1 -1
  20. package/dist/components/error-boundary.d.ts +2 -15
  21. package/dist/components/error-boundary.d.ts.map +1 -1
  22. package/dist/components/error-boundary.js +2 -74
  23. package/dist/components/error-boundary.js.map +1 -1
  24. package/dist/components/index.d.ts +2 -1
  25. package/dist/components/link.js +2 -0
  26. package/dist/components/link.js.map +1 -1
  27. package/dist/control/case.d.ts.map +1 -1
  28. package/dist/control/case.js +1 -0
  29. package/dist/control/case.js.map +1 -1
  30. package/dist/control/for.d.ts +3 -3
  31. package/dist/control/for.d.ts.map +1 -1
  32. package/dist/control/for.js +2 -2
  33. package/dist/control/for.js.map +1 -1
  34. package/dist/control/show.js +1 -0
  35. package/dist/control/show.js.map +1 -1
  36. package/dist/data/data-runtime.js.map +1 -1
  37. package/dist/data/invalidation.js +2 -2
  38. package/dist/data/invalidation.js.map +1 -1
  39. package/dist/data/mutation-cell.d.ts.map +1 -1
  40. package/dist/data/mutation-cell.js +1 -1
  41. package/dist/data/mutation-cell.js.map +1 -1
  42. package/dist/data/query-cell.js +2 -2
  43. package/dist/data/query-cell.js.map +1 -1
  44. package/dist/data/shared.js +1 -0
  45. package/dist/data/shared.js.map +1 -1
  46. package/dist/data/testing.js +2 -0
  47. package/dist/foundations/index.d.ts +1 -1
  48. package/dist/foundations/index.js +1 -1
  49. package/dist/foundations/state/controllable.d.ts +0 -1
  50. package/dist/foundations/state/controllable.d.ts.map +1 -1
  51. package/dist/foundations/state/controllable.js +1 -0
  52. package/dist/foundations/state/controllable.js.map +1 -1
  53. package/dist/foundations/structures/index.d.ts +1 -1
  54. package/dist/foundations/structures/index.js +2 -1
  55. package/dist/foundations/structures/portal.d.ts +2 -24
  56. package/dist/foundations/structures/portal.js +3 -187
  57. package/dist/fx/fx.js +2 -2
  58. package/dist/fx/fx.js.map +1 -1
  59. package/dist/fx/index.js +1 -0
  60. package/dist/index.d.ts +3 -3
  61. package/dist/index.js +4 -4
  62. package/dist/index.js.map +1 -1
  63. package/dist/jsx/types.d.ts.map +1 -1
  64. package/dist/jsx-dev-runtime.js +1 -0
  65. package/dist/jsx-dev-runtime.js.map +1 -1
  66. package/dist/jsx-runtime.js +1 -0
  67. package/dist/jsx-runtime.js.map +1 -1
  68. package/dist/renderer/attributes.js +1 -0
  69. package/dist/renderer/attributes.js.map +1 -1
  70. package/dist/renderer/boundaries.js +5 -5
  71. package/dist/renderer/boundaries.js.map +1 -1
  72. package/dist/renderer/child-shape.js +2 -2
  73. package/dist/renderer/child-shape.js.map +1 -1
  74. package/dist/renderer/children-fastpath.js +149 -0
  75. package/dist/renderer/children-fastpath.js.map +1 -0
  76. package/dist/renderer/children.js +3 -138
  77. package/dist/renderer/children.js.map +1 -1
  78. package/dist/renderer/cleanup.js +2 -2
  79. package/dist/renderer/cleanup.js.map +1 -1
  80. package/dist/renderer/component-host-cleanup.js +1 -1
  81. package/dist/renderer/component-host-cleanup.js.map +1 -1
  82. package/dist/renderer/component-host-instances.js +1 -1
  83. package/dist/renderer/component-host-instances.js.map +1 -1
  84. package/dist/renderer/component-host.js +1 -1
  85. package/dist/renderer/component-host.js.map +1 -1
  86. package/dist/renderer/dom-host.js.map +1 -1
  87. package/dist/renderer/dom-internal.js +5 -4
  88. package/dist/renderer/dom-internal.js.map +1 -1
  89. package/dist/renderer/dom.js +2 -1
  90. package/dist/renderer/element-children.js.map +1 -1
  91. package/dist/renderer/error-boundary-dom.js +51 -2
  92. package/dist/renderer/error-boundary-dom.js.map +1 -1
  93. package/dist/renderer/evaluate-reconcile.js +6 -5
  94. package/dist/renderer/evaluate-reconcile.js.map +1 -1
  95. package/dist/renderer/evaluate.js.map +1 -1
  96. package/dist/renderer/fastpath.js +3 -2
  97. package/dist/renderer/fastpath.js.map +1 -1
  98. package/dist/renderer/for-commit-dom-map.js.map +1 -1
  99. package/dist/renderer/for-commit-removal.js +2 -2
  100. package/dist/renderer/for-commit-removal.js.map +1 -1
  101. package/dist/renderer/for-commit-reorder.js +2 -2
  102. package/dist/renderer/for-commit-reorder.js.map +1 -1
  103. package/dist/renderer/for-commit.js +3 -3
  104. package/dist/renderer/for-commit.js.map +1 -1
  105. package/dist/renderer/index.js +3 -1
  106. package/dist/renderer/index.js.map +1 -1
  107. package/dist/renderer/prop-bindings.js +4 -4
  108. package/dist/renderer/prop-bindings.js.map +1 -1
  109. package/dist/renderer/reactive-child-dom.js.map +1 -1
  110. package/dist/renderer/reactive-children.js +4 -4
  111. package/dist/renderer/reactive-children.js.map +1 -1
  112. package/dist/renderer/reconcile-fastpaths.js +2 -1
  113. package/dist/renderer/reconcile-fastpaths.js.map +1 -1
  114. package/dist/renderer/reconcile-resolution.js +3 -3
  115. package/dist/renderer/reconcile-resolution.js.map +1 -1
  116. package/dist/renderer/retained-element-rollback.js +2 -1
  117. package/dist/renderer/retained-element-rollback.js.map +1 -1
  118. package/dist/renderer/stable-patch.js +2 -3
  119. package/dist/renderer/stable-patch.js.map +1 -1
  120. package/dist/renderer/utils.js +2 -1
  121. package/dist/renderer/utils.js.map +1 -1
  122. package/dist/resources/index.js +1 -2
  123. package/dist/router/activity.d.ts.map +1 -1
  124. package/dist/router/activity.js +20 -22
  125. package/dist/router/activity.js.map +1 -1
  126. package/dist/router/authoring.js +1 -1
  127. package/dist/router/authoring.js.map +1 -1
  128. package/dist/router/index.d.ts +1 -1
  129. package/dist/router/navigate.js +1 -1
  130. package/dist/router/navigate.js.map +1 -1
  131. package/dist/router/navigation-registry.js +1 -1
  132. package/dist/router/navigation-registry.js.map +1 -1
  133. package/dist/router/navigation-targets.d.ts.map +1 -1
  134. package/dist/router/navigation-targets.js +7 -5
  135. package/dist/router/navigation-targets.js.map +1 -1
  136. package/dist/router/rendering.js +1 -0
  137. package/dist/router/rendering.js.map +1 -1
  138. package/dist/router/resolution.d.ts +1 -14
  139. package/dist/router/resolution.d.ts.map +1 -1
  140. package/dist/router/resolution.js +6 -173
  141. package/dist/router/resolution.js.map +1 -1
  142. package/dist/router/route-matching.d.ts +20 -0
  143. package/dist/router/route-matching.d.ts.map +1 -0
  144. package/dist/router/route-matching.js +175 -0
  145. package/dist/router/route-matching.js.map +1 -0
  146. package/dist/router/route.js +4 -2
  147. package/dist/router/testing.js +4 -0
  148. package/dist/runtime/access.d.ts +20 -0
  149. package/dist/runtime/access.d.ts.map +1 -0
  150. package/dist/runtime/component-cleanup.js +1 -1
  151. package/dist/runtime/component-cleanup.js.map +1 -1
  152. package/dist/runtime/component-commit.js +1 -1
  153. package/dist/runtime/component-commit.js.map +1 -1
  154. package/dist/runtime/component-internal.d.ts +1 -1
  155. package/dist/runtime/component-internal.js +1 -1
  156. package/dist/runtime/component-internal.js.map +1 -1
  157. package/dist/runtime/component-lifecycle.d.ts +1 -1
  158. package/dist/runtime/component-lifecycle.js +1 -1
  159. package/dist/runtime/component-lifecycle.js.map +1 -1
  160. package/dist/runtime/component-scope.d.ts +1 -1
  161. package/dist/runtime/dev-namespace.d.ts +31 -0
  162. package/dist/runtime/dev-namespace.d.ts.map +1 -0
  163. package/dist/runtime/error-boundary.d.ts +5 -0
  164. package/dist/runtime/error-boundary.d.ts.map +1 -0
  165. package/dist/runtime/error-boundary.js +31 -0
  166. package/dist/runtime/error-boundary.js.map +1 -0
  167. package/dist/runtime/events.d.ts +58 -0
  168. package/dist/runtime/events.d.ts.map +1 -0
  169. package/dist/runtime/events.js +1 -1
  170. package/dist/runtime/events.js.map +1 -1
  171. package/dist/runtime/execution-model.d.ts +7 -0
  172. package/dist/runtime/execution-model.d.ts.map +1 -0
  173. package/dist/runtime/fastlane.d.ts +34 -0
  174. package/dist/runtime/fastlane.d.ts.map +1 -0
  175. package/dist/runtime/for-internal.d.ts +5 -5
  176. package/dist/runtime/for-internal.d.ts.map +1 -1
  177. package/dist/runtime/for-internal.js.map +1 -1
  178. package/dist/runtime/for-signals.d.ts +1 -1
  179. package/dist/runtime/for-signals.d.ts.map +1 -1
  180. package/dist/runtime/for-signals.js +1 -1
  181. package/dist/runtime/for-signals.js.map +1 -1
  182. package/dist/runtime/for-types.d.ts +9 -0
  183. package/dist/runtime/for-types.d.ts.map +1 -0
  184. package/dist/runtime/index.d.ts +24 -0
  185. package/dist/runtime/index.js +31 -0
  186. package/dist/runtime/perf-metrics.d.ts +26 -0
  187. package/dist/runtime/perf-metrics.d.ts.map +1 -0
  188. package/dist/runtime/portal.d.ts +22 -0
  189. package/dist/runtime/portal.d.ts.map +1 -0
  190. package/dist/runtime/portal.js +213 -0
  191. package/dist/runtime/portal.js.map +1 -0
  192. package/dist/runtime/resource-cell.js +1 -1
  193. package/dist/runtime/resource-cell.js.map +1 -1
  194. package/dist/runtime/resource-operation.js +1 -1
  195. package/dist/runtime/runtime.d.ts +1 -1
  196. package/dist/runtime/scheduler.js +2 -2
  197. package/dist/runtime/scheduler.js.map +1 -1
  198. package/dist/runtime/selector-store.js +24 -0
  199. package/dist/runtime/selector-store.js.map +1 -0
  200. package/dist/runtime/selector.d.ts.map +1 -1
  201. package/dist/runtime/selector.js +3 -18
  202. package/dist/runtime/selector.js.map +1 -1
  203. package/dist/ssg/create-static-gen.js +1 -0
  204. package/dist/ssg/create-static-gen.js.map +1 -1
  205. package/dist/ssg/static-routes.js +1 -0
  206. package/dist/ssg/static-routes.js.map +1 -1
  207. package/dist/ssr/boundaries.js +2 -2
  208. package/dist/ssr/boundaries.js.map +1 -1
  209. package/dist/ssr/component-runtime.js +3 -3
  210. package/dist/ssr/component-runtime.js.map +1 -1
  211. package/dist/ssr/render-resolved.js +1 -1
  212. package/dist/ssr/render-sync.js +1 -1
  213. package/dist/ssr/render-sync.js.map +1 -1
  214. package/dist/ssr/route-policy-resolution.js +2 -1
  215. package/dist/ssr/route-policy-resolution.js.map +1 -1
  216. package/dist/ssr/route-render.js +2 -1
  217. package/dist/ssr/route-render.js.map +1 -1
  218. package/dist/testing/index.d.ts.map +1 -1
  219. package/dist/testing/index.js +3 -2
  220. package/dist/testing/index.js.map +1 -1
  221. package/package.json +4 -4
  222. package/dist/dev/invariant.js +0 -29
  223. package/dist/dev/invariant.js.map +0 -1
  224. package/dist/dev/logger.js.map +0 -1
  225. package/dist/foundations/structures/portal.d.ts.map +0 -1
  226. package/dist/foundations/structures/portal.js.map +0 -1
  227. package/dist/runtime/component-contracts.js +0 -5
@@ -1 +1 @@
1
- {"version":3,"file":"route-render.js","names":["RouteModule.resolveRouteRequest","RouteModule.resolveRouteFromRoutes"],"sources":["../../src/ssr/route-render.ts"],"sourcesContent":["import {\n type DocumentRenderArgs,\n type DocumentRenderContext,\n type DocumentRenderer,\n renderDocument,\n} from '../common/ssr';\nimport type {\n RouteAuthOptions,\n RouteHandler,\n RouteManifest,\n RouteRegistry,\n RouteRequestResult,\n} from '../common/router';\nimport * as RouteModule from '../router/route';\nimport {\n createRenderContext,\n type RenderContext,\n type SSRData,\n} from './context';\nimport { resolvePolicyAwareSSRRoute } from './route-policy-resolution';\nimport { StringSink, StreamSink, type RenderSink } from './sink';\n\nexport type SSRRoute = {\n path: string;\n handler: RouteHandler;\n namespace?: string;\n};\n\ntype SSRRouteSource =\n | {\n registry: RouteRegistry;\n routes?: readonly SSRRoute[];\n }\n | {\n registry?: RouteRegistry;\n routes: readonly SSRRoute[];\n };\n\nexport type RouteRenderOptions = SSRRouteSource & {\n url: string;\n seed?: number;\n data?: SSRData;\n document?: DocumentRenderer;\n};\n\nexport type RouteStreamOptions = RouteRenderOptions & {\n onChunk(html: string): void;\n onComplete(): void;\n};\n\ntype ResolvedSSRRouteRender = {\n url: string;\n requestUrl: URL;\n route: SSRRoute;\n params: Record<string, string>;\n seed: number;\n data?: SSRData;\n ctx: RenderContext;\n document?: DocumentRenderer;\n};\n\nexport type RouteAppRenderInput = {\n route: SSRRoute;\n params: Record<string, string>;\n data?: SSRData;\n ctx: RenderContext;\n sink: RenderSink;\n};\n\nexport interface RouteRenderHost {\n renderAppToSink(input: RouteAppRenderInput): void;\n}\n\nexport async function resolveRequest(\n opts:\n | {\n url: string;\n registry: RouteRegistry;\n manifest?: RouteManifest;\n routes?: Array<{\n path: string;\n handler: RouteHandler;\n namespace?: string;\n }>;\n auth?: RouteAuthOptions;\n signal?: AbortSignal;\n }\n | {\n url: string;\n manifest: RouteManifest;\n registry?: RouteRegistry;\n routes?: Array<{\n path: string;\n handler: RouteHandler;\n namespace?: string;\n }>;\n auth?: RouteAuthOptions;\n signal?: AbortSignal;\n }\n | {\n url: string;\n manifest?: RouteManifest;\n registry?: RouteRegistry;\n routes: Array<{\n path: string;\n handler: RouteHandler;\n namespace?: string;\n }>;\n auth?: RouteAuthOptions;\n signal?: AbortSignal;\n }\n): Promise<RouteRequestResult> {\n const { url, auth, signal } = opts;\n const manifest = opts.manifest ?? opts.registry?.manifest;\n const routes = opts.routes ?? opts.registry?.routes;\n\n if (manifest) {\n return await RouteModule.resolveRouteRequest(url, {\n manifest,\n mode: 'ssr',\n auth,\n signal,\n });\n }\n\n if (!routes) {\n throw new Error('resolveRequest requires a route manifest or route table.');\n }\n\n const requestUrl = new URL(url, 'http://localhost');\n const resolved = RouteModule.resolveRouteFromRoutes(\n requestUrl.pathname,\n routes\n );\n\n if (!resolved) {\n return null;\n }\n\n return {\n kind: 'render',\n handler: resolved.handler,\n params: resolved.params,\n };\n}\n\nfunction resolveSSRRouteSource(source: SSRRouteSource): SSRRoute[] {\n const routes = source.routes ?? source.registry?.routes;\n if (!routes || routes.length === 0) {\n throw new Error('SSR requires a route registry or route table.');\n }\n\n return routes.map((route) => ({\n ...route,\n path: route.path,\n handler: route.handler,\n namespace: route.namespace,\n }));\n}\n\nfunction resolveSSRRouteRender(\n opts: RouteRenderOptions\n): ResolvedSSRRouteRender {\n const { seed = 12345, data, document } = opts;\n const routeTable = resolveSSRRouteSource(opts);\n const resolvedRoute = resolvePolicyAwareSSRRoute(opts, routeTable);\n const requestUrl = new URL(resolvedRoute.url, 'http://localhost');\n\n const ctx = createRenderContext(seed, {\n url: resolvedRoute.url,\n data,\n params: resolvedRoute.params,\n routes: routeTable,\n });\n\n return {\n url: resolvedRoute.url,\n requestUrl,\n route: resolvedRoute.route,\n params: resolvedRoute.params,\n seed,\n data,\n ctx,\n document,\n };\n}\n\nfunction buildDocumentRenderArgs(\n resolved: ResolvedSSRRouteRender,\n appHtml: string\n): DocumentRenderArgs {\n const context: DocumentRenderContext = {\n mode: 'ssr',\n url: resolved.url,\n pathname: resolved.requestUrl.pathname,\n search: resolved.requestUrl.search,\n hash: resolved.requestUrl.hash,\n params: resolved.params,\n data: resolved.data,\n seed: resolved.seed,\n route: {\n path: resolved.route.path,\n namespace: resolved.route.namespace,\n },\n };\n\n return {\n appHtml,\n context,\n };\n}\n\nfunction renderResolvedRouteAppToSink(\n resolved: ResolvedSSRRouteRender,\n sink: RenderSink,\n host: RouteRenderHost\n): void {\n host.renderAppToSink({\n route: resolved.route,\n params: resolved.params,\n data: resolved.data,\n ctx: resolved.ctx,\n sink,\n });\n}\n\nfunction renderToSinkInternal(\n opts: RouteRenderOptions & { sink: RenderSink },\n host: RouteRenderHost\n) {\n const { sink, ...renderOptions } = opts;\n const resolved = resolveSSRRouteRender(renderOptions);\n\n if (!resolved.document) {\n renderResolvedRouteAppToSink(resolved, sink, host);\n return;\n }\n\n const appSink = new StringSink();\n renderResolvedRouteAppToSink(resolved, appSink, host);\n appSink.end();\n sink.write(\n renderDocument(\n resolved.document,\n buildDocumentRenderArgs(resolved, appSink.toString()),\n 'renderToString()/renderToStream()'\n )\n );\n}\n\nexport function renderRouteToString(\n opts: RouteRenderOptions,\n host: RouteRenderHost\n): string {\n const sink = new StringSink();\n renderToSinkInternal({ ...opts, sink }, host);\n sink.end();\n return sink.toString();\n}\n\nexport function renderRouteToStream(\n opts: RouteStreamOptions,\n host: RouteRenderHost\n): void {\n const sink = new StreamSink(opts.onChunk, opts.onComplete);\n renderToSinkInternal({ ...opts, sink }, host);\n sink.end();\n}\n"],"mappings":";;;;;;;AAyEA,eAAsB,eACpB,MAqC6B;CAC7B,MAAM,EAAE,KAAK,MAAM,WAAW;CAC9B,MAAM,WAAW,KAAK,YAAY,KAAK,UAAU;CACjD,MAAM,SAAS,KAAK,UAAU,KAAK,UAAU;CAE7C,IAAI,UACF,OAAO,MAAMA,oBAAgC,KAAK;EAChD;EACA,MAAM;EACN;EACA;CACF,CAAC;CAGH,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,0DAA0D;CAI5E,MAAM,WAAWC,uBACf,IAFqB,IAAI,KAAK,kBAE9B,CAAA,CAAW,UACX,MACF;CAEA,IAAI,CAAC,UACH,OAAO;CAGT,OAAO;EACL,MAAM;EACN,SAAS,SAAS;EAClB,QAAQ,SAAS;CACnB;AACF;AAEA,SAAS,sBAAsB,QAAoC;CACjE,MAAM,SAAS,OAAO,UAAU,OAAO,UAAU;CACjD,IAAI,CAAC,UAAU,OAAO,WAAW,GAC/B,MAAM,IAAI,MAAM,+CAA+C;CAGjE,OAAO,OAAO,KAAK,WAAW;EAC5B,GAAG;EACH,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,WAAW,MAAM;CACnB,EAAE;AACJ;AAEA,SAAS,sBACP,MACwB;CACxB,MAAM,EAAE,OAAO,OAAO,MAAM,aAAa;CACzC,MAAM,aAAa,sBAAsB,IAAI;CAC7C,MAAM,gBAAgB,2BAA2B,MAAM,UAAU;CACjE,MAAM,aAAa,IAAI,IAAI,cAAc,KAAK,kBAAkB;CAEhE,MAAM,MAAM,oBAAoB,MAAM;EACpC,KAAK,cAAc;EACnB;EACA,QAAQ,cAAc;EACtB,QAAQ;CACV,CAAC;CAED,OAAO;EACL,KAAK,cAAc;EACnB;EACA,OAAO,cAAc;EACrB,QAAQ,cAAc;EACtB;EACA;EACA;EACA;CACF;AACF;AAEA,SAAS,wBACP,UACA,SACoB;CAgBpB,OAAO;EACL;EACA;GAhBA,MAAM;GACN,KAAK,SAAS;GACd,UAAU,SAAS,WAAW;GAC9B,QAAQ,SAAS,WAAW;GAC5B,MAAM,SAAS,WAAW;GAC1B,QAAQ,SAAS;GACjB,MAAM,SAAS;GACf,MAAM,SAAS;GACf,OAAO;IACL,MAAM,SAAS,MAAM;IACrB,WAAW,SAAS,MAAM;GAC5B;EAKA;CACF;AACF;AAEA,SAAS,6BACP,UACA,MACA,MACM;CACN,KAAK,gBAAgB;EACnB,OAAO,SAAS;EAChB,QAAQ,SAAS;EACjB,MAAM,SAAS;EACf,KAAK,SAAS;EACd;CACF,CAAC;AACH;AAEA,SAAS,qBACP,MACA,MACA;CACA,MAAM,EAAE,MAAM,GAAG,kBAAkB;CACnC,MAAM,WAAW,sBAAsB,aAAa;CAEpD,IAAI,CAAC,SAAS,UAAU;EACtB,6BAA6B,UAAU,MAAM,IAAI;EACjD;CACF;CAEA,MAAM,UAAU,IAAI,WAAW;CAC/B,6BAA6B,UAAU,SAAS,IAAI;CACpD,QAAQ,IAAI;CACZ,KAAK,MACH,eACE,SAAS,UACT,wBAAwB,UAAU,QAAQ,SAAS,CAAC,GACpD,mCACF,CACF;AACF;AAEA,SAAgB,oBACd,MACA,MACQ;CACR,MAAM,OAAO,IAAI,WAAW;CAC5B,qBAAqB;EAAE,GAAG;EAAM;CAAK,GAAG,IAAI;CAC5C,KAAK,IAAI;CACT,OAAO,KAAK,SAAS;AACvB;AAEA,SAAgB,oBACd,MACA,MACM;CACN,MAAM,OAAO,IAAI,WAAW,KAAK,SAAS,KAAK,UAAU;CACzD,qBAAqB;EAAE,GAAG;EAAM;CAAK,GAAG,IAAI;CAC5C,KAAK,IAAI;AACX"}
1
+ {"version":3,"file":"route-render.js","names":["RouteModule.resolveRouteRequest","RouteModule.resolveRouteFromRoutes"],"sources":["../../src/ssr/route-render.ts"],"sourcesContent":["import {\n type DocumentRenderArgs,\n type DocumentRenderContext,\n type DocumentRenderer,\n renderDocument,\n} from '../common/ssr';\nimport type {\n RouteAuthOptions,\n RouteHandler,\n RouteManifest,\n RouteRegistry,\n RouteRequestResult,\n} from '../common/router';\nimport * as RouteModule from '../router/route';\nimport {\n createRenderContext,\n type RenderContext,\n type SSRData,\n} from './context';\nimport { resolvePolicyAwareSSRRoute } from './route-policy-resolution';\nimport { StringSink, StreamSink, type RenderSink } from './sink';\n\nexport type SSRRoute = {\n path: string;\n handler: RouteHandler;\n namespace?: string;\n};\n\ntype SSRRouteSource =\n | {\n registry: RouteRegistry;\n routes?: readonly SSRRoute[];\n }\n | {\n registry?: RouteRegistry;\n routes: readonly SSRRoute[];\n };\n\nexport type RouteRenderOptions = SSRRouteSource & {\n url: string;\n seed?: number;\n data?: SSRData;\n document?: DocumentRenderer;\n};\n\nexport type RouteStreamOptions = RouteRenderOptions & {\n onChunk(html: string): void;\n onComplete(): void;\n};\n\ntype ResolvedSSRRouteRender = {\n url: string;\n requestUrl: URL;\n route: SSRRoute;\n params: Record<string, string>;\n seed: number;\n data?: SSRData;\n ctx: RenderContext;\n document?: DocumentRenderer;\n};\n\nexport type RouteAppRenderInput = {\n route: SSRRoute;\n params: Record<string, string>;\n data?: SSRData;\n ctx: RenderContext;\n sink: RenderSink;\n};\n\nexport interface RouteRenderHost {\n renderAppToSink(input: RouteAppRenderInput): void;\n}\n\nexport async function resolveRequest(\n opts:\n | {\n url: string;\n registry: RouteRegistry;\n manifest?: RouteManifest;\n routes?: Array<{\n path: string;\n handler: RouteHandler;\n namespace?: string;\n }>;\n auth?: RouteAuthOptions;\n signal?: AbortSignal;\n }\n | {\n url: string;\n manifest: RouteManifest;\n registry?: RouteRegistry;\n routes?: Array<{\n path: string;\n handler: RouteHandler;\n namespace?: string;\n }>;\n auth?: RouteAuthOptions;\n signal?: AbortSignal;\n }\n | {\n url: string;\n manifest?: RouteManifest;\n registry?: RouteRegistry;\n routes: Array<{\n path: string;\n handler: RouteHandler;\n namespace?: string;\n }>;\n auth?: RouteAuthOptions;\n signal?: AbortSignal;\n }\n): Promise<RouteRequestResult> {\n const { url, auth, signal } = opts;\n const manifest = opts.manifest ?? opts.registry?.manifest;\n const routes = opts.routes ?? opts.registry?.routes;\n\n if (manifest) {\n return await RouteModule.resolveRouteRequest(url, {\n manifest,\n mode: 'ssr',\n auth,\n signal,\n });\n }\n\n if (!routes) {\n throw new Error('resolveRequest requires a route manifest or route table.');\n }\n\n const requestUrl = new URL(url, 'http://localhost');\n const resolved = RouteModule.resolveRouteFromRoutes(\n requestUrl.pathname,\n routes\n );\n\n if (!resolved) {\n return null;\n }\n\n return {\n kind: 'render',\n handler: resolved.handler,\n params: resolved.params,\n };\n}\n\nfunction resolveSSRRouteSource(source: SSRRouteSource): SSRRoute[] {\n const routes = source.routes ?? source.registry?.routes;\n if (!routes || routes.length === 0) {\n throw new Error('SSR requires a route registry or route table.');\n }\n\n return routes.map((route) => ({\n ...route,\n path: route.path,\n handler: route.handler,\n namespace: route.namespace,\n }));\n}\n\nfunction resolveSSRRouteRender(\n opts: RouteRenderOptions\n): ResolvedSSRRouteRender {\n const { seed = 12345, data, document } = opts;\n const routeTable = resolveSSRRouteSource(opts);\n const resolvedRoute = resolvePolicyAwareSSRRoute(opts, routeTable);\n const requestUrl = new URL(resolvedRoute.url, 'http://localhost');\n\n const ctx = createRenderContext(seed, {\n url: resolvedRoute.url,\n data,\n params: resolvedRoute.params,\n routes: routeTable,\n });\n\n return {\n url: resolvedRoute.url,\n requestUrl,\n route: resolvedRoute.route,\n params: resolvedRoute.params,\n seed,\n data,\n ctx,\n document,\n };\n}\n\nfunction buildDocumentRenderArgs(\n resolved: ResolvedSSRRouteRender,\n appHtml: string\n): DocumentRenderArgs {\n const context: DocumentRenderContext = {\n mode: 'ssr',\n url: resolved.url,\n pathname: resolved.requestUrl.pathname,\n search: resolved.requestUrl.search,\n hash: resolved.requestUrl.hash,\n params: resolved.params,\n data: resolved.data,\n seed: resolved.seed,\n route: {\n path: resolved.route.path,\n namespace: resolved.route.namespace,\n },\n };\n\n return {\n appHtml,\n context,\n };\n}\n\nfunction renderResolvedRouteAppToSink(\n resolved: ResolvedSSRRouteRender,\n sink: RenderSink,\n host: RouteRenderHost\n): void {\n host.renderAppToSink({\n route: resolved.route,\n params: resolved.params,\n data: resolved.data,\n ctx: resolved.ctx,\n sink,\n });\n}\n\nfunction renderToSinkInternal(\n opts: RouteRenderOptions & { sink: RenderSink },\n host: RouteRenderHost\n) {\n const { sink, ...renderOptions } = opts;\n const resolved = resolveSSRRouteRender(renderOptions);\n\n if (!resolved.document) {\n renderResolvedRouteAppToSink(resolved, sink, host);\n return;\n }\n\n const appSink = new StringSink();\n renderResolvedRouteAppToSink(resolved, appSink, host);\n appSink.end();\n sink.write(\n renderDocument(\n resolved.document,\n buildDocumentRenderArgs(resolved, appSink.toString()),\n 'renderToString()/renderToStream()'\n )\n );\n}\n\nexport function renderRouteToString(\n opts: RouteRenderOptions,\n host: RouteRenderHost\n): string {\n const sink = new StringSink();\n renderToSinkInternal({ ...opts, sink }, host);\n sink.end();\n return sink.toString();\n}\n\nexport function renderRouteToStream(\n opts: RouteStreamOptions,\n host: RouteRenderHost\n): void {\n const sink = new StreamSink(opts.onChunk, opts.onComplete);\n renderToSinkInternal({ ...opts, sink }, host);\n sink.end();\n}\n"],"mappings":";;;;;;;;AAyEA,eAAsB,eACpB,MAqC6B;CAC7B,MAAM,EAAE,KAAK,MAAM,WAAW;CAC9B,MAAM,WAAW,KAAK,YAAY,KAAK,UAAU;CACjD,MAAM,SAAS,KAAK,UAAU,KAAK,UAAU;CAE7C,IAAI,UACF,OAAO,MAAMA,oBAAgC,KAAK;EAChD;EACA,MAAM;EACN;EACA;CACF,CAAC;CAGH,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,0DAA0D;CAI5E,MAAM,WAAWC,uBACf,IAFqB,IAAI,KAAK,kBAE9B,CAAA,CAAW,UACX,MACF;CAEA,IAAI,CAAC,UACH,OAAO;CAGT,OAAO;EACL,MAAM;EACN,SAAS,SAAS;EAClB,QAAQ,SAAS;CACnB;AACF;AAEA,SAAS,sBAAsB,QAAoC;CACjE,MAAM,SAAS,OAAO,UAAU,OAAO,UAAU;CACjD,IAAI,CAAC,UAAU,OAAO,WAAW,GAC/B,MAAM,IAAI,MAAM,+CAA+C;CAGjE,OAAO,OAAO,KAAK,WAAW;EAC5B,GAAG;EACH,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,WAAW,MAAM;CACnB,EAAE;AACJ;AAEA,SAAS,sBACP,MACwB;CACxB,MAAM,EAAE,OAAO,OAAO,MAAM,aAAa;CACzC,MAAM,aAAa,sBAAsB,IAAI;CAC7C,MAAM,gBAAgB,2BAA2B,MAAM,UAAU;CACjE,MAAM,aAAa,IAAI,IAAI,cAAc,KAAK,kBAAkB;CAEhE,MAAM,MAAM,oBAAoB,MAAM;EACpC,KAAK,cAAc;EACnB;EACA,QAAQ,cAAc;EACtB,QAAQ;CACV,CAAC;CAED,OAAO;EACL,KAAK,cAAc;EACnB;EACA,OAAO,cAAc;EACrB,QAAQ,cAAc;EACtB;EACA;EACA;EACA;CACF;AACF;AAEA,SAAS,wBACP,UACA,SACoB;CAgBpB,OAAO;EACL;EACA;GAhBA,MAAM;GACN,KAAK,SAAS;GACd,UAAU,SAAS,WAAW;GAC9B,QAAQ,SAAS,WAAW;GAC5B,MAAM,SAAS,WAAW;GAC1B,QAAQ,SAAS;GACjB,MAAM,SAAS;GACf,MAAM,SAAS;GACf,OAAO;IACL,MAAM,SAAS,MAAM;IACrB,WAAW,SAAS,MAAM;GAC5B;EAKA;CACF;AACF;AAEA,SAAS,6BACP,UACA,MACA,MACM;CACN,KAAK,gBAAgB;EACnB,OAAO,SAAS;EAChB,QAAQ,SAAS;EACjB,MAAM,SAAS;EACf,KAAK,SAAS;EACd;CACF,CAAC;AACH;AAEA,SAAS,qBACP,MACA,MACA;CACA,MAAM,EAAE,MAAM,GAAG,kBAAkB;CACnC,MAAM,WAAW,sBAAsB,aAAa;CAEpD,IAAI,CAAC,SAAS,UAAU;EACtB,6BAA6B,UAAU,MAAM,IAAI;EACjD;CACF;CAEA,MAAM,UAAU,IAAI,WAAW;CAC/B,6BAA6B,UAAU,SAAS,IAAI;CACpD,QAAQ,IAAI;CACZ,KAAK,MACH,eACE,SAAS,UACT,wBAAwB,UAAU,QAAQ,SAAS,CAAC,GACpD,mCACF,CACF;AACF;AAEA,SAAgB,oBACd,MACA,MACQ;CACR,MAAM,OAAO,IAAI,WAAW;CAC5B,qBAAqB;EAAE,GAAG;EAAM;CAAK,GAAG,IAAI;CAC5C,KAAK,IAAI;CACT,OAAO,KAAK,SAAS;AACvB;AAEA,SAAgB,oBACd,MACA,MACM;CACN,MAAM,OAAO,IAAI,WAAW,KAAK,SAAS,KAAK,UAAU;CACzD,qBAAqB;EAAE,GAAG;EAAM;CAAK,GAAG,IAAI;CAC5C,KAAK,IAAI;AACX"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/testing/index.ts"],"mappings":";;;KAeY,WAAA,gBAA2B,OAAO;AAAA,UAE7B,gBAAA;EACf,OAAA,GAAU,WAAW;AAAA;AAAA,UAGN,kBAAA;EACf,MAAA;EACA,gBAAgB;AAAA;AAAA,UAGD,oBAAA;EAAA,SACN,KAAA,WAAgB,kBAAkB;EAAA,SAClC,QAAA;EACT,KAAA;EACA,IAAA;AAAA;AAAA,UAGQ,iBAAA;EACR,QAAA,GAAW,aAAA;EACX,MAAA,YAAkB,KAAK;AAAA;AAAA,UAGR,mBAAA;EACf,IAAA;EACA,IAAA;EACA,eAAA;EACA,OAAA;EACA,SAAA;EACA,OAAA;AAAA;AAAA,KAGG,gBAAA,GAAmB,OAAO,CAAC,gBAAA;AAAA,iBAkBvB,gBAAA,eACP,IAAA,EAAM,CAAA,EACN,OAAA,GAAU,gBAAA,GACT,KAAA,CAAM,CAAA;AAAA,cAeI,SAAA,SAAS,gBAAA;6BACA,OAAA,GAAiB,gBAAA,GAAmB,KAAA,CAAM,CAAA;2BAe5C,KAAA,MACP,YAAA,GACM,CAAA,EAAC,OAAA,GACN,gBAAA,GACT,KAAA,CAAM,CAAA;2BAec,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,GAAmB,KAAA,CAAM,CAAA;sBAenD,IAAA,EACV,CAAA,EAAC,MAAA,GACC,gBAAA,EAAgB,OAAA,GACd,gBAAA,GACT,KAAA,CAAM,CAAA;6BAegB,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,GAAmB,KAAA,CAAM,CAAA;AAAA;AAAA,cAgB5D,UAAA;;+BApFS,OAAA,GAAiB,gBAAA,KAAmB,KAAA,CAAM,CAAA;6BAe5C,KAAA,MACP,YAAA,GACM,CAAA,EAAC,OAAA,GACN,gBAAA,KACT,KAAA,CAAM,CAAA;6BAec,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,KAAmB,KAAA,CAAM,CAAA;wBAenD,IAAA,EACV,CAAA,EAAC,MAAA,GACC,gBAAA,EAAgB,OAAA,GACd,gBAAA,KACT,KAAA,CAAM,CAAA;+BAegB,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,KAAmB,KAAA,CAAM,CAAA;AAAA;AAAA,iBAyBzD,0BAAA,IAA8B,oBAAoB;AAAA,iBAmClD,UAAA,CACd,IAAA,UACA,OAAA,GAAS,iBAAA,GACR,UAAU;AAAA,iBAoDG,gBAAA,CACd,OAAA,GAAS,iBAAA,GACR,mBAAmB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/testing/index.ts"],"mappings":";;;KAcY,WAAA,gBAA2B,OAAO;AAAA,UAE7B,gBAAA;EACf,OAAA,GAAU,WAAW;AAAA;AAAA,UAGN,kBAAA;EACf,MAAA;EACA,gBAAgB;AAAA;AAAA,UAGD,oBAAA;EAAA,SACN,KAAA,WAAgB,kBAAkB;EAAA,SAClC,QAAA;EACT,KAAA;EACA,IAAA;AAAA;AAAA,UAGQ,iBAAA;EACR,QAAA,GAAW,aAAA;EACX,MAAA,YAAkB,KAAK;AAAA;AAAA,UAGR,mBAAA;EACf,IAAA;EACA,IAAA;EACA,eAAA;EACA,OAAA;EACA,SAAA;EACA,OAAA;AAAA;AAAA,KAGG,gBAAA,GAAmB,OAAO,CAAC,gBAAA;AAAA,iBAkBvB,gBAAA,eACP,IAAA,EAAM,CAAA,EACN,OAAA,GAAU,gBAAA,GACT,KAAA,CAAM,CAAA;AAAA,cAeI,SAAA,SAAS,gBAAA;6BACA,OAAA,GAAiB,gBAAA,GAAmB,KAAA,CAAM,CAAA;2BAe5C,KAAA,MACP,YAAA,GACM,CAAA,EAAC,OAAA,GACN,gBAAA,GACT,KAAA,CAAM,CAAA;2BAec,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,GAAmB,KAAA,CAAM,CAAA;sBAenD,IAAA,EACV,CAAA,EAAC,MAAA,GACC,gBAAA,EAAgB,OAAA,GACd,gBAAA,GACT,KAAA,CAAM,CAAA;6BAegB,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,GAAmB,KAAA,CAAM,CAAA;AAAA;AAAA,cAgB5D,UAAA;;+BApFS,OAAA,GAAiB,gBAAA,KAAmB,KAAA,CAAM,CAAA;6BAe5C,KAAA,MACP,YAAA,GACM,CAAA,EAAC,OAAA,GACN,gBAAA,KACT,KAAA,CAAM,CAAA;6BAec,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,KAAmB,KAAA,CAAM,CAAA;wBAenD,IAAA,EACV,CAAA,EAAC,MAAA,GACC,gBAAA,EAAgB,OAAA,GACd,gBAAA,KACT,KAAA,CAAM,CAAA;+BAegB,IAAA,EAAQ,CAAA,EAAC,OAAA,GAAY,gBAAA,KAAmB,KAAA,CAAM,CAAA;AAAA;AAAA,iBAyBzD,0BAAA,IAA8B,oBAAoB;AAAA,iBAmClD,UAAA,CACd,IAAA,UACA,OAAA,GAAS,iBAAA,GACR,UAAU;AAAA,iBAoDG,gBAAA,CACd,OAAA,GAAS,iBAAA,GACR,mBAAmB"}
@@ -1,7 +1,8 @@
1
1
  import { parseSegments } from "../router/match.js";
2
- import { computeRouteActivityMatches } from "../router/resolution.js";
3
- import "../router/route.js";
2
+ import { computeRouteActivityMatches } from "../router/route-matching.js";
4
3
  import { addInvalidationListener } from "../data/invalidation-listeners.js";
4
+ import "../data/testing.js";
5
+ import "../router/testing.js";
5
6
  //#region src/testing/index.ts
6
7
  function normalizeRefresh(options) {
7
8
  return async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/testing/index.ts"],"sourcesContent":["import type { Query, QueryStaleReason } from '../data';\nimport { parseSegments } from '../router/match';\nimport { computeRouteActivityMatches } from '../router/route';\nimport type {\n ParsedSegment,\n Route,\n RouteManifest,\n RouteMatch,\n RouteRecord,\n} from '../common/router';\nimport {\n addInvalidationListener,\n type InvalidationEvent,\n} from '../data/invalidation-listeners';\n\nexport type MockRefresh = () => void | Promise<void>;\n\nexport interface MockQueryOptions {\n refresh?: MockRefresh;\n}\n\nexport interface InvalidationRecord {\n prefix: string;\n markPendingWrite: boolean;\n}\n\nexport interface InvalidationRecorder {\n readonly calls: readonly InvalidationRecord[];\n readonly prefixes: readonly string[];\n clear(): void;\n stop(): void;\n}\n\ninterface MatchRouteOptions {\n manifest?: RouteManifest;\n routes?: readonly Route[];\n}\n\nexport interface RoutePatternWarning {\n kind: 'route-collision';\n path: string;\n conflictingPath: string;\n segment: string;\n namespace: string | undefined;\n message: string;\n}\n\ntype StaleValueReason = Exclude<QueryStaleReason, 'error'>;\n\nfunction normalizeRefresh(options?: MockQueryOptions): () => Promise<void> {\n return async () => {\n await options?.refresh?.();\n };\n}\n\nfunction makeQuery<T extends {}>(\n state: Omit<Query<T>, 'refresh'>,\n options?: MockQueryOptions\n): Query<T> {\n return {\n ...state,\n refresh: normalizeRefresh(options),\n } as Query<T>;\n}\n\nfunction createFreshQuery<T extends {}>(\n data: T,\n options?: MockQueryOptions\n): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: false,\n stale: false,\n consistency: 'fresh',\n staleReason: null,\n },\n options\n );\n}\n\nexport const mockQuery = Object.assign(createFreshQuery, {\n loading<T extends {} = {}>(options?: MockQueryOptions): Query<T> {\n return makeQuery<T>(\n {\n data: null,\n error: null,\n loading: true,\n refreshing: false,\n stale: false,\n consistency: 'fresh',\n staleReason: null,\n },\n options\n );\n },\n\n error<T extends {} = {}>(\n error: {},\n previousData?: T,\n options?: MockQueryOptions\n ): Query<T> {\n return makeQuery(\n {\n data: previousData ?? null,\n error,\n loading: false,\n refreshing: false,\n stale: true,\n consistency: 'stale',\n staleReason: 'error',\n } as Omit<Query<T>, 'refresh'>,\n options\n );\n },\n\n refreshing<T extends {}>(data: T, options?: MockQueryOptions): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: true,\n stale: true,\n consistency: 'refreshing',\n staleReason: null,\n },\n options\n );\n },\n\n stale<T extends {}>(\n data: T,\n reason: StaleValueReason = 'inconsistent',\n options?: MockQueryOptions\n ): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: false,\n stale: true,\n consistency: 'stale',\n staleReason: reason,\n },\n options\n );\n },\n\n pendingWrite<T extends {}>(data: T, options?: MockQueryOptions): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: true,\n stale: true,\n consistency: 'pending-write',\n staleReason: null,\n },\n options\n );\n },\n});\n\nexport const queryState = {\n fresh: createFreshQuery,\n loading: mockQuery.loading,\n error: mockQuery.error,\n refreshing: mockQuery.refreshing,\n stale: mockQuery.stale,\n pendingWrite: mockQuery.pendingWrite,\n};\n\nexport function createInvalidationRecorder(): InvalidationRecorder {\n const records: InvalidationRecord[] = [];\n let active = true;\n\n const unsubscribe = addInvalidationListener((event: InvalidationEvent) => {\n records.push({\n prefix: event.prefix,\n markPendingWrite: event.markPendingWrite,\n });\n });\n\n return {\n get calls() {\n return records.slice();\n },\n\n get prefixes() {\n return records.map((record) => record.prefix);\n },\n\n clear() {\n records.length = 0;\n },\n\n stop() {\n if (!active) {\n return;\n }\n\n active = false;\n unsubscribe();\n },\n };\n}\n\nexport function matchRoute(\n path: string,\n options: MatchRouteOptions = {}\n): RouteMatch | null {\n return computeRouteActivityMatches(path, options)[0] ?? null;\n}\n\ntype RoutePatternRecord = {\n path: string;\n segments: ParsedSegment[];\n namespace: string | undefined;\n};\n\nfunction getRoutePatternRecords(\n options: MatchRouteOptions\n): RoutePatternRecord[] {\n if (options.manifest) {\n return options.manifest.records.map((record: RouteRecord) => ({\n path: record.path,\n segments: record.segments,\n namespace: record.options.namespace,\n }));\n }\n\n return (options.routes ?? []).map((route) => ({\n path: route.path,\n segments: parseSegments(route.path),\n namespace: route.namespace,\n }));\n}\n\nfunction routePrefixMatches(\n splatPrefix: readonly ParsedSegment[],\n routeSegments: readonly ParsedSegment[]\n): boolean {\n if (routeSegments.length <= splatPrefix.length) {\n return false;\n }\n\n for (let index = 0; index < splatPrefix.length; index++) {\n const splatSegment = splatPrefix[index];\n const routeSegment = routeSegments[index];\n\n if (\n splatSegment.kind === 'static' &&\n routeSegment.kind === 'static' &&\n splatSegment.value !== routeSegment.value\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function getRouteWarnings(\n options: MatchRouteOptions = {}\n): RoutePatternWarning[] {\n const records = getRoutePatternRecords(options);\n const warnings: RoutePatternWarning[] = [];\n\n for (const record of records) {\n const splatIndex = record.segments.findIndex(\n (segment) => segment.kind === 'splat'\n );\n if (splatIndex === -1) {\n continue;\n }\n\n const splatPrefix = record.segments.slice(0, splatIndex);\n for (const candidate of records) {\n if (\n candidate === record ||\n candidate.namespace !== record.namespace ||\n !routePrefixMatches(splatPrefix, candidate.segments)\n ) {\n continue;\n }\n\n const reservedSegment = candidate.segments[splatIndex];\n if (reservedSegment?.kind !== 'static') {\n continue;\n }\n\n warnings.push({\n kind: 'route-collision',\n path: record.path,\n conflictingPath: candidate.path,\n segment: reservedSegment.value,\n namespace: record.namespace,\n message: `Route \"${candidate.path}\" reserves segment \"${reservedSegment.value}\" under named splat route \"${record.path}\".`,\n });\n }\n }\n\n return warnings.sort((left, right) => {\n const pathOrder = left.path.localeCompare(right.path);\n if (pathOrder !== 0) {\n return pathOrder;\n }\n return left.conflictingPath.localeCompare(right.conflictingPath);\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/testing/index.ts"],"sourcesContent":["import type { Query, QueryStaleReason } from '../data';\nimport type {\n ParsedSegment,\n Route,\n RouteManifest,\n RouteMatch,\n RouteRecord,\n} from '../common/router';\nimport {\n type InvalidationEvent,\n addInvalidationListener,\n} from '../data/testing';\nimport { computeRouteActivityMatches, parseSegments } from '../router/testing';\n\nexport type MockRefresh = () => void | Promise<void>;\n\nexport interface MockQueryOptions {\n refresh?: MockRefresh;\n}\n\nexport interface InvalidationRecord {\n prefix: string;\n markPendingWrite: boolean;\n}\n\nexport interface InvalidationRecorder {\n readonly calls: readonly InvalidationRecord[];\n readonly prefixes: readonly string[];\n clear(): void;\n stop(): void;\n}\n\ninterface MatchRouteOptions {\n manifest?: RouteManifest;\n routes?: readonly Route[];\n}\n\nexport interface RoutePatternWarning {\n kind: 'route-collision';\n path: string;\n conflictingPath: string;\n segment: string;\n namespace: string | undefined;\n message: string;\n}\n\ntype StaleValueReason = Exclude<QueryStaleReason, 'error'>;\n\nfunction normalizeRefresh(options?: MockQueryOptions): () => Promise<void> {\n return async () => {\n await options?.refresh?.();\n };\n}\n\nfunction makeQuery<T extends {}>(\n state: Omit<Query<T>, 'refresh'>,\n options?: MockQueryOptions\n): Query<T> {\n return {\n ...state,\n refresh: normalizeRefresh(options),\n } as Query<T>;\n}\n\nfunction createFreshQuery<T extends {}>(\n data: T,\n options?: MockQueryOptions\n): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: false,\n stale: false,\n consistency: 'fresh',\n staleReason: null,\n },\n options\n );\n}\n\nexport const mockQuery = Object.assign(createFreshQuery, {\n loading<T extends {} = {}>(options?: MockQueryOptions): Query<T> {\n return makeQuery<T>(\n {\n data: null,\n error: null,\n loading: true,\n refreshing: false,\n stale: false,\n consistency: 'fresh',\n staleReason: null,\n },\n options\n );\n },\n\n error<T extends {} = {}>(\n error: {},\n previousData?: T,\n options?: MockQueryOptions\n ): Query<T> {\n return makeQuery(\n {\n data: previousData ?? null,\n error,\n loading: false,\n refreshing: false,\n stale: true,\n consistency: 'stale',\n staleReason: 'error',\n } as Omit<Query<T>, 'refresh'>,\n options\n );\n },\n\n refreshing<T extends {}>(data: T, options?: MockQueryOptions): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: true,\n stale: true,\n consistency: 'refreshing',\n staleReason: null,\n },\n options\n );\n },\n\n stale<T extends {}>(\n data: T,\n reason: StaleValueReason = 'inconsistent',\n options?: MockQueryOptions\n ): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: false,\n stale: true,\n consistency: 'stale',\n staleReason: reason,\n },\n options\n );\n },\n\n pendingWrite<T extends {}>(data: T, options?: MockQueryOptions): Query<T> {\n return makeQuery(\n {\n data,\n error: null,\n loading: false,\n refreshing: true,\n stale: true,\n consistency: 'pending-write',\n staleReason: null,\n },\n options\n );\n },\n});\n\nexport const queryState = {\n fresh: createFreshQuery,\n loading: mockQuery.loading,\n error: mockQuery.error,\n refreshing: mockQuery.refreshing,\n stale: mockQuery.stale,\n pendingWrite: mockQuery.pendingWrite,\n};\n\nexport function createInvalidationRecorder(): InvalidationRecorder {\n const records: InvalidationRecord[] = [];\n let active = true;\n\n const unsubscribe = addInvalidationListener((event: InvalidationEvent) => {\n records.push({\n prefix: event.prefix,\n markPendingWrite: event.markPendingWrite,\n });\n });\n\n return {\n get calls() {\n return records.slice();\n },\n\n get prefixes() {\n return records.map((record) => record.prefix);\n },\n\n clear() {\n records.length = 0;\n },\n\n stop() {\n if (!active) {\n return;\n }\n\n active = false;\n unsubscribe();\n },\n };\n}\n\nexport function matchRoute(\n path: string,\n options: MatchRouteOptions = {}\n): RouteMatch | null {\n return computeRouteActivityMatches(path, options)[0] ?? null;\n}\n\ntype RoutePatternRecord = {\n path: string;\n segments: ParsedSegment[];\n namespace: string | undefined;\n};\n\nfunction getRoutePatternRecords(\n options: MatchRouteOptions\n): RoutePatternRecord[] {\n if (options.manifest) {\n return options.manifest.records.map((record: RouteRecord) => ({\n path: record.path,\n segments: record.segments,\n namespace: record.options.namespace,\n }));\n }\n\n return (options.routes ?? []).map((route) => ({\n path: route.path,\n segments: parseSegments(route.path),\n namespace: route.namespace,\n }));\n}\n\nfunction routePrefixMatches(\n splatPrefix: readonly ParsedSegment[],\n routeSegments: readonly ParsedSegment[]\n): boolean {\n if (routeSegments.length <= splatPrefix.length) {\n return false;\n }\n\n for (let index = 0; index < splatPrefix.length; index++) {\n const splatSegment = splatPrefix[index];\n const routeSegment = routeSegments[index];\n\n if (\n splatSegment.kind === 'static' &&\n routeSegment.kind === 'static' &&\n splatSegment.value !== routeSegment.value\n ) {\n return false;\n }\n }\n\n return true;\n}\n\nexport function getRouteWarnings(\n options: MatchRouteOptions = {}\n): RoutePatternWarning[] {\n const records = getRoutePatternRecords(options);\n const warnings: RoutePatternWarning[] = [];\n\n for (const record of records) {\n const splatIndex = record.segments.findIndex(\n (segment) => segment.kind === 'splat'\n );\n if (splatIndex === -1) {\n continue;\n }\n\n const splatPrefix = record.segments.slice(0, splatIndex);\n for (const candidate of records) {\n if (\n candidate === record ||\n candidate.namespace !== record.namespace ||\n !routePrefixMatches(splatPrefix, candidate.segments)\n ) {\n continue;\n }\n\n const reservedSegment = candidate.segments[splatIndex];\n if (reservedSegment?.kind !== 'static') {\n continue;\n }\n\n warnings.push({\n kind: 'route-collision',\n path: record.path,\n conflictingPath: candidate.path,\n segment: reservedSegment.value,\n namespace: record.namespace,\n message: `Route \"${candidate.path}\" reserves segment \"${reservedSegment.value}\" under named splat route \"${record.path}\".`,\n });\n }\n }\n\n return warnings.sort((left, right) => {\n const pathOrder = left.path.localeCompare(right.path);\n if (pathOrder !== 0) {\n return pathOrder;\n }\n return left.conflictingPath.localeCompare(right.conflictingPath);\n });\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askrjs/askr",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "description": "Actor-backed deterministic UI framework",
5
5
  "keywords": [
6
6
  "askr",
@@ -132,14 +132,14 @@
132
132
  "bench:tier4": "cross-env NODE_ENV=production vp test bench --run --reporter=default --config vitest.bench.tier4.config.ts"
133
133
  },
134
134
  "devDependencies": {
135
- "@types/node": "^26.0.1",
136
- "@vitest/browser-playwright": "4.1.9",
135
+ "@types/node": "^26.1.1",
136
+ "@vitest/browser-playwright": "4.1.10",
137
137
  "cross-env": "^10.1.0",
138
138
  "jsdom": "^29.1.1",
139
139
  "playwright": "^1.61.1",
140
140
  "tsd": "^0.33.0",
141
141
  "typescript": "^6.0.3",
142
- "vite-plus": "^0.2.1"
142
+ "vite-plus": "^0.2.4"
143
143
  },
144
144
  "tsd": {
145
145
  "compilerOptions": {
@@ -1,29 +0,0 @@
1
- //#region src/dev/invariant.ts
2
- /**
3
- * Invariant assertion utilities for correctness checking
4
- * Production-safe: invariants are enforced at build-time or with minimal overhead
5
- *
6
- * Core principle: fail fast when invariants are violated
7
- * All functions throw descriptive errors for debugging
8
- */
9
- /**
10
- * Assert a condition; throw with context if false
11
- * @internal
12
- */
13
- function invariant(condition, message, context) {
14
- if (!condition) {
15
- const contextStr = context ? "\n" + JSON.stringify(context, null, 2) : "";
16
- throw new Error(`[Askr Invariant] ${message}${contextStr}`);
17
- }
18
- }
19
- /**
20
- * Assert scheduling precondition (not reentering, not during render, etc)
21
- * @internal
22
- */
23
- function assertSchedulingPrecondition(condition, violationMessage) {
24
- invariant(condition, `[Scheduler Precondition] ${violationMessage}`);
25
- }
26
- //#endregion
27
- export { assertSchedulingPrecondition, invariant };
28
-
29
- //# sourceMappingURL=invariant.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"invariant.js","names":[],"sources":["../../src/dev/invariant.ts"],"sourcesContent":["/**\n * Invariant assertion utilities for correctness checking\n * Production-safe: invariants are enforced at build-time or with minimal overhead\n *\n * Core principle: fail fast when invariants are violated\n * All functions throw descriptive errors for debugging\n */\n\n/**\n * Assert a condition; throw with context if false\n * @internal\n */\nexport function invariant(\n condition: boolean,\n message: string,\n context?: Record<string, unknown>\n): asserts condition {\n if (!condition) {\n const contextStr = context ? '\\n' + JSON.stringify(context, null, 2) : '';\n throw new Error(`[Askr Invariant] ${message}${contextStr}`);\n }\n}\n\n/**\n * Assert object property exists and has correct type\n * @internal\n */\nexport function assertProperty<T extends object, K extends keyof T>(\n obj: T,\n prop: K,\n expectedType?: string\n): asserts obj is T & Required<Pick<T, K>> {\n invariant(prop in obj, `Object missing required property '${String(prop)}'`, {\n object: obj,\n });\n\n if (expectedType) {\n const actualType = typeof obj[prop];\n invariant(\n actualType === expectedType,\n `Property '${String(prop)}' has type '${actualType}', expected '${expectedType}'`,\n { value: obj[prop], expectedType }\n );\n }\n}\n\n/**\n * Assert a reference is not null/undefined\n * @internal\n */\nexport function assertDefined<T>(\n value: T | null | undefined,\n message: string\n): asserts value is T {\n invariant(value !== null && value !== undefined, message, { value });\n}\n\n/**\n * Assert a task runs exactly once atomically\n * Useful for verifying lifecycle events fire precisely when expected\n * @internal\n */\nexport class Once {\n private called = false;\n private calledAt: number | null = null;\n readonly name: string;\n\n constructor(name: string) {\n this.name = name;\n }\n\n check(): boolean {\n return this.called;\n }\n\n mark(): void {\n invariant(\n !this.called,\n `${this.name} called multiple times (previously at ${this.calledAt}ms)`,\n { now: Date.now() }\n );\n this.called = true;\n this.calledAt = Date.now();\n }\n\n reset(): void {\n this.called = false;\n this.calledAt = null;\n }\n}\n\n/**\n * Assert a value falls in an enumerated set\n * @internal\n */\nexport function assertEnum<T extends readonly unknown[]>(\n value: unknown,\n allowedValues: T,\n fieldName: string\n): asserts value is T[number] {\n invariant(\n allowedValues.includes(value),\n `${fieldName} must be one of [${allowedValues.join(', ')}], got ${JSON.stringify(value)}`,\n { value, allowed: allowedValues }\n );\n}\n\n/**\n * Assert execution context (scheduler, component, etc)\n * @internal\n */\nexport function assertContext(\n actual: unknown,\n expected: unknown,\n contextName: string\n): asserts actual is typeof expected {\n invariant(\n actual === expected,\n `Invalid ${contextName} context. Expected ${expected}, got ${actual}`,\n { expected, actual }\n );\n}\n\n/**\n * Assert scheduling precondition (not reentering, not during render, etc)\n * @internal\n */\nexport function assertSchedulingPrecondition(\n condition: boolean,\n violationMessage: string\n): asserts condition {\n invariant(condition, `[Scheduler Precondition] ${violationMessage}`);\n}\n\n/**\n * Assert state precondition\n * @internal\n */\nexport function assertStatePrecondition(\n condition: boolean,\n violationMessage: string\n): asserts condition {\n invariant(condition, `[State Precondition] ${violationMessage}`);\n}\n\n/**\n * Verify AbortController lifecycle\n * @internal\n */\nexport function assertAbortControllerState(\n signal: AbortSignal,\n expectedAborted: boolean,\n context: string\n): void {\n invariant(\n signal.aborted === expectedAborted,\n `AbortSignal ${expectedAborted ? 'should be' : 'should not be'} aborted in ${context}`,\n { actual: signal.aborted, expected: expectedAborted }\n );\n}\n\n/**\n * Guard: throw if callback is null when it shouldn't be\n * Used for notifyUpdate, event handlers, etc.\n * @internal\n */\nexport function assertCallbackAvailable<\n T extends (...args: unknown[]) => unknown,\n>(callback: T | null | undefined, callbackName: string): asserts callback is T {\n invariant(\n callback !== null && callback !== undefined,\n `${callbackName} callback is required but not available`,\n { callback }\n );\n}\n\n/**\n * Verify evaluation generation prevents stale evaluations\n * @internal\n */\nexport function assertEvaluationGeneration(\n current: number,\n latest: number,\n context: string\n): void {\n invariant(\n current === latest,\n `Stale evaluation generation in ${context}: current ${current}, latest ${latest}`,\n { current, latest }\n );\n}\n\n/**\n * Verify mounted flag state\n * @internal\n */\nexport function assertMountedState(\n mounted: boolean,\n expectedMounted: boolean,\n context: string\n): void {\n invariant(\n mounted === expectedMounted,\n `Invalid mounted state in ${context}: expected ${expectedMounted}, got ${mounted}`,\n { mounted, expected: expectedMounted }\n );\n}\n\n/**\n * Verify no null target when rendering\n * @internal\n */\nexport function assertRenderTarget(\n target: Element | null,\n context: string\n): asserts target is Element {\n invariant(target !== null, `Cannot render in ${context}: target is null`, {\n target,\n });\n}\n"],"mappings":";;;;;;;;;;;;AAYA,SAAgB,UACd,WACA,SACA,SACmB;CACnB,IAAI,CAAC,WAAW;EACd,MAAM,aAAa,UAAU,OAAO,KAAK,UAAU,SAAS,MAAM,CAAC,IAAI;EACvE,MAAM,IAAI,MAAM,oBAAoB,UAAU,YAAY;CAC5D;AACF;;;;;AA0GA,SAAgB,6BACd,WACA,kBACmB;CACnB,UAAU,WAAW,4BAA4B,kBAAkB;AACrE"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.js","names":[],"sources":["../../src/dev/logger.ts"],"sourcesContent":["/**\n * Centralized logger interface\n * - Keeps production builds silent for debug/warn/info messages\n * - Ensures consistent behavior across the codebase\n * - Protects against missing `console` in some environments\n */\n\nimport { isProductionEnvironment } from '../common/env';\n\nfunction callConsole(method: string, args: unknown[]): void {\n const c = typeof console !== 'undefined' ? (console as unknown) : undefined;\n if (!c) return;\n const fn = (c as Record<string, unknown>)[method];\n if (typeof fn === 'function') {\n try {\n (fn as (...a: unknown[]) => unknown).apply(console, args as unknown[]);\n } catch {\n // ignore logging errors\n }\n }\n}\n\nexport const logger = {\n debug: (...args: unknown[]) => {\n if (isProductionEnvironment()) return;\n callConsole('debug', args);\n },\n\n info: (...args: unknown[]) => {\n if (isProductionEnvironment()) return;\n callConsole('info', args);\n },\n\n warn: (...args: unknown[]) => {\n if (isProductionEnvironment()) return;\n callConsole('warn', args);\n },\n\n error: (...args: unknown[]) => {\n callConsole('error', args);\n },\n};\n"],"mappings":";;;;;;;;AASA,SAAS,YAAY,QAAgB,MAAuB;CAC1D,MAAM,IAAI,OAAO,YAAY,cAAe,UAAsB;CAClE,IAAI,CAAC,GAAG;CACR,MAAM,KAAM,EAA8B;CAC1C,IAAI,OAAO,OAAO,YAChB,IAAI;EACF,GAAqC,MAAM,SAAS,IAAiB;CACvE,QAAQ,CAER;AAEJ;AAEA,MAAa,SAAS;CACpB,QAAQ,GAAG,SAAoB;EAC7B,IAAI,wBAAwB,GAAG;EAC/B,YAAY,SAAS,IAAI;CAC3B;CAEA,OAAO,GAAG,SAAoB;EAC5B,IAAI,wBAAwB,GAAG;EAC/B,YAAY,QAAQ,IAAI;CAC1B;CAEA,OAAO,GAAG,SAAoB;EAC5B,IAAI,wBAAwB,GAAG;EAC/B,YAAY,QAAQ,IAAI;CAC1B;CAEA,QAAQ,GAAG,SAAoB;EAC7B,YAAY,SAAS,IAAI;CAC3B;AACF"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"portal.d.ts","names":[],"sources":["../../../src/foundations/structures/portal.tsx"],"mappings":";;;;UAoCiB,MAAA,WAAiB,eAAA,GAAkB,eAAA;;;EASxB;EAJ1B,MAAA,CAAO,KAAA;IAAS,QAAA,GAAW,CAAA;EAAA;AAAA;AAAA,UAGZ,WAAA;EACf,QAAA,GAAW,eAAe;AAAA;AAAA,iBA+BZ,YAAA,WACJ,eAAA,GAAkB,eAAA,KACzB,MAAA,CAAO,CAAA;AAAA,iBAyDI,mBAAA;AAAA,iBAMA,yBAAA,CAA0B,KAAoB;AAAA,iBAsI9C,6BAAA,CACd,QAA2B,EAAjB,iBAAiB;AAAA,cAkBhB,aAAA,EAAe,MAAM,CAAC,eAAA;AAAA,iBAkBnB,MAAA,CAAO,KAAkB,EAAX,WAAW"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"portal.js","names":[],"sources":["../../../src/foundations/structures/portal.tsx"],"sourcesContent":["/**\n * Portal / Host primitive.\n *\n * Foundations remain runtime-agnostic: a portal is an explicit read/write slot.\n * Scheduling and attachment are owned by the runtime when `createPortalSlot`\n * exists; otherwise this falls back to a local slot (deterministic, but does\n * not schedule updates).\n *\n * POLICY DECISIONS (LOCKED):\n *\n * 1. Local Mutable State\n * Foundations may use local mutable state ONLY to model deterministic slots,\n * never to coordinate timing, effects, or ordering. The fallback mode uses\n * closure-local `mounted` and `value` variables which are non-escaping and\n * deterministic.\n *\n * 2. Return Type Philosophy\n * Portal call signatures return `unknown` (intentionally opaque). The runtime\n * owns the concrete type. This prevents foundations from assuming JSX.Element\n * or DOM node types, maintaining runtime-agnostic portability.\n */\n\nimport {\n markReactivePropsDirtySource,\n markReadableDerivedSubscribersDirty,\n notifyReadableReaders,\n recordReadableRead,\n type ReadableSource,\n} from '../../runtime/readable';\nimport {\n getCurrentComponentInstance,\n getCurrentPortalScope,\n type ComponentInstance,\n} from '../../runtime/component';\nimport type { RenderableChild } from '../../common/vnode';\n\nexport interface Portal<T extends RenderableChild = RenderableChild> {\n /** Mount point — rendered exactly once */\n (): unknown;\n\n /** Render content into the portal */\n render(props: { children?: T }): unknown;\n}\n\nexport interface PortalProps {\n children?: RenderableChild;\n}\n\nfunction createPortalSlot<T>(): {\n read(): unknown;\n write(value: T | undefined): void;\n} {\n let currentValue: T | undefined;\n\n const source = (() => {\n recordReadableRead(source);\n return currentValue;\n }) as ReadableSource<T | undefined>;\n\n return {\n read() {\n return source();\n },\n write(value: T | undefined) {\n if (Object.is(currentValue, value)) {\n return;\n }\n\n currentValue = value;\n markReadableDerivedSubscribersDirty(source);\n markReactivePropsDirtySource(source);\n notifyReadableReaders(source);\n },\n };\n}\n\nexport function definePortal<\n T extends RenderableChild = RenderableChild,\n>(): Portal<T> {\n // Using `typeof createPortalSlot` is safe even if the identifier is not\n // defined at runtime (it returns 'undefined' rather than throwing).\n if (typeof createPortalSlot === 'function') {\n const slot = createPortalSlot<T>();\n\n function PortalHost() {\n return slot.read();\n }\n\n PortalHost.render = function PortalRender(props: { children?: T }) {\n slot.write(props.children);\n return null;\n };\n\n return PortalHost as Portal<T>;\n }\n\n // Deterministic local fallback (SSR/tests). No runtime scheduling.\n // Writes are accepted only after the host has rendered at least once.\n //\n // CRITICAL BEHAVIOR:\n // - Writes update local state but do NOT trigger re-renders\n // - The portal host will reflect changes only when the component tree\n // re-renders for other reasons (e.g., parent state change)\n // - This is safe for SSR and tests where rendering is synchronous\n // and externally controlled\n // - In runtime mode, createPortalSlot handles scheduling automatically\n let mounted = false;\n let value: T | undefined;\n\n function PortalHostFallback() {\n mounted = true;\n return value as unknown;\n }\n\n PortalHostFallback.render = function PortalRenderFallback(props: {\n children?: T;\n }) {\n if (!mounted) return null;\n value = props.children;\n return null;\n };\n\n return PortalHostFallback as Portal<T>;\n}\n\ntype DefaultPortalState = {\n portal: Portal<RenderableChild>;\n owner: ComponentInstance | null;\n cleanupOwners: WeakSet<ComponentInstance>;\n};\n\nlet _defaultPortalStates = new Map<object, DefaultPortalState>();\nlet _hasPendingDefaultPortalValue = false;\nlet _pendingDefaultPortalValue: RenderableChild | undefined = undefined;\n\nexport function _resetDefaultPortal(): void {\n _defaultPortalStates = new Map<object, DefaultPortalState>();\n _hasPendingDefaultPortalValue = false;\n _pendingDefaultPortalValue = undefined;\n}\n\nexport function disposeDefaultPortalScope(scope: object | null): void {\n if (!scope) {\n return;\n }\n\n const state = _defaultPortalStates.get(scope);\n if (state) {\n state.portal.render({ children: undefined });\n }\n\n _defaultPortalStates.delete(scope);\n}\n\nfunction isComponentPortalScope(scope: object): scope is ComponentInstance {\n return Array.isArray((scope as ComponentInstance).cleanupFns);\n}\n\nfunction isStaleDefaultPortalScope(scope: object): boolean {\n if (!isComponentPortalScope(scope)) {\n return false;\n }\n\n if (scope.target && scope.target.isConnected === false) {\n return true;\n }\n\n return scope.mounted === false;\n}\n\nfunction pruneStaleDefaultPortalScopes(): void {\n if (_defaultPortalStates.size === 0) {\n return;\n }\n\n for (const scope of Array.from(_defaultPortalStates.keys())) {\n if (isStaleDefaultPortalScope(scope)) {\n disposeDefaultPortalScope(scope);\n }\n }\n}\n\nfunction getSingleDefaultPortalScope(): object | null {\n pruneStaleDefaultPortalScopes();\n\n if (_defaultPortalStates.size !== 1) {\n return null;\n }\n\n return _defaultPortalStates.keys().next().value ?? null;\n}\n\nfunction getDefaultPortalState(scope: object): DefaultPortalState {\n let state = _defaultPortalStates.get(scope);\n if (!state) {\n state = {\n portal: definePortal<RenderableChild>(),\n owner: null,\n cleanupOwners: new WeakSet<ComponentInstance>(),\n };\n _defaultPortalStates.set(scope, state);\n }\n return state;\n}\n\nfunction resolveDefaultPortalScope(\n owner: ComponentInstance | null\n): object | null {\n return (\n owner?.portalScope ??\n getCurrentPortalScope() ??\n getSingleDefaultPortalScope()\n );\n}\n\nfunction writeDefaultPortal(\n props: PortalProps,\n owner: ComponentInstance | null\n): void {\n const scope = resolveDefaultPortalScope(owner);\n if (!scope) {\n if (_defaultPortalStates.size !== 0) {\n return;\n }\n\n _hasPendingDefaultPortalValue = true;\n _pendingDefaultPortalValue = props.children;\n return;\n }\n\n const state = getDefaultPortalState(scope);\n _hasPendingDefaultPortalValue = false;\n _pendingDefaultPortalValue = undefined;\n state.portal.render(props);\n state.owner = owner;\n}\n\nfunction applyPendingDefaultPortalValue(scope: object): void {\n if (!_hasPendingDefaultPortalValue) {\n return;\n }\n\n const state = getDefaultPortalState(scope);\n state.portal.render({ children: _pendingDefaultPortalValue });\n state.owner = null;\n _hasPendingDefaultPortalValue = false;\n _pendingDefaultPortalValue = undefined;\n}\n\nfunction registerDefaultPortalOwner(owner: ComponentInstance): void {\n const scope = resolveDefaultPortalScope(owner);\n if (!scope) {\n return;\n }\n\n const state = getDefaultPortalState(scope);\n if (state.cleanupOwners.has(owner)) {\n return;\n }\n\n state.cleanupOwners.add(owner);\n owner.cleanupFns.push(() => {\n const currentState = _defaultPortalStates.get(scope);\n if (!currentState) {\n return;\n }\n\n if (currentState.owner === owner) {\n currentState.portal.render({ children: undefined });\n currentState.owner = null;\n }\n currentState.cleanupOwners.delete(owner);\n });\n}\n\nexport function clearDefaultPortalForInstance(\n instance: ComponentInstance\n): void {\n const scope = instance.portalScope;\n if (!scope) {\n return;\n }\n\n const state = _defaultPortalStates.get(scope);\n if (!state) {\n return;\n }\n\n _hasPendingDefaultPortalValue = false;\n _pendingDefaultPortalValue = undefined;\n state.portal.render({ children: undefined });\n state.owner = null;\n}\n\nexport const DefaultPortal: Portal<RenderableChild> = (() => {\n function Host() {\n const scope = resolveDefaultPortalScope(getCurrentComponentInstance());\n if (!scope) {\n return null;\n }\n\n applyPendingDefaultPortalValue(scope);\n const v = getDefaultPortalState(scope).portal();\n return v === undefined ? null : v;\n }\n Host.render = function Render(props: { children?: RenderableChild }) {\n writeDefaultPortal(props, getCurrentComponentInstance());\n return null;\n };\n return Host as Portal<RenderableChild>;\n})();\n\nexport function Portal(props: PortalProps): null {\n const owner = getCurrentComponentInstance();\n if (owner) {\n registerDefaultPortalOwner(owner);\n }\n writeDefaultPortal(props, owner);\n return null;\n}\n\n/**\n * NOTE:\n * createPortalSlot is a runtime primitive.\n * It owns scheduling, consistency, and SSR behavior.\n */\n"],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import { getCurrentInstance } from "./component-scope.js";
2
- import { cleanupComponent } from "./component-cleanup.js";
3
- import { captureInlineRenderSnapshot, createComponentInstance, mountInstanceInline, renderComponentInline, warnUnusedStateReads } from "./component-internal.js";
4
- import "./component.js";
5
- export { captureInlineRenderSnapshot, cleanupComponent, createComponentInstance, getCurrentInstance, mountInstanceInline, renderComponentInline, warnUnusedStateReads };