@noego/wood 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +7 -0
  2. package/dist/browser-test-setup.cjs +29 -0
  3. package/dist/browser-test-setup.cjs.map +1 -0
  4. package/dist/browser-test-setup.d.cts +8 -0
  5. package/dist/browser-test-setup.d.ts +8 -0
  6. package/dist/browser-test-setup.js +9 -0
  7. package/dist/browser-test-setup.js.map +1 -0
  8. package/dist/client/global_polyfill.d.cts +1 -0
  9. package/dist/client/global_polyfill.d.ts +1 -0
  10. package/dist/client/index.cjs +7 -0
  11. package/dist/client/index.cjs.map +1 -1
  12. package/dist/client/index.d.cts +8 -4
  13. package/dist/client/index.d.ts +8 -4
  14. package/dist/client/index.js +6 -1
  15. package/dist/client/index.js.map +1 -1
  16. package/dist/codegen/renderer_app_generator.cjs +97 -24
  17. package/dist/codegen/renderer_app_generator.cjs.map +1 -1
  18. package/dist/codegen/renderer_app_generator.js +97 -24
  19. package/dist/codegen/renderer_app_generator.js.map +1 -1
  20. package/dist/codegen/type_generator.cjs +9 -0
  21. package/dist/codegen/type_generator.cjs.map +1 -1
  22. package/dist/codegen/type_generator.js +9 -0
  23. package/dist/codegen/type_generator.js.map +1 -1
  24. package/dist/config/config_parser.cjs +10 -0
  25. package/dist/config/config_parser.cjs.map +1 -1
  26. package/dist/config/config_parser.js +10 -0
  27. package/dist/config/config_parser.js.map +1 -1
  28. package/dist/fetch.cjs +38 -0
  29. package/dist/fetch.cjs.map +1 -0
  30. package/dist/fetch.d.cts +7 -0
  31. package/dist/fetch.d.ts +7 -0
  32. package/dist/fetch.js +12 -0
  33. package/dist/fetch.js.map +1 -0
  34. package/dist/frontend/frontend_page.cjs +3 -3
  35. package/dist/frontend/frontend_page.cjs.map +1 -1
  36. package/dist/frontend/frontend_page.d.cts +1 -1
  37. package/dist/frontend/frontend_page.d.ts +1 -1
  38. package/dist/frontend/frontend_page.js +3 -3
  39. package/dist/frontend/frontend_page.js.map +1 -1
  40. package/dist/frontend/frontend_surface.cjs +31 -17
  41. package/dist/frontend/frontend_surface.cjs.map +1 -1
  42. package/dist/frontend/frontend_surface.d.cts +13 -2
  43. package/dist/frontend/frontend_surface.d.ts +13 -2
  44. package/dist/frontend/frontend_surface.js +37 -17
  45. package/dist/frontend/frontend_surface.js.map +1 -1
  46. package/dist/frontend/index.d.cts +3 -0
  47. package/dist/frontend/index.d.ts +3 -0
  48. package/dist/index.cjs +5 -0
  49. package/dist/index.cjs.map +1 -1
  50. package/dist/index.d.cts +27 -1
  51. package/dist/index.d.ts +27 -1
  52. package/dist/index.js +3 -0
  53. package/dist/index.js.map +1 -1
  54. package/dist/loader/index.cjs +19 -2
  55. package/dist/loader/index.cjs.map +1 -1
  56. package/dist/loader/index.d.cts +1 -0
  57. package/dist/loader/index.d.ts +1 -0
  58. package/dist/loader/index.js +19 -1
  59. package/dist/loader/index.js.map +1 -1
  60. package/dist/loader/loader_orchestration.cjs +82 -0
  61. package/dist/loader/loader_orchestration.cjs.map +1 -0
  62. package/dist/loader/loader_orchestration.d.cts +66 -0
  63. package/dist/loader/loader_orchestration.d.ts +66 -0
  64. package/dist/loader/loader_orchestration.js +51 -0
  65. package/dist/loader/loader_orchestration.js.map +1 -0
  66. package/dist/loader/loader_runner.cjs +46 -41
  67. package/dist/loader/loader_runner.cjs.map +1 -1
  68. package/dist/loader/loader_runner.d.cts +12 -6
  69. package/dist/loader/loader_runner.d.ts +12 -6
  70. package/dist/loader/loader_runner.js +50 -41
  71. package/dist/loader/loader_runner.js.map +1 -1
  72. package/dist/native_browser.types-BY2daUOS.d.ts +189 -0
  73. package/dist/native_browser.types-vWXtE4rM.d.cts +189 -0
  74. package/dist/navigation/index.cjs +15 -2
  75. package/dist/navigation/index.cjs.map +1 -1
  76. package/dist/navigation/index.d.cts +6 -28
  77. package/dist/navigation/index.d.ts +6 -28
  78. package/dist/navigation/index.js +8 -1
  79. package/dist/navigation/index.js.map +1 -1
  80. package/dist/navigation/layout_preservation.cjs.map +1 -1
  81. package/dist/navigation/layout_preservation.d.cts +27 -2
  82. package/dist/navigation/layout_preservation.d.ts +27 -2
  83. package/dist/navigation/layout_preservation.js.map +1 -1
  84. package/dist/runtime/get_container.cjs +2 -0
  85. package/dist/runtime/get_container.cjs.map +1 -1
  86. package/dist/runtime/get_container.js +2 -0
  87. package/dist/runtime/get_container.js.map +1 -1
  88. package/dist/runtime/index.cjs +5 -0
  89. package/dist/runtime/index.cjs.map +1 -1
  90. package/dist/runtime/index.d.cts +2 -0
  91. package/dist/runtime/index.d.ts +2 -0
  92. package/dist/runtime/index.js +3 -0
  93. package/dist/runtime/index.js.map +1 -1
  94. package/dist/runtime/runtime_capabilities.cjs +35 -0
  95. package/dist/runtime/runtime_capabilities.cjs.map +1 -0
  96. package/dist/runtime/runtime_capabilities.d.cts +6 -0
  97. package/dist/runtime/runtime_capabilities.d.ts +6 -0
  98. package/dist/runtime/runtime_capabilities.js +11 -0
  99. package/dist/runtime/runtime_capabilities.js.map +1 -0
  100. package/dist/runtime/runtime_module.cjs +2 -0
  101. package/dist/runtime/runtime_module.cjs.map +1 -1
  102. package/dist/runtime/runtime_module.js +2 -0
  103. package/dist/runtime/runtime_module.js.map +1 -1
  104. package/dist/test-wood.cjs +150 -0
  105. package/dist/test-wood.cjs.map +1 -0
  106. package/dist/test-wood.d.cts +62 -0
  107. package/dist/test-wood.d.ts +62 -0
  108. package/dist/test-wood.js +115 -0
  109. package/dist/test-wood.js.map +1 -0
  110. package/dist/testing/browser.cjs +92 -163
  111. package/dist/testing/browser.cjs.map +1 -1
  112. package/dist/testing/browser.d.cts +14 -13
  113. package/dist/testing/browser.d.ts +14 -13
  114. package/dist/testing/browser.js +88 -162
  115. package/dist/testing/browser.js.map +1 -1
  116. package/dist/testing/create_controller_harness.d.cts +3 -1
  117. package/dist/testing/create_controller_harness.d.ts +3 -1
  118. package/dist/testing/create_router_bridge.cjs +19 -15
  119. package/dist/testing/create_router_bridge.cjs.map +1 -1
  120. package/dist/testing/create_router_bridge.d.cts +8 -1
  121. package/dist/testing/create_router_bridge.d.ts +8 -1
  122. package/dist/testing/create_router_bridge.js +18 -15
  123. package/dist/testing/create_router_bridge.js.map +1 -1
  124. package/dist/testing/index.cjs +12 -4
  125. package/dist/testing/index.cjs.map +1 -1
  126. package/dist/testing/index.d.cts +12 -5
  127. package/dist/testing/index.d.ts +12 -5
  128. package/dist/testing/index.js +9 -3
  129. package/dist/testing/index.js.map +1 -1
  130. package/dist/testing/native_browser/browser_pool.cjs +31 -0
  131. package/dist/testing/native_browser/browser_pool.cjs.map +1 -0
  132. package/dist/testing/native_browser/browser_pool.d.cts +1 -0
  133. package/dist/testing/native_browser/browser_pool.d.ts +1 -0
  134. package/dist/testing/native_browser/browser_pool.js +6 -0
  135. package/dist/testing/native_browser/browser_pool.js.map +1 -0
  136. package/dist/testing/native_browser/happy_dom_tab.cjs +107 -0
  137. package/dist/testing/native_browser/happy_dom_tab.cjs.map +1 -0
  138. package/dist/testing/native_browser/happy_dom_tab.d.cts +35 -0
  139. package/dist/testing/native_browser/happy_dom_tab.d.ts +35 -0
  140. package/dist/testing/native_browser/happy_dom_tab.js +73 -0
  141. package/dist/testing/native_browser/happy_dom_tab.js.map +1 -0
  142. package/dist/testing/native_browser/happy_dom_transfer.cjs +29 -0
  143. package/dist/testing/native_browser/happy_dom_transfer.cjs.map +1 -0
  144. package/dist/testing/native_browser/happy_dom_transfer.d.cts +1 -0
  145. package/dist/testing/native_browser/happy_dom_transfer.d.ts +1 -0
  146. package/dist/testing/native_browser/happy_dom_transfer.js +5 -0
  147. package/dist/testing/native_browser/happy_dom_transfer.js.map +1 -0
  148. package/dist/testing/native_browser/host_transport.cjs +89 -0
  149. package/dist/testing/native_browser/host_transport.cjs.map +1 -0
  150. package/dist/testing/native_browser/host_transport.d.cts +44 -0
  151. package/dist/testing/native_browser/host_transport.d.ts +44 -0
  152. package/dist/testing/native_browser/host_transport.js +65 -0
  153. package/dist/testing/native_browser/host_transport.js.map +1 -0
  154. package/dist/testing/native_browser/native_browser.types.cjs +17 -0
  155. package/dist/testing/native_browser/native_browser.types.cjs.map +1 -0
  156. package/dist/testing/native_browser/native_browser.types.d.cts +31 -0
  157. package/dist/testing/native_browser/native_browser.types.d.ts +31 -0
  158. package/dist/testing/native_browser/native_browser.types.js +1 -0
  159. package/dist/testing/native_browser/native_browser.types.js.map +1 -0
  160. package/dist/testing/native_browser/native_browser_environment.cjs +143 -0
  161. package/dist/testing/native_browser/native_browser_environment.cjs.map +1 -0
  162. package/dist/testing/native_browser/native_browser_environment.d.cts +36 -0
  163. package/dist/testing/native_browser/native_browser_environment.d.ts +36 -0
  164. package/dist/testing/native_browser/native_browser_environment.js +109 -0
  165. package/dist/testing/native_browser/native_browser_environment.js.map +1 -0
  166. package/dist/testing/native_browser/native_browser_lifecycle.cjs +31 -0
  167. package/dist/testing/native_browser/native_browser_lifecycle.cjs.map +1 -0
  168. package/dist/testing/native_browser/native_browser_lifecycle.d.cts +1 -0
  169. package/dist/testing/native_browser/native_browser_lifecycle.d.ts +1 -0
  170. package/dist/testing/native_browser/native_browser_lifecycle.js +6 -0
  171. package/dist/testing/native_browser/native_browser_lifecycle.js.map +1 -0
  172. package/dist/testing/native_browser/playwright_tab.cjs +124 -0
  173. package/dist/testing/native_browser/playwright_tab.cjs.map +1 -0
  174. package/dist/testing/native_browser/playwright_tab.d.cts +35 -0
  175. package/dist/testing/native_browser/playwright_tab.d.ts +35 -0
  176. package/dist/testing/native_browser/playwright_tab.js +100 -0
  177. package/dist/testing/native_browser/playwright_tab.js.map +1 -0
  178. package/dist/testing/native_browser/renderer_compilation.cjs +149 -0
  179. package/dist/testing/native_browser/renderer_compilation.cjs.map +1 -0
  180. package/dist/testing/native_browser/renderer_compilation.d.cts +35 -0
  181. package/dist/testing/native_browser/renderer_compilation.d.ts +35 -0
  182. package/dist/testing/native_browser/renderer_compilation.js +115 -0
  183. package/dist/testing/native_browser/renderer_compilation.js.map +1 -0
  184. package/dist/testing/native_browser/renderer_entry.cjs +148 -0
  185. package/dist/testing/native_browser/renderer_entry.cjs.map +1 -0
  186. package/dist/testing/native_browser/renderer_entry.d.cts +13 -0
  187. package/dist/testing/native_browser/renderer_entry.d.ts +13 -0
  188. package/dist/testing/native_browser/renderer_entry.js +114 -0
  189. package/dist/testing/native_browser/renderer_entry.js.map +1 -0
  190. package/dist/testing/registration_only_root.cjs +61 -5
  191. package/dist/testing/registration_only_root.cjs.map +1 -1
  192. package/dist/testing/registration_only_root.d.cts +25 -4
  193. package/dist/testing/registration_only_root.d.ts +25 -4
  194. package/dist/testing/registration_only_root.js +60 -5
  195. package/dist/testing/registration_only_root.js.map +1 -1
  196. package/dist/testing/runner_importer.cjs +75 -0
  197. package/dist/testing/runner_importer.cjs.map +1 -0
  198. package/dist/testing/runner_importer.d.cts +8 -0
  199. package/dist/testing/runner_importer.d.ts +8 -0
  200. package/dist/testing/runner_importer.js +41 -0
  201. package/dist/testing/runner_importer.js.map +1 -0
  202. package/dist/testing/test_wood_config.cjs +387 -272
  203. package/dist/testing/test_wood_config.cjs.map +1 -1
  204. package/dist/testing/test_wood_config.d.cts +19 -123
  205. package/dist/testing/test_wood_config.d.ts +19 -123
  206. package/dist/testing/test_wood_config.js +396 -270
  207. package/dist/testing/test_wood_config.js.map +1 -1
  208. package/dist/testing/wood_config_source.cjs +12 -0
  209. package/dist/testing/wood_config_source.cjs.map +1 -1
  210. package/dist/testing/wood_config_source.d.cts +10 -0
  211. package/dist/testing/wood_config_source.d.ts +10 -0
  212. package/dist/testing/wood_config_source.js +12 -0
  213. package/dist/testing/wood_config_source.js.map +1 -1
  214. package/dist/testing/wood_env_renderer.cjs +28 -3
  215. package/dist/testing/wood_env_renderer.cjs.map +1 -1
  216. package/dist/testing/wood_env_renderer.d.cts +13 -1
  217. package/dist/testing/wood_env_renderer.d.ts +13 -1
  218. package/dist/testing/wood_env_renderer.js +28 -3
  219. package/dist/testing/wood_env_renderer.js.map +1 -1
  220. package/dist/testing/wood_lazy_runtime.cjs +109 -0
  221. package/dist/testing/wood_lazy_runtime.cjs.map +1 -0
  222. package/dist/testing/wood_lazy_runtime.d.cts +36 -0
  223. package/dist/testing/wood_lazy_runtime.d.ts +36 -0
  224. package/dist/testing/wood_lazy_runtime.js +84 -0
  225. package/dist/testing/wood_lazy_runtime.js.map +1 -0
  226. package/dist/testing/wood_test_selection.cjs +34 -55
  227. package/dist/testing/wood_test_selection.cjs.map +1 -1
  228. package/dist/testing/wood_test_selection.d.cts +18 -24
  229. package/dist/testing/wood_test_selection.d.ts +18 -24
  230. package/dist/testing/wood_test_selection.js +30 -54
  231. package/dist/testing/wood_test_selection.js.map +1 -1
  232. package/dist/testing-api.cjs +17 -0
  233. package/dist/testing-api.cjs.map +1 -0
  234. package/dist/testing-api.d.cts +18 -0
  235. package/dist/testing-api.d.ts +18 -0
  236. package/dist/testing-api.js +1 -0
  237. package/dist/testing-api.js.map +1 -0
  238. package/dist/types/config.cjs.map +1 -1
  239. package/dist/types/config.d.cts +4 -0
  240. package/dist/types/config.d.ts +4 -0
  241. package/docs/native-browser-testing.md +164 -0
  242. package/package.json +31 -5
  243. package/src/components/NavigationShell.browser.test.ts +10 -10
  244. package/src/components/NavigationShell.cleanup.browser.test.ts +57 -0
  245. package/src/components/NavigationShell.scopes.browser.test.ts +5 -5
  246. package/src/components/NavigationShell.svelte +50 -24
  247. package/src/navigation/layout_preservation.ts +3 -1
@@ -0,0 +1,189 @@
1
+ import { ConfigureFetch, TestFetchRuntime } from '@noego/testing/fetch';
2
+ import { Page } from 'playwright';
3
+ import { Window } from 'happy-dom';
4
+ import { ModuleImporter, WoodConfigSource } from './testing/wood_config_source.js';
5
+ import { ViewDef } from './types/views.js';
6
+ import { RouterBridgeEvents } from './testing/create_router_bridge.js';
7
+ import { WoodTestApi, WoodTestRawApi } from './testing-api.js';
8
+ import { IContainer } from '@noego/ioc';
9
+ import { ENV_REGISTRY, TestStub, ClassToken, ReplacementClass, ReplacementOptions, ReplacementFunction, MethodDescriptor, ExecutableReplacement, LoaderIdentity } from '@noego/testing';
10
+ import { WoodRouter } from './router/wood_router.js';
11
+ import { WoodConfig } from './types/config.js';
12
+ import { OperationDef } from './types/operations.js';
13
+ import { FrontendApplicationSurface } from './frontend/frontend_surface.js';
14
+ import { FrontendPage } from './frontend/frontend_page.js';
15
+ import { WoodTestSelection, ResolvedWoodSelection } from './testing/wood_test_selection.js';
16
+ import { WoodRendererHooks } from './testing/wood_env_renderer.js';
17
+
18
+ /** What the app's `main.testing.compose` default export receives. */
19
+ interface WoodComposeContext {
20
+ /** Standard per-environment backend push source; hosts subscribe automatically. */
21
+ readonly events: RouterBridgeEvents;
22
+ readonly configPath: string;
23
+ readonly configDir: string;
24
+ readonly config: WoodConfig;
25
+ readonly selection: ResolvedWoodSelection;
26
+ /** The selected operations (the router will serve exactly these). */
27
+ readonly operations: ReadonlyMap<string, OperationDef>;
28
+ readonly importer: ModuleImporter;
29
+ /**
30
+ * Dispatch through the environment's router. Available from `start()`
31
+ * onward (the router is built after compose returns); calling it during
32
+ * compose itself fails.
33
+ */
34
+ call<T = unknown>(operation: string, input?: unknown): Promise<T>;
35
+ }
36
+ /** What the compose hook may hand back; every member is optional. */
37
+ interface WoodComposeResult extends WoodRendererHooks {
38
+ /**
39
+ * Runs AFTER the test's substitutions are installed on the root (compose
40
+ * itself runs before them, so production registrations never shadow a
41
+ * seam). Seed world state and warm caches here — through the seamed graph,
42
+ * exactly as the test will observe it.
43
+ */
44
+ start?(): void | Promise<void>;
45
+ /**
46
+ * Quiesce BEFORE the main root disposes its instances: silence push
47
+ * delivery, drain detached work — everything that still needs the live
48
+ * graph (database, tracer) the services' own dispose hooks run against.
49
+ */
50
+ drain?(): void | Promise<void>;
51
+ /** Release resources AFTER the roots are disposed (close files, remove dirs). */
52
+ dispose?(): void | Promise<void>;
53
+ }
54
+ /**
55
+ * The app's backend composition on the root the builder hands it. Register
56
+ * lazily: nothing expensive should run until a test resolves it.
57
+ */
58
+ type WoodComposeMain = (root: IContainer, context: WoodComposeContext) => WoodComposeResult | void | Promise<WoodComposeResult | void>;
59
+ type Params = Record<string, string>;
60
+ interface TestWoodEnvironment {
61
+ /** The main-process IoC root of this environment. */
62
+ readonly root: IContainer;
63
+ readonly router: WoodRouter;
64
+ /** The selected operations. */
65
+ readonly operations: ReadonlyMap<string, OperationDef>;
66
+ /** Typed nested operation API backed by the real selected WoodRouter. */
67
+ readonly api: WoodTestApi;
68
+ /** Object-shaped untyped payload surface for deliberate runtime-validation probes. */
69
+ readonly rawApi: WoodTestRawApi;
70
+ /** Execute a selected operation through the real pipeline. */
71
+ call<T = unknown>(operation: string, input?: unknown): Promise<T>;
72
+ /** Resolve a controller class through a fresh main scope (root seams apply). */
73
+ controller<T>(controller: new (...args: never[]) => T): Promise<T>;
74
+ /** Resolve any dependency from the main root; class tokens retain their instance type. */
75
+ get<T>(token: {
76
+ readonly prototype: T;
77
+ }): Promise<T>;
78
+ get<T = unknown>(token: unknown): Promise<T>;
79
+ /** Renderer surface — present only when `pages` was selected. */
80
+ readonly frontend: FrontendApplicationSurface;
81
+ /** Backend push emitter feeding renderer subscriptions (pages only). */
82
+ readonly events: RouterBridgeEvents;
83
+ readonly rendererRoot: IContainer;
84
+ open(page: string, params?: Params, query?: Params): Promise<FrontendPage>;
85
+ navigate(page: string, params?: Params, query?: Params): Promise<FrontendPage>;
86
+ current(): FrontendPage | null;
87
+ settle(): Promise<void>;
88
+ /** DOM driver — present only when `dom` was selected. */
89
+ readonly target: Element;
90
+ click(selector: string): Promise<void>;
91
+ type(selector: string, text: string): Promise<void>;
92
+ submit(selector: string): Promise<void>;
93
+ text(selector: string): Promise<string>;
94
+ exists(selector: string): Promise<boolean>;
95
+ /** Finalize `test.*` expectations; fails on undrained renderer work. */
96
+ verify(): Promise<void>;
97
+ dispose(): Promise<void>;
98
+ readonly [ENV_REGISTRY]: unknown;
99
+ }
100
+ declare class TestWoodBuilder<H extends WoodBrowserHost | null = null> {
101
+ private readonly state;
102
+ private constructor();
103
+ static create(configPath: string): TestWoodBuilder;
104
+ fetch(configure: ConfigureFetch): TestWoodBuilder<H>;
105
+ browser(): TestWoodBuilder<'playwright'>;
106
+ browser(host: 'playwright'): TestWoodBuilder<'playwright'>;
107
+ browser(host: 'happy_dom'): TestWoodBuilder<'happy_dom'>;
108
+ /** Declare selected tiers, snapshotting the source selector at call time. */
109
+ select(selection: WoodTestSelection): TestWoodBuilder<H>;
110
+ /** Route hook/controller imports through a caller-owned importer (escape hatch). */
111
+ importer(importer: ModuleImporter): TestWoodBuilder<H>;
112
+ /** Compose a reusable canonical testStub() replacement description. */
113
+ use(preset: TestStub): TestWoodBuilder<H>;
114
+ /** Replace the class bound to an exact declared token; the declared lifetime is kept. */
115
+ class<T>(target: ClassToken<T>, replacement: ReplacementClass<T>, options?: ReplacementOptions): TestWoodBuilder<H>;
116
+ /** Replace a declared factory/provider (dependencies and lifetime kept) or a callable value. */
117
+ function(target: unknown, replacement: ReplacementFunction, options?: ReplacementOptions): TestWoodBuilder<H>;
118
+ /** A test.* method seam on the FINAL binding of an exact declared token. */
119
+ method(target: unknown, method: string, replacement: MethodDescriptor, options?: ReplacementOptions): TestWoodBuilder<H>;
120
+ /** Provide a caller-owned value for an exact declared token (never disposed by the app). */
121
+ value(target: unknown, replacement: unknown, options?: ReplacementOptions): TestWoodBuilder<H>;
122
+ /**
123
+ * Replace the executable satisfying a production middleware identity
124
+ * (`file.path:selector` as written in the operations source). Membership,
125
+ * order and inheritance always come from the source.
126
+ */
127
+ middleware(identity: string, replacement: ExecutableReplacement, options?: ReplacementOptions): TestWoodBuilder<H>;
128
+ /**
129
+ * Replace the DATA LOADER behind a selected page/layout: the companion
130
+ * `.load` source of a view (`pages/chat.svelte` → `pages/chat.load.ts`).
131
+ * The identity is the config-relative source path (`ui/pages/chat.load.ts`),
132
+ * export `default`; the executable receives the loader `RequestData`
133
+ * (`url` = page identity, `params`, `query`) and yields the data the
134
+ * controller's `initialize({ params, query, data })` receives. A source
135
+ * with no companion loader is not a declared identity (build error).
136
+ * Controllers are replaced with `.class`, never here.
137
+ */
138
+ load(identity: LoaderIdentity, replacement: ExecutableReplacement, options?: ReplacementOptions): TestWoodBuilder<H>;
139
+ /** Build; without `select()`, every owner the config declares is selected whole. */
140
+ build(): Promise<WoodTestEnvironmentFor<H>>;
141
+ private derive;
142
+ }
143
+ declare function testWood(configPath: string): TestWoodBuilder;
144
+
145
+ type WoodBrowserHost = 'playwright' | 'happy_dom';
146
+ type NativeWoodPage<H extends WoodBrowserHost> = H extends 'happy_dom' ? Window : Page;
147
+ /** Route data, not a second browser-driver API. */
148
+ interface WoodBrowserOpenOptions {
149
+ readonly params?: Readonly<Record<string, string>>;
150
+ readonly query?: Readonly<Record<string, string>>;
151
+ }
152
+ /** Native hosts expose application composition, NOT Wood's legacy DOM wrappers. */
153
+ type NativeWoodTestEnvironment<H extends WoodBrowserHost> = Pick<TestWoodEnvironment, 'root' | 'router' | 'operations' | 'api' | 'rawApi' | 'get' | 'controller' | 'events' | 'verify' | 'settle' | 'dispose'> & {
154
+ readonly browserHost: H;
155
+ /** Each open is a new tab/window. Tabs in one env share its isolated browser context. */
156
+ open(page: string, options?: WoodBrowserOpenOptions): Promise<NativeWoodPage<H>>;
157
+ };
158
+ type WoodTestEnvironmentFor<H extends WoodBrowserHost | null> = H extends WoodBrowserHost ? NativeWoodTestEnvironment<H> : TestWoodEnvironment;
159
+ interface NativeBrowserInputs {
160
+ readonly network: TestFetchRuntime;
161
+ readonly source: WoodConfigSource;
162
+ readonly views: readonly ViewDef[];
163
+ readonly environment: TestWoodEnvironment;
164
+ /** Read after main startup; a compose hook may select its event source in start(). */
165
+ readonly events: () => RouterBridgeEvents;
166
+ }
167
+ /** Framework-owned resource record. Its native object is returned without a wrapper. */
168
+ interface NativeBrowserTab {
169
+ readonly native: Page | Window;
170
+ flush(): Promise<void>;
171
+ dispose(): Promise<void>;
172
+ }
173
+ interface NativeRendererAsset {
174
+ readonly fileName: string;
175
+ readonly source: Uint8Array;
176
+ }
177
+ interface NativeRendererBundle {
178
+ readonly code: string;
179
+ readonly css: string;
180
+ /** Vite-emitted worker/wasm/image/etc. files served from the tab's synthetic origin. */
181
+ readonly assets: ReadonlyMap<string, NativeRendererAsset>;
182
+ }
183
+ interface NativeRendererRoute {
184
+ readonly page: string;
185
+ readonly params: Readonly<Record<string, string>>;
186
+ readonly query: Readonly<Record<string, string>>;
187
+ }
188
+
189
+ export { type NativeWoodPage as N, type TestWoodEnvironment as T, type WoodBrowserHost as W, type NativeWoodTestEnvironment as a, type WoodBrowserOpenOptions as b, type WoodTestEnvironmentFor as c, TestWoodBuilder as d, type WoodComposeContext as e, type WoodComposeMain as f, type WoodComposeResult as g, type NativeBrowserInputs as h, type NativeRendererBundle as i, type NativeRendererRoute as j, type NativeBrowserTab as k, type NativeRendererAsset as l, testWood as t };
@@ -0,0 +1,189 @@
1
+ import { ConfigureFetch, TestFetchRuntime } from '@noego/testing/fetch';
2
+ import { Page } from 'playwright';
3
+ import { Window } from 'happy-dom';
4
+ import { ModuleImporter, WoodConfigSource } from './testing/wood_config_source.cjs';
5
+ import { ViewDef } from './types/views.cjs';
6
+ import { RouterBridgeEvents } from './testing/create_router_bridge.cjs';
7
+ import { WoodTestApi, WoodTestRawApi } from './testing-api.cjs';
8
+ import { IContainer } from '@noego/ioc';
9
+ import { ENV_REGISTRY, TestStub, ClassToken, ReplacementClass, ReplacementOptions, ReplacementFunction, MethodDescriptor, ExecutableReplacement, LoaderIdentity } from '@noego/testing';
10
+ import { WoodRouter } from './router/wood_router.cjs';
11
+ import { WoodConfig } from './types/config.cjs';
12
+ import { OperationDef } from './types/operations.cjs';
13
+ import { FrontendApplicationSurface } from './frontend/frontend_surface.cjs';
14
+ import { FrontendPage } from './frontend/frontend_page.cjs';
15
+ import { WoodTestSelection, ResolvedWoodSelection } from './testing/wood_test_selection.cjs';
16
+ import { WoodRendererHooks } from './testing/wood_env_renderer.cjs';
17
+
18
+ /** What the app's `main.testing.compose` default export receives. */
19
+ interface WoodComposeContext {
20
+ /** Standard per-environment backend push source; hosts subscribe automatically. */
21
+ readonly events: RouterBridgeEvents;
22
+ readonly configPath: string;
23
+ readonly configDir: string;
24
+ readonly config: WoodConfig;
25
+ readonly selection: ResolvedWoodSelection;
26
+ /** The selected operations (the router will serve exactly these). */
27
+ readonly operations: ReadonlyMap<string, OperationDef>;
28
+ readonly importer: ModuleImporter;
29
+ /**
30
+ * Dispatch through the environment's router. Available from `start()`
31
+ * onward (the router is built after compose returns); calling it during
32
+ * compose itself fails.
33
+ */
34
+ call<T = unknown>(operation: string, input?: unknown): Promise<T>;
35
+ }
36
+ /** What the compose hook may hand back; every member is optional. */
37
+ interface WoodComposeResult extends WoodRendererHooks {
38
+ /**
39
+ * Runs AFTER the test's substitutions are installed on the root (compose
40
+ * itself runs before them, so production registrations never shadow a
41
+ * seam). Seed world state and warm caches here — through the seamed graph,
42
+ * exactly as the test will observe it.
43
+ */
44
+ start?(): void | Promise<void>;
45
+ /**
46
+ * Quiesce BEFORE the main root disposes its instances: silence push
47
+ * delivery, drain detached work — everything that still needs the live
48
+ * graph (database, tracer) the services' own dispose hooks run against.
49
+ */
50
+ drain?(): void | Promise<void>;
51
+ /** Release resources AFTER the roots are disposed (close files, remove dirs). */
52
+ dispose?(): void | Promise<void>;
53
+ }
54
+ /**
55
+ * The app's backend composition on the root the builder hands it. Register
56
+ * lazily: nothing expensive should run until a test resolves it.
57
+ */
58
+ type WoodComposeMain = (root: IContainer, context: WoodComposeContext) => WoodComposeResult | void | Promise<WoodComposeResult | void>;
59
+ type Params = Record<string, string>;
60
+ interface TestWoodEnvironment {
61
+ /** The main-process IoC root of this environment. */
62
+ readonly root: IContainer;
63
+ readonly router: WoodRouter;
64
+ /** The selected operations. */
65
+ readonly operations: ReadonlyMap<string, OperationDef>;
66
+ /** Typed nested operation API backed by the real selected WoodRouter. */
67
+ readonly api: WoodTestApi;
68
+ /** Object-shaped untyped payload surface for deliberate runtime-validation probes. */
69
+ readonly rawApi: WoodTestRawApi;
70
+ /** Execute a selected operation through the real pipeline. */
71
+ call<T = unknown>(operation: string, input?: unknown): Promise<T>;
72
+ /** Resolve a controller class through a fresh main scope (root seams apply). */
73
+ controller<T>(controller: new (...args: never[]) => T): Promise<T>;
74
+ /** Resolve any dependency from the main root; class tokens retain their instance type. */
75
+ get<T>(token: {
76
+ readonly prototype: T;
77
+ }): Promise<T>;
78
+ get<T = unknown>(token: unknown): Promise<T>;
79
+ /** Renderer surface — present only when `pages` was selected. */
80
+ readonly frontend: FrontendApplicationSurface;
81
+ /** Backend push emitter feeding renderer subscriptions (pages only). */
82
+ readonly events: RouterBridgeEvents;
83
+ readonly rendererRoot: IContainer;
84
+ open(page: string, params?: Params, query?: Params): Promise<FrontendPage>;
85
+ navigate(page: string, params?: Params, query?: Params): Promise<FrontendPage>;
86
+ current(): FrontendPage | null;
87
+ settle(): Promise<void>;
88
+ /** DOM driver — present only when `dom` was selected. */
89
+ readonly target: Element;
90
+ click(selector: string): Promise<void>;
91
+ type(selector: string, text: string): Promise<void>;
92
+ submit(selector: string): Promise<void>;
93
+ text(selector: string): Promise<string>;
94
+ exists(selector: string): Promise<boolean>;
95
+ /** Finalize `test.*` expectations; fails on undrained renderer work. */
96
+ verify(): Promise<void>;
97
+ dispose(): Promise<void>;
98
+ readonly [ENV_REGISTRY]: unknown;
99
+ }
100
+ declare class TestWoodBuilder<H extends WoodBrowserHost | null = null> {
101
+ private readonly state;
102
+ private constructor();
103
+ static create(configPath: string): TestWoodBuilder;
104
+ fetch(configure: ConfigureFetch): TestWoodBuilder<H>;
105
+ browser(): TestWoodBuilder<'playwright'>;
106
+ browser(host: 'playwright'): TestWoodBuilder<'playwright'>;
107
+ browser(host: 'happy_dom'): TestWoodBuilder<'happy_dom'>;
108
+ /** Declare selected tiers, snapshotting the source selector at call time. */
109
+ select(selection: WoodTestSelection): TestWoodBuilder<H>;
110
+ /** Route hook/controller imports through a caller-owned importer (escape hatch). */
111
+ importer(importer: ModuleImporter): TestWoodBuilder<H>;
112
+ /** Compose a reusable canonical testStub() replacement description. */
113
+ use(preset: TestStub): TestWoodBuilder<H>;
114
+ /** Replace the class bound to an exact declared token; the declared lifetime is kept. */
115
+ class<T>(target: ClassToken<T>, replacement: ReplacementClass<T>, options?: ReplacementOptions): TestWoodBuilder<H>;
116
+ /** Replace a declared factory/provider (dependencies and lifetime kept) or a callable value. */
117
+ function(target: unknown, replacement: ReplacementFunction, options?: ReplacementOptions): TestWoodBuilder<H>;
118
+ /** A test.* method seam on the FINAL binding of an exact declared token. */
119
+ method(target: unknown, method: string, replacement: MethodDescriptor, options?: ReplacementOptions): TestWoodBuilder<H>;
120
+ /** Provide a caller-owned value for an exact declared token (never disposed by the app). */
121
+ value(target: unknown, replacement: unknown, options?: ReplacementOptions): TestWoodBuilder<H>;
122
+ /**
123
+ * Replace the executable satisfying a production middleware identity
124
+ * (`file.path:selector` as written in the operations source). Membership,
125
+ * order and inheritance always come from the source.
126
+ */
127
+ middleware(identity: string, replacement: ExecutableReplacement, options?: ReplacementOptions): TestWoodBuilder<H>;
128
+ /**
129
+ * Replace the DATA LOADER behind a selected page/layout: the companion
130
+ * `.load` source of a view (`pages/chat.svelte` → `pages/chat.load.ts`).
131
+ * The identity is the config-relative source path (`ui/pages/chat.load.ts`),
132
+ * export `default`; the executable receives the loader `RequestData`
133
+ * (`url` = page identity, `params`, `query`) and yields the data the
134
+ * controller's `initialize({ params, query, data })` receives. A source
135
+ * with no companion loader is not a declared identity (build error).
136
+ * Controllers are replaced with `.class`, never here.
137
+ */
138
+ load(identity: LoaderIdentity, replacement: ExecutableReplacement, options?: ReplacementOptions): TestWoodBuilder<H>;
139
+ /** Build; without `select()`, every owner the config declares is selected whole. */
140
+ build(): Promise<WoodTestEnvironmentFor<H>>;
141
+ private derive;
142
+ }
143
+ declare function testWood(configPath: string): TestWoodBuilder;
144
+
145
+ type WoodBrowserHost = 'playwright' | 'happy_dom';
146
+ type NativeWoodPage<H extends WoodBrowserHost> = H extends 'happy_dom' ? Window : Page;
147
+ /** Route data, not a second browser-driver API. */
148
+ interface WoodBrowserOpenOptions {
149
+ readonly params?: Readonly<Record<string, string>>;
150
+ readonly query?: Readonly<Record<string, string>>;
151
+ }
152
+ /** Native hosts expose application composition, NOT Wood's legacy DOM wrappers. */
153
+ type NativeWoodTestEnvironment<H extends WoodBrowserHost> = Pick<TestWoodEnvironment, 'root' | 'router' | 'operations' | 'api' | 'rawApi' | 'get' | 'controller' | 'events' | 'verify' | 'settle' | 'dispose'> & {
154
+ readonly browserHost: H;
155
+ /** Each open is a new tab/window. Tabs in one env share its isolated browser context. */
156
+ open(page: string, options?: WoodBrowserOpenOptions): Promise<NativeWoodPage<H>>;
157
+ };
158
+ type WoodTestEnvironmentFor<H extends WoodBrowserHost | null> = H extends WoodBrowserHost ? NativeWoodTestEnvironment<H> : TestWoodEnvironment;
159
+ interface NativeBrowserInputs {
160
+ readonly network: TestFetchRuntime;
161
+ readonly source: WoodConfigSource;
162
+ readonly views: readonly ViewDef[];
163
+ readonly environment: TestWoodEnvironment;
164
+ /** Read after main startup; a compose hook may select its event source in start(). */
165
+ readonly events: () => RouterBridgeEvents;
166
+ }
167
+ /** Framework-owned resource record. Its native object is returned without a wrapper. */
168
+ interface NativeBrowserTab {
169
+ readonly native: Page | Window;
170
+ flush(): Promise<void>;
171
+ dispose(): Promise<void>;
172
+ }
173
+ interface NativeRendererAsset {
174
+ readonly fileName: string;
175
+ readonly source: Uint8Array;
176
+ }
177
+ interface NativeRendererBundle {
178
+ readonly code: string;
179
+ readonly css: string;
180
+ /** Vite-emitted worker/wasm/image/etc. files served from the tab's synthetic origin. */
181
+ readonly assets: ReadonlyMap<string, NativeRendererAsset>;
182
+ }
183
+ interface NativeRendererRoute {
184
+ readonly page: string;
185
+ readonly params: Readonly<Record<string, string>>;
186
+ readonly query: Readonly<Record<string, string>>;
187
+ }
188
+
189
+ export { type NativeWoodPage as N, type TestWoodEnvironment as T, type WoodBrowserHost as W, type NativeWoodTestEnvironment as a, type WoodBrowserOpenOptions as b, type WoodTestEnvironmentFor as c, TestWoodBuilder as d, type WoodComposeContext as e, type WoodComposeMain as f, type WoodComposeResult as g, type NativeBrowserInputs as h, type NativeRendererBundle as i, type NativeRendererRoute as j, type NativeBrowserTab as k, type NativeRendererAsset as l, testWood as t };
@@ -18,20 +18,27 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var navigation_exports = {};
20
20
  __export(navigation_exports, {
21
+ NO_LOADERS: () => import_loader_orchestration.NO_LOADERS,
21
22
  Navigation: () => Navigation,
22
23
  WOOD_AUTOMATION_GLOBAL_KEY: () => import_automation_introspection.WOOD_AUTOMATION_GLOBAL_KEY,
24
+ assertDataLoader: () => import_loader_orchestration.assertDataLoader,
23
25
  clearNavigationForTests: () => clearNavigationForTests,
24
26
  computePreservedLayoutDepth: () => import_layout_preservation.computePreservedLayoutDepth,
27
+ createLoaderRequest: () => import_loader_orchestration.createLoaderRequest,
25
28
  getNavigation: () => getNavigation,
26
29
  go: () => go,
27
30
  goback: () => goback,
28
31
  goto: () => goto,
29
- installAutomationIntrospection: () => import_automation_introspection.installAutomationIntrospection
32
+ initializeArgument: () => import_loader_orchestration.initializeArgument,
33
+ initializeController: () => import_loader_orchestration.initializeController,
34
+ installAutomationIntrospection: () => import_automation_introspection.installAutomationIntrospection,
35
+ runViewLoaders: () => import_loader_orchestration.runViewLoaders
30
36
  });
31
37
  module.exports = __toCommonJS(navigation_exports);
32
38
  var import_tracing = require("../tracing/index.js");
33
39
  var import_automation_introspection = require("./automation_introspection.cjs");
34
40
  var import_layout_preservation = require("./layout_preservation.cjs");
41
+ var import_loader_orchestration = require("../loader/loader_orchestration.cjs");
35
42
  const NAVIGATION_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.navigation");
36
43
  const HISTORY_STATE_MARKER = "__wood_navigation_state__";
37
44
  class Navigation {
@@ -205,14 +212,20 @@ function clearNavigationForTests() {
205
212
  }
206
213
  // Annotate the CommonJS export names for ESM import in node:
207
214
  0 && (module.exports = {
215
+ NO_LOADERS,
208
216
  Navigation,
209
217
  WOOD_AUTOMATION_GLOBAL_KEY,
218
+ assertDataLoader,
210
219
  clearNavigationForTests,
211
220
  computePreservedLayoutDepth,
221
+ createLoaderRequest,
212
222
  getNavigation,
213
223
  go,
214
224
  goback,
215
225
  goto,
216
- installAutomationIntrospection
226
+ initializeArgument,
227
+ initializeController,
228
+ installAutomationIntrospection,
229
+ runViewLoaders
217
230
  });
218
231
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/navigation/index.ts"],"sourcesContent":["import { emitRendererTrace } from '../tracing/index.js';\n\nconst NAVIGATION_SYMBOL = Symbol.for('@noego/wood.navigation');\nconst HISTORY_STATE_MARKER = '__wood_navigation_state__';\n\nexport interface NavigationEntry {\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n options: NavigationOptions;\n}\n\nexport interface NavigationOptions {\n preserveLayouts?: boolean;\n}\n\ntype NavigationHistoryState = NavigationEntry & {\n [HISTORY_STATE_MARKER]: true;\n};\n\ntype NavigationListener = (entry: NavigationEntry | null) => void;\n\nexport class Navigation {\n private entries: NavigationEntry[] = [];\n private index = -1;\n private listeners = new Set<NavigationListener>();\n\n getCurrent(): NavigationEntry | null {\n if (this.index < 0 || this.index >= this.entries.length) {\n return null;\n }\n return this.cloneEntry(this.entries[this.index]);\n }\n\n getPages(): NavigationEntry[] {\n return this.entries.map((entry) => this.cloneEntry(entry));\n }\n\n getParams(): Record<string, string> {\n const current = this.getCurrent();\n if (!current) {\n return {};\n }\n return { ...current.params };\n }\n\n replace(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n\n if (this.index < 0) {\n this.entries.push(entry);\n this.index = 0;\n } else {\n this.entries[this.index] = entry;\n }\n\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.replace',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n if (this.index < this.entries.length - 1) {\n this.entries = this.entries.slice(0, this.index + 1);\n }\n this.entries.push(entry);\n this.index = this.entries.length - 1;\n\n this.writeWindowHistory('pushState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.go',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n goto(delta: number): NavigationEntry | null {\n return this.moveCursor(delta);\n }\n\n goBack(): NavigationEntry | null {\n return this.goto(-1);\n }\n\n goForward(): NavigationEntry | null {\n return this.goto(1);\n }\n\n subscribe(listener: NavigationListener): () => void {\n this.listeners.add(listener);\n listener(this.getCurrent());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private moveCursor(delta: number): NavigationEntry | null {\n if (delta === 0) {\n return this.getCurrent();\n }\n\n const nextIndex = this.index + delta;\n if (nextIndex < 0 || nextIndex >= this.entries.length) {\n return this.getCurrent();\n }\n\n this.index = nextIndex;\n const entry = this.entries[this.index];\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.goto',\n payload: {\n delta,\n page: entry.page,\n },\n });\n return this.cloneEntry(entry);\n }\n\n private notify(): void {\n const current = this.getCurrent();\n for (const listener of this.listeners) {\n listener(current);\n }\n }\n\n private createEntry(\n page: string,\n params: Record<string, string>,\n query: Record<string, string>,\n options: NavigationOptions,\n ): NavigationEntry {\n return {\n page,\n params: this.normalizeRecord(params),\n query: this.normalizeRecord(query),\n options: { ...options },\n };\n }\n\n private cloneEntry(entry: NavigationEntry): NavigationEntry {\n return {\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n }\n\n private normalizeRecord(input: Record<string, string>): Record<string, string> {\n const output: Record<string, string> = {};\n for (const [key, value] of Object.entries(input ?? {})) {\n output[String(key)] = String(value);\n }\n return output;\n }\n\n private writeWindowHistory(\n mode: 'pushState' | 'replaceState',\n entry: NavigationEntry,\n ): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const state: NavigationHistoryState = {\n [HISTORY_STATE_MARKER]: true,\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n\n window.history[mode](state, '');\n }\n}\n\ntype GlobalWithNavigation = typeof globalThis & {\n [NAVIGATION_SYMBOL]?: Navigation;\n};\n\nfunction createNavigationInstance(): Navigation {\n return new Navigation();\n}\n\nexport function getNavigation(): Navigation {\n const globalObj = globalThis as GlobalWithNavigation;\n if (!globalObj[NAVIGATION_SYMBOL]) {\n globalObj[NAVIGATION_SYMBOL] = createNavigationInstance();\n }\n return globalObj[NAVIGATION_SYMBOL];\n}\n\nexport function goto(\n delta: number,\n): NavigationEntry | null {\n return getNavigation().goto(delta);\n}\n\nexport function go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n): NavigationEntry {\n return getNavigation().go(page, params, query, options);\n}\n\nexport function goback(): NavigationEntry | null {\n return goto(-1);\n}\n\n/** Test-only helper to clear the navigation singleton. */\nexport function clearNavigationForTests(): void {\n const globalObj = globalThis as GlobalWithNavigation;\n delete globalObj[NAVIGATION_SYMBOL];\n}\n\n// Dev/test-only automation introspection surface (Axe AXE-WP-02).\n// Benign import cycle: automation_introspection uses getNavigation lazily.\n// NOTE: keep these re-exports single-line — the tsup extension-rewrite plugin\n// only rewrites single-line import/export specifiers.\nexport { installAutomationIntrospection, WOOD_AUTOMATION_GLOBAL_KEY } from './automation_introspection.cjs';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.cjs';\nexport { computePreservedLayoutDepth } from './layout_preservation.cjs';\nexport type { LayoutStack } from './layout_preservation.cjs';\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/navigation/index.ts"],"sourcesContent":["import { emitRendererTrace } from '../tracing/index.js';\n\nconst NAVIGATION_SYMBOL = Symbol.for('@noego/wood.navigation');\nconst HISTORY_STATE_MARKER = '__wood_navigation_state__';\n\nexport interface NavigationEntry {\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n options: NavigationOptions;\n}\n\nimport type { NavigationOptions } from './layout_preservation.js';\nexport type { NavigationOptions } from './layout_preservation.js';\n\ntype NavigationHistoryState = NavigationEntry & {\n [HISTORY_STATE_MARKER]: true;\n};\n\ntype NavigationListener = (entry: NavigationEntry | null) => void;\n\nexport class Navigation {\n private entries: NavigationEntry[] = [];\n private index = -1;\n private listeners = new Set<NavigationListener>();\n\n getCurrent(): NavigationEntry | null {\n if (this.index < 0 || this.index >= this.entries.length) {\n return null;\n }\n return this.cloneEntry(this.entries[this.index]);\n }\n\n getPages(): NavigationEntry[] {\n return this.entries.map((entry) => this.cloneEntry(entry));\n }\n\n getParams(): Record<string, string> {\n const current = this.getCurrent();\n if (!current) {\n return {};\n }\n return { ...current.params };\n }\n\n replace(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n\n if (this.index < 0) {\n this.entries.push(entry);\n this.index = 0;\n } else {\n this.entries[this.index] = entry;\n }\n\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.replace',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n ): NavigationEntry {\n const entry = this.createEntry(page, params, query, options);\n if (this.index < this.entries.length - 1) {\n this.entries = this.entries.slice(0, this.index + 1);\n }\n this.entries.push(entry);\n this.index = this.entries.length - 1;\n\n this.writeWindowHistory('pushState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.go',\n payload: {\n page: entry.page,\n params: entry.params,\n query: entry.query,\n options: entry.options,\n },\n });\n return this.cloneEntry(entry);\n }\n\n goto(delta: number): NavigationEntry | null {\n return this.moveCursor(delta);\n }\n\n goBack(): NavigationEntry | null {\n return this.goto(-1);\n }\n\n goForward(): NavigationEntry | null {\n return this.goto(1);\n }\n\n subscribe(listener: NavigationListener): () => void {\n this.listeners.add(listener);\n listener(this.getCurrent());\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private moveCursor(delta: number): NavigationEntry | null {\n if (delta === 0) {\n return this.getCurrent();\n }\n\n const nextIndex = this.index + delta;\n if (nextIndex < 0 || nextIndex >= this.entries.length) {\n return this.getCurrent();\n }\n\n this.index = nextIndex;\n const entry = this.entries[this.index];\n this.writeWindowHistory('replaceState', entry);\n this.notify();\n emitRendererTrace('info', {\n source: 'wood.navigation',\n type: 'navigation.goto',\n payload: {\n delta,\n page: entry.page,\n },\n });\n return this.cloneEntry(entry);\n }\n\n private notify(): void {\n const current = this.getCurrent();\n for (const listener of this.listeners) {\n listener(current);\n }\n }\n\n private createEntry(\n page: string,\n params: Record<string, string>,\n query: Record<string, string>,\n options: NavigationOptions,\n ): NavigationEntry {\n return {\n page,\n params: this.normalizeRecord(params),\n query: this.normalizeRecord(query),\n options: { ...options },\n };\n }\n\n private cloneEntry(entry: NavigationEntry): NavigationEntry {\n return {\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n }\n\n private normalizeRecord(input: Record<string, string>): Record<string, string> {\n const output: Record<string, string> = {};\n for (const [key, value] of Object.entries(input ?? {})) {\n output[String(key)] = String(value);\n }\n return output;\n }\n\n private writeWindowHistory(\n mode: 'pushState' | 'replaceState',\n entry: NavigationEntry,\n ): void {\n if (typeof window === 'undefined') {\n return;\n }\n\n const state: NavigationHistoryState = {\n [HISTORY_STATE_MARKER]: true,\n page: entry.page,\n params: { ...entry.params },\n query: { ...entry.query },\n options: { ...entry.options },\n };\n\n window.history[mode](state, '');\n }\n}\n\ntype GlobalWithNavigation = typeof globalThis & {\n [NAVIGATION_SYMBOL]?: Navigation;\n};\n\nfunction createNavigationInstance(): Navigation {\n return new Navigation();\n}\n\nexport function getNavigation(): Navigation {\n const globalObj = globalThis as GlobalWithNavigation;\n if (!globalObj[NAVIGATION_SYMBOL]) {\n globalObj[NAVIGATION_SYMBOL] = createNavigationInstance();\n }\n return globalObj[NAVIGATION_SYMBOL];\n}\n\nexport function goto(\n delta: number,\n): NavigationEntry | null {\n return getNavigation().goto(delta);\n}\n\nexport function go(\n page: string,\n params: Record<string, string> = {},\n query: Record<string, string> = {},\n options: NavigationOptions = {},\n): NavigationEntry {\n return getNavigation().go(page, params, query, options);\n}\n\nexport function goback(): NavigationEntry | null {\n return goto(-1);\n}\n\n/** Test-only helper to clear the navigation singleton. */\nexport function clearNavigationForTests(): void {\n const globalObj = globalThis as GlobalWithNavigation;\n delete globalObj[NAVIGATION_SYMBOL];\n}\n\n// Dev/test-only automation introspection surface (Axe AXE-WP-02).\n// Benign import cycle: automation_introspection uses getNavigation lazily.\n// NOTE: keep these re-exports single-line — the tsup extension-rewrite plugin\n// only rewrites single-line import/export specifiers.\nexport { installAutomationIntrospection, WOOD_AUTOMATION_GLOBAL_KEY } from './automation_introspection.cjs';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.cjs';\nexport { computePreservedLayoutDepth } from './layout_preservation.cjs';\nexport type { LayoutStack } from './layout_preservation.cjs';\n// Shared page/layout data-loader orchestration for the generated renderer app.\nexport { createLoaderRequest, initializeArgument, initializeController, runViewLoaders, assertDataLoader, NO_LOADERS } from '../loader/loader_orchestration.cjs';\nexport type { DataLoader, LoadedData, RouteInput, ViewLoaderResult, ViewLoaderSet } from '../loader/loader_orchestration.cjs';\n"],"mappings":"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","names":[]}
@@ -1,28 +1,8 @@
1
+ import { NavigationOptions } from './layout_preservation.cjs';
2
+ export { LayoutStack, computePreservedLayoutDepth } from './layout_preservation.cjs';
1
3
  export { InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, WoodAutomationEvent, WoodAutomationIntrospection, WoodAutomationSnapshot, installAutomationIntrospection } from './automation_introspection.cjs';
2
-
3
- /**
4
- * Layout preservation depth — the single production rule for how many
5
- * leading layouts a navigation transition keeps mounted.
6
- *
7
- * One implementation, two callers: the renderer's NavigationShell (real
8
- * component transitions) and the Node frontend application slice
9
- * (`createFrontendSurface`). They must agree — a slice test that preserved
10
- * a layout the renderer rebuilds, or vice versa, would be evidence about a
11
- * rule that does not exist in production.
12
- *
13
- * The rule: walk the layout stacks in parallel and keep a layout only while
14
- * BOTH sides declare the same layout path, the same layout controller, and
15
- * both mark it `preserve: true`. `NavigationOptions.preserveLayouts`
16
- * overrides the declaration in both directions.
17
- */
18
-
19
- /** The layout stack of one view, in the shape both callers can supply. */
20
- interface LayoutStack {
21
- layoutPaths: readonly string[];
22
- layoutControllers?: ReadonlyArray<string | undefined>;
23
- layoutPreserve?: readonly boolean[];
24
- }
25
- declare function computePreservedLayoutDepth(from: LayoutStack, to: LayoutStack, options?: NavigationOptions): number;
4
+ export { DataLoader, LoadedData, NO_LOADERS, RouteInput, ViewLoaderResult, ViewLoaderSet, assertDataLoader, createLoaderRequest, initializeArgument, initializeController, runViewLoaders } from '../loader/loader_orchestration.cjs';
5
+ import '../types/context.cjs';
26
6
 
27
7
  interface NavigationEntry {
28
8
  page: string;
@@ -30,9 +10,7 @@ interface NavigationEntry {
30
10
  query: Record<string, string>;
31
11
  options: NavigationOptions;
32
12
  }
33
- interface NavigationOptions {
34
- preserveLayouts?: boolean;
35
- }
13
+
36
14
  type NavigationListener = (entry: NavigationEntry | null) => void;
37
15
  declare class Navigation {
38
16
  private entries;
@@ -61,4 +39,4 @@ declare function goback(): NavigationEntry | null;
61
39
  /** Test-only helper to clear the navigation singleton. */
62
40
  declare function clearNavigationForTests(): void;
63
41
 
64
- export { type LayoutStack, Navigation, type NavigationEntry, type NavigationOptions, clearNavigationForTests, computePreservedLayoutDepth, getNavigation, go, goback, goto };
42
+ export { Navigation, type NavigationEntry, NavigationOptions, clearNavigationForTests, getNavigation, go, goback, goto };
@@ -1,28 +1,8 @@
1
+ import { NavigationOptions } from './layout_preservation.js';
2
+ export { LayoutStack, computePreservedLayoutDepth } from './layout_preservation.js';
1
3
  export { InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, WoodAutomationEvent, WoodAutomationIntrospection, WoodAutomationSnapshot, installAutomationIntrospection } from './automation_introspection.js';
2
-
3
- /**
4
- * Layout preservation depth — the single production rule for how many
5
- * leading layouts a navigation transition keeps mounted.
6
- *
7
- * One implementation, two callers: the renderer's NavigationShell (real
8
- * component transitions) and the Node frontend application slice
9
- * (`createFrontendSurface`). They must agree — a slice test that preserved
10
- * a layout the renderer rebuilds, or vice versa, would be evidence about a
11
- * rule that does not exist in production.
12
- *
13
- * The rule: walk the layout stacks in parallel and keep a layout only while
14
- * BOTH sides declare the same layout path, the same layout controller, and
15
- * both mark it `preserve: true`. `NavigationOptions.preserveLayouts`
16
- * overrides the declaration in both directions.
17
- */
18
-
19
- /** The layout stack of one view, in the shape both callers can supply. */
20
- interface LayoutStack {
21
- layoutPaths: readonly string[];
22
- layoutControllers?: ReadonlyArray<string | undefined>;
23
- layoutPreserve?: readonly boolean[];
24
- }
25
- declare function computePreservedLayoutDepth(from: LayoutStack, to: LayoutStack, options?: NavigationOptions): number;
4
+ export { DataLoader, LoadedData, NO_LOADERS, RouteInput, ViewLoaderResult, ViewLoaderSet, assertDataLoader, createLoaderRequest, initializeArgument, initializeController, runViewLoaders } from '../loader/loader_orchestration.js';
5
+ import '../types/context.js';
26
6
 
27
7
  interface NavigationEntry {
28
8
  page: string;
@@ -30,9 +10,7 @@ interface NavigationEntry {
30
10
  query: Record<string, string>;
31
11
  options: NavigationOptions;
32
12
  }
33
- interface NavigationOptions {
34
- preserveLayouts?: boolean;
35
- }
13
+
36
14
  type NavigationListener = (entry: NavigationEntry | null) => void;
37
15
  declare class Navigation {
38
16
  private entries;
@@ -61,4 +39,4 @@ declare function goback(): NavigationEntry | null;
61
39
  /** Test-only helper to clear the navigation singleton. */
62
40
  declare function clearNavigationForTests(): void;
63
41
 
64
- export { type LayoutStack, Navigation, type NavigationEntry, type NavigationOptions, clearNavigationForTests, computePreservedLayoutDepth, getNavigation, go, goback, goto };
42
+ export { Navigation, type NavigationEntry, NavigationOptions, clearNavigationForTests, getNavigation, go, goback, goto };
@@ -172,15 +172,22 @@ function clearNavigationForTests() {
172
172
  }
173
173
  import { installAutomationIntrospection, WOOD_AUTOMATION_GLOBAL_KEY } from "./automation_introspection.js";
174
174
  import { computePreservedLayoutDepth } from "./layout_preservation.js";
175
+ import { createLoaderRequest, initializeArgument, initializeController, runViewLoaders, assertDataLoader, NO_LOADERS } from "../loader/loader_orchestration.js";
175
176
  export {
177
+ NO_LOADERS,
176
178
  Navigation,
177
179
  WOOD_AUTOMATION_GLOBAL_KEY,
180
+ assertDataLoader,
178
181
  clearNavigationForTests,
179
182
  computePreservedLayoutDepth,
183
+ createLoaderRequest,
180
184
  getNavigation,
181
185
  go,
182
186
  goback,
183
187
  goto,
184
- installAutomationIntrospection
188
+ initializeArgument,
189
+ initializeController,
190
+ installAutomationIntrospection,
191
+ runViewLoaders
185
192
  };
186
193
  //# sourceMappingURL=index.js.map