@generative-a11y/devtools 0.1.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.
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/index.cjs +373 -0
- package/dist/index.d.cts +106 -0
- package/dist/index.d.ts +106 -0
- package/dist/index.js +348 -0
- package/dist/overlay.cjs +837 -0
- package/dist/overlay.d.cts +15 -0
- package/dist/overlay.d.ts +15 -0
- package/dist/overlay.js +802 -0
- package/package.json +81 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { GenerativeA11yRuntime, AdapterFidelity, RuntimeDiagnosticEventV1, RuntimeDiagnosticSnapshotV1 } from '@generative-a11y/core';
|
|
2
|
+
|
|
3
|
+
type DevtoolsRecordKind = RuntimeDiagnosticEventV1["kind"] | "dom-delivery";
|
|
4
|
+
interface DevtoolsRecord {
|
|
5
|
+
readonly runtimeId: string;
|
|
6
|
+
/** Opaque key for the immutable adapter evidence captured with this record. */
|
|
7
|
+
readonly runtimeSourceId?: string;
|
|
8
|
+
readonly sequence?: number;
|
|
9
|
+
readonly captureSequence: number;
|
|
10
|
+
readonly at: number;
|
|
11
|
+
readonly kind: DevtoolsRecordKind;
|
|
12
|
+
readonly sourceType?: string;
|
|
13
|
+
readonly sourceEventId?: string;
|
|
14
|
+
readonly disposition?: string;
|
|
15
|
+
readonly reason?: string;
|
|
16
|
+
readonly announcementId?: string;
|
|
17
|
+
readonly responseId?: string;
|
|
18
|
+
readonly responseInstanceId?: string;
|
|
19
|
+
readonly nextResponseInstanceId?: string;
|
|
20
|
+
readonly attempt?: number;
|
|
21
|
+
readonly toolId?: string;
|
|
22
|
+
readonly toolInstanceId?: string;
|
|
23
|
+
readonly interactionId?: string;
|
|
24
|
+
readonly approvalId?: string;
|
|
25
|
+
readonly progress?: number;
|
|
26
|
+
readonly outcome?: string;
|
|
27
|
+
readonly count?: number;
|
|
28
|
+
readonly scheduledAt?: number;
|
|
29
|
+
readonly dueAt?: number;
|
|
30
|
+
readonly delayMs?: number;
|
|
31
|
+
readonly queueSequence?: number;
|
|
32
|
+
readonly channel?: "polite" | "assertive";
|
|
33
|
+
readonly deliveryStatus?: "notified" | "mutated" | "unavailable" | "disposed";
|
|
34
|
+
readonly deliveryMethod?: "aria-notify" | "live-region" | "none";
|
|
35
|
+
readonly errorName?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Explicit, serializable evidence declared by an integration. Devtools never
|
|
39
|
+
* detects framework state or infers fidelity on its own.
|
|
40
|
+
*/
|
|
41
|
+
interface DevtoolsRuntimeSource {
|
|
42
|
+
readonly adapter: string;
|
|
43
|
+
readonly evidence: readonly string[];
|
|
44
|
+
readonly fidelity: Readonly<Omit<AdapterFidelity, "optionalEvents"> & {
|
|
45
|
+
readonly optionalEvents?: readonly NonNullable<AdapterFidelity["optionalEvents"]>[number][];
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
48
|
+
interface DeliveryRecordInput {
|
|
49
|
+
readonly runtimeId: string;
|
|
50
|
+
readonly result: {
|
|
51
|
+
readonly status: "notified" | "mutated" | "unavailable" | "disposed";
|
|
52
|
+
readonly method: "aria-notify" | "live-region" | "none";
|
|
53
|
+
readonly channel: "polite" | "assertive";
|
|
54
|
+
readonly announcementId: string;
|
|
55
|
+
readonly sourceType: string;
|
|
56
|
+
readonly at: number;
|
|
57
|
+
readonly sourceEventId?: string;
|
|
58
|
+
readonly responseId?: string;
|
|
59
|
+
readonly toolId?: string;
|
|
60
|
+
readonly interactionId?: string;
|
|
61
|
+
readonly error?: {
|
|
62
|
+
readonly name: string;
|
|
63
|
+
readonly message?: string;
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
interface DevtoolsSnapshot {
|
|
68
|
+
readonly paused: boolean;
|
|
69
|
+
readonly droppedCount: number;
|
|
70
|
+
readonly records: readonly DevtoolsRecord[];
|
|
71
|
+
readonly runtimeIds: readonly string[];
|
|
72
|
+
readonly runtimeSnapshots: Readonly<Record<string, RuntimeDiagnosticSnapshotV1>>;
|
|
73
|
+
readonly runtimeSources: Readonly<Record<string, DevtoolsRuntimeSource>>;
|
|
74
|
+
}
|
|
75
|
+
interface DevtoolsTraceExportV1 {
|
|
76
|
+
readonly schemaVersion: 1;
|
|
77
|
+
readonly kind: "generative-a11y/devtools-trace";
|
|
78
|
+
readonly paused: boolean;
|
|
79
|
+
readonly droppedCount: number;
|
|
80
|
+
readonly records: readonly DevtoolsRecord[];
|
|
81
|
+
readonly runtimeSnapshots: Readonly<Record<string, RuntimeDiagnosticSnapshotV1>>;
|
|
82
|
+
readonly runtimeSources: Readonly<Record<string, DevtoolsRuntimeSource>>;
|
|
83
|
+
}
|
|
84
|
+
interface DevtoolsStoreOptions {
|
|
85
|
+
readonly maxEntries?: number;
|
|
86
|
+
}
|
|
87
|
+
interface AttachRuntimeOptions {
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly runtime: Pick<GenerativeA11yRuntime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
|
|
90
|
+
readonly source?: DevtoolsRuntimeSource;
|
|
91
|
+
}
|
|
92
|
+
interface DevtoolsStore {
|
|
93
|
+
attachRuntime(options: AttachRuntimeOptions): () => void;
|
|
94
|
+
getSnapshot(): DevtoolsSnapshot;
|
|
95
|
+
subscribe(listener: () => void): () => void;
|
|
96
|
+
pauseCapture(): void;
|
|
97
|
+
resumeCapture(): void;
|
|
98
|
+
refreshSnapshots(): void;
|
|
99
|
+
recordDelivery(input: DeliveryRecordInput): void;
|
|
100
|
+
clear(): void;
|
|
101
|
+
exportTrace(): DevtoolsTraceExportV1;
|
|
102
|
+
dispose(): void;
|
|
103
|
+
}
|
|
104
|
+
declare function createDevtoolsStore(options?: DevtoolsStoreOptions): DevtoolsStore;
|
|
105
|
+
|
|
106
|
+
export { type AttachRuntimeOptions, type DeliveryRecordInput, type DevtoolsRecord, type DevtoolsRecordKind, type DevtoolsRuntimeSource, type DevtoolsSnapshot, type DevtoolsStore, type DevtoolsStoreOptions, type DevtoolsTraceExportV1, createDevtoolsStore };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
|
|
3
|
+
if (event.kind === "event-observed") {
|
|
4
|
+
return Object.freeze({
|
|
5
|
+
runtimeId,
|
|
6
|
+
...runtimeSourceId ? { runtimeSourceId } : {},
|
|
7
|
+
sequence: event.sequence,
|
|
8
|
+
captureSequence,
|
|
9
|
+
at: event.at,
|
|
10
|
+
kind: event.kind,
|
|
11
|
+
sourceType: event.event.type,
|
|
12
|
+
...event.event.eventId ? { sourceEventId: event.event.eventId } : {},
|
|
13
|
+
..."responseId" in event.event ? { responseId: event.event.responseId } : {},
|
|
14
|
+
..."responseInstanceId" in event.event && event.event.responseInstanceId ? { responseInstanceId: event.event.responseInstanceId } : {},
|
|
15
|
+
..."nextResponseInstanceId" in event.event && event.event.nextResponseInstanceId ? { nextResponseInstanceId: event.event.nextResponseInstanceId } : {},
|
|
16
|
+
..."attempt" in event.event && event.event.attempt !== void 0 ? { attempt: event.event.attempt } : {},
|
|
17
|
+
..."toolId" in event.event ? { toolId: event.event.toolId } : {},
|
|
18
|
+
..."toolInstanceId" in event.event && event.event.toolInstanceId ? { toolInstanceId: event.event.toolInstanceId } : {},
|
|
19
|
+
..."interactionId" in event.event ? { interactionId: event.event.interactionId } : {},
|
|
20
|
+
..."approvalId" in event.event ? { approvalId: event.event.approvalId } : {},
|
|
21
|
+
..."progress" in event.event && event.event.progress !== void 0 ? { progress: event.event.progress } : {},
|
|
22
|
+
..."outcome" in event.event ? { outcome: event.event.outcome } : {},
|
|
23
|
+
..."count" in event.event ? { count: event.event.count } : {}
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
return Object.freeze({
|
|
27
|
+
runtimeId,
|
|
28
|
+
...runtimeSourceId ? { runtimeSourceId } : {},
|
|
29
|
+
sequence: event.sequence,
|
|
30
|
+
captureSequence,
|
|
31
|
+
at: event.at,
|
|
32
|
+
kind: event.kind,
|
|
33
|
+
...event.decision.sourceType ? { sourceType: event.decision.sourceType } : {},
|
|
34
|
+
...event.decision.sourceEventId ? { sourceEventId: event.decision.sourceEventId } : {},
|
|
35
|
+
disposition: event.decision.disposition,
|
|
36
|
+
reason: event.decision.reason,
|
|
37
|
+
...event.decision.announcement ? { announcementId: event.decision.announcement.id } : {},
|
|
38
|
+
...event.decision.announcement ? { channel: event.decision.announcement.channel } : {},
|
|
39
|
+
...event.decision.responseId ? { responseId: event.decision.responseId } : {},
|
|
40
|
+
...event.decision.toolId ? { toolId: event.decision.toolId } : {},
|
|
41
|
+
...event.decision.interactionId ? { interactionId: event.decision.interactionId } : {},
|
|
42
|
+
...event.decision.scheduledAt !== void 0 ? { scheduledAt: event.decision.scheduledAt } : {},
|
|
43
|
+
...event.decision.dueAt !== void 0 ? { dueAt: event.decision.dueAt } : {},
|
|
44
|
+
...event.decision.delayMs !== void 0 ? { delayMs: event.decision.delayMs } : {},
|
|
45
|
+
...event.decision.queueSequence !== void 0 ? { queueSequence: event.decision.queueSequence } : {}
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function copyRuntimeSource(source) {
|
|
49
|
+
if (source === void 0) return void 0;
|
|
50
|
+
if (typeof source.adapter !== "string" || !source.adapter.trim() || source.adapter.length > 80)
|
|
51
|
+
throw new TypeError("source adapter must be a non-empty string");
|
|
52
|
+
if (!Array.isArray(source.evidence))
|
|
53
|
+
throw new TypeError("source evidence must be an array");
|
|
54
|
+
if (source.evidence.length > 12 || source.evidence.some(
|
|
55
|
+
(item) => typeof item !== "string" || !item.trim() || item.length > 120
|
|
56
|
+
))
|
|
57
|
+
throw new TypeError(
|
|
58
|
+
"source evidence entries must be public strings up to 120 characters"
|
|
59
|
+
);
|
|
60
|
+
const { fidelity } = source;
|
|
61
|
+
if (typeof fidelity !== "object" || fidelity === null)
|
|
62
|
+
throw new TypeError("source fidelity must be an object");
|
|
63
|
+
const lifecycleFidelity = /* @__PURE__ */ new Set(["exact", "action-wrapper", "unavailable"]);
|
|
64
|
+
const connectionFidelity = /* @__PURE__ */ new Set([...lifecycleFidelity, "inferred"]);
|
|
65
|
+
if (!lifecycleFidelity.has(fidelity.interruption))
|
|
66
|
+
throw new TypeError(
|
|
67
|
+
"source interruption fidelity contains an unsupported value"
|
|
68
|
+
);
|
|
69
|
+
if (!lifecycleFidelity.has(fidelity.retries))
|
|
70
|
+
throw new TypeError("source retry fidelity contains an unsupported value");
|
|
71
|
+
if (!connectionFidelity.has(fidelity.connection))
|
|
72
|
+
throw new TypeError(
|
|
73
|
+
"source connection fidelity contains an unsupported value"
|
|
74
|
+
);
|
|
75
|
+
const optionalEvents = fidelity.optionalEvents;
|
|
76
|
+
const validOptionalEvents = /* @__PURE__ */ new Set([
|
|
77
|
+
"tool.progress",
|
|
78
|
+
"tool.failed",
|
|
79
|
+
"citation.available",
|
|
80
|
+
"interaction.requested"
|
|
81
|
+
]);
|
|
82
|
+
if (optionalEvents !== void 0 && (!Array.isArray(optionalEvents) || optionalEvents.some((event) => !validOptionalEvents.has(event))))
|
|
83
|
+
throw new TypeError("source optional events contain an unsupported value");
|
|
84
|
+
return Object.freeze({
|
|
85
|
+
adapter: source.adapter.trim(),
|
|
86
|
+
evidence: Object.freeze(source.evidence.map((item) => item.trim())),
|
|
87
|
+
fidelity: Object.freeze({
|
|
88
|
+
interruption: fidelity.interruption,
|
|
89
|
+
retries: fidelity.retries,
|
|
90
|
+
connection: fidelity.connection,
|
|
91
|
+
...optionalEvents ? { optionalEvents: Object.freeze([...optionalEvents]) } : {}
|
|
92
|
+
})
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function asDeliveryRecord(input, captureSequence, runtimeSourceId) {
|
|
96
|
+
const { result } = input;
|
|
97
|
+
return Object.freeze({
|
|
98
|
+
runtimeId: input.runtimeId,
|
|
99
|
+
...runtimeSourceId ? { runtimeSourceId } : {},
|
|
100
|
+
captureSequence,
|
|
101
|
+
at: result.at,
|
|
102
|
+
kind: "dom-delivery",
|
|
103
|
+
sourceType: result.sourceType,
|
|
104
|
+
announcementId: result.announcementId,
|
|
105
|
+
channel: result.channel,
|
|
106
|
+
deliveryStatus: result.status,
|
|
107
|
+
deliveryMethod: result.method,
|
|
108
|
+
...result.sourceEventId ? { sourceEventId: result.sourceEventId } : {},
|
|
109
|
+
...result.responseId ? { responseId: result.responseId } : {},
|
|
110
|
+
...result.toolId ? { toolId: result.toolId } : {},
|
|
111
|
+
...result.interactionId ? { interactionId: result.interactionId } : {},
|
|
112
|
+
...result.error?.name ? { errorName: result.error.name } : {}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function copyRuntimeSnapshot(source) {
|
|
116
|
+
return Object.freeze({
|
|
117
|
+
schemaVersion: 1,
|
|
118
|
+
at: source.at,
|
|
119
|
+
policy: Object.freeze({
|
|
120
|
+
...source.policy,
|
|
121
|
+
text: Object.freeze({ ...source.policy.text }),
|
|
122
|
+
tools: Object.freeze({ ...source.policy.tools })
|
|
123
|
+
}),
|
|
124
|
+
pending: Object.freeze({
|
|
125
|
+
announcements: Object.freeze(
|
|
126
|
+
source.pending.announcements.map((item) => Object.freeze({ ...item }))
|
|
127
|
+
),
|
|
128
|
+
flushes: Object.freeze(
|
|
129
|
+
source.pending.flushes.map((item) => Object.freeze({ ...item }))
|
|
130
|
+
)
|
|
131
|
+
}),
|
|
132
|
+
responses: Object.freeze(
|
|
133
|
+
source.responses.map((item) => Object.freeze({ ...item }))
|
|
134
|
+
),
|
|
135
|
+
tools: Object.freeze(
|
|
136
|
+
source.tools.map((item) => Object.freeze({ ...item }))
|
|
137
|
+
),
|
|
138
|
+
pendingCount: source.pendingCount
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function createDevtoolsStore(options = {}) {
|
|
142
|
+
const maxEntries = options.maxEntries ?? 250;
|
|
143
|
+
if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0)
|
|
144
|
+
throw new RangeError("maxEntries must be a positive safe integer");
|
|
145
|
+
const records = [];
|
|
146
|
+
const runtimes = /* @__PURE__ */ new Map();
|
|
147
|
+
const runtimeSources = /* @__PURE__ */ new Map();
|
|
148
|
+
const sourceRevisions = /* @__PURE__ */ new Map();
|
|
149
|
+
const runtimeSnapshots = /* @__PURE__ */ new Map();
|
|
150
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
151
|
+
let paused = false;
|
|
152
|
+
let droppedCount = 0;
|
|
153
|
+
let nextCaptureSequence = 0;
|
|
154
|
+
let disposed = false;
|
|
155
|
+
let cachedSnapshot;
|
|
156
|
+
const notify = () => {
|
|
157
|
+
cachedSnapshot = void 0;
|
|
158
|
+
for (const listener of [...listeners]) {
|
|
159
|
+
try {
|
|
160
|
+
listener();
|
|
161
|
+
} catch {
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const snapshot = () => {
|
|
166
|
+
if (cachedSnapshot) return cachedSnapshot;
|
|
167
|
+
const snapshots = Object.freeze(
|
|
168
|
+
Object.fromEntries(
|
|
169
|
+
[...runtimeSnapshots.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([id, value]) => [id, value])
|
|
170
|
+
)
|
|
171
|
+
);
|
|
172
|
+
const sources = Object.freeze(
|
|
173
|
+
Object.fromEntries(
|
|
174
|
+
[...runtimeSources.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([id, source]) => [id, source])
|
|
175
|
+
)
|
|
176
|
+
);
|
|
177
|
+
cachedSnapshot = Object.freeze({
|
|
178
|
+
paused,
|
|
179
|
+
droppedCount,
|
|
180
|
+
records: Object.freeze([...records]),
|
|
181
|
+
runtimeIds: Object.freeze([...runtimes.keys()].sort()),
|
|
182
|
+
runtimeSnapshots: snapshots,
|
|
183
|
+
runtimeSources: sources
|
|
184
|
+
});
|
|
185
|
+
return cachedSnapshot;
|
|
186
|
+
};
|
|
187
|
+
const refreshRuntimeSnapshot = (runtimeId, runtime) => {
|
|
188
|
+
try {
|
|
189
|
+
runtimeSnapshots.set(
|
|
190
|
+
runtimeId,
|
|
191
|
+
copyRuntimeSnapshot(runtime.getDiagnosticSnapshot())
|
|
192
|
+
);
|
|
193
|
+
} catch {
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const refreshAllSnapshots = () => {
|
|
197
|
+
for (const [runtimeId, attachment] of runtimes)
|
|
198
|
+
refreshRuntimeSnapshot(runtimeId, attachment.runtime);
|
|
199
|
+
};
|
|
200
|
+
const appendRecord = (record) => {
|
|
201
|
+
if (records.length === maxEntries) {
|
|
202
|
+
records.shift();
|
|
203
|
+
droppedCount += 1;
|
|
204
|
+
}
|
|
205
|
+
records.push(record);
|
|
206
|
+
};
|
|
207
|
+
const pruneRuntimeSources = () => {
|
|
208
|
+
const retained = new Set(
|
|
209
|
+
records.flatMap(
|
|
210
|
+
(record) => record.runtimeSourceId ? [record.runtimeSourceId] : []
|
|
211
|
+
)
|
|
212
|
+
);
|
|
213
|
+
for (const attachment of runtimes.values())
|
|
214
|
+
if (attachment.sourceId) retained.add(attachment.sourceId);
|
|
215
|
+
for (const sourceId of runtimeSources.keys())
|
|
216
|
+
if (!retained.has(sourceId)) runtimeSources.delete(sourceId);
|
|
217
|
+
};
|
|
218
|
+
const capture = (runtimeId, runtime, runtimeSourceId, event) => {
|
|
219
|
+
if (paused || disposed) return;
|
|
220
|
+
appendRecord(
|
|
221
|
+
asRecord(runtimeId, event, nextCaptureSequence++, runtimeSourceId)
|
|
222
|
+
);
|
|
223
|
+
pruneRuntimeSources();
|
|
224
|
+
refreshRuntimeSnapshot(runtimeId, runtime);
|
|
225
|
+
notify();
|
|
226
|
+
};
|
|
227
|
+
return {
|
|
228
|
+
attachRuntime({ id, runtime, source }) {
|
|
229
|
+
if (disposed)
|
|
230
|
+
throw new Error("Cannot attach to a disposed devtools store");
|
|
231
|
+
if (!id.trim()) throw new TypeError("runtime id must be non-empty");
|
|
232
|
+
const copiedSource = copyRuntimeSource(source);
|
|
233
|
+
let revision = (sourceRevisions.get(id) ?? 0) + 1;
|
|
234
|
+
let sourceId = copiedSource ? revision === 1 ? id : `${id}#${revision}` : void 0;
|
|
235
|
+
while (sourceId && runtimeSources.has(sourceId)) {
|
|
236
|
+
revision += 1;
|
|
237
|
+
sourceId = `${id}#${revision}`;
|
|
238
|
+
}
|
|
239
|
+
let active = false;
|
|
240
|
+
const unsubscribe = runtime.subscribeDiagnosticEvents((event) => {
|
|
241
|
+
if (active) capture(id, runtime, sourceId, event);
|
|
242
|
+
});
|
|
243
|
+
const previous = runtimes.get(id);
|
|
244
|
+
const attachment = {
|
|
245
|
+
runtime,
|
|
246
|
+
unsubscribe,
|
|
247
|
+
source: copiedSource,
|
|
248
|
+
sourceId
|
|
249
|
+
};
|
|
250
|
+
active = true;
|
|
251
|
+
previous?.unsubscribe();
|
|
252
|
+
runtimes.set(id, attachment);
|
|
253
|
+
if (copiedSource && sourceId) {
|
|
254
|
+
runtimeSources.set(sourceId, copiedSource);
|
|
255
|
+
sourceRevisions.set(id, revision);
|
|
256
|
+
}
|
|
257
|
+
refreshRuntimeSnapshot(id, runtime);
|
|
258
|
+
pruneRuntimeSources();
|
|
259
|
+
notify();
|
|
260
|
+
let attached = true;
|
|
261
|
+
return () => {
|
|
262
|
+
if (!attached) return;
|
|
263
|
+
attached = false;
|
|
264
|
+
unsubscribe();
|
|
265
|
+
if (runtimes.get(id) === attachment) {
|
|
266
|
+
runtimes.delete(id);
|
|
267
|
+
runtimeSnapshots.delete(id);
|
|
268
|
+
}
|
|
269
|
+
pruneRuntimeSources();
|
|
270
|
+
notify();
|
|
271
|
+
};
|
|
272
|
+
},
|
|
273
|
+
getSnapshot: snapshot,
|
|
274
|
+
subscribe(listener) {
|
|
275
|
+
if (disposed)
|
|
276
|
+
throw new Error("Cannot subscribe to a disposed devtools store");
|
|
277
|
+
listeners.add(listener);
|
|
278
|
+
return () => listeners.delete(listener);
|
|
279
|
+
},
|
|
280
|
+
pauseCapture() {
|
|
281
|
+
if (disposed || paused) return;
|
|
282
|
+
paused = true;
|
|
283
|
+
notify();
|
|
284
|
+
},
|
|
285
|
+
resumeCapture() {
|
|
286
|
+
if (disposed || !paused) return;
|
|
287
|
+
paused = false;
|
|
288
|
+
notify();
|
|
289
|
+
},
|
|
290
|
+
refreshSnapshots() {
|
|
291
|
+
if (disposed) return;
|
|
292
|
+
refreshAllSnapshots();
|
|
293
|
+
notify();
|
|
294
|
+
},
|
|
295
|
+
recordDelivery(input) {
|
|
296
|
+
if (!input.runtimeId.trim())
|
|
297
|
+
throw new TypeError("delivery runtimeId must be non-empty");
|
|
298
|
+
if (!Number.isFinite(input.result.at))
|
|
299
|
+
throw new TypeError("delivery at must be finite");
|
|
300
|
+
if (paused || disposed) return;
|
|
301
|
+
appendRecord(
|
|
302
|
+
asDeliveryRecord(
|
|
303
|
+
input,
|
|
304
|
+
nextCaptureSequence++,
|
|
305
|
+
runtimes.get(input.runtimeId)?.sourceId
|
|
306
|
+
)
|
|
307
|
+
);
|
|
308
|
+
pruneRuntimeSources();
|
|
309
|
+
notify();
|
|
310
|
+
},
|
|
311
|
+
clear() {
|
|
312
|
+
if (disposed) return;
|
|
313
|
+
records.length = 0;
|
|
314
|
+
droppedCount = 0;
|
|
315
|
+
pruneRuntimeSources();
|
|
316
|
+
notify();
|
|
317
|
+
},
|
|
318
|
+
exportTrace() {
|
|
319
|
+
refreshAllSnapshots();
|
|
320
|
+
notify();
|
|
321
|
+
const current = snapshot();
|
|
322
|
+
return Object.freeze({
|
|
323
|
+
schemaVersion: 1,
|
|
324
|
+
kind: "generative-a11y/devtools-trace",
|
|
325
|
+
paused: current.paused,
|
|
326
|
+
droppedCount: current.droppedCount,
|
|
327
|
+
records: current.records,
|
|
328
|
+
runtimeSnapshots: current.runtimeSnapshots,
|
|
329
|
+
runtimeSources: current.runtimeSources
|
|
330
|
+
});
|
|
331
|
+
},
|
|
332
|
+
dispose() {
|
|
333
|
+
if (disposed) return;
|
|
334
|
+
disposed = true;
|
|
335
|
+
for (const { unsubscribe } of runtimes.values()) unsubscribe();
|
|
336
|
+
runtimes.clear();
|
|
337
|
+
runtimeSnapshots.clear();
|
|
338
|
+
runtimeSources.clear();
|
|
339
|
+
sourceRevisions.clear();
|
|
340
|
+
records.length = 0;
|
|
341
|
+
notify();
|
|
342
|
+
listeners.clear();
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
export {
|
|
347
|
+
createDevtoolsStore
|
|
348
|
+
};
|