@noego/wood 0.4.8 → 0.4.10
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/bin/axe.js +313 -98
- package/bin/wood.js +7 -1
- package/dist/automation/actions.cjs +17 -0
- package/dist/automation/actions.cjs.map +1 -0
- package/dist/automation/actions.d.cts +57 -0
- package/dist/automation/actions.d.ts +57 -0
- package/dist/automation/actions.js +1 -0
- package/dist/automation/actions.js.map +1 -0
- package/dist/automation/actions_executor.cjs +101 -0
- package/dist/automation/actions_executor.cjs.map +1 -0
- package/dist/automation/actions_executor.d.cts +16 -0
- package/dist/automation/actions_executor.d.ts +16 -0
- package/dist/automation/actions_executor.js +76 -0
- package/dist/automation/actions_executor.js.map +1 -0
- package/dist/automation/connection.cjs +86 -0
- package/dist/automation/connection.cjs.map +1 -0
- package/dist/automation/connection.d.cts +18 -0
- package/dist/automation/connection.d.ts +18 -0
- package/dist/automation/connection.js +51 -0
- package/dist/automation/connection.js.map +1 -0
- package/dist/automation/errors.cjs +50 -0
- package/dist/automation/errors.cjs.map +1 -0
- package/dist/automation/errors.d.cts +31 -0
- package/dist/automation/errors.d.ts +31 -0
- package/dist/automation/errors.js +24 -0
- package/dist/automation/errors.js.map +1 -0
- package/dist/automation/index.cjs +49 -0
- package/dist/automation/index.cjs.map +1 -0
- package/dist/automation/index.d.cts +16 -0
- package/dist/automation/index.d.ts +16 -0
- package/dist/automation/index.js +15 -0
- package/dist/automation/index.js.map +1 -0
- package/dist/automation/introspection_reader.cjs +75 -0
- package/dist/automation/introspection_reader.cjs.map +1 -0
- package/dist/automation/introspection_reader.d.cts +20 -0
- package/dist/automation/introspection_reader.d.ts +20 -0
- package/dist/automation/introspection_reader.js +48 -0
- package/dist/automation/introspection_reader.js.map +1 -0
- package/dist/automation/locator.cjs +102 -0
- package/dist/automation/locator.cjs.map +1 -0
- package/dist/automation/locator.d.cts +51 -0
- package/dist/automation/locator.d.ts +51 -0
- package/dist/automation/locator.js +75 -0
- package/dist/automation/locator.js.map +1 -0
- package/dist/automation/observation.cjs +17 -0
- package/dist/automation/observation.cjs.map +1 -0
- package/dist/automation/observation.d.cts +44 -0
- package/dist/automation/observation.d.ts +44 -0
- package/dist/automation/observation.js +1 -0
- package/dist/automation/observation.js.map +1 -0
- package/dist/automation/receipts.cjs +17 -0
- package/dist/automation/receipts.cjs.map +1 -0
- package/dist/automation/receipts.d.cts +27 -0
- package/dist/automation/receipts.d.ts +27 -0
- package/dist/automation/receipts.js +1 -0
- package/dist/automation/receipts.js.map +1 -0
- package/dist/automation/scenario.cjs +696 -0
- package/dist/automation/scenario.cjs.map +1 -0
- package/dist/automation/scenario.d.cts +89 -0
- package/dist/automation/scenario.d.ts +89 -0
- package/dist/automation/scenario.js +660 -0
- package/dist/automation/scenario.js.map +1 -0
- package/dist/automation/scrolling.cjs +17 -0
- package/dist/automation/scrolling.cjs.map +1 -0
- package/dist/automation/scrolling.d.cts +51 -0
- package/dist/automation/scrolling.d.ts +51 -0
- package/dist/automation/scrolling.js +1 -0
- package/dist/automation/scrolling.js.map +1 -0
- package/dist/automation/scrolling_executor.cjs +109 -0
- package/dist/automation/scrolling_executor.cjs.map +1 -0
- package/dist/automation/scrolling_executor.d.cts +13 -0
- package/dist/automation/scrolling_executor.d.ts +13 -0
- package/dist/automation/scrolling_executor.js +84 -0
- package/dist/automation/scrolling_executor.js.map +1 -0
- package/dist/automation/target_identity.cjs +17 -0
- package/dist/automation/target_identity.cjs.map +1 -0
- package/dist/automation/target_identity.d.cts +28 -0
- package/dist/automation/target_identity.d.ts +28 -0
- package/dist/automation/target_identity.js +1 -0
- package/dist/automation/target_identity.js.map +1 -0
- package/dist/automation/target_registry.cjs +148 -0
- package/dist/automation/target_registry.cjs.map +1 -0
- package/dist/automation/target_registry.d.cts +32 -0
- package/dist/automation/target_registry.d.ts +32 -0
- package/dist/automation/target_registry.js +122 -0
- package/dist/automation/target_registry.js.map +1 -0
- package/dist/automation/waits.cjs +17 -0
- package/dist/automation/waits.cjs.map +1 -0
- package/dist/automation/waits.d.cts +44 -0
- package/dist/automation/waits.d.ts +44 -0
- package/dist/automation/waits.js +1 -0
- package/dist/automation/waits.js.map +1 -0
- package/dist/automation/waits_executor.cjs +104 -0
- package/dist/automation/waits_executor.cjs.map +1 -0
- package/dist/automation/waits_executor.d.cts +14 -0
- package/dist/automation/waits_executor.d.ts +14 -0
- package/dist/automation/waits_executor.js +79 -0
- package/dist/automation/waits_executor.js.map +1 -0
- package/dist/client/index.d.cts +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/codegen/renderer_app_generator.cjs +16 -1
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +16 -1
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/navigation/automation_introspection.cjs +110 -0
- package/dist/navigation/automation_introspection.cjs.map +1 -0
- package/dist/navigation/automation_introspection.d.cts +60 -0
- package/dist/navigation/automation_introspection.d.ts +60 -0
- package/dist/navigation/automation_introspection.js +85 -0
- package/dist/navigation/automation_introspection.js.map +1 -0
- package/dist/navigation/index.cjs +7 -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 +4 -1
- package/dist/navigation/index.js.map +1 -1
- package/dist/testing/automation_assertions.cjs +417 -0
- package/dist/testing/automation_assertions.cjs.map +1 -0
- package/dist/testing/automation_assertions.d.cts +44 -0
- package/dist/testing/automation_assertions.d.ts +44 -0
- package/dist/testing/automation_assertions.js +385 -0
- package/dist/testing/automation_assertions.js.map +1 -0
- package/dist/testing/browser.cjs +26 -34
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +2 -1
- package/dist/testing/browser.d.ts +2 -1
- package/dist/testing/browser.js +30 -31
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +1 -0
- package/dist/testing/create_controller_harness.d.ts +1 -0
- package/dist/testing/geometry.cjs +109 -0
- package/dist/testing/geometry.cjs.map +1 -0
- package/dist/testing/geometry.d.cts +45 -0
- package/dist/testing/geometry.d.ts +45 -0
- package/dist/testing/geometry.js +79 -0
- package/dist/testing/geometry.js.map +1 -0
- package/dist/testing/index.cjs +31 -2
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +4 -0
- package/dist/testing/index.d.ts +4 -0
- package/dist/testing/index.js +31 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/tracing/trace_hub.cjs +3 -0
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.js +3 -0
- package/dist/tracing/trace_hub.js.map +1 -1
- package/package.json +7 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dev/test-only automation introspection (Axe.md AXE-WP-02).
|
|
3
|
+
*
|
|
4
|
+
* Exposes a narrow, versioned inspection surface for the Axe live driver:
|
|
5
|
+
* current route, readiness, and route-change subscription. It exposes no
|
|
6
|
+
* privileged operations.
|
|
7
|
+
*
|
|
8
|
+
* Deviation from the spec's `bridge.__automation` shape: the preload bridge
|
|
9
|
+
* (`__NOEGO_WOOD_BRIDGE__`) is a sealed contextBridge object that renderer
|
|
10
|
+
* code cannot extend, so the surface is installed as the sibling main-world
|
|
11
|
+
* global `__NOEGO_WOOD_AUTOMATION__`. Axe reads it the same way.
|
|
12
|
+
*
|
|
13
|
+
* This module lives in the renderer bundle. It must only be installed in
|
|
14
|
+
* development and explicit test builds — the generated renderer app gates the
|
|
15
|
+
* install call; this module never self-installs on import.
|
|
16
|
+
*/
|
|
17
|
+
declare const WOOD_AUTOMATION_GLOBAL_KEY = "__NOEGO_WOOD_AUTOMATION__";
|
|
18
|
+
interface WoodAutomationSnapshot {
|
|
19
|
+
version: 1;
|
|
20
|
+
windowId: string | null;
|
|
21
|
+
currentRoute: {
|
|
22
|
+
page: string;
|
|
23
|
+
params: Record<string, string>;
|
|
24
|
+
query: Record<string, string>;
|
|
25
|
+
} | null;
|
|
26
|
+
navigationDepth: number;
|
|
27
|
+
rendererReady: boolean;
|
|
28
|
+
pendingWork: {
|
|
29
|
+
bridgeCalls: number;
|
|
30
|
+
renders: number;
|
|
31
|
+
animations: number;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
type WoodAutomationEvent = {
|
|
35
|
+
kind: 'route';
|
|
36
|
+
entry: WoodAutomationSnapshot['currentRoute'];
|
|
37
|
+
};
|
|
38
|
+
interface WoodAutomationIntrospection {
|
|
39
|
+
version: 1;
|
|
40
|
+
snapshot: () => WoodAutomationSnapshot;
|
|
41
|
+
waitForIdle: (options?: {
|
|
42
|
+
timeoutMs?: number;
|
|
43
|
+
idleFrames?: number;
|
|
44
|
+
}) => Promise<boolean>;
|
|
45
|
+
subscribe: (listener: (event: WoodAutomationEvent) => void) => () => void;
|
|
46
|
+
}
|
|
47
|
+
interface InstallAutomationIntrospectionOptions {
|
|
48
|
+
/** Wood window identity when known at install time. */
|
|
49
|
+
windowId?: string | null;
|
|
50
|
+
/** Override for tests; defaults to `globalThis`. */
|
|
51
|
+
globalObject?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Install the introspection global. Idempotent: repeated installs replace the
|
|
55
|
+
* previous surface (fresh navigation subscription, updated windowId).
|
|
56
|
+
* Returns an uninstall function.
|
|
57
|
+
*/
|
|
58
|
+
declare function installAutomationIntrospection(options?: InstallAutomationIntrospectionOptions): () => void;
|
|
59
|
+
|
|
60
|
+
export { type InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, type WoodAutomationEvent, type WoodAutomationIntrospection, type WoodAutomationSnapshot, installAutomationIntrospection };
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { getNavigation } from "./index.js";
|
|
2
|
+
const WOOD_AUTOMATION_GLOBAL_KEY = "__NOEGO_WOOD_AUTOMATION__";
|
|
3
|
+
function toRoute(entry) {
|
|
4
|
+
if (!entry) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
return { page: entry.page, params: { ...entry.params }, query: { ...entry.query } };
|
|
8
|
+
}
|
|
9
|
+
function installAutomationIntrospection(options = {}) {
|
|
10
|
+
const globalObject = options.globalObject ?? globalThis;
|
|
11
|
+
const navigation = getNavigation();
|
|
12
|
+
let routeRevision = 0;
|
|
13
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
14
|
+
const unsubscribeNavigation = navigation.subscribe((entry) => {
|
|
15
|
+
routeRevision += 1;
|
|
16
|
+
const event = { kind: "route", entry: toRoute(entry) };
|
|
17
|
+
for (const listener of listeners) {
|
|
18
|
+
listener(event);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const surface = {
|
|
22
|
+
version: 1,
|
|
23
|
+
snapshot: () => ({
|
|
24
|
+
version: 1,
|
|
25
|
+
windowId: options.windowId ?? null,
|
|
26
|
+
currentRoute: toRoute(navigation.getCurrent()),
|
|
27
|
+
navigationDepth: navigation.getPages().length,
|
|
28
|
+
rendererReady: true,
|
|
29
|
+
pendingWork: {
|
|
30
|
+
// Bounded placeholders until render/bridge instrumentation lands;
|
|
31
|
+
// consumers must treat unknown pending work as zero, not omit checks.
|
|
32
|
+
bridgeCalls: 0,
|
|
33
|
+
renders: 0,
|
|
34
|
+
animations: 0
|
|
35
|
+
}
|
|
36
|
+
}),
|
|
37
|
+
waitForIdle: (waitOptions) => {
|
|
38
|
+
const timeoutMs = waitOptions?.timeoutMs ?? 2e3;
|
|
39
|
+
const idleFramesRequired = waitOptions?.idleFrames ?? 3;
|
|
40
|
+
const raf = typeof requestAnimationFrame === "function" ? (cb) => requestAnimationFrame(() => cb()) : (cb) => void setTimeout(cb, 16);
|
|
41
|
+
return new Promise((resolve) => {
|
|
42
|
+
const startedAt = Date.now();
|
|
43
|
+
let lastSeenRevision = routeRevision;
|
|
44
|
+
let idleFrames = 0;
|
|
45
|
+
const step = () => {
|
|
46
|
+
if (Date.now() - startedAt > timeoutMs) {
|
|
47
|
+
resolve(false);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (routeRevision !== lastSeenRevision) {
|
|
51
|
+
lastSeenRevision = routeRevision;
|
|
52
|
+
idleFrames = 0;
|
|
53
|
+
} else {
|
|
54
|
+
idleFrames += 1;
|
|
55
|
+
if (idleFrames >= idleFramesRequired) {
|
|
56
|
+
resolve(true);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
raf(step);
|
|
61
|
+
};
|
|
62
|
+
raf(step);
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
subscribe: (listener) => {
|
|
66
|
+
listeners.add(listener);
|
|
67
|
+
return () => {
|
|
68
|
+
listeners.delete(listener);
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
globalObject[WOOD_AUTOMATION_GLOBAL_KEY] = surface;
|
|
73
|
+
return () => {
|
|
74
|
+
unsubscribeNavigation();
|
|
75
|
+
listeners.clear();
|
|
76
|
+
if (globalObject[WOOD_AUTOMATION_GLOBAL_KEY] === surface) {
|
|
77
|
+
delete globalObject[WOOD_AUTOMATION_GLOBAL_KEY];
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export {
|
|
82
|
+
WOOD_AUTOMATION_GLOBAL_KEY,
|
|
83
|
+
installAutomationIntrospection
|
|
84
|
+
};
|
|
85
|
+
//# sourceMappingURL=automation_introspection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/navigation/automation_introspection.ts"],"sourcesContent":["/**\n * Dev/test-only automation introspection (Axe.md AXE-WP-02).\n *\n * Exposes a narrow, versioned inspection surface for the Axe live driver:\n * current route, readiness, and route-change subscription. It exposes no\n * privileged operations.\n *\n * Deviation from the spec's `bridge.__automation` shape: the preload bridge\n * (`__NOEGO_WOOD_BRIDGE__`) is a sealed contextBridge object that renderer\n * code cannot extend, so the surface is installed as the sibling main-world\n * global `__NOEGO_WOOD_AUTOMATION__`. Axe reads it the same way.\n *\n * This module lives in the renderer bundle. It must only be installed in\n * development and explicit test builds — the generated renderer app gates the\n * install call; this module never self-installs on import.\n */\n\nimport { getNavigation, type NavigationEntry } from './index.js';\n\nexport const WOOD_AUTOMATION_GLOBAL_KEY = '__NOEGO_WOOD_AUTOMATION__';\n\nexport interface WoodAutomationSnapshot {\n version: 1;\n windowId: string | null;\n currentRoute: {\n page: string;\n params: Record<string, string>;\n query: Record<string, string>;\n } | null;\n navigationDepth: number;\n rendererReady: boolean;\n pendingWork: {\n bridgeCalls: number;\n renders: number;\n animations: number;\n };\n}\n\nexport type WoodAutomationEvent =\n | { kind: 'route'; entry: WoodAutomationSnapshot['currentRoute'] };\n\nexport interface WoodAutomationIntrospection {\n version: 1;\n snapshot: () => WoodAutomationSnapshot;\n waitForIdle: (options?: { timeoutMs?: number; idleFrames?: number }) => Promise<boolean>;\n subscribe: (listener: (event: WoodAutomationEvent) => void) => () => void;\n}\n\nexport interface InstallAutomationIntrospectionOptions {\n /** Wood window identity when known at install time. */\n windowId?: string | null;\n /** Override for tests; defaults to `globalThis`. */\n globalObject?: Record<string, unknown>;\n}\n\nfunction toRoute(entry: NavigationEntry | null): WoodAutomationSnapshot['currentRoute'] {\n if (!entry) {\n return null;\n }\n return { page: entry.page, params: { ...entry.params }, query: { ...entry.query } };\n}\n\n/**\n * Install the introspection global. Idempotent: repeated installs replace the\n * previous surface (fresh navigation subscription, updated windowId).\n * Returns an uninstall function.\n */\nexport function installAutomationIntrospection(\n options: InstallAutomationIntrospectionOptions = {},\n): () => void {\n const globalObject = options.globalObject ?? (globalThis as unknown as Record<string, unknown>);\n const navigation = getNavigation();\n\n let routeRevision = 0;\n const listeners = new Set<(event: WoodAutomationEvent) => void>();\n\n const unsubscribeNavigation = navigation.subscribe((entry) => {\n routeRevision += 1;\n const event: WoodAutomationEvent = { kind: 'route', entry: toRoute(entry) };\n for (const listener of listeners) {\n listener(event);\n }\n });\n\n const surface: WoodAutomationIntrospection = {\n version: 1,\n snapshot: () => ({\n version: 1,\n windowId: options.windowId ?? null,\n currentRoute: toRoute(navigation.getCurrent()),\n navigationDepth: navigation.getPages().length,\n rendererReady: true,\n pendingWork: {\n // Bounded placeholders until render/bridge instrumentation lands;\n // consumers must treat unknown pending work as zero, not omit checks.\n bridgeCalls: 0,\n renders: 0,\n animations: 0,\n },\n }),\n waitForIdle: (waitOptions) => {\n const timeoutMs = waitOptions?.timeoutMs ?? 2_000;\n const idleFramesRequired = waitOptions?.idleFrames ?? 3;\n const raf: (cb: () => void) => void =\n typeof requestAnimationFrame === 'function'\n ? (cb) => requestAnimationFrame(() => cb())\n : (cb) => void setTimeout(cb, 16);\n\n return new Promise<boolean>((resolve) => {\n const startedAt = Date.now();\n let lastSeenRevision = routeRevision;\n let idleFrames = 0;\n\n const step = (): void => {\n if (Date.now() - startedAt > timeoutMs) {\n resolve(false);\n return;\n }\n if (routeRevision !== lastSeenRevision) {\n lastSeenRevision = routeRevision;\n idleFrames = 0;\n } else {\n idleFrames += 1;\n if (idleFrames >= idleFramesRequired) {\n resolve(true);\n return;\n }\n }\n raf(step);\n };\n\n raf(step);\n });\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n\n globalObject[WOOD_AUTOMATION_GLOBAL_KEY] = surface;\n\n return () => {\n unsubscribeNavigation();\n listeners.clear();\n if (globalObject[WOOD_AUTOMATION_GLOBAL_KEY] === surface) {\n delete globalObject[WOOD_AUTOMATION_GLOBAL_KEY];\n }\n };\n}\n"],"mappings":"AAiBA,SAAS,qBAA2C;AAE7C,MAAM,6BAA6B;AAoC1C,SAAS,QAAQ,OAAuE;AACtF,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,SAAO,EAAE,MAAM,MAAM,MAAM,QAAQ,EAAE,GAAG,MAAM,OAAO,GAAG,OAAO,EAAE,GAAG,MAAM,MAAM,EAAE;AACpF;AAOO,SAAS,+BACd,UAAiD,CAAC,GACtC;AACZ,QAAM,eAAe,QAAQ,gBAAiB;AAC9C,QAAM,aAAa,cAAc;AAEjC,MAAI,gBAAgB;AACpB,QAAM,YAAY,oBAAI,IAA0C;AAEhE,QAAM,wBAAwB,WAAW,UAAU,CAAC,UAAU;AAC5D,qBAAiB;AACjB,UAAM,QAA6B,EAAE,MAAM,SAAS,OAAO,QAAQ,KAAK,EAAE;AAC1E,eAAW,YAAY,WAAW;AAChC,eAAS,KAAK;AAAA,IAChB;AAAA,EACF,CAAC;AAED,QAAM,UAAuC;AAAA,IAC3C,SAAS;AAAA,IACT,UAAU,OAAO;AAAA,MACf,SAAS;AAAA,MACT,UAAU,QAAQ,YAAY;AAAA,MAC9B,cAAc,QAAQ,WAAW,WAAW,CAAC;AAAA,MAC7C,iBAAiB,WAAW,SAAS,EAAE;AAAA,MACvC,eAAe;AAAA,MACf,aAAa;AAAA;AAAA;AAAA,QAGX,aAAa;AAAA,QACb,SAAS;AAAA,QACT,YAAY;AAAA,MACd;AAAA,IACF;AAAA,IACA,aAAa,CAAC,gBAAgB;AAC5B,YAAM,YAAY,aAAa,aAAa;AAC5C,YAAM,qBAAqB,aAAa,cAAc;AACtD,YAAM,MACJ,OAAO,0BAA0B,aAC7B,CAAC,OAAO,sBAAsB,MAAM,GAAG,CAAC,IACxC,CAAC,OAAO,KAAK,WAAW,IAAI,EAAE;AAEpC,aAAO,IAAI,QAAiB,CAAC,YAAY;AACvC,cAAM,YAAY,KAAK,IAAI;AAC3B,YAAI,mBAAmB;AACvB,YAAI,aAAa;AAEjB,cAAM,OAAO,MAAY;AACvB,cAAI,KAAK,IAAI,IAAI,YAAY,WAAW;AACtC,oBAAQ,KAAK;AACb;AAAA,UACF;AACA,cAAI,kBAAkB,kBAAkB;AACtC,+BAAmB;AACnB,yBAAa;AAAA,UACf,OAAO;AACL,0BAAc;AACd,gBAAI,cAAc,oBAAoB;AACpC,sBAAQ,IAAI;AACZ;AAAA,YACF;AAAA,UACF;AACA,cAAI,IAAI;AAAA,QACV;AAEA,YAAI,IAAI;AAAA,MACV,CAAC;AAAA,IACH;AAAA,IACA,WAAW,CAAC,aAAa;AACvB,gBAAU,IAAI,QAAQ;AACtB,aAAO,MAAM;AACX,kBAAU,OAAO,QAAQ;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AAEA,eAAa,0BAA0B,IAAI;AAE3C,SAAO,MAAM;AACX,0BAAsB;AACtB,cAAU,MAAM;AAChB,QAAI,aAAa,0BAA0B,MAAM,SAAS;AACxD,aAAO,aAAa,0BAA0B;AAAA,IAChD;AAAA,EACF;AACF;","names":[]}
|
|
@@ -19,14 +19,17 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
var navigation_exports = {};
|
|
20
20
|
__export(navigation_exports, {
|
|
21
21
|
Navigation: () => Navigation,
|
|
22
|
+
WOOD_AUTOMATION_GLOBAL_KEY: () => import_automation_introspection.WOOD_AUTOMATION_GLOBAL_KEY,
|
|
22
23
|
clearNavigationForTests: () => clearNavigationForTests,
|
|
23
24
|
getNavigation: () => getNavigation,
|
|
24
25
|
go: () => go,
|
|
25
26
|
goback: () => goback,
|
|
26
|
-
goto: () => goto
|
|
27
|
+
goto: () => goto,
|
|
28
|
+
installAutomationIntrospection: () => import_automation_introspection.installAutomationIntrospection
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(navigation_exports);
|
|
29
31
|
var import_tracing = require("../tracing/index.js");
|
|
32
|
+
var import_automation_introspection = require("./automation_introspection.cjs");
|
|
30
33
|
const NAVIGATION_SYMBOL = /* @__PURE__ */ Symbol.for("@noego/wood.navigation");
|
|
31
34
|
const HISTORY_STATE_MARKER = "__wood_navigation_state__";
|
|
32
35
|
class Navigation {
|
|
@@ -201,10 +204,12 @@ function clearNavigationForTests() {
|
|
|
201
204
|
// Annotate the CommonJS export names for ESM import in node:
|
|
202
205
|
0 && (module.exports = {
|
|
203
206
|
Navigation,
|
|
207
|
+
WOOD_AUTOMATION_GLOBAL_KEY,
|
|
204
208
|
clearNavigationForTests,
|
|
205
209
|
getNavigation,
|
|
206
210
|
go,
|
|
207
211
|
goback,
|
|
208
|
-
goto
|
|
212
|
+
goto,
|
|
213
|
+
installAutomationIntrospection
|
|
209
214
|
});
|
|
210
215
|
//# 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"],"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\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';\n"],"mappings":"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","names":[]}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, WoodAutomationEvent, WoodAutomationIntrospection, WoodAutomationSnapshot, installAutomationIntrospection } from './automation_introspection.cjs';
|
|
2
|
+
|
|
1
3
|
interface NavigationEntry {
|
|
2
4
|
page: string;
|
|
3
5
|
params: Record<string, string>;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
export { InstallAutomationIntrospectionOptions, WOOD_AUTOMATION_GLOBAL_KEY, WoodAutomationEvent, WoodAutomationIntrospection, WoodAutomationSnapshot, installAutomationIntrospection } from './automation_introspection.js';
|
|
2
|
+
|
|
1
3
|
interface NavigationEntry {
|
|
2
4
|
page: string;
|
|
3
5
|
params: Record<string, string>;
|
package/dist/navigation/index.js
CHANGED
|
@@ -170,12 +170,15 @@ function clearNavigationForTests() {
|
|
|
170
170
|
const globalObj = globalThis;
|
|
171
171
|
delete globalObj[NAVIGATION_SYMBOL];
|
|
172
172
|
}
|
|
173
|
+
import { installAutomationIntrospection, WOOD_AUTOMATION_GLOBAL_KEY } from "./automation_introspection.js";
|
|
173
174
|
export {
|
|
174
175
|
Navigation,
|
|
176
|
+
WOOD_AUTOMATION_GLOBAL_KEY,
|
|
175
177
|
clearNavigationForTests,
|
|
176
178
|
getNavigation,
|
|
177
179
|
go,
|
|
178
180
|
goback,
|
|
179
|
-
goto
|
|
181
|
+
goto,
|
|
182
|
+
installAutomationIntrospection
|
|
180
183
|
};
|
|
181
184
|
//# 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\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"],"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\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.js';\nexport type { WoodAutomationSnapshot, WoodAutomationEvent, WoodAutomationIntrospection, InstallAutomationIntrospectionOptions } from './automation_introspection.js';\n"],"mappings":"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","names":[]}
|