@noego/wood 0.6.2 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/dist/browser-test-setup.cjs +29 -0
- package/dist/browser-test-setup.cjs.map +1 -0
- package/dist/browser-test-setup.d.cts +8 -0
- package/dist/browser-test-setup.d.ts +8 -0
- package/dist/browser-test-setup.js +9 -0
- package/dist/browser-test-setup.js.map +1 -0
- package/dist/client/global_polyfill.d.cts +1 -0
- package/dist/client/global_polyfill.d.ts +1 -0
- package/dist/client/index.cjs +7 -0
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +7 -4
- package/dist/client/index.d.ts +7 -4
- package/dist/client/index.js +6 -1
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +97 -24
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +97 -24
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +9 -0
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +9 -0
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/config/config_parser.cjs +10 -0
- package/dist/config/config_parser.cjs.map +1 -1
- package/dist/config/config_parser.js +10 -0
- package/dist/config/config_parser.js.map +1 -1
- package/dist/fetch.cjs +38 -0
- package/dist/fetch.cjs.map +1 -0
- package/dist/fetch.d.cts +7 -0
- package/dist/fetch.d.ts +7 -0
- package/dist/fetch.js +12 -0
- package/dist/fetch.js.map +1 -0
- package/dist/frontend/frontend_page.cjs +3 -3
- package/dist/frontend/frontend_page.cjs.map +1 -1
- package/dist/frontend/frontend_page.d.cts +1 -1
- package/dist/frontend/frontend_page.d.ts +1 -1
- package/dist/frontend/frontend_page.js +3 -3
- package/dist/frontend/frontend_page.js.map +1 -1
- package/dist/frontend/frontend_surface.cjs +31 -17
- package/dist/frontend/frontend_surface.cjs.map +1 -1
- package/dist/frontend/frontend_surface.d.cts +12 -2
- package/dist/frontend/frontend_surface.d.ts +12 -2
- package/dist/frontend/frontend_surface.js +37 -17
- package/dist/frontend/frontend_surface.js.map +1 -1
- package/dist/frontend/index.d.cts +2 -0
- package/dist/frontend/index.d.ts +2 -0
- package/dist/index.cjs +5 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +25 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/loader/index.cjs +19 -2
- package/dist/loader/index.cjs.map +1 -1
- package/dist/loader/index.d.cts +1 -0
- package/dist/loader/index.d.ts +1 -0
- package/dist/loader/index.js +19 -1
- package/dist/loader/index.js.map +1 -1
- package/dist/loader/loader_orchestration.cjs +82 -0
- package/dist/loader/loader_orchestration.cjs.map +1 -0
- package/dist/loader/loader_orchestration.d.cts +66 -0
- package/dist/loader/loader_orchestration.d.ts +66 -0
- package/dist/loader/loader_orchestration.js +51 -0
- package/dist/loader/loader_orchestration.js.map +1 -0
- package/dist/loader/loader_runner.cjs +46 -41
- package/dist/loader/loader_runner.cjs.map +1 -1
- package/dist/loader/loader_runner.d.cts +12 -6
- package/dist/loader/loader_runner.d.ts +12 -6
- package/dist/loader/loader_runner.js +50 -41
- package/dist/loader/loader_runner.js.map +1 -1
- package/dist/native_browser.types-BY2daUOS.d.ts +189 -0
- package/dist/native_browser.types-vWXtE4rM.d.cts +189 -0
- package/dist/navigation/index.cjs +15 -2
- package/dist/navigation/index.cjs.map +1 -1
- package/dist/navigation/index.d.cts +2 -0
- package/dist/navigation/index.d.ts +2 -0
- package/dist/navigation/index.js +8 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/runtime/get_container.cjs +2 -0
- package/dist/runtime/get_container.cjs.map +1 -1
- package/dist/runtime/get_container.js +2 -0
- package/dist/runtime/get_container.js.map +1 -1
- package/dist/runtime/index.cjs +5 -0
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +2 -0
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/runtime_capabilities.cjs +35 -0
- package/dist/runtime/runtime_capabilities.cjs.map +1 -0
- package/dist/runtime/runtime_capabilities.d.cts +6 -0
- package/dist/runtime/runtime_capabilities.d.ts +6 -0
- package/dist/runtime/runtime_capabilities.js +11 -0
- package/dist/runtime/runtime_capabilities.js.map +1 -0
- package/dist/runtime/runtime_module.cjs +2 -0
- package/dist/runtime/runtime_module.cjs.map +1 -1
- package/dist/runtime/runtime_module.js +2 -0
- package/dist/runtime/runtime_module.js.map +1 -1
- package/dist/test-wood.cjs +150 -0
- package/dist/test-wood.cjs.map +1 -0
- package/dist/test-wood.d.cts +62 -0
- package/dist/test-wood.d.ts +62 -0
- package/dist/test-wood.js +115 -0
- package/dist/test-wood.js.map +1 -0
- package/dist/testing/browser.cjs +92 -163
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +14 -13
- package/dist/testing/browser.d.ts +14 -13
- package/dist/testing/browser.js +88 -162
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +2 -1
- package/dist/testing/create_controller_harness.d.ts +2 -1
- package/dist/testing/create_router_bridge.cjs +19 -15
- package/dist/testing/create_router_bridge.cjs.map +1 -1
- package/dist/testing/create_router_bridge.d.cts +8 -1
- package/dist/testing/create_router_bridge.d.ts +8 -1
- package/dist/testing/create_router_bridge.js +18 -15
- package/dist/testing/create_router_bridge.js.map +1 -1
- package/dist/testing/index.cjs +12 -4
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +11 -5
- package/dist/testing/index.d.ts +11 -5
- package/dist/testing/index.js +9 -3
- package/dist/testing/index.js.map +1 -1
- package/dist/testing/native_browser/browser_pool.cjs +31 -0
- package/dist/testing/native_browser/browser_pool.cjs.map +1 -0
- package/dist/testing/native_browser/browser_pool.d.cts +1 -0
- package/dist/testing/native_browser/browser_pool.d.ts +1 -0
- package/dist/testing/native_browser/browser_pool.js +6 -0
- package/dist/testing/native_browser/browser_pool.js.map +1 -0
- package/dist/testing/native_browser/happy_dom_tab.cjs +107 -0
- package/dist/testing/native_browser/happy_dom_tab.cjs.map +1 -0
- package/dist/testing/native_browser/happy_dom_tab.d.cts +35 -0
- package/dist/testing/native_browser/happy_dom_tab.d.ts +35 -0
- package/dist/testing/native_browser/happy_dom_tab.js +73 -0
- package/dist/testing/native_browser/happy_dom_tab.js.map +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.cjs +29 -0
- package/dist/testing/native_browser/happy_dom_transfer.cjs.map +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.d.cts +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.d.ts +1 -0
- package/dist/testing/native_browser/happy_dom_transfer.js +5 -0
- package/dist/testing/native_browser/happy_dom_transfer.js.map +1 -0
- package/dist/testing/native_browser/host_transport.cjs +89 -0
- package/dist/testing/native_browser/host_transport.cjs.map +1 -0
- package/dist/testing/native_browser/host_transport.d.cts +44 -0
- package/dist/testing/native_browser/host_transport.d.ts +44 -0
- package/dist/testing/native_browser/host_transport.js +65 -0
- package/dist/testing/native_browser/host_transport.js.map +1 -0
- package/dist/testing/native_browser/native_browser.types.cjs +17 -0
- package/dist/testing/native_browser/native_browser.types.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser.types.d.cts +31 -0
- package/dist/testing/native_browser/native_browser.types.d.ts +31 -0
- package/dist/testing/native_browser/native_browser.types.js +1 -0
- package/dist/testing/native_browser/native_browser.types.js.map +1 -0
- package/dist/testing/native_browser/native_browser_environment.cjs +143 -0
- package/dist/testing/native_browser/native_browser_environment.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser_environment.d.cts +36 -0
- package/dist/testing/native_browser/native_browser_environment.d.ts +36 -0
- package/dist/testing/native_browser/native_browser_environment.js +109 -0
- package/dist/testing/native_browser/native_browser_environment.js.map +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.cjs +31 -0
- package/dist/testing/native_browser/native_browser_lifecycle.cjs.map +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.d.cts +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.d.ts +1 -0
- package/dist/testing/native_browser/native_browser_lifecycle.js +6 -0
- package/dist/testing/native_browser/native_browser_lifecycle.js.map +1 -0
- package/dist/testing/native_browser/playwright_tab.cjs +124 -0
- package/dist/testing/native_browser/playwright_tab.cjs.map +1 -0
- package/dist/testing/native_browser/playwright_tab.d.cts +35 -0
- package/dist/testing/native_browser/playwright_tab.d.ts +35 -0
- package/dist/testing/native_browser/playwright_tab.js +100 -0
- package/dist/testing/native_browser/playwright_tab.js.map +1 -0
- package/dist/testing/native_browser/renderer_compilation.cjs +149 -0
- package/dist/testing/native_browser/renderer_compilation.cjs.map +1 -0
- package/dist/testing/native_browser/renderer_compilation.d.cts +35 -0
- package/dist/testing/native_browser/renderer_compilation.d.ts +35 -0
- package/dist/testing/native_browser/renderer_compilation.js +115 -0
- package/dist/testing/native_browser/renderer_compilation.js.map +1 -0
- package/dist/testing/native_browser/renderer_entry.cjs +148 -0
- package/dist/testing/native_browser/renderer_entry.cjs.map +1 -0
- package/dist/testing/native_browser/renderer_entry.d.cts +13 -0
- package/dist/testing/native_browser/renderer_entry.d.ts +13 -0
- package/dist/testing/native_browser/renderer_entry.js +114 -0
- package/dist/testing/native_browser/renderer_entry.js.map +1 -0
- package/dist/testing/registration_only_root.cjs +61 -5
- package/dist/testing/registration_only_root.cjs.map +1 -1
- package/dist/testing/registration_only_root.d.cts +25 -4
- package/dist/testing/registration_only_root.d.ts +25 -4
- package/dist/testing/registration_only_root.js +60 -5
- package/dist/testing/registration_only_root.js.map +1 -1
- package/dist/testing/runner_importer.cjs +75 -0
- package/dist/testing/runner_importer.cjs.map +1 -0
- package/dist/testing/runner_importer.d.cts +8 -0
- package/dist/testing/runner_importer.d.ts +8 -0
- package/dist/testing/runner_importer.js +41 -0
- package/dist/testing/runner_importer.js.map +1 -0
- package/dist/testing/test_wood_config.cjs +407 -273
- package/dist/testing/test_wood_config.cjs.map +1 -1
- package/dist/testing/test_wood_config.d.cts +18 -123
- package/dist/testing/test_wood_config.d.ts +18 -123
- package/dist/testing/test_wood_config.js +416 -271
- package/dist/testing/test_wood_config.js.map +1 -1
- package/dist/testing/wood_config_source.cjs +12 -0
- package/dist/testing/wood_config_source.cjs.map +1 -1
- package/dist/testing/wood_config_source.d.cts +10 -0
- package/dist/testing/wood_config_source.d.ts +10 -0
- package/dist/testing/wood_config_source.js +12 -0
- package/dist/testing/wood_config_source.js.map +1 -1
- package/dist/testing/wood_env_renderer.cjs +31 -4
- package/dist/testing/wood_env_renderer.cjs.map +1 -1
- package/dist/testing/wood_env_renderer.d.cts +14 -1
- package/dist/testing/wood_env_renderer.d.ts +14 -1
- package/dist/testing/wood_env_renderer.js +31 -4
- package/dist/testing/wood_env_renderer.js.map +1 -1
- package/dist/testing/wood_lazy_runtime.cjs +109 -0
- package/dist/testing/wood_lazy_runtime.cjs.map +1 -0
- package/dist/testing/wood_lazy_runtime.d.cts +36 -0
- package/dist/testing/wood_lazy_runtime.d.ts +36 -0
- package/dist/testing/wood_lazy_runtime.js +84 -0
- package/dist/testing/wood_lazy_runtime.js.map +1 -0
- package/dist/testing/wood_test_selection.cjs +34 -55
- package/dist/testing/wood_test_selection.cjs.map +1 -1
- package/dist/testing/wood_test_selection.d.cts +18 -24
- package/dist/testing/wood_test_selection.d.ts +18 -24
- package/dist/testing/wood_test_selection.js +30 -54
- package/dist/testing/wood_test_selection.js.map +1 -1
- package/dist/testing-api.cjs +17 -0
- package/dist/testing-api.cjs.map +1 -0
- package/dist/testing-api.d.cts +18 -0
- package/dist/testing-api.d.ts +18 -0
- package/dist/testing-api.js +1 -0
- package/dist/testing-api.js.map +1 -0
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.cts +4 -0
- package/dist/types/config.d.ts +4 -0
- package/docs/native-browser-testing.md +164 -0
- package/package.json +31 -5
- package/src/components/NavigationShell.browser.test.ts +10 -10
- package/src/components/NavigationShell.cleanup.browser.test.ts +57 -0
- package/src/components/NavigationShell.scopes.browser.test.ts +5 -5
- package/src/components/NavigationShell.svelte +50 -24
|
@@ -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
|
-
|
|
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
|
-
|
|
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\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"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAAkC;AA2PlC,sCAA2E;AAE3E,iCAA4C;AA3P5C,MAAM,oBAAoB,uBAAO,IAAI,wBAAwB;AAC7D,MAAM,uBAAuB;AAkBtB,MAAM,WAAW;AAAA,EAAjB;AACL,SAAQ,UAA6B,CAAC;AACtC,SAAQ,QAAQ;AAChB,SAAQ,YAAY,oBAAI,IAAwB;AAAA;AAAA,EAEhD,aAAqC;AACnC,QAAI,KAAK,QAAQ,KAAK,KAAK,SAAS,KAAK,QAAQ,QAAQ;AACvD,aAAO;AAAA,IACT;AACA,WAAO,KAAK,WAAW,KAAK,QAAQ,KAAK,KAAK,CAAC;AAAA,EACjD;AAAA,EAEA,WAA8B;AAC5B,WAAO,KAAK,QAAQ,IAAI,CAAC,UAAU,KAAK,WAAW,KAAK,CAAC;AAAA,EAC3D;AAAA,EAEA,YAAoC;AAClC,UAAM,UAAU,KAAK,WAAW;AAChC,QAAI,CAAC,SAAS;AACZ,aAAO,CAAC;AAAA,IACV;AACA,WAAO,EAAE,GAAG,QAAQ,OAAO;AAAA,EAC7B;AAAA,EAEA,QACE,MACA,SAAiC,CAAC,GAClC,QAAgC,CAAC,GACjC,UAA6B,CAAC,GACb;AACjB,UAAM,QAAQ,KAAK,YAAY,MAAM,QAAQ,OAAO,OAAO;AAE3D,QAAI,KAAK,QAAQ,GAAG;AAClB,WAAK,QAAQ,KAAK,KAAK;AACvB,WAAK,QAAQ;AAAA,IACf,OAAO;AACL,WAAK,QAAQ,KAAK,KAAK,IAAI;AAAA,IAC7B;AAEA,SAAK,mBAAmB,gBAAgB,KAAK;AAC7C,SAAK,OAAO;AACZ,0CAAkB,QAAQ;AAAA,MACxB,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,QACd,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,MACjB;AAAA,IACF,CAAC;AACD,WAAO,KAAK,WAAW,KAAK;AAAA,EAC9B;AAAA,EAEA,GACE,MACA,SAAiC,CAAC,GAClC,QAAgC,CAAC,GACjC,UAA6B,CAAC,GACb;AACjB,UAAM,QAAQ,KAAK,YAAY,MAAM,QAAQ,OAAO,OAAO;AAC3D,QAAI,KAAK,QAAQ,KAAK,QAAQ,SAAS,GAAG;AACxC,WAAK,UAAU,KAAK,QAAQ,MAAM,GAAG,KAAK,QAAQ,CAAC;AAAA,IACrD;AACA,SAAK,QAAQ,KAAK,KAAK;AACvB,SAAK,QAAQ,KAAK,QAAQ,SAAS;AAEnC,SAAK,mBAAmB,aAAa,KAAK;AAC1C,SAAK,OAAO;AACZ,0CAAkB,QAAQ;AAAA,MACxB,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,QACd,OAAO,MAAM;AAAA,QACb,SAAS,MAAM;AAAA,MACjB;AAAA,IACF,CAAC;AACD,WAAO,KAAK,WAAW,KAAK;AAAA,EAC9B;AAAA,EAEA,KAAK,OAAuC;AAC1C,WAAO,KAAK,WAAW,KAAK;AAAA,EAC9B;AAAA,EAEA,SAAiC;AAC/B,WAAO,KAAK,KAAK,EAAE;AAAA,EACrB;AAAA,EAEA,YAAoC;AAClC,WAAO,KAAK,KAAK,CAAC;AAAA,EACpB;AAAA,EAEA,UAAU,UAA0C;AAClD,SAAK,UAAU,IAAI,QAAQ;AAC3B,aAAS,KAAK,WAAW,CAAC;AAC1B,WAAO,MAAM;AACX,WAAK,UAAU,OAAO,QAAQ;AAAA,IAChC;AAAA,EACF;AAAA,EAEQ,WAAW,OAAuC;AACxD,QAAI,UAAU,GAAG;AACf,aAAO,KAAK,WAAW;AAAA,IACzB;AAEA,UAAM,YAAY,KAAK,QAAQ;AAC/B,QAAI,YAAY,KAAK,aAAa,KAAK,QAAQ,QAAQ;AACrD,aAAO,KAAK,WAAW;AAAA,IACzB;AAEA,SAAK,QAAQ;AACb,UAAM,QAAQ,KAAK,QAAQ,KAAK,KAAK;AACrC,SAAK,mBAAmB,gBAAgB,KAAK;AAC7C,SAAK,OAAO;AACZ,0CAAkB,QAAQ;AAAA,MACxB,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,SAAS;AAAA,QACP;AAAA,QACA,MAAM,MAAM;AAAA,MACd;AAAA,IACF,CAAC;AACD,WAAO,KAAK,WAAW,KAAK;AAAA,EAC9B;AAAA,EAEQ,SAAe;AACrB,UAAM,UAAU,KAAK,WAAW;AAChC,eAAW,YAAY,KAAK,WAAW;AACrC,eAAS,OAAO;AAAA,IAClB;AAAA,EACF;AAAA,EAEQ,YACN,MACA,QACA,OACA,SACiB;AACjB,WAAO;AAAA,MACL;AAAA,MACA,QAAQ,KAAK,gBAAgB,MAAM;AAAA,MACnC,OAAO,KAAK,gBAAgB,KAAK;AAAA,MACjC,SAAS,EAAE,GAAG,QAAQ;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,WAAW,OAAyC;AAC1D,WAAO;AAAA,MACL,MAAM,MAAM;AAAA,MACZ,QAAQ,EAAE,GAAG,MAAM,OAAO;AAAA,MAC1B,OAAO,EAAE,GAAG,MAAM,MAAM;AAAA,MACxB,SAAS,EAAE,GAAG,MAAM,QAAQ;AAAA,IAC9B;AAAA,EACF;AAAA,EAEQ,gBAAgB,OAAuD;AAC7E,UAAM,SAAiC,CAAC;AACxC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC,GAAG;AACtD,aAAO,OAAO,GAAG,CAAC,IAAI,OAAO,KAAK;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBACN,MACA,OACM;AACN,QAAI,OAAO,WAAW,aAAa;AACjC;AAAA,IACF;AAEA,UAAM,QAAgC;AAAA,MACpC,CAAC,oBAAoB,GAAG;AAAA,MACxB,MAAM,MAAM;AAAA,MACZ,QAAQ,EAAE,GAAG,MAAM,OAAO;AAAA,MAC1B,OAAO,EAAE,GAAG,MAAM,MAAM;AAAA,MACxB,SAAS,EAAE,GAAG,MAAM,QAAQ;AAAA,IAC9B;AAEA,WAAO,QAAQ,IAAI,EAAE,OAAO,EAAE;AAAA,EAChC;AACF;AAMA,SAAS,2BAAuC;AAC9C,SAAO,IAAI,WAAW;AACxB;AAEO,SAAS,gBAA4B;AAC1C,QAAM,YAAY;AAClB,MAAI,CAAC,UAAU,iBAAiB,GAAG;AACjC,cAAU,iBAAiB,IAAI,yBAAyB;AAAA,EAC1D;AACA,SAAO,UAAU,iBAAiB;AACpC;AAEO,SAAS,KACd,OACwB;AACxB,SAAO,cAAc,EAAE,KAAK,KAAK;AACnC;AAEO,SAAS,GACd,MACA,SAAiC,CAAC,GAClC,QAAgC,CAAC,GACjC,UAA6B,CAAC,GACb;AACjB,SAAO,cAAc,EAAE,GAAG,MAAM,QAAQ,OAAO,OAAO;AACxD;AAEO,SAAS,SAAiC;AAC/C,SAAO,KAAK,EAAE;AAChB;AAGO,SAAS,0BAAgC;AAC9C,QAAM,YAAY;AAClB,SAAO,UAAU,iBAAiB;AACpC;","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,6 +1,8 @@
|
|
|
1
1
|
import { NavigationOptions } from './layout_preservation.cjs';
|
|
2
2
|
export { LayoutStack, computePreservedLayoutDepth } from './layout_preservation.cjs';
|
|
3
3
|
export { InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, WoodAutomationEvent, WoodAutomationIntrospection, WoodAutomationSnapshot, installAutomationIntrospection } from './automation_introspection.cjs';
|
|
4
|
+
export { DataLoader, LoadedData, NO_LOADERS, RouteInput, ViewLoaderResult, ViewLoaderSet, assertDataLoader, createLoaderRequest, initializeArgument, initializeController, runViewLoaders } from '../loader/loader_orchestration.cjs';
|
|
5
|
+
import '../types/context.cjs';
|
|
4
6
|
|
|
5
7
|
interface NavigationEntry {
|
|
6
8
|
page: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { NavigationOptions } from './layout_preservation.js';
|
|
2
2
|
export { LayoutStack, computePreservedLayoutDepth } from './layout_preservation.js';
|
|
3
3
|
export { InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, WoodAutomationEvent, WoodAutomationIntrospection, WoodAutomationSnapshot, installAutomationIntrospection } from './automation_introspection.js';
|
|
4
|
+
export { DataLoader, LoadedData, NO_LOADERS, RouteInput, ViewLoaderResult, ViewLoaderSet, assertDataLoader, createLoaderRequest, initializeArgument, initializeController, runViewLoaders } from '../loader/loader_orchestration.js';
|
|
5
|
+
import '../types/context.js';
|
|
4
6
|
|
|
5
7
|
interface NavigationEntry {
|
|
6
8
|
page: string;
|
package/dist/navigation/index.js
CHANGED
|
@@ -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
|
-
|
|
188
|
+
initializeArgument,
|
|
189
|
+
initializeController,
|
|
190
|
+
installAutomationIntrospection,
|
|
191
|
+
runViewLoaders
|
|
185
192
|
};
|
|
186
193
|
//# sourceMappingURL=index.js.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\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.js';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.js';\nexport { computePreservedLayoutDepth } from './layout_preservation.js';\nexport type { LayoutStack } from './layout_preservation.js';\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.js';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.js';\nexport { computePreservedLayoutDepth } from './layout_preservation.js';\nexport type { LayoutStack } from './layout_preservation.js';\n// Shared page/layout data-loader orchestration for the generated renderer app.\nexport { createLoaderRequest, initializeArgument, initializeController, runViewLoaders, assertDataLoader, NO_LOADERS } from '../loader/loader_orchestration.js';\nexport type { DataLoader, LoadedData, RouteInput, ViewLoaderResult, ViewLoaderSet } from '../loader/loader_orchestration.js';\n"],"mappings":"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","names":[]}
|
|
@@ -25,10 +25,12 @@ __export(get_container_exports, {
|
|
|
25
25
|
module.exports = __toCommonJS(get_container_exports);
|
|
26
26
|
var import_ioc = require("@noego/ioc");
|
|
27
27
|
var import_logger = require("@noego/logger");
|
|
28
|
+
var import_runtime_capabilities = require("./runtime_capabilities.js");
|
|
28
29
|
const logger = (0, import_logger.getLogger)("wood:runtime:container");
|
|
29
30
|
const CONTAINER_REGISTRY_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.container.registry");
|
|
30
31
|
function createWoodRoot(options = {}) {
|
|
31
32
|
const root = (0, import_ioc.createContainer)();
|
|
33
|
+
(0, import_runtime_capabilities.installRuntimeCapabilities)(root);
|
|
32
34
|
options.configure?.(root);
|
|
33
35
|
return root;
|
|
34
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/runtime/get_container.ts"],"sourcesContent":["import { createContainer } from '@noego/ioc';\nimport type { IContainer } from '@noego/ioc';\nimport { getLogger } from '@noego/logger';\n\nconst logger = getLogger('wood:runtime:container');\n\nconst CONTAINER_REGISTRY_SYMBOL = Symbol.for('@noego/wood.container.registry');\n\nexport interface GetContainerOptions {\n /** Scope key for the container instance. Defaults to process.cwd(). */\n scope?: string;\n /** Called only when a new scoped container is created. */\n configure?: (container: any) => void;\n}\n\nexport interface CreateWoodRootOptions {\n /** Applied to the fresh root before it is returned. */\n configure?: (container: IContainer) => void;\n}\n\n/**\n * Create an explicit Wood composition root: a fresh real `@noego/ioc`\n * container owned by the caller. This is the canonical construction path —\n * runtime boot, tests, and tools receive/create a root explicitly and pass\n * it down; operation/renderer scopes are children of it.\n *\n * Decorator metadata uses `Symbol.for(...)` keys and the global\n * reflect-metadata registry, so consumer-decorated classes resolve\n * correctly regardless of which package instance created the container —\n * the old `createRequire` consumer-package resolution is unnecessary.\n */\nexport function createWoodRoot(options: CreateWoodRootOptions = {}): IContainer {\n const root = createContainer() as IContainer;\n options.configure?.(root);\n return root;\n}\n\ntype ContainerRegistry = Map<string, any>;\n\nfunction registry(): ContainerRegistry {\n const globalObj = globalThis as typeof globalThis & {\n [CONTAINER_REGISTRY_SYMBOL]?: ContainerRegistry;\n };\n\n if (!globalObj[CONTAINER_REGISTRY_SYMBOL]) {\n globalObj[CONTAINER_REGISTRY_SYMBOL] = new Map<string, any>();\n logger.info('container registry created', { symbol: CONTAINER_REGISTRY_SYMBOL.toString() });\n }\n\n return globalObj[CONTAINER_REGISTRY_SYMBOL]!;\n}\n\n/**\n * COMPAT: return a process-global scoped container from the registry.\n *\n * The canonical architecture owns an explicit root (see createWoodRoot);\n * this global accessor remains as a runtime-boundary convenience while\n * consumers migrate. Note its known trap: `configure` runs only on first\n * creation for a scope key.\n */\nexport function getContainer(options: GetContainerOptions = {}): any {\n const scope = options.scope ?? process.cwd();\n const containers = registry();\n\n const existing = containers.get(scope);\n if (existing) {\n logger.info('container reused', { scope });\n return existing;\n }\n\n const created = createWoodRoot();\n containers.set(scope, created);\n logger.info('container created', { scope });\n\n if (options.configure) {\n options.configure(created);\n logger.info('container configured', { scope });\n }\n\n return created;\n}\n\nexport function clearContainerRegistryForTests(): void {\n const containers = registry();\n containers.clear();\n logger.info('container registry cleared');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAgC;AAEhC,oBAA0B;
|
|
1
|
+
{"version":3,"sources":["../../src/runtime/get_container.ts"],"sourcesContent":["import { createContainer } from '@noego/ioc';\nimport type { IContainer } from '@noego/ioc';\nimport { getLogger } from '@noego/logger';\nimport { installRuntimeCapabilities } from './runtime_capabilities.js';\n\nconst logger = getLogger('wood:runtime:container');\n\nconst CONTAINER_REGISTRY_SYMBOL = Symbol.for('@noego/wood.container.registry');\n\nexport interface GetContainerOptions {\n /** Scope key for the container instance. Defaults to process.cwd(). */\n scope?: string;\n /** Called only when a new scoped container is created. */\n configure?: (container: any) => void;\n}\n\nexport interface CreateWoodRootOptions {\n /** Applied to the fresh root before it is returned. */\n configure?: (container: IContainer) => void;\n}\n\n/**\n * Create an explicit Wood composition root: a fresh real `@noego/ioc`\n * container owned by the caller. This is the canonical construction path —\n * runtime boot, tests, and tools receive/create a root explicitly and pass\n * it down; operation/renderer scopes are children of it.\n *\n * Decorator metadata uses `Symbol.for(...)` keys and the global\n * reflect-metadata registry, so consumer-decorated classes resolve\n * correctly regardless of which package instance created the container —\n * the old `createRequire` consumer-package resolution is unnecessary.\n */\nexport function createWoodRoot(options: CreateWoodRootOptions = {}): IContainer {\n const root = createContainer() as IContainer;\n installRuntimeCapabilities(root);\n options.configure?.(root);\n return root;\n}\n\ntype ContainerRegistry = Map<string, any>;\n\nfunction registry(): ContainerRegistry {\n const globalObj = globalThis as typeof globalThis & {\n [CONTAINER_REGISTRY_SYMBOL]?: ContainerRegistry;\n };\n\n if (!globalObj[CONTAINER_REGISTRY_SYMBOL]) {\n globalObj[CONTAINER_REGISTRY_SYMBOL] = new Map<string, any>();\n logger.info('container registry created', { symbol: CONTAINER_REGISTRY_SYMBOL.toString() });\n }\n\n return globalObj[CONTAINER_REGISTRY_SYMBOL]!;\n}\n\n/**\n * COMPAT: return a process-global scoped container from the registry.\n *\n * The canonical architecture owns an explicit root (see createWoodRoot);\n * this global accessor remains as a runtime-boundary convenience while\n * consumers migrate. Note its known trap: `configure` runs only on first\n * creation for a scope key.\n */\nexport function getContainer(options: GetContainerOptions = {}): any {\n const scope = options.scope ?? process.cwd();\n const containers = registry();\n\n const existing = containers.get(scope);\n if (existing) {\n logger.info('container reused', { scope });\n return existing;\n }\n\n const created = createWoodRoot();\n containers.set(scope, created);\n logger.info('container created', { scope });\n\n if (options.configure) {\n options.configure(created);\n logger.info('container configured', { scope });\n }\n\n return created;\n}\n\nexport function clearContainerRegistryForTests(): void {\n const containers = registry();\n containers.clear();\n logger.info('container registry cleared');\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iBAAgC;AAEhC,oBAA0B;AAC1B,kCAA2C;AAE3C,MAAM,aAAS,yBAAU,wBAAwB;AAEjD,MAAM,4BAA4B,uBAAO,IAAI,gCAAgC;AAyBtE,SAAS,eAAe,UAAiC,CAAC,GAAe;AAC9E,QAAM,WAAO,4BAAgB;AAC7B,8DAA2B,IAAI;AAC/B,UAAQ,YAAY,IAAI;AACxB,SAAO;AACT;AAIA,SAAS,WAA8B;AACrC,QAAM,YAAY;AAIlB,MAAI,CAAC,UAAU,yBAAyB,GAAG;AACzC,cAAU,yBAAyB,IAAI,oBAAI,IAAiB;AAC5D,WAAO,KAAK,8BAA8B,EAAE,QAAQ,0BAA0B,SAAS,EAAE,CAAC;AAAA,EAC5F;AAEA,SAAO,UAAU,yBAAyB;AAC5C;AAUO,SAAS,aAAa,UAA+B,CAAC,GAAQ;AACnE,QAAM,QAAQ,QAAQ,SAAS,QAAQ,IAAI;AAC3C,QAAM,aAAa,SAAS;AAE5B,QAAM,WAAW,WAAW,IAAI,KAAK;AACrC,MAAI,UAAU;AACZ,WAAO,KAAK,oBAAoB,EAAE,MAAM,CAAC;AACzC,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe;AAC/B,aAAW,IAAI,OAAO,OAAO;AAC7B,SAAO,KAAK,qBAAqB,EAAE,MAAM,CAAC;AAE1C,MAAI,QAAQ,WAAW;AACrB,YAAQ,UAAU,OAAO;AACzB,WAAO,KAAK,wBAAwB,EAAE,MAAM,CAAC;AAAA,EAC/C;AAEA,SAAO;AACT;AAEO,SAAS,iCAAuC;AACrD,QAAM,aAAa,SAAS;AAC5B,aAAW,MAAM;AACjB,SAAO,KAAK,4BAA4B;AAC1C;","names":[]}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { createContainer } from "@noego/ioc";
|
|
2
2
|
import { getLogger } from "@noego/logger";
|
|
3
|
+
import { installRuntimeCapabilities } from "./runtime_capabilities.js";
|
|
3
4
|
const logger = getLogger("wood:runtime:container");
|
|
4
5
|
const CONTAINER_REGISTRY_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.container.registry");
|
|
5
6
|
function createWoodRoot(options = {}) {
|
|
6
7
|
const root = createContainer();
|
|
8
|
+
installRuntimeCapabilities(root);
|
|
7
9
|
options.configure?.(root);
|
|
8
10
|
return root;
|
|
9
11
|
}
|