codex-chatgpt-control 0.5.1-alpha.2 → 0.5.1-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +43 -0
  3. package/contracts/v1/fixtures/backend-capabilities.json +40 -1
  4. package/contracts/v1/fixtures/backend-compatibility.json +21 -0
  5. package/contracts/v1/fixtures/backend-version.json +6 -1
  6. package/contracts/v1/fixtures/download-blocked-by-browser.json +22 -0
  7. package/contracts/v1/fixtures/download-receipt-failed.json +22 -0
  8. package/contracts/v1/fixtures/download-receipt-timeout.json +22 -0
  9. package/contracts/v1/fixtures/journal-rpc-indeterminate.json +32 -0
  10. package/contracts/v1/fixtures/journal-rpc-unsupported-platform.json +32 -0
  11. package/contracts/v1/fixtures/journal-runtime-unavailable.json +32 -0
  12. package/contracts/v1/fixtures/operation-action-prepared-event.json +42 -0
  13. package/contracts/v1/fixtures/operation-action.json +13 -0
  14. package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
  15. package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
  16. package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
  17. package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
  18. package/contracts/v1/fixtures/operation-blocker.json +10 -0
  19. package/contracts/v1/fixtures/operation-collect-request.json +17 -0
  20. package/contracts/v1/fixtures/operation-collect-result.json +42 -0
  21. package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
  22. package/contracts/v1/fixtures/operation-control-request.json +18 -0
  23. package/contracts/v1/fixtures/operation-control-result.json +31 -0
  24. package/contracts/v1/fixtures/operation-event.json +18 -0
  25. package/contracts/v1/fixtures/operation-handle.json +10 -0
  26. package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
  27. package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
  28. package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
  29. package/contracts/v1/fixtures/operation-receipt.json +32 -0
  30. package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
  31. package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
  32. package/contracts/v1/fixtures/operation-request.json +33 -0
  33. package/contracts/v1/fixtures/operation-state.json +144 -0
  34. package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
  35. package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
  36. package/contracts/v1/fixtures/operation-submit-result.json +16 -0
  37. package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
  38. package/contracts/v1/manifest.json +185 -1
  39. package/contracts/v1/parity-suite.json +106 -8
  40. package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
  41. package/contracts/v1/schemas/backend-request.schema.json +8 -2
  42. package/contracts/v1/schemas/capabilities.schema.json +81 -1
  43. package/contracts/v1/schemas/manifest.schema.json +57 -0
  44. package/contracts/v1/schemas/operation-action.schema.json +155 -0
  45. package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
  46. package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
  47. package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
  48. package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
  49. package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
  50. package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
  51. package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
  52. package/contracts/v1/schemas/operation-event.schema.json +756 -0
  53. package/contracts/v1/schemas/operation-handle.schema.json +55 -0
  54. package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
  55. package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
  56. package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
  57. package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
  58. package/contracts/v1/schemas/operation-request.schema.json +158 -0
  59. package/contracts/v1/schemas/operation-state.schema.json +691 -0
  60. package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
  61. package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
  62. package/contracts/v1/surface-drift-policy.json +50 -0
  63. package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
  64. package/dist/codex-chatgpt-control-backend.mjs +45882 -9361
  65. package/dist/codex-chatgpt-control-journal.mjs +5547 -0
  66. package/dist/codex-chatgpt-control-live-smoke.bundle.mjs +51677 -0
  67. package/dist/codex-chatgpt-control-release-canary.bundle.mjs +52104 -0
  68. package/dist/codex-chatgpt-control.bundle.mjs +48392 -10260
  69. package/dist/src/backend/client.d.ts +103 -2
  70. package/dist/src/backend/client.js +1436 -97
  71. package/dist/src/backend/compatibility.d.ts +12 -0
  72. package/dist/src/backend/compatibility.js +208 -0
  73. package/dist/src/backend/protocol.d.ts +84 -1
  74. package/dist/src/backend/protocol.js +31 -5
  75. package/dist/src/backend/runtime-identity.d.ts +10 -0
  76. package/dist/src/backend/runtime-identity.js +141 -0
  77. package/dist/src/backend/session.d.ts +10 -2
  78. package/dist/src/backend/session.js +478 -7
  79. package/dist/src/backend/stdio-server.d.ts +4 -1
  80. package/dist/src/backend/stdio-server.js +240 -28
  81. package/dist/src/browser/active-composer-file-input.d.ts +9 -0
  82. package/dist/src/browser/active-composer-file-input.js +33 -0
  83. package/dist/src/browser/attach.d.ts +4 -1
  84. package/dist/src/browser/attach.js +136 -28
  85. package/dist/src/browser/chatgpt-url.d.ts +2 -0
  86. package/dist/src/browser/chatgpt-url.js +9 -0
  87. package/dist/src/browser/downloads.d.ts +17 -1
  88. package/dist/src/browser/downloads.js +150 -28
  89. package/dist/src/browser/page-state.js +6 -0
  90. package/dist/src/client.d.ts +43 -0
  91. package/dist/src/client.js +1279 -59
  92. package/dist/src/commands/artifacts.js +6 -4
  93. package/dist/src/commands/chat-popover.d.ts +37 -0
  94. package/dist/src/commands/chat-popover.js +537 -0
  95. package/dist/src/commands/configuration.d.ts +5 -0
  96. package/dist/src/commands/configuration.js +134 -21
  97. package/dist/src/commands/context.js +10 -3
  98. package/dist/src/commands/doctor.d.ts +1 -1
  99. package/dist/src/commands/doctor.js +27 -4
  100. package/dist/src/commands/experience.d.ts +5 -0
  101. package/dist/src/commands/experience.js +104 -21
  102. package/dist/src/commands/files.js +14 -33
  103. package/dist/src/commands/modes.js +85 -21
  104. package/dist/src/commands/power-discovery.d.ts +130 -0
  105. package/dist/src/commands/power-discovery.js +669 -0
  106. package/dist/src/commands/project-sources.js +325 -31
  107. package/dist/src/commands/sequence.js +59 -32
  108. package/dist/src/commands/session.js +19 -6
  109. package/dist/src/commands/work.js +31 -0
  110. package/dist/src/dom/composer-text.d.ts +6 -0
  111. package/dist/src/dom/composer-text.js +85 -0
  112. package/dist/src/errors.d.ts +9 -0
  113. package/dist/src/errors.js +22 -0
  114. package/dist/src/index.d.ts +6 -0
  115. package/dist/src/index.js +9 -0
  116. package/dist/src/operations/artifact-output.d.ts +69 -0
  117. package/dist/src/operations/artifact-output.js +1748 -0
  118. package/dist/src/operations/artifact-stream.d.ts +19 -0
  119. package/dist/src/operations/artifact-stream.js +35 -0
  120. package/dist/src/operations/artifact-transfer.d.ts +149 -0
  121. package/dist/src/operations/artifact-transfer.js +1312 -0
  122. package/dist/src/operations/browser-adapter.d.ts +167 -0
  123. package/dist/src/operations/browser-adapter.js +2103 -0
  124. package/dist/src/operations/browser-observation.d.ts +110 -0
  125. package/dist/src/operations/browser-observation.js +1256 -0
  126. package/dist/src/operations/browser-target.d.ts +105 -0
  127. package/dist/src/operations/browser-target.js +531 -0
  128. package/dist/src/operations/canonical.d.ts +4 -0
  129. package/dist/src/operations/canonical.js +412 -0
  130. package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
  131. package/dist/src/operations/chatgpt-runtime.js +1232 -0
  132. package/dist/src/operations/client.d.ts +138 -0
  133. package/dist/src/operations/client.js +1145 -0
  134. package/dist/src/operations/collector.d.ts +195 -0
  135. package/dist/src/operations/collector.js +1039 -0
  136. package/dist/src/operations/configuration-routing.d.ts +4 -0
  137. package/dist/src/operations/configuration-routing.js +14 -0
  138. package/dist/src/operations/control.d.ts +372 -0
  139. package/dist/src/operations/control.js +1498 -0
  140. package/dist/src/operations/file-identity.d.ts +33 -0
  141. package/dist/src/operations/file-identity.js +153 -0
  142. package/dist/src/operations/handle.d.ts +19 -0
  143. package/dist/src/operations/handle.js +727 -0
  144. package/dist/src/operations/index.d.ts +25 -0
  145. package/dist/src/operations/index.js +25 -0
  146. package/dist/src/operations/journal-authority.d.ts +12 -0
  147. package/dist/src/operations/journal-authority.js +1 -0
  148. package/dist/src/operations/journal-rpc-client.d.ts +12 -0
  149. package/dist/src/operations/journal-rpc-client.js +225 -0
  150. package/dist/src/operations/journal-rpc-protocol.d.ts +32 -0
  151. package/dist/src/operations/journal-rpc-protocol.js +214 -0
  152. package/dist/src/operations/journal-rpc-server.d.ts +15 -0
  153. package/dist/src/operations/journal-rpc-server.js +272 -0
  154. package/dist/src/operations/journal.d.ts +143 -0
  155. package/dist/src/operations/journal.js +1957 -0
  156. package/dist/src/operations/production-attachments.d.ts +118 -0
  157. package/dist/src/operations/production-attachments.js +1035 -0
  158. package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
  159. package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
  160. package/dist/src/operations/production-chatgpt-attachments.d.ts +80 -0
  161. package/dist/src/operations/production-chatgpt-attachments.js +1639 -0
  162. package/dist/src/operations/production-configuration.d.ts +42 -0
  163. package/dist/src/operations/production-configuration.js +1544 -0
  164. package/dist/src/operations/production-primitives.d.ts +53 -0
  165. package/dist/src/operations/production-primitives.js +856 -0
  166. package/dist/src/operations/production-work-steer.d.ts +203 -0
  167. package/dist/src/operations/production-work-steer.js +1218 -0
  168. package/dist/src/operations/recovery.d.ts +80 -0
  169. package/dist/src/operations/recovery.js +174 -0
  170. package/dist/src/operations/runtime-adapter.d.ts +126 -0
  171. package/dist/src/operations/runtime-adapter.js +802 -0
  172. package/dist/src/operations/send-once.d.ts +224 -0
  173. package/dist/src/operations/send-once.js +1081 -0
  174. package/dist/src/operations/service.d.ts +286 -0
  175. package/dist/src/operations/service.js +2831 -0
  176. package/dist/src/operations/staging.d.ts +136 -0
  177. package/dist/src/operations/staging.js +630 -0
  178. package/dist/src/operations/state-machine.d.ts +29 -0
  179. package/dist/src/operations/state-machine.js +2047 -0
  180. package/dist/src/operations/submission.d.ts +423 -0
  181. package/dist/src/operations/submission.js +1676 -0
  182. package/dist/src/operations/transactional-chat-power.d.ts +17 -0
  183. package/dist/src/operations/transactional-chat-power.js +212 -0
  184. package/dist/src/operations/turn-ownership.d.ts +202 -0
  185. package/dist/src/operations/turn-ownership.js +700 -0
  186. package/dist/src/operations/types.d.ts +454 -0
  187. package/dist/src/operations/types.js +20 -0
  188. package/dist/src/operations/wire-requests.d.ts +21 -0
  189. package/dist/src/operations/wire-requests.js +396 -0
  190. package/dist/src/operations/wire-results.d.ts +97 -0
  191. package/dist/src/operations/wire-results.js +818 -0
  192. package/dist/src/runner/responses.d.ts +3 -1
  193. package/dist/src/runner/responses.js +19 -1
  194. package/dist/src/runner/result.js +227 -55
  195. package/dist/src/runner/types.d.ts +12 -0
  196. package/dist/src/runtime/command-routing.d.ts +149 -0
  197. package/dist/src/runtime/command-routing.js +431 -0
  198. package/dist/src/runtime/coordinated-browser.d.ts +24 -0
  199. package/dist/src/runtime/coordinated-browser.js +315 -0
  200. package/dist/src/runtime/coordinated-page.d.ts +41 -0
  201. package/dist/src/runtime/coordinated-page.js +651 -0
  202. package/dist/src/runtime/operation-context.d.ts +142 -0
  203. package/dist/src/runtime/operation-context.js +410 -0
  204. package/dist/src/runtime/runtime-session.d.ts +95 -0
  205. package/dist/src/runtime/runtime-session.js +314 -0
  206. package/dist/src/runtime/tab-coordinator.d.ts +200 -0
  207. package/dist/src/runtime/tab-coordinator.js +1200 -0
  208. package/dist/src/runtime/value-boundaries.d.ts +18 -0
  209. package/dist/src/runtime/value-boundaries.js +49 -0
  210. package/dist/src/safety/blockers.js +8 -1
  211. package/dist/src/safety/untrusted-output.js +2 -1
  212. package/dist/src/scripts/backend-server.js +4 -1
  213. package/dist/src/scripts/capture-surface-profile.js +7 -2
  214. package/dist/src/scripts/journal-server.d.ts +2 -0
  215. package/dist/src/scripts/journal-server.js +37 -0
  216. package/dist/src/scripts/live-smoke/harness.js +79 -7
  217. package/dist/src/scripts/live-smoke/scenarios.d.ts +42 -1
  218. package/dist/src/scripts/live-smoke/scenarios.js +147 -30
  219. package/dist/src/scripts/live-smoke/transactional.d.ts +17 -0
  220. package/dist/src/scripts/live-smoke/transactional.js +254 -0
  221. package/dist/src/scripts/live-smoke/types.d.ts +3 -0
  222. package/dist/src/scripts/release-canary-module.js +17 -4
  223. package/dist/src/types.d.ts +38 -1
  224. package/package.json +8 -3
  225. package/references/2026-08-16-transactional-operations.md +459 -0
  226. package/references/2026-09-06-journal-service.md +140 -0
  227. package/references/agents-runner.md +34 -0
  228. package/references/backend-protocol.md +176 -0
  229. package/references/python-parity.md +137 -0
  230. package/references/responses-adapter.md +19 -0
  231. package/references/streaming.md +6 -0
@@ -0,0 +1,651 @@
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ /**
3
+ * The priority mapping is deliberately public. It makes a call site review
4
+ *able without having to infer scheduler intent from a method name.
5
+ */
6
+ export const COORDINATED_PAGE_PRIORITIES = Object.freeze({
7
+ read: "read",
8
+ mutation: "mutation",
9
+ control: "control"
10
+ });
11
+ const MAX_PROTO_DEPTH = 12;
12
+ const MAX_CAPABILITY_DEPTH = 8;
13
+ const MAX_ARGUMENTS = 16;
14
+ const MAX_CACHED_PAGE_AFFINITIES = 256;
15
+ export class CoordinatedPageError extends Error {
16
+ code = "coordinated_page_invalid";
17
+ constructor(message, options) {
18
+ super(message, options);
19
+ this.name = "CoordinatedPageError";
20
+ }
21
+ }
22
+ const pageWrappers = new WeakMap();
23
+ const rawValues = new WeakMap();
24
+ // waitForEvent has a short actor-held registration lifetime and a potentially
25
+ // long event lifetime outside the actor. Mutation flows need an explicit
26
+ // fence for the former before they click.
27
+ const eventRegistrationBarriers = new WeakMap();
28
+ const mutationGuards = new AsyncLocalStorage();
29
+ /** Carry a short-lived activation guard into already queued locator mutations. */
30
+ export function withCoordinatedMutationGuard(signal, assertActive, run) {
31
+ return mutationGuards.run({ signal, assertActive }, () => {
32
+ assertActive();
33
+ return run();
34
+ });
35
+ }
36
+ /** Return the registration fence for a coordinated waitForEvent promise. */
37
+ export function coordinatedEventRegistrationBarrier(value) {
38
+ return isObjectLike(value) ? eventRegistrationBarriers.get(value) : undefined;
39
+ }
40
+ function isObjectLike(value) {
41
+ return (typeof value === "object" && value !== null) || typeof value === "function";
42
+ }
43
+ function labelForKey(key) {
44
+ try {
45
+ return typeof key === "symbol" ? key.toString() : String(key);
46
+ }
47
+ catch {
48
+ return "unknown";
49
+ }
50
+ }
51
+ function invalid(message, cause) {
52
+ throw new CoordinatedPageError(message, cause === undefined ? undefined : { cause });
53
+ }
54
+ function readDataMember(value, key, label) {
55
+ let current = value;
56
+ for (let depth = 0; current !== null && depth < MAX_PROTO_DEPTH; depth += 1) {
57
+ let descriptor;
58
+ try {
59
+ descriptor = Object.getOwnPropertyDescriptor(current, key);
60
+ }
61
+ catch (error) {
62
+ return invalid(`Cannot inspect ${label}: the provider object rejected a bounded descriptor read`, error);
63
+ }
64
+ if (descriptor !== undefined) {
65
+ if (!("value" in descriptor)) {
66
+ return invalid(`Cannot use ${label}: accessor-backed provider members are not supported`);
67
+ }
68
+ if (current !== value && typeof descriptor.value === "function") {
69
+ // The Codex browser bridge exposes class instances through proxies.
70
+ // Its normal property read returns a receiver-safe bound callable;
71
+ // applying the raw prototype method to the proxy fails private-field
72
+ // brand checks. Only consult the provider binding after proving the
73
+ // member is an inherited data method, never for an accessor.
74
+ try {
75
+ const receiverSafe = Reflect.get(value, key, value);
76
+ if (typeof receiverSafe === "function")
77
+ return receiverSafe;
78
+ }
79
+ catch (error) {
80
+ return invalid(`Cannot use ${label}: provider method binding failed`, error);
81
+ }
82
+ }
83
+ return descriptor.value;
84
+ }
85
+ try {
86
+ const prototype = Object.getPrototypeOf(current);
87
+ current = isObjectLike(prototype) ? prototype : null;
88
+ }
89
+ catch (error) {
90
+ return invalid(`Cannot inspect ${label}: the provider prototype chain is not readable`, error);
91
+ }
92
+ }
93
+ if (current !== null)
94
+ return invalid(`Cannot inspect ${label}: provider prototype depth exceeded`);
95
+ return undefined;
96
+ }
97
+ function requiredCallable(value, key, label) {
98
+ const member = readDataMember(value, key, label);
99
+ if (typeof member !== "function")
100
+ return invalid(`${label} is not available as a callable provider method`);
101
+ return member;
102
+ }
103
+ function optionalCallable(value, key, label) {
104
+ const member = readDataMember(value, key, label);
105
+ if (member === undefined)
106
+ return undefined;
107
+ if (typeof member !== "function")
108
+ return invalid(`${label} is not callable`);
109
+ return member;
110
+ }
111
+ function requiredRecord(value, label) {
112
+ if (!isObjectLike(value))
113
+ return invalid(`${label} must be an object`);
114
+ return value;
115
+ }
116
+ function validateStableOwnerId(value, label) {
117
+ if (typeof value !== "string")
118
+ return invalid(`${label} must be a stable string`);
119
+ const normalized = value.trim();
120
+ if (normalized.length === 0 || normalized.length > 512 || /[\u0000-\u001f\u007f]/u.test(normalized)) {
121
+ return invalid(`${label} must be a non-empty stable string`);
122
+ }
123
+ return normalized;
124
+ }
125
+ function normalizeOwner(value) {
126
+ const owner = requiredRecord(value, "owner");
127
+ const backendSessionId = validateStableOwnerId(readDataMember(owner, "backendSessionId", "owner.backendSessionId"), "owner.backendSessionId");
128
+ const ownerIdValue = readDataMember(owner, "ownerId", "owner.ownerId");
129
+ const operationIdValue = readDataMember(owner, "operationId", "owner.operationId");
130
+ const ownerId = ownerIdValue === undefined ? undefined : validateStableOwnerId(ownerIdValue, "owner.ownerId");
131
+ const operationId = operationIdValue === undefined
132
+ ? undefined
133
+ : validateStableOwnerId(operationIdValue, "owner.operationId");
134
+ return Object.freeze({
135
+ backendSessionId,
136
+ ...(ownerId === undefined ? {} : { ownerId }),
137
+ ...(operationId === undefined ? {} : { operationId })
138
+ });
139
+ }
140
+ function normalizeResource(value) {
141
+ const resource = requiredRecord(value, "resource");
142
+ const kind = readDataMember(resource, "kind", "resource.kind");
143
+ const key = readDataMember(resource, "key", "resource.key");
144
+ if (kind !== "tab" && kind !== "browser")
145
+ return invalid("resource.kind must be tab or browser");
146
+ if (typeof key !== "string" || key.length === 0)
147
+ return invalid("resource.key must be a canonical coordinator key");
148
+ const parts = key.split(":");
149
+ const expectedParts = kind === "tab" ? 4 : 3;
150
+ if (parts.length !== expectedParts || parts[0] !== kind)
151
+ return invalid("resource.key must be a canonical coordinator key");
152
+ for (let index = 1; index < parts.length; index += 1) {
153
+ const encoded = parts[index];
154
+ if (encoded === undefined || encoded.length === 0)
155
+ return invalid("resource.key must be a canonical coordinator key");
156
+ let decoded;
157
+ try {
158
+ decoded = decodeURIComponent(encoded);
159
+ }
160
+ catch (error) {
161
+ return invalid("resource.key must be a canonical coordinator key", error);
162
+ }
163
+ if (encodeURIComponent(decoded) !== encoded)
164
+ return invalid("resource.key must be a canonical coordinator key");
165
+ validateStableOwnerId(decoded, `resource.key part ${index}`);
166
+ if (["unknown", "undefined", "null", "n/a", "na"].includes(decoded.toLowerCase())) {
167
+ return invalid("resource.key must be a canonical coordinator key");
168
+ }
169
+ }
170
+ return Object.freeze({ kind, key });
171
+ }
172
+ function normalizeOptions(value) {
173
+ const options = requiredRecord(value, "coordinated page options");
174
+ const coordinator = readDataMember(options, "coordinator", "options.coordinator");
175
+ if (!isObjectLike(coordinator))
176
+ return invalid("options.coordinator must be a ProcessTabCoordinator");
177
+ if (typeof readDataMember(coordinator, "withTabTransaction", "coordinator.withTabTransaction") !== "function"
178
+ || typeof readDataMember(coordinator, "withBrowserAcquisition", "coordinator.withBrowserAcquisition") !== "function") {
179
+ return invalid("options.coordinator must expose both coordinator transaction methods");
180
+ }
181
+ const resource = normalizeResource(readDataMember(options, "resource", "options.resource"));
182
+ const owner = normalizeOwner(readDataMember(options, "owner", "options.owner"));
183
+ const timeoutValue = readDataMember(options, "defaultTimeoutMs", "options.defaultTimeoutMs");
184
+ if (timeoutValue !== undefined && (!Number.isSafeInteger(timeoutValue) || timeoutValue < 0)) {
185
+ return invalid("options.defaultTimeoutMs must be a non-negative safe integer");
186
+ }
187
+ const defaultTimeoutMs = timeoutValue === undefined ? undefined : timeoutValue;
188
+ return Object.freeze({
189
+ coordinator: coordinator,
190
+ resource,
191
+ owner,
192
+ ...(defaultTimeoutMs === undefined ? {} : { defaultTimeoutMs })
193
+ });
194
+ }
195
+ function safeInvocation(fn, receiver, args) {
196
+ if (args.length > MAX_ARGUMENTS)
197
+ return invalid("Provider invocation argument count exceeded the bounded facade limit");
198
+ try {
199
+ return Reflect.apply(fn, receiver, args);
200
+ }
201
+ catch (error) {
202
+ throw error;
203
+ }
204
+ }
205
+ function absorbRejection(promise) {
206
+ // Keep the original promise for caller-visible error identity while
207
+ // attaching a rejection handler immediately if a caller abandons it.
208
+ void promise.catch(() => undefined);
209
+ return promise;
210
+ }
211
+ function timeoutFromArg(value, label) {
212
+ if (!isObjectLike(value))
213
+ return undefined;
214
+ const timeout = readDataMember(value, "timeoutMs", `${label}.timeoutMs`);
215
+ if (timeout === undefined)
216
+ return undefined;
217
+ if (typeof timeout !== "number" || !Number.isFinite(timeout) || timeout < 0) {
218
+ return invalid(`${label}.timeoutMs must be a non-negative finite number`);
219
+ }
220
+ return timeout;
221
+ }
222
+ function timeoutFromEventOptions(value) {
223
+ // Event settlement is intentionally not governed by this deadline: only
224
+ // provider registration runs under the actor. Reading timeoutMs here is
225
+ // still useful to reject malformed accessor-backed options early without
226
+ // ever holding the actor while the event waits.
227
+ if (!isObjectLike(value))
228
+ return undefined;
229
+ const timeoutMs = readDataMember(value, "timeoutMs", "waitForEvent.options.timeoutMs");
230
+ if (timeoutMs !== undefined && (typeof timeoutMs !== "number" || !Number.isFinite(timeoutMs) || timeoutMs < 0)) {
231
+ return invalid("waitForEvent.options.timeoutMs must be a non-negative finite number");
232
+ }
233
+ const timeout = readDataMember(value, "timeout", "waitForEvent.options.timeout");
234
+ if (timeout !== undefined && (typeof timeout !== "number" || !Number.isFinite(timeout) || timeout < 0)) {
235
+ return invalid("waitForEvent.options.timeout must be a non-negative finite number");
236
+ }
237
+ if (timeoutMs === undefined)
238
+ return timeout;
239
+ if (timeout === undefined)
240
+ return timeoutMs;
241
+ return Math.min(timeoutMs, timeout);
242
+ }
243
+ function isPromiseLike(value) {
244
+ return isObjectLike(value) && typeof readDataMember(value, "then", "provider promise.then") === "function";
245
+ }
246
+ function makeCacheKey(options) {
247
+ const owner = options.owner;
248
+ return [
249
+ options.resource.kind,
250
+ options.resource.key,
251
+ owner.backendSessionId,
252
+ owner.ownerId ?? "",
253
+ owner.operationId ?? "",
254
+ options.defaultTimeoutMs === undefined ? "" : String(options.defaultTimeoutMs)
255
+ ].map(part => encodeURIComponent(part)).join(":");
256
+ }
257
+ function getPageCache(rawPage, coordinator) {
258
+ let byCoordinator = pageWrappers.get(rawPage);
259
+ if (byCoordinator === undefined) {
260
+ byCoordinator = new WeakMap();
261
+ pageWrappers.set(rawPage, byCoordinator);
262
+ }
263
+ let byAffinity = byCoordinator.get(coordinator);
264
+ if (byAffinity === undefined) {
265
+ byAffinity = new Map();
266
+ byCoordinator.set(coordinator, byAffinity);
267
+ }
268
+ return byAffinity;
269
+ }
270
+ function cachePage(cache, affinity, page) {
271
+ cache.delete(affinity);
272
+ cache.set(affinity, new WeakRef(page));
273
+ for (const [key, reference] of cache) {
274
+ if (reference.deref() === undefined)
275
+ cache.delete(key);
276
+ }
277
+ while (cache.size > MAX_CACHED_PAGE_AFFINITIES) {
278
+ const oldest = cache.keys().next().value;
279
+ if (oldest === undefined)
280
+ break;
281
+ cache.delete(oldest);
282
+ }
283
+ }
284
+ function wrapResult(value, state, label, depth = 0) {
285
+ if (depth > MAX_CAPABILITY_DEPTH || !isObjectLike(value))
286
+ return value;
287
+ if (isFileChooserCandidate(value))
288
+ return wrapFileChooser(value, state, label);
289
+ // Capability methods generally return ordinary data (inventories, assets,
290
+ // and receipts), not another provider object. Do not proxy those values:
291
+ // array/string helpers must remain local synchronous operations.
292
+ return value;
293
+ }
294
+ function isFileChooserCandidate(value) {
295
+ return typeof readDataMember(value, "setFiles", "file chooser.setFiles") === "function";
296
+ }
297
+ function assertProxyInterceptable(target, key, label) {
298
+ let descriptor;
299
+ try {
300
+ descriptor = Object.getOwnPropertyDescriptor(target, key);
301
+ }
302
+ catch (error) {
303
+ invalid(`Cannot wrap ${label}: provider object rejected a descriptor read`, error);
304
+ }
305
+ if (descriptor !== undefined && descriptor.configurable === false && "value" in descriptor && descriptor.writable === false) {
306
+ return invalid(`Cannot wrap ${label}: provider method is a non-configurable immutable property`);
307
+ }
308
+ }
309
+ function wrapFileChooser(rawChooser, state, label) {
310
+ const existing = state.fileChooserWrappers.get(rawChooser);
311
+ if (existing !== undefined)
312
+ return existing;
313
+ assertProxyInterceptable(rawChooser, "setFiles", `${label}.setFiles`);
314
+ const wrapper = new Proxy(rawChooser, {
315
+ get(target, property) {
316
+ const propertyLabel = `${label}.${labelForKey(property)}`;
317
+ if (property === "setFiles") {
318
+ const setFiles = requiredCallable(target, property, propertyLabel);
319
+ return (paths, options) => {
320
+ return routeTransaction(state, "mutation", propertyLabel, timeoutFromArg(options, propertyLabel), () => safeInvocation(setFiles, target, [paths, options]));
321
+ };
322
+ }
323
+ if (property === "element") {
324
+ assertProxyInterceptable(target, property, propertyLabel);
325
+ const element = optionalCallable(target, property, propertyLabel);
326
+ if (element === undefined)
327
+ return undefined;
328
+ return () => routeTransaction(state, "read", propertyLabel, undefined, async () => {
329
+ const result = await safeInvocation(element, target, []);
330
+ return wrapLocator(await result, state, propertyLabel);
331
+ });
332
+ }
333
+ if (property === "isMultiple") {
334
+ assertProxyInterceptable(target, property, propertyLabel);
335
+ const isMultiple = optionalCallable(target, property, propertyLabel);
336
+ if (isMultiple === undefined)
337
+ return undefined;
338
+ return () => routeTransaction(state, "read", propertyLabel, undefined, () => safeInvocation(isMultiple, target, []));
339
+ }
340
+ const member = readDataMember(target, property, propertyLabel);
341
+ if (typeof member === "function")
342
+ return member.bind(target);
343
+ return member;
344
+ }
345
+ });
346
+ state.fileChooserWrappers.set(rawChooser, wrapper);
347
+ rawValues.set(wrapper, rawChooser);
348
+ return wrapper;
349
+ }
350
+ function capabilityPriority(name) {
351
+ const lower = name.toLowerCase();
352
+ if (/^(get|list|read|inspect|status|count|query|fetch|metadata|inventory)/u.test(lower))
353
+ return "read";
354
+ if (/^(stop|cancel)/u.test(lower))
355
+ return "control";
356
+ return "mutation";
357
+ }
358
+ function wrapCapability(value, state, label, depth) {
359
+ const existing = state.capabilityWrappers.get(value);
360
+ if (existing !== undefined)
361
+ return existing;
362
+ const wrapper = new Proxy(value, {
363
+ get(target, property) {
364
+ if (property === "then")
365
+ return undefined;
366
+ const propertyLabel = `${label}.${labelForKey(property)}`;
367
+ const member = readDataMember(target, property, propertyLabel);
368
+ if (typeof member !== "function")
369
+ return member;
370
+ if (typeof property === "symbol")
371
+ return member;
372
+ assertProxyInterceptable(target, property, propertyLabel);
373
+ return (...args) => routeTransaction(state, capabilityPriority(labelForKey(property)), propertyLabel, timeoutFromArg(args.at(-1), propertyLabel), async () => wrapResult(await safeInvocation(member, target, args), state, propertyLabel, depth + 1));
374
+ }
375
+ });
376
+ state.capabilityWrappers.set(value, wrapper);
377
+ rawValues.set(wrapper, value);
378
+ return wrapper;
379
+ }
380
+ function wrapLocator(rawLocator, state, label) {
381
+ if (!isObjectLike(rawLocator))
382
+ return invalid(`${label} did not return a locator object`);
383
+ const existing = state.locatorWrappers.get(rawLocator);
384
+ if (existing !== undefined)
385
+ return existing;
386
+ const wrapper = {};
387
+ const locator = rawLocator;
388
+ state.locatorWrappers.set(locator, wrapper);
389
+ rawValues.set(wrapper, locator);
390
+ const sync = (name) => {
391
+ const member = optionalCallable(locator, name, `${label}.${name}`);
392
+ if (member === undefined)
393
+ return;
394
+ wrapper[name] = (...args) => {
395
+ const child = safeInvocation(member, locator, args);
396
+ return wrapLocator(child, state, `${label}.${name}`);
397
+ };
398
+ };
399
+ sync("nth");
400
+ sync("first");
401
+ sync("last");
402
+ sync("locator");
403
+ sync("filter");
404
+ sync("getByRole");
405
+ sync("getByText");
406
+ const transaction = (name, priority, argumentTimeoutIndex) => {
407
+ const member = optionalCallable(locator, name, `${label}.${name}`);
408
+ if (member === undefined)
409
+ return;
410
+ wrapper[name] = (...args) => routeTransaction(state, priority, `${label}.${name}`, argumentTimeoutIndex === undefined ? state.options.defaultTimeoutMs : timeoutFromArg(args[argumentTimeoutIndex], `${label}.${name}`) ?? state.options.defaultTimeoutMs, () => safeInvocation(member, locator, args));
411
+ };
412
+ transaction("click", "mutation", 0);
413
+ transaction("press", "mutation", 1);
414
+ transaction("fill", "mutation", 1);
415
+ transaction("textContent", "read", 0);
416
+ transaction("innerText", "read", 0);
417
+ transaction("innerHTML", "read", 0);
418
+ transaction("count", "read", undefined);
419
+ transaction("allTextContents", "read", 0);
420
+ transaction("isVisible", "read", 0);
421
+ transaction("evaluate", "mutation", 2);
422
+ transaction("setInputFiles", "mutation", 1);
423
+ return wrapper;
424
+ }
425
+ function wrapPlaywright(value, state, label) {
426
+ const existing = state.playwrightWrappers.get(value);
427
+ if (existing !== undefined)
428
+ return existing;
429
+ const wrapper = new Proxy(value, {
430
+ get(target, property) {
431
+ const propertyLabel = `${label}.${labelForKey(property)}`;
432
+ const member = readDataMember(target, property, propertyLabel);
433
+ if (typeof member !== "function")
434
+ return member;
435
+ if (typeof property === "symbol")
436
+ return member;
437
+ if (property === "waitForTimeout") {
438
+ assertProxyInterceptable(target, property, propertyLabel);
439
+ return (milliseconds) => {
440
+ const result = safeInvocation(member, target, [milliseconds]);
441
+ return absorbRejection(Promise.resolve(result));
442
+ };
443
+ }
444
+ assertProxyInterceptable(target, property, propertyLabel);
445
+ return (...args) => routeTransaction(state, "read", propertyLabel, timeoutFromArg(args.at(-1), propertyLabel) ?? state.options.defaultTimeoutMs, async () => wrapResult(await safeInvocation(member, target, args), state, propertyLabel));
446
+ }
447
+ });
448
+ state.playwrightWrappers.set(value, wrapper);
449
+ rawValues.set(wrapper, value);
450
+ return wrapper;
451
+ }
452
+ function routeTransaction(state, priority, label, timeoutMs, callback) {
453
+ const guard = priority === "mutation" ? mutationGuards.getStore() : undefined;
454
+ const requestOptions = {
455
+ owner: state.options.owner,
456
+ priority,
457
+ label,
458
+ ...(timeoutMs === undefined ? {} : { timeoutMs }),
459
+ ...(guard === undefined ? {} : { signal: guard.signal })
460
+ };
461
+ const { coordinator, resource } = state.options;
462
+ const guardedCallback = () => {
463
+ // The guard must run inside the actor: a listener can fail while a
464
+ // different owner holds the tab and this mutation is waiting in its queue.
465
+ guard?.assertActive();
466
+ return callback();
467
+ };
468
+ const pending = resource.kind === "tab"
469
+ ? coordinator.withTabTransaction(resource.key, requestOptions, guardedCallback)
470
+ : coordinator.withBrowserAcquisition(resource.key, requestOptions, guardedCallback);
471
+ return absorbRejection(pending);
472
+ }
473
+ function waitForEvent(state, rawPage, event, optionsOrCallback) {
474
+ const wait = requiredCallable(rawPage, "waitForEvent", "page.waitForEvent");
475
+ const eventTimeoutMs = timeoutFromEventOptions(optionsOrCallback);
476
+ const registrationTimeoutMs = eventTimeoutMs === undefined
477
+ ? state.options.defaultTimeoutMs
478
+ : state.options.defaultTimeoutMs === undefined
479
+ ? eventTimeoutMs
480
+ : Math.min(eventTimeoutMs, state.options.defaultTimeoutMs);
481
+ const registration = routeTransaction(state, "read", "page.waitForEvent.register", registrationTimeoutMs, () => {
482
+ let candidate;
483
+ try {
484
+ candidate = safeInvocation(wait, rawPage, [event, optionsOrCallback]);
485
+ }
486
+ catch (error) {
487
+ throw error;
488
+ }
489
+ const providerPromise = Promise.resolve(candidate);
490
+ const settled = providerPromise.then(value => value, error => { throw error; });
491
+ void settled.catch(() => undefined);
492
+ return { promise: settled };
493
+ });
494
+ const result = registration.then(async ({ promise }) => wrapResult(await promise, state, "page.waitForEvent.result"));
495
+ const handled = absorbRejection(result);
496
+ // Registration failure must also reject the fence so mutation callers never
497
+ // activate after a listener failed to arm. Event data stays on its promise.
498
+ const barrier = registration.then(() => undefined);
499
+ void barrier.catch(() => undefined);
500
+ eventRegistrationBarriers.set(handled, barrier);
501
+ return handled;
502
+ }
503
+ function makeKeyboard(rawKeyboard, state) {
504
+ const press = optionalCallable(rawKeyboard, "press", "page.keyboard.press");
505
+ if (press === undefined)
506
+ return {};
507
+ return {
508
+ press: (key) => routeTransaction(state, "mutation", "page.keyboard.press", state.options.defaultTimeoutMs, () => safeInvocation(press, rawKeyboard, [key]))
509
+ };
510
+ }
511
+ function makeMouse(rawMouse, state) {
512
+ const move = optionalCallable(rawMouse, "move", "page.mouse.move");
513
+ const click = optionalCallable(rawMouse, "click", "page.mouse.click");
514
+ return {
515
+ ...(move === undefined ? {} : {
516
+ move: (x, y) => routeTransaction(state, "mutation", "page.mouse.move", state.options.defaultTimeoutMs, () => safeInvocation(move, rawMouse, [x, y]))
517
+ }),
518
+ ...(click === undefined ? {} : {
519
+ click: (x, y) => routeTransaction(state, "mutation", "page.mouse.click", state.options.defaultTimeoutMs, () => safeInvocation(click, rawMouse, [x, y]))
520
+ })
521
+ };
522
+ }
523
+ function makeCua(rawCua, state) {
524
+ const move = optionalCallable(rawCua, "move", "page.cua.move");
525
+ const click = optionalCallable(rawCua, "click", "page.cua.click");
526
+ const keypress = optionalCallable(rawCua, "keypress", "page.cua.keypress");
527
+ return {
528
+ ...(move === undefined ? {} : {
529
+ move: (options) => routeTransaction(state, "mutation", "page.cua.move", state.options.defaultTimeoutMs, () => safeInvocation(move, rawCua, [options]))
530
+ }),
531
+ ...(click === undefined ? {} : {
532
+ click: (options) => routeTransaction(state, "mutation", "page.cua.click", state.options.defaultTimeoutMs, () => safeInvocation(click, rawCua, [options]))
533
+ }),
534
+ ...(keypress === undefined ? {} : {
535
+ keypress: (options) => routeTransaction(state, "mutation", "page.cua.keypress", state.options.defaultTimeoutMs, () => safeInvocation(keypress, rawCua, [options]))
536
+ })
537
+ };
538
+ }
539
+ function makeCapabilities(rawCapabilities, state) {
540
+ const get = optionalCallable(rawCapabilities, "get", "page.capabilities.get");
541
+ if (get === undefined)
542
+ return {};
543
+ return {
544
+ get: (id) => routeTransaction(state, "read", "page.capabilities.get", state.options.defaultTimeoutMs, async () => {
545
+ const value = await safeInvocation(get, rawCapabilities, [id]);
546
+ return isObjectLike(value) ? wrapCapability(value, state, "page.capabilities.result", 0) : value;
547
+ })
548
+ };
549
+ }
550
+ function buildPage(state) {
551
+ const rawPage = state.rawPage;
552
+ const wrapper = {};
553
+ rawValues.set(wrapper, rawPage);
554
+ for (const property of ["id", "tabId"]) {
555
+ const value = readDataMember(rawPage, property, `page.${property}`);
556
+ if (value !== undefined)
557
+ wrapper[property] = value;
558
+ }
559
+ const locator = optionalCallable(rawPage, "locator", "page.locator");
560
+ if (locator !== undefined)
561
+ wrapper.locator = (selector) => wrapLocator(safeInvocation(locator, rawPage, [selector]), state, "page.locator");
562
+ const getByRole = optionalCallable(rawPage, "getByRole", "page.getByRole");
563
+ if (getByRole !== undefined)
564
+ wrapper.getByRole = (role, options) => wrapLocator(safeInvocation(getByRole, rawPage, [role, options]), state, "page.getByRole");
565
+ const getByPlaceholder = optionalCallable(rawPage, "getByPlaceholder", "page.getByPlaceholder");
566
+ if (getByPlaceholder !== undefined)
567
+ wrapper.getByPlaceholder = (text, options) => wrapLocator(safeInvocation(getByPlaceholder, rawPage, [text, options]), state, "page.getByPlaceholder");
568
+ const getByText = optionalCallable(rawPage, "getByText", "page.getByText");
569
+ if (getByText !== undefined)
570
+ wrapper.getByText = (text, options) => wrapLocator(safeInvocation(getByText, rawPage, [text, options]), state, "page.getByText");
571
+ const url = optionalCallable(rawPage, "url", "page.url");
572
+ if (url !== undefined)
573
+ wrapper.url = () => routeTransaction(state, "read", "page.url", state.options.defaultTimeoutMs, () => safeInvocation(url, rawPage, []));
574
+ const title = optionalCallable(rawPage, "title", "page.title");
575
+ if (title !== undefined)
576
+ wrapper.title = () => routeTransaction(state, "read", "page.title", state.options.defaultTimeoutMs, () => safeInvocation(title, rawPage, []));
577
+ const goto = optionalCallable(rawPage, "goto", "page.goto");
578
+ if (goto !== undefined)
579
+ wrapper.goto = (urlValue, options) => routeTransaction(state, "mutation", "page.goto", timeoutFromArg(options, "page.goto") ?? state.options.defaultTimeoutMs, () => safeInvocation(goto, rawPage, [urlValue, options]));
580
+ const evaluate = optionalCallable(rawPage, "evaluate", "page.evaluate");
581
+ if (evaluate !== undefined)
582
+ wrapper.evaluate = (fn, arg, options) => routeTransaction(state, "mutation", "page.evaluate", timeoutFromArg(options, "page.evaluate") ?? state.options.defaultTimeoutMs, () => safeInvocation(evaluate, rawPage, [fn, arg, options]));
583
+ const content = optionalCallable(rawPage, "content", "page.content");
584
+ if (content !== undefined)
585
+ wrapper.content = (options) => routeTransaction(state, "read", "page.content", timeoutFromArg(options, "page.content") ?? state.options.defaultTimeoutMs, () => safeInvocation(content, rawPage, [options]));
586
+ const close = optionalCallable(rawPage, "close", "page.close");
587
+ if (close !== undefined)
588
+ wrapper.close = () => routeTransaction(state, "mutation", "page.close", state.options.defaultTimeoutMs, () => safeInvocation(close, rawPage, []));
589
+ const waitForTimeout = optionalCallable(rawPage, "waitForTimeout", "page.waitForTimeout");
590
+ if (waitForTimeout !== undefined)
591
+ wrapper.waitForTimeout = (milliseconds) => {
592
+ const result = safeInvocation(waitForTimeout, rawPage, [milliseconds]);
593
+ return absorbRejection(Promise.resolve(result));
594
+ };
595
+ const waitForEventMethod = optionalCallable(rawPage, "waitForEvent", "page.waitForEvent");
596
+ if (waitForEventMethod !== undefined)
597
+ wrapper.waitForEvent = (event, optionsOrCallback) => waitForEvent(state, rawPage, event, optionsOrCallback);
598
+ const keyboard = readDataMember(rawPage, "keyboard", "page.keyboard");
599
+ if (keyboard !== undefined)
600
+ wrapper.keyboard = makeKeyboard(requiredRecord(keyboard, "page.keyboard"), state);
601
+ const mouse = readDataMember(rawPage, "mouse", "page.mouse");
602
+ if (mouse !== undefined)
603
+ wrapper.mouse = makeMouse(requiredRecord(mouse, "page.mouse"), state);
604
+ const cua = readDataMember(rawPage, "cua", "page.cua");
605
+ if (cua !== undefined)
606
+ wrapper.cua = makeCua(requiredRecord(cua, "page.cua"), state);
607
+ const capabilities = readDataMember(rawPage, "capabilities", "page.capabilities");
608
+ if (capabilities !== undefined)
609
+ wrapper.capabilities = makeCapabilities(requiredRecord(capabilities, "page.capabilities"), state);
610
+ const playwright = readDataMember(rawPage, "playwright", "page.playwright");
611
+ if (playwright !== undefined)
612
+ wrapper.playwright = wrapPlaywright(requiredRecord(playwright, "page.playwright"), state, "page.playwright");
613
+ return wrapper;
614
+ }
615
+ /**
616
+ * Wrap one provider page. The raw page is never enumerated or copied; only
617
+ * the documented PageLike members are read through bounded data descriptors.
618
+ * Locator construction remains synchronous, while each locator action is a
619
+ * separate short coordinator transaction.
620
+ */
621
+ export function createCoordinatedPage(page, options) {
622
+ if (!isObjectLike(page))
623
+ return invalid("page must be a provider PageLike object");
624
+ const normalized = normalizeOptions(options);
625
+ const cache = getPageCache(page, normalized.coordinator);
626
+ const affinity = makeCacheKey(normalized);
627
+ const existing = cache.get(affinity)?.deref();
628
+ if (existing !== undefined) {
629
+ cachePage(cache, affinity, existing);
630
+ return existing;
631
+ }
632
+ cache.delete(affinity);
633
+ const state = {
634
+ rawPage: page,
635
+ options: normalized,
636
+ locatorWrappers: new WeakMap(),
637
+ capabilityWrappers: new WeakMap(),
638
+ fileChooserWrappers: new WeakMap(),
639
+ playwrightWrappers: new WeakMap()
640
+ };
641
+ const wrapper = buildPage(state);
642
+ cachePage(cache, affinity, wrapper);
643
+ rawValues.set(wrapper, page);
644
+ return wrapper;
645
+ }
646
+ /** Explicit identity seam for integrations that need the underlying provider page. */
647
+ export function unwrapCoordinatedPage(page) {
648
+ if (!isObjectLike(page))
649
+ return page;
650
+ return rawValues.get(page) ?? page;
651
+ }