@a11y-oracle/core-engine 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,219 @@
1
+ /**
2
+ * @module speech-engine
3
+ *
4
+ * The central class of A11y-Oracle. {@link SpeechEngine} connects to the
5
+ * browser's Accessibility Tree via the Chrome DevTools Protocol and generates
6
+ * standardized speech output following the format:
7
+ *
8
+ * ```
9
+ * [Computed Name], [Role], [State/Properties]
10
+ * ```
11
+ *
12
+ * Chrome's CDP already computes accessible names per the W3C AccName spec,
13
+ * so the engine's job is to:
14
+ * 1. Fetch the AXTree via `Accessibility.getFullAXTree()`
15
+ * 2. Find the currently focused node
16
+ * 3. Map the node's role and properties to human-readable strings
17
+ * 4. Assemble the final speech string
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { SpeechEngine } from '@a11y-oracle/core-engine';
22
+ *
23
+ * const engine = new SpeechEngine(cdpSession);
24
+ * await engine.enable();
25
+ *
26
+ * const result = await engine.getSpeech();
27
+ * console.log(result?.speech); // "Products, button, collapsed"
28
+ * ```
29
+ */
30
+ import { ROLE_TO_SPEECH, LANDMARK_ROLES } from './role-map.js';
31
+ import { extractStates } from './state-map.js';
32
+ /**
33
+ * Generates standardized speech output from the browser's Accessibility Tree.
34
+ *
35
+ * The engine operates through a {@link CDPSessionLike} interface, making it
36
+ * framework-agnostic. It works with Playwright's CDP sessions, raw WebSocket
37
+ * connections, or any other CDP-compatible client.
38
+ *
39
+ * ## Speech Output Format
40
+ *
41
+ * Every element produces a string in this format:
42
+ * ```
43
+ * [Computed Name], [Role], [State/Properties]
44
+ * ```
45
+ *
46
+ * Parts are omitted if they are empty. For example:
47
+ * - `"Products, button, collapsed"` — name + role + state
48
+ * - `"Main, navigation landmark"` — name + role (landmark)
49
+ * - `"Home, link"` — name + role (no states)
50
+ *
51
+ * ## Landmark Roles
52
+ *
53
+ * Landmark roles (navigation, main, banner, etc.) automatically append
54
+ * the word "landmark" to their role string unless
55
+ * {@link SpeechEngineOptions.includeLandmarks} is set to `false`.
56
+ */
57
+ export class SpeechEngine {
58
+ cdp;
59
+ options;
60
+ /**
61
+ * Create a new SpeechEngine instance.
62
+ *
63
+ * @param cdp - A CDP session-like object for sending protocol commands.
64
+ * @param options - Optional configuration for speech output behavior.
65
+ */
66
+ constructor(cdp, options = {}) {
67
+ this.cdp = cdp;
68
+ this.options = {
69
+ includeLandmarks: options.includeLandmarks ?? true,
70
+ includeDescription: options.includeDescription ?? false,
71
+ };
72
+ }
73
+ /**
74
+ * Enable the CDP Accessibility domain.
75
+ *
76
+ * Must be called before any other method. Enables the browser to
77
+ * start tracking and reporting accessibility tree data.
78
+ */
79
+ async enable() {
80
+ await this.cdp.send('Accessibility.enable');
81
+ }
82
+ /**
83
+ * Disable the CDP Accessibility domain.
84
+ *
85
+ * Call this when you're done using the engine to free browser resources.
86
+ */
87
+ async disable() {
88
+ await this.cdp.send('Accessibility.disable');
89
+ }
90
+ /**
91
+ * Get the speech output for the currently focused element.
92
+ *
93
+ * Fetches the full AXTree, locates the node with `focused: true`,
94
+ * and computes its speech string.
95
+ *
96
+ * @returns The {@link SpeechResult} for the focused element, or `null`
97
+ * if no element has focus or the focused element is ignored.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * // After pressing Tab to focus a button
102
+ * const result = await engine.getSpeech();
103
+ * console.log(result?.speech); // "Products, button, collapsed"
104
+ * console.log(result?.name); // "Products"
105
+ * console.log(result?.role); // "button"
106
+ * console.log(result?.states); // ["collapsed"]
107
+ * ```
108
+ */
109
+ async getSpeech() {
110
+ const { nodes } = await this.cdp.send('Accessibility.getFullAXTree');
111
+ const focusedNode = this.findFocusedNode(nodes);
112
+ if (!focusedNode)
113
+ return null;
114
+ return this.computeSpeech(focusedNode);
115
+ }
116
+ /**
117
+ * Get speech output for ALL non-ignored, non-silent nodes in the tree.
118
+ *
119
+ * Useful for asserting on landmarks, headings, or other structural
120
+ * elements that may not have focus.
121
+ *
122
+ * @returns An array of {@link SpeechResult} objects for every visible
123
+ * node that produces speech output.
124
+ *
125
+ * @example
126
+ * ```typescript
127
+ * const all = await engine.getFullTreeSpeech();
128
+ * const nav = all.find(r => r.speech === 'Main, navigation landmark');
129
+ * expect(nav).toBeDefined();
130
+ * ```
131
+ */
132
+ async getFullTreeSpeech() {
133
+ const { nodes } = await this.cdp.send('Accessibility.getFullAXTree');
134
+ return nodes
135
+ .map((node) => this.computeSpeech(node))
136
+ .filter((result) => result !== null);
137
+ }
138
+ /**
139
+ * Find the most specific focused node in the flat AXTree node list.
140
+ *
141
+ * CDP returns the AXTree as a flat array with the document node first
142
+ * and more specific nodes later. Multiple nodes can report `focused: true`
143
+ * (e.g., both the RootWebArea and the actual focused element). This method
144
+ * returns the **last** focused node, which is the most specific (deepest)
145
+ * element that actually has user focus.
146
+ *
147
+ * @param nodes - The flat array of AXNodes from `getFullAXTree()`.
148
+ * @returns The most specific focused node, or `null` if no node is focused.
149
+ */
150
+ findFocusedNode(nodes) {
151
+ let lastFocused = null;
152
+ for (const node of nodes) {
153
+ const focused = node.properties?.find((p) => p.name === 'focused');
154
+ if (focused?.value?.value === true) {
155
+ lastFocused = node;
156
+ }
157
+ }
158
+ return lastFocused;
159
+ }
160
+ /**
161
+ * Compute the speech string for a single AXNode.
162
+ *
163
+ * Follows the output format: `[Computed Name], [Role], [State/Properties]`.
164
+ * Parts are omitted when empty. Ignored nodes and nodes with no
165
+ * meaningful content return `null`.
166
+ *
167
+ * @param node - A CDP AXNode from the accessibility tree.
168
+ * @returns A {@link SpeechResult} with the computed speech, or `null`
169
+ * if the node should be silent (ignored, no role, no name).
170
+ *
171
+ * @example
172
+ * ```typescript
173
+ * const result = engine.computeSpeech(axNode);
174
+ * // { speech: "Products, button, collapsed", name: "Products", ... }
175
+ * ```
176
+ */
177
+ computeSpeech(node) {
178
+ const role = node.role?.value;
179
+ if (!role)
180
+ return null;
181
+ // Skip ignored/invisible nodes
182
+ if (node.ignored)
183
+ return null;
184
+ const name = node.name?.value ?? '';
185
+ let speechRole = ROLE_TO_SPEECH[role] ?? role;
186
+ // Skip nodes with no role output and no name (generic containers, etc.)
187
+ if (!speechRole && !name)
188
+ return null;
189
+ // Append "landmark" to landmark roles
190
+ if (this.options.includeLandmarks && LANDMARK_ROLES.has(role)) {
191
+ speechRole = `${speechRole} landmark`;
192
+ }
193
+ const states = extractStates(node.properties);
194
+ // Build the speech parts: [name], [role], [states...]
195
+ const parts = [];
196
+ if (name)
197
+ parts.push(name);
198
+ if (speechRole)
199
+ parts.push(speechRole);
200
+ parts.push(...states);
201
+ // Optionally include description
202
+ if (this.options.includeDescription) {
203
+ const description = node.description?.value ?? '';
204
+ if (description)
205
+ parts.push(description);
206
+ }
207
+ const speech = parts.join(', ');
208
+ // Don't return results with empty speech
209
+ if (!speech)
210
+ return null;
211
+ return {
212
+ speech,
213
+ name,
214
+ role: speechRole,
215
+ states,
216
+ rawNode: node,
217
+ };
218
+ }
219
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * @module state-map
3
+ *
4
+ * Maps Chrome DevTools Protocol AXNode property values to human-readable
5
+ * state strings used in speech output.
6
+ *
7
+ * CDP provides node properties as an array of `{ name, value }` objects.
8
+ * This module translates those boolean/enumerated properties into the
9
+ * words a screen reader would announce (e.g., `expanded: false` → `"collapsed"`).
10
+ */
11
+ /**
12
+ * Defines how a single CDP AXNode property maps to spoken state strings.
13
+ *
14
+ * For boolean properties, `trueValue` is spoken when the property is `true`,
15
+ * and `falseValue` when `false`. An empty string means the state is not
16
+ * announced for that value.
17
+ */
18
+ export interface StateMapping {
19
+ /** The CDP property name (e.g., `"expanded"`, `"checked"`). */
20
+ property: string;
21
+ /** The string to speak when the property value is `true`. */
22
+ trueValue: string;
23
+ /** The string to speak when the property value is `false`. Empty string means silent. */
24
+ falseValue: string;
25
+ }
26
+ /**
27
+ * Ordered list of CDP property → spoken state mappings.
28
+ *
29
+ * The order determines the sequence in which states appear in the speech
30
+ * output when multiple states are present. For example, a required invalid
31
+ * field produces `"..., required, invalid"`.
32
+ *
33
+ * @example
34
+ * ```
35
+ * aria-expanded="false" → "collapsed"
36
+ * aria-expanded="true" → "expanded"
37
+ * aria-checked="true" → "checked"
38
+ * aria-disabled="true" → "dimmed"
39
+ * ```
40
+ */
41
+ export declare const STATE_MAPPINGS: StateMapping[];
42
+ /**
43
+ * Represents a single property from a CDP AXNode's `properties` array.
44
+ *
45
+ * CDP encodes property values as `{ type, value }` objects. For boolean
46
+ * properties, `type` is `"boolean"` or `"booleanOrUndefined"` and `value`
47
+ * is `true` or `false`.
48
+ */
49
+ export interface AXNodeProperty {
50
+ name: string;
51
+ value: {
52
+ type: string;
53
+ value?: unknown;
54
+ };
55
+ }
56
+ /**
57
+ * Extract human-readable state strings from a CDP AXNode's properties array.
58
+ *
59
+ * Iterates through {@link STATE_MAPPINGS} and checks whether each mapped
60
+ * property is present in the node's properties. Also handles the special
61
+ * `level` property for headings.
62
+ *
63
+ * @param properties - The `properties` array from a CDP AXNode, or `undefined`.
64
+ * @returns An array of state strings (e.g., `["collapsed"]`, `["checked", "required"]`).
65
+ * Returns an empty array if no properties are present or none match.
66
+ *
67
+ * @example
68
+ * ```typescript
69
+ * extractStates([
70
+ * { name: 'expanded', value: { type: 'boolean', value: false } },
71
+ * { name: 'required', value: { type: 'boolean', value: true } },
72
+ * ]);
73
+ * // → ['collapsed', 'required']
74
+ *
75
+ * extractStates([
76
+ * { name: 'level', value: { type: 'integer', value: 2 } },
77
+ * ]);
78
+ * // → ['level 2']
79
+ * ```
80
+ */
81
+ export declare function extractStates(properties: AXNodeProperty[] | undefined): string[];
82
+ //# sourceMappingURL=state-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-map.d.ts","sourceRoot":"","sources":["../../src/lib/state-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,yFAAyF;IACzF,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,cAAc,EAAE,YAAY,EAUxC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,cAAc,EAAE,GAAG,SAAS,GACvC,MAAM,EAAE,CAwBV"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @module state-map
3
+ *
4
+ * Maps Chrome DevTools Protocol AXNode property values to human-readable
5
+ * state strings used in speech output.
6
+ *
7
+ * CDP provides node properties as an array of `{ name, value }` objects.
8
+ * This module translates those boolean/enumerated properties into the
9
+ * words a screen reader would announce (e.g., `expanded: false` → `"collapsed"`).
10
+ */
11
+ /**
12
+ * Ordered list of CDP property → spoken state mappings.
13
+ *
14
+ * The order determines the sequence in which states appear in the speech
15
+ * output when multiple states are present. For example, a required invalid
16
+ * field produces `"..., required, invalid"`.
17
+ *
18
+ * @example
19
+ * ```
20
+ * aria-expanded="false" → "collapsed"
21
+ * aria-expanded="true" → "expanded"
22
+ * aria-checked="true" → "checked"
23
+ * aria-disabled="true" → "dimmed"
24
+ * ```
25
+ */
26
+ export const STATE_MAPPINGS = [
27
+ { property: 'expanded', trueValue: 'expanded', falseValue: 'collapsed' },
28
+ { property: 'checked', trueValue: 'checked', falseValue: 'not checked' },
29
+ { property: 'selected', trueValue: 'selected', falseValue: '' },
30
+ { property: 'pressed', trueValue: 'pressed', falseValue: 'not pressed' },
31
+ { property: 'disabled', trueValue: 'dimmed', falseValue: '' },
32
+ { property: 'required', trueValue: 'required', falseValue: '' },
33
+ { property: 'invalid', trueValue: 'invalid', falseValue: '' },
34
+ { property: 'readonly', trueValue: 'read only', falseValue: '' },
35
+ { property: 'multiselectable', trueValue: 'multi selectable', falseValue: '' },
36
+ ];
37
+ /**
38
+ * Extract human-readable state strings from a CDP AXNode's properties array.
39
+ *
40
+ * Iterates through {@link STATE_MAPPINGS} and checks whether each mapped
41
+ * property is present in the node's properties. Also handles the special
42
+ * `level` property for headings.
43
+ *
44
+ * @param properties - The `properties` array from a CDP AXNode, or `undefined`.
45
+ * @returns An array of state strings (e.g., `["collapsed"]`, `["checked", "required"]`).
46
+ * Returns an empty array if no properties are present or none match.
47
+ *
48
+ * @example
49
+ * ```typescript
50
+ * extractStates([
51
+ * { name: 'expanded', value: { type: 'boolean', value: false } },
52
+ * { name: 'required', value: { type: 'boolean', value: true } },
53
+ * ]);
54
+ * // → ['collapsed', 'required']
55
+ *
56
+ * extractStates([
57
+ * { name: 'level', value: { type: 'integer', value: 2 } },
58
+ * ]);
59
+ * // → ['level 2']
60
+ * ```
61
+ */
62
+ export function extractStates(properties) {
63
+ if (!properties || properties.length === 0)
64
+ return [];
65
+ const states = [];
66
+ for (const mapping of STATE_MAPPINGS) {
67
+ const prop = properties.find((p) => p.name === mapping.property);
68
+ if (!prop)
69
+ continue;
70
+ const val = prop.value?.value;
71
+ if (val === true || val === 'true') {
72
+ if (mapping.trueValue)
73
+ states.push(mapping.trueValue);
74
+ }
75
+ else if (val === false || val === 'false') {
76
+ if (mapping.falseValue)
77
+ states.push(mapping.falseValue);
78
+ }
79
+ }
80
+ // Handle heading level (special property, not boolean)
81
+ const level = properties.find((p) => p.name === 'level');
82
+ if (level?.value?.value !== undefined) {
83
+ states.push(`level ${level.value.value}`);
84
+ }
85
+ return states;
86
+ }
@@ -0,0 +1,162 @@
1
+ /**
2
+ * @module types
3
+ *
4
+ * Core type definitions for the A11y-Oracle speech engine.
5
+ *
6
+ * The key abstraction is {@link CDPSessionLike}, which decouples the engine
7
+ * from any specific test framework. Both Playwright's `CDPSession` and a raw
8
+ * WebSocket CDP client can satisfy this interface.
9
+ */
10
+ import type { Protocol } from 'devtools-protocol';
11
+ import type { CDPSessionLike as BaseCDPSessionLike } from '@a11y-oracle/cdp-types';
12
+ /**
13
+ * Extended CDP session interface with typed Accessibility domain methods.
14
+ *
15
+ * Extends the base {@link BaseCDPSessionLike} from `@a11y-oracle/cdp-types`
16
+ * with specific overloads for the Accessibility CDP domain used by the
17
+ * speech engine and orchestrator.
18
+ */
19
+ export interface CDPSessionLike extends BaseCDPSessionLike {
20
+ send(method: 'Accessibility.enable'): Promise<void>;
21
+ send(method: 'Accessibility.disable'): Promise<void>;
22
+ send(method: 'Accessibility.getFullAXTree', params?: {
23
+ depth?: number;
24
+ frameId?: string;
25
+ }): Promise<Protocol.Accessibility.GetFullAXTreeResponse>;
26
+ send(method: string, params?: Record<string, unknown>): Promise<unknown>;
27
+ }
28
+ /**
29
+ * The result of computing speech output for a single accessibility node.
30
+ *
31
+ * Contains both the final speech string and its constituent parts for
32
+ * granular assertions.
33
+ *
34
+ * @example
35
+ * ```typescript
36
+ * const result: SpeechResult = {
37
+ * speech: 'Products, button, collapsed',
38
+ * name: 'Products',
39
+ * role: 'button',
40
+ * states: ['collapsed'],
41
+ * rawNode: { ... } // CDP AXNode
42
+ * };
43
+ * ```
44
+ */
45
+ export interface SpeechResult {
46
+ /** The full speech string, e.g. `"Products, button, collapsed"`. */
47
+ speech: string;
48
+ /** The computed accessible name. */
49
+ name: string;
50
+ /** The human-readable role string (already mapped from CDP role). */
51
+ role: string;
52
+ /** Array of state strings, e.g. `["collapsed"]`, `["checked", "required"]`. */
53
+ states: string[];
54
+ /** The raw CDP AXNode for advanced inspection. */
55
+ rawNode: Protocol.Accessibility.AXNode;
56
+ }
57
+ /**
58
+ * DOM-level information about the currently focused element.
59
+ *
60
+ * This is the orchestrator's view of the focused element — a simpler,
61
+ * framework-agnostic shape compared to `FocusedElementInfo` from
62
+ * keyboard-engine (which is a raw CDP extraction type).
63
+ */
64
+ export interface A11yFocusedElement {
65
+ /** Tag name, e.g. `'BUTTON'`. */
66
+ tag: string;
67
+ /** Element `id` attribute, or empty string. */
68
+ id: string;
69
+ /** Element `className` attribute, or empty string. */
70
+ className: string;
71
+ /** Trimmed text content of the element. */
72
+ textContent: string;
73
+ /** The element's `role` attribute, or empty string. */
74
+ role: string;
75
+ /** The element's `aria-label` attribute, or empty string. */
76
+ ariaLabel: string;
77
+ /** The element's `tabIndex` property. */
78
+ tabIndex: number;
79
+ /** Bounding rectangle in viewport coordinates. */
80
+ rect: {
81
+ x: number;
82
+ y: number;
83
+ width: number;
84
+ height: number;
85
+ };
86
+ }
87
+ /**
88
+ * Visual focus indicator analysis from CSS computed styles.
89
+ *
90
+ * A simplified projection of the full {@link FocusIndicator} from
91
+ * `@a11y-oracle/focus-analyzer`, carrying only the fields needed
92
+ * for unified state assertions.
93
+ */
94
+ export interface A11yFocusIndicator {
95
+ /** Whether any visual focus indicator is detected. */
96
+ isVisible: boolean;
97
+ /**
98
+ * Contrast ratio of the focus indicator against the background.
99
+ * `null` if the colors could not be reliably parsed.
100
+ */
101
+ contrastRatio: number | null;
102
+ /**
103
+ * Whether the indicator meets WCAG 2.4.12 AA
104
+ * (contrast ≥ 3.0 and indicator is visible).
105
+ */
106
+ meetsWCAG_AA: boolean;
107
+ }
108
+ /**
109
+ * Unified accessibility state combining speech output, focus information,
110
+ * and visual indicator analysis.
111
+ *
112
+ * Returned by {@link A11yOrchestrator.pressKey} and
113
+ * {@link A11yOrchestrator.getState} to give a single snapshot of
114
+ * "what the screen reader says" + "where focus is" + "how focus looks".
115
+ *
116
+ * @example
117
+ * ```typescript
118
+ * const state = await orchestrator.pressKey('Tab');
119
+ * console.log(state.speech); // "Products, button, collapsed"
120
+ * console.log(state.focusedElement?.tag); // "BUTTON"
121
+ * console.log(state.focusIndicator.meetsWCAG_AA); // true
122
+ * ```
123
+ */
124
+ export interface A11yState {
125
+ /** The full speech string, e.g. `"Products, button, collapsed"`. */
126
+ speech: string;
127
+ /** The full speech result with raw AXNode data. `null` if no focused element. */
128
+ speechResult: SpeechResult | null;
129
+ /** DOM-level info about the focused element. `null` if no element has focus. */
130
+ focusedElement: A11yFocusedElement | null;
131
+ /** Visual focus indicator analysis. */
132
+ focusIndicator: A11yFocusIndicator;
133
+ }
134
+ /**
135
+ * Configuration options for the {@link A11yOrchestrator}.
136
+ */
137
+ export interface A11yOrchestratorOptions extends SpeechEngineOptions {
138
+ /**
139
+ * Milliseconds to wait after a key press before reading state,
140
+ * allowing CSS transitions and focus events to settle.
141
+ * Defaults to `50`.
142
+ */
143
+ focusSettleMs?: number;
144
+ }
145
+ /**
146
+ * Configuration options for the {@link SpeechEngine}.
147
+ */
148
+ export interface SpeechEngineOptions {
149
+ /**
150
+ * Whether to include landmark roles in speech output.
151
+ * When `true` (default), landmarks like `<nav>` produce
152
+ * `"Main, navigation landmark"`.
153
+ */
154
+ includeLandmarks?: boolean;
155
+ /**
156
+ * Whether to include the accessible description in speech output.
157
+ * When `true`, the description is appended after states.
158
+ * Defaults to `false`.
159
+ */
160
+ includeDescription?: boolean;
161
+ }
162
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEnF;;;;;;GAMG;AACH,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,IAAI,CACF,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,IAAI,CACF,MAAM,EAAE,uBAAuB,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,IAAI,CACF,MAAM,EAAE,6BAA6B,EACrC,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,GAC5C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACzD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC1E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,YAAY;IAC3B,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,IAAI,EAAE,MAAM,CAAC;IACb,+EAA+E;IAC/E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,kDAAkD;IAClD,OAAO,EAAE,QAAQ,CAAC,aAAa,CAAC,MAAM,CAAC;CACxC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,IAAI,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/D;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,SAAS,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B;;;OAGG;IACH,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,SAAS;IACxB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,iFAAiF;IACjF,YAAY,EAAE,YAAY,GAAG,IAAI,CAAC;IAClC,gFAAgF;IAChF,cAAc,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,uCAAuC;IACvC,cAAc,EAAE,kBAAkB,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAClE;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @module types
3
+ *
4
+ * Core type definitions for the A11y-Oracle speech engine.
5
+ *
6
+ * The key abstraction is {@link CDPSessionLike}, which decouples the engine
7
+ * from any specific test framework. Both Playwright's `CDPSession` and a raw
8
+ * WebSocket CDP client can satisfy this interface.
9
+ */
10
+ export {};
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@a11y-oracle/core-engine",
3
+ "version": "1.0.0",
4
+ "description": "Framework-agnostic accessibility speech engine and unified A11yOrchestrator via Chrome DevTools Protocol",
5
+ "license": "MIT",
6
+ "author": "a11y-oracle",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/a11y-oracle/a11y-oracle.git",
10
+ "directory": "libs/core-engine"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/a11y-oracle/a11y-oracle/issues"
14
+ },
15
+ "homepage": "https://github.com/a11y-oracle/a11y-oracle/tree/main/libs/core-engine",
16
+ "keywords": [
17
+ "accessibility",
18
+ "a11y",
19
+ "screen-reader",
20
+ "speech",
21
+ "wcag",
22
+ "aria",
23
+ "cdp",
24
+ "testing"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "type": "module",
30
+ "main": "./dist/index.js",
31
+ "module": "./dist/index.js",
32
+ "types": "./dist/index.d.ts",
33
+ "exports": {
34
+ "./package.json": "./package.json",
35
+ ".": {
36
+ "types": "./dist/index.d.ts",
37
+ "import": "./dist/index.js",
38
+ "default": "./dist/index.js"
39
+ }
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "!**/*.tsbuildinfo"
44
+ ],
45
+ "dependencies": {
46
+ "@a11y-oracle/cdp-types": "1.0.0",
47
+ "@a11y-oracle/keyboard-engine": "1.0.0",
48
+ "@a11y-oracle/focus-analyzer": "1.0.0",
49
+ "devtools-protocol": "^0.0.1591961",
50
+ "tslib": "^2.3.0"
51
+ }
52
+ }