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

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 (191) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +27 -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/operation-action-prepared-event.json +42 -0
  7. package/contracts/v1/fixtures/operation-action.json +13 -0
  8. package/contracts/v1/fixtures/operation-artifact-receipt.json +14 -0
  9. package/contracts/v1/fixtures/operation-artifact-transfer-intent-event.json +24 -0
  10. package/contracts/v1/fixtures/operation-artifact-transfer-receipt-event.json +26 -0
  11. package/contracts/v1/fixtures/operation-artifact-transfer-state.json +178 -0
  12. package/contracts/v1/fixtures/operation-blocker.json +10 -0
  13. package/contracts/v1/fixtures/operation-collect-request.json +17 -0
  14. package/contracts/v1/fixtures/operation-collect-result.json +42 -0
  15. package/contracts/v1/fixtures/operation-control-receipt.json +13 -0
  16. package/contracts/v1/fixtures/operation-control-request.json +18 -0
  17. package/contracts/v1/fixtures/operation-control-result.json +31 -0
  18. package/contracts/v1/fixtures/operation-event.json +18 -0
  19. package/contracts/v1/fixtures/operation-handle.json +10 -0
  20. package/contracts/v1/fixtures/operation-inspect-request.json +13 -0
  21. package/contracts/v1/fixtures/operation-inspect-result.json +205 -0
  22. package/contracts/v1/fixtures/operation-ownership-baseline-event.json +34 -0
  23. package/contracts/v1/fixtures/operation-receipt.json +32 -0
  24. package/contracts/v1/fixtures/operation-recovery-decision.json +7 -0
  25. package/contracts/v1/fixtures/operation-recovery-observation.json +12 -0
  26. package/contracts/v1/fixtures/operation-request.json +33 -0
  27. package/contracts/v1/fixtures/operation-state.json +144 -0
  28. package/contracts/v1/fixtures/operation-submission-witness-event.json +20 -0
  29. package/contracts/v1/fixtures/operation-submission-witness.json +11 -0
  30. package/contracts/v1/fixtures/operation-submit-result.json +16 -0
  31. package/contracts/v1/fixtures/operation-target-established-event.json +21 -0
  32. package/contracts/v1/manifest.json +155 -1
  33. package/contracts/v1/parity-suite.json +96 -1
  34. package/contracts/v1/schemas/backend-compatibility.schema.json +65 -0
  35. package/contracts/v1/schemas/backend-request.schema.json +8 -2
  36. package/contracts/v1/schemas/capabilities.schema.json +81 -1
  37. package/contracts/v1/schemas/manifest.schema.json +57 -0
  38. package/contracts/v1/schemas/operation-action.schema.json +155 -0
  39. package/contracts/v1/schemas/operation-artifact-receipt.schema.json +89 -0
  40. package/contracts/v1/schemas/operation-blocker.schema.json +70 -0
  41. package/contracts/v1/schemas/operation-collect-request.schema.json +46 -0
  42. package/contracts/v1/schemas/operation-collect-result.schema.json +74 -0
  43. package/contracts/v1/schemas/operation-control-receipt.schema.json +108 -0
  44. package/contracts/v1/schemas/operation-control-request.schema.json +111 -0
  45. package/contracts/v1/schemas/operation-control-result.schema.json +112 -0
  46. package/contracts/v1/schemas/operation-event.schema.json +756 -0
  47. package/contracts/v1/schemas/operation-handle.schema.json +55 -0
  48. package/contracts/v1/schemas/operation-inspect-request.schema.json +42 -0
  49. package/contracts/v1/schemas/operation-inspect-result.schema.json +1662 -0
  50. package/contracts/v1/schemas/operation-receipt.schema.json +153 -0
  51. package/contracts/v1/schemas/operation-recovery.schema.json +314 -0
  52. package/contracts/v1/schemas/operation-request.schema.json +158 -0
  53. package/contracts/v1/schemas/operation-state.schema.json +691 -0
  54. package/contracts/v1/schemas/operation-submission-witness.schema.json +48 -0
  55. package/contracts/v1/schemas/operation-submit-result.schema.json +94 -0
  56. package/contracts/v1/surface-drift-policy.json +50 -0
  57. package/contracts/v1/vectors/operation-request-digest-v1.json +43 -0
  58. package/dist/codex-chatgpt-control-backend.mjs +43897 -9094
  59. package/dist/codex-chatgpt-control.bundle.mjs +46360 -10262
  60. package/dist/src/backend/client.d.ts +103 -2
  61. package/dist/src/backend/client.js +1436 -97
  62. package/dist/src/backend/compatibility.d.ts +12 -0
  63. package/dist/src/backend/compatibility.js +208 -0
  64. package/dist/src/backend/protocol.d.ts +84 -1
  65. package/dist/src/backend/protocol.js +31 -5
  66. package/dist/src/backend/runtime-identity.d.ts +10 -0
  67. package/dist/src/backend/runtime-identity.js +141 -0
  68. package/dist/src/backend/session.d.ts +10 -2
  69. package/dist/src/backend/session.js +478 -7
  70. package/dist/src/backend/stdio-server.d.ts +4 -1
  71. package/dist/src/backend/stdio-server.js +240 -28
  72. package/dist/src/browser/active-composer-file-input.d.ts +9 -0
  73. package/dist/src/browser/active-composer-file-input.js +33 -0
  74. package/dist/src/browser/attach.d.ts +4 -1
  75. package/dist/src/browser/attach.js +136 -28
  76. package/dist/src/browser/downloads.d.ts +2 -0
  77. package/dist/src/client.d.ts +38 -0
  78. package/dist/src/client.js +1222 -59
  79. package/dist/src/commands/configuration.js +13 -7
  80. package/dist/src/commands/doctor.d.ts +1 -1
  81. package/dist/src/commands/doctor.js +26 -3
  82. package/dist/src/commands/experience.js +35 -0
  83. package/dist/src/commands/files.js +4 -27
  84. package/dist/src/commands/modes.js +49 -17
  85. package/dist/src/commands/power-discovery.d.ts +130 -0
  86. package/dist/src/commands/power-discovery.js +627 -0
  87. package/dist/src/commands/project-sources.js +325 -31
  88. package/dist/src/commands/sequence.js +59 -32
  89. package/dist/src/commands/session.js +7 -2
  90. package/dist/src/commands/work.js +31 -0
  91. package/dist/src/errors.d.ts +9 -0
  92. package/dist/src/errors.js +22 -0
  93. package/dist/src/index.d.ts +6 -0
  94. package/dist/src/index.js +9 -0
  95. package/dist/src/operations/artifact-output.d.ts +69 -0
  96. package/dist/src/operations/artifact-output.js +1748 -0
  97. package/dist/src/operations/artifact-stream.d.ts +19 -0
  98. package/dist/src/operations/artifact-stream.js +35 -0
  99. package/dist/src/operations/artifact-transfer.d.ts +149 -0
  100. package/dist/src/operations/artifact-transfer.js +1312 -0
  101. package/dist/src/operations/browser-adapter.d.ts +161 -0
  102. package/dist/src/operations/browser-adapter.js +2023 -0
  103. package/dist/src/operations/browser-observation.d.ts +110 -0
  104. package/dist/src/operations/browser-observation.js +1208 -0
  105. package/dist/src/operations/browser-target.d.ts +103 -0
  106. package/dist/src/operations/browser-target.js +489 -0
  107. package/dist/src/operations/canonical.d.ts +4 -0
  108. package/dist/src/operations/canonical.js +412 -0
  109. package/dist/src/operations/chatgpt-runtime.d.ts +72 -0
  110. package/dist/src/operations/chatgpt-runtime.js +1150 -0
  111. package/dist/src/operations/client.d.ts +138 -0
  112. package/dist/src/operations/client.js +1143 -0
  113. package/dist/src/operations/collector.d.ts +195 -0
  114. package/dist/src/operations/collector.js +1039 -0
  115. package/dist/src/operations/control.d.ts +372 -0
  116. package/dist/src/operations/control.js +1498 -0
  117. package/dist/src/operations/file-identity.d.ts +33 -0
  118. package/dist/src/operations/file-identity.js +153 -0
  119. package/dist/src/operations/handle.d.ts +19 -0
  120. package/dist/src/operations/handle.js +727 -0
  121. package/dist/src/operations/index.d.ts +22 -0
  122. package/dist/src/operations/index.js +22 -0
  123. package/dist/src/operations/journal.d.ts +142 -0
  124. package/dist/src/operations/journal.js +1931 -0
  125. package/dist/src/operations/production-attachments.d.ts +116 -0
  126. package/dist/src/operations/production-attachments.js +1018 -0
  127. package/dist/src/operations/production-chatgpt-artifacts.d.ts +74 -0
  128. package/dist/src/operations/production-chatgpt-artifacts.js +1146 -0
  129. package/dist/src/operations/production-chatgpt-attachments.d.ts +71 -0
  130. package/dist/src/operations/production-chatgpt-attachments.js +1563 -0
  131. package/dist/src/operations/production-configuration.d.ts +42 -0
  132. package/dist/src/operations/production-configuration.js +1363 -0
  133. package/dist/src/operations/production-primitives.d.ts +53 -0
  134. package/dist/src/operations/production-primitives.js +1073 -0
  135. package/dist/src/operations/production-work-steer.d.ts +203 -0
  136. package/dist/src/operations/production-work-steer.js +1218 -0
  137. package/dist/src/operations/recovery.d.ts +80 -0
  138. package/dist/src/operations/recovery.js +174 -0
  139. package/dist/src/operations/runtime-adapter.d.ts +118 -0
  140. package/dist/src/operations/runtime-adapter.js +786 -0
  141. package/dist/src/operations/send-once.d.ts +224 -0
  142. package/dist/src/operations/send-once.js +1081 -0
  143. package/dist/src/operations/service.d.ts +281 -0
  144. package/dist/src/operations/service.js +2810 -0
  145. package/dist/src/operations/staging.d.ts +136 -0
  146. package/dist/src/operations/staging.js +630 -0
  147. package/dist/src/operations/state-machine.d.ts +29 -0
  148. package/dist/src/operations/state-machine.js +2047 -0
  149. package/dist/src/operations/submission.d.ts +423 -0
  150. package/dist/src/operations/submission.js +1676 -0
  151. package/dist/src/operations/turn-ownership.d.ts +202 -0
  152. package/dist/src/operations/turn-ownership.js +700 -0
  153. package/dist/src/operations/types.d.ts +454 -0
  154. package/dist/src/operations/types.js +20 -0
  155. package/dist/src/operations/wire-requests.d.ts +21 -0
  156. package/dist/src/operations/wire-requests.js +396 -0
  157. package/dist/src/operations/wire-results.d.ts +97 -0
  158. package/dist/src/operations/wire-results.js +818 -0
  159. package/dist/src/runner/responses.d.ts +3 -1
  160. package/dist/src/runner/responses.js +19 -1
  161. package/dist/src/runner/result.js +227 -55
  162. package/dist/src/runner/types.d.ts +12 -0
  163. package/dist/src/runtime/command-routing.d.ts +149 -0
  164. package/dist/src/runtime/command-routing.js +431 -0
  165. package/dist/src/runtime/coordinated-browser.d.ts +24 -0
  166. package/dist/src/runtime/coordinated-browser.js +315 -0
  167. package/dist/src/runtime/coordinated-page.d.ts +39 -0
  168. package/dist/src/runtime/coordinated-page.js +634 -0
  169. package/dist/src/runtime/operation-context.d.ts +142 -0
  170. package/dist/src/runtime/operation-context.js +410 -0
  171. package/dist/src/runtime/runtime-session.d.ts +95 -0
  172. package/dist/src/runtime/runtime-session.js +314 -0
  173. package/dist/src/runtime/tab-coordinator.d.ts +200 -0
  174. package/dist/src/runtime/tab-coordinator.js +1200 -0
  175. package/dist/src/runtime/value-boundaries.d.ts +18 -0
  176. package/dist/src/runtime/value-boundaries.js +49 -0
  177. package/dist/src/safety/untrusted-output.js +2 -1
  178. package/dist/src/scripts/backend-server.js +4 -1
  179. package/dist/src/scripts/live-smoke/harness.js +79 -7
  180. package/dist/src/scripts/live-smoke/scenarios.d.ts +28 -0
  181. package/dist/src/scripts/live-smoke/scenarios.js +110 -18
  182. package/dist/src/scripts/live-smoke/types.d.ts +3 -0
  183. package/dist/src/scripts/release-canary-module.js +17 -4
  184. package/dist/src/types.d.ts +38 -1
  185. package/package.json +1 -1
  186. package/references/2026-08-16-transactional-operations.md +459 -0
  187. package/references/agents-runner.md +34 -0
  188. package/references/backend-protocol.md +73 -0
  189. package/references/python-parity.md +72 -0
  190. package/references/responses-adapter.md +19 -0
  191. package/references/streaming.md +6 -0
@@ -0,0 +1,412 @@
1
+ import { createHmac } from "node:crypto";
2
+ const DIGEST_PREFIX = "hmac-sha256:";
3
+ // Canonicalization is used on durable, authenticated material. Keep the
4
+ // limits deliberately generous for normal operation records, but make a
5
+ // caller/provider supplied graph incapable of consuming unbounded memory.
6
+ const MAX_CANONICAL_DEPTH = 32;
7
+ const MAX_CANONICAL_NODES = 100_000;
8
+ const MAX_CANONICAL_PROPERTIES = 32_768;
9
+ const MAX_CANONICAL_ARRAY_LENGTH = 32_768;
10
+ const MAX_CANONICAL_BYTES = 16 * 1024 * 1024;
11
+ const MAX_CANONICAL_KEY_BYTES = 4096;
12
+ const SAFE_CANONICAL_ERROR = "Canonical JSON input could not be inspected safely.";
13
+ const RESERVED_CANONICAL_KEYS = new Set(["$undefined", "$date", "$bytes"]);
14
+ const TYPED_ARRAY_PROTOTYPE = Object.getPrototypeOf(Uint8Array.prototype);
15
+ const TYPED_ARRAY_BYTE_LENGTH_GETTER = Object.getOwnPropertyDescriptor(TYPED_ARRAY_PROTOTYPE, "byteLength")?.get;
16
+ export function canonicalJson(value) {
17
+ const budget = { nodes: 0, properties: 0, bytes: 0 };
18
+ const canonical = canonicalValue(value, new WeakSet(), budget, 0);
19
+ let encoded;
20
+ try {
21
+ encoded = JSON.stringify(canonical);
22
+ }
23
+ catch {
24
+ throw new TypeError(SAFE_CANONICAL_ERROR);
25
+ }
26
+ if (typeof encoded !== "string")
27
+ throw new TypeError(SAFE_CANONICAL_ERROR);
28
+ if (Buffer.byteLength(encoded, "utf8") > MAX_CANONICAL_BYTES) {
29
+ throw new TypeError("Canonical JSON exceeds the bounded byte limit.");
30
+ }
31
+ return encoded;
32
+ }
33
+ export function hmacDigest(key, domain, value) {
34
+ const hmac = createHmac("sha256", key);
35
+ hmac.update(`${domain}\0`, "utf8");
36
+ hmac.update(canonicalJson(value), "utf8");
37
+ return `${DIGEST_PREFIX}${hmac.digest("hex")}`;
38
+ }
39
+ export function operationRequestDigest(key, input) {
40
+ const inputValues = safeRecordValues(input, [
41
+ "operationId", "surface", "target", "prompt", "configuration", "tools", "files", "capturePolicy", "behavior"
42
+ ]);
43
+ const operationId = inputValues.get("operationId");
44
+ const surface = inputValues.get("surface");
45
+ const target = inputValues.get("target");
46
+ const prompt = inputValues.get("prompt");
47
+ const configuration = inputValues.get("configuration");
48
+ const tools = inputValues.get("tools");
49
+ const files = inputValues.get("files");
50
+ const capturePolicy = inputValues.get("capturePolicy");
51
+ const behavior = inputValues.get("behavior");
52
+ if (typeof prompt !== "string")
53
+ throw new TypeError(SAFE_CANONICAL_ERROR);
54
+ const fileProjection = [];
55
+ if (files !== undefined) {
56
+ for (const file of safeArrayElements(files)) {
57
+ fileProjection.push(canonicalFileProjection(key, file));
58
+ }
59
+ }
60
+ return hmacDigest(key, "codex-chatgpt-control/operation-request/v1", {
61
+ schemaVersion: "chatgpt.browser_control.operation_request_identity.v1",
62
+ operationId,
63
+ surface,
64
+ target,
65
+ prompt: {
66
+ digest: hmacDigest(key, "codex-chatgpt-control/prompt/v1", prompt),
67
+ bytes: Buffer.byteLength(prompt, "utf8")
68
+ },
69
+ configuration,
70
+ tools,
71
+ files: fileProjection,
72
+ // Capture format is part of the immutable request identity. Older
73
+ // request records omitted it, so canonicalize an omitted/undefined value
74
+ // to the historical default instead of allowing an equivalent request to
75
+ // hash differently after a restart.
76
+ capturePolicy: canonicalCapturePolicy(capturePolicy),
77
+ behavior
78
+ });
79
+ }
80
+ function canonicalFileProjection(key, value) {
81
+ const values = safeRecordValues(value, ["displayName", "bytes", "contentSha256"]);
82
+ const displayName = values.get("displayName");
83
+ const bytes = values.get("bytes");
84
+ const contentSha256 = values.get("contentSha256");
85
+ if (typeof displayName !== "string"
86
+ || !Number.isSafeInteger(bytes)
87
+ || typeof contentSha256 !== "string") {
88
+ throw new TypeError(SAFE_CANONICAL_ERROR);
89
+ }
90
+ const byteCount = bytes;
91
+ return {
92
+ displayNameDigest: hmacDigest(key, "codex-chatgpt-control/file-display-name/v1", displayName.normalize("NFC")),
93
+ bytes: byteCount,
94
+ contentDigest: hmacDigest(key, "codex-chatgpt-control/file-content-sha256/v1", contentSha256.toLowerCase())
95
+ };
96
+ }
97
+ function canonicalCapturePolicy(value) {
98
+ if (value === undefined) {
99
+ return {
100
+ responseContent: "include",
101
+ responseFormat: "markdown",
102
+ artifacts: "receipt_only"
103
+ };
104
+ }
105
+ const values = safeRecordValues(value, ["responseContent", "responseFormat", "artifacts", "outputDirectory"]);
106
+ // Request-local destination authority is deliberately excluded from durable
107
+ // operation identity. A transfer action binds its exact destination with
108
+ // a separate keyed identity and receipt; retaining an absolute path here
109
+ // would also make the same durable transfer obligation depend on
110
+ // process-local spelling. Project only the closed, path-free capture
111
+ // contract and expand every historical default so omitted and explicit
112
+ // defaults hash identically.
113
+ return {
114
+ responseContent: values.get("responseContent") ?? "include",
115
+ responseFormat: values.get("responseFormat") ?? "markdown",
116
+ artifacts: values.get("artifacts") ?? "receipt_only"
117
+ };
118
+ }
119
+ function canonicalValue(value, ancestors, budget, depth) {
120
+ consumeNode(budget, depth);
121
+ if (value === undefined)
122
+ return { $undefined: true };
123
+ if (value === null || typeof value === "boolean")
124
+ return value;
125
+ if (typeof value === "string") {
126
+ consumeBytes(budget, value);
127
+ return value;
128
+ }
129
+ if (typeof value === "number") {
130
+ if (!Number.isFinite(value)) {
131
+ throw new TypeError("Canonical JSON does not support non-finite numbers.");
132
+ }
133
+ return Object.is(value, -0) ? 0 : value;
134
+ }
135
+ if (typeof value === "bigint" || typeof value === "function" || typeof value === "symbol") {
136
+ throw new TypeError(`Canonical JSON does not support ${typeof value} values.`);
137
+ }
138
+ if (typeof value !== "object")
139
+ throw new TypeError(SAFE_CANONICAL_ERROR);
140
+ const object = value;
141
+ if (ancestors.has(object)) {
142
+ throw new TypeError("Canonical JSON does not support cyclic values.");
143
+ }
144
+ ancestors.add(object);
145
+ try {
146
+ const prototype = safeGetPrototype(object);
147
+ let isArray = false;
148
+ try {
149
+ isArray = Array.isArray(object);
150
+ }
151
+ catch {
152
+ throw new TypeError(SAFE_CANONICAL_ERROR);
153
+ }
154
+ if (isArray) {
155
+ if (prototype !== Array.prototype)
156
+ throw new TypeError("Canonical JSON supports only standard arrays.");
157
+ return canonicalArray(object, ancestors, budget, depth);
158
+ }
159
+ if (prototype === Date.prototype)
160
+ return canonicalDate(object, budget);
161
+ if (prototype === Uint8Array.prototype)
162
+ return canonicalBytes(object, budget);
163
+ if (prototype !== Object.prototype && prototype !== null) {
164
+ throw new TypeError("Canonical JSON supports only plain objects, arrays, dates, and byte arrays.");
165
+ }
166
+ return canonicalObject(object, ancestors, budget, depth);
167
+ }
168
+ finally {
169
+ ancestors.delete(object);
170
+ }
171
+ }
172
+ function canonicalObject(value, ancestors, budget, depth) {
173
+ const descriptors = safeDescriptors(value);
174
+ const keys = descriptorKeys(descriptors);
175
+ if (keys.length > MAX_CANONICAL_PROPERTIES)
176
+ throw new TypeError("Canonical JSON exceeds the bounded property limit.");
177
+ const result = Object.create(null);
178
+ const stringKeys = [];
179
+ for (const key of keys) {
180
+ if (typeof key !== "string")
181
+ throw new TypeError("Canonical JSON does not support symbol properties.");
182
+ stringKeys.push(key);
183
+ }
184
+ stringKeys.sort();
185
+ for (const key of stringKeys) {
186
+ if (RESERVED_CANONICAL_KEYS.has(key)) {
187
+ throw new TypeError("Canonical JSON contains a reserved marker key.");
188
+ }
189
+ const descriptor = descriptorValue(descriptors, key);
190
+ assertDataDescriptor(descriptor);
191
+ if (descriptor.enumerable !== true)
192
+ throw new TypeError("Canonical JSON supports only enumerable own data properties.");
193
+ consumeProperty(budget, key);
194
+ Object.defineProperty(result, key, {
195
+ value: canonicalValue(descriptor.value, ancestors, budget, depth + 1),
196
+ enumerable: true,
197
+ writable: true,
198
+ configurable: true
199
+ });
200
+ }
201
+ return result;
202
+ }
203
+ function canonicalArray(value, ancestors, budget, depth) {
204
+ const descriptors = safeDescriptors(value);
205
+ const keys = descriptorKeys(descriptors);
206
+ const lengthDescriptor = descriptorValue(descriptors, "length");
207
+ assertDataDescriptor(lengthDescriptor);
208
+ if (lengthDescriptor.enumerable !== false || lengthDescriptor.configurable !== false || typeof lengthDescriptor.value !== "number") {
209
+ throw new TypeError("Canonical JSON contains an invalid array length.");
210
+ }
211
+ const length = lengthDescriptor.value;
212
+ if (!Number.isSafeInteger(length) || length < 0 || length > MAX_CANONICAL_ARRAY_LENGTH) {
213
+ throw new TypeError("Canonical JSON contains an oversized array.");
214
+ }
215
+ for (const key of keys) {
216
+ if (typeof key !== "string")
217
+ throw new TypeError("Canonical JSON does not support symbol properties.");
218
+ }
219
+ if (keys.length !== length + 1)
220
+ throw new TypeError("Canonical JSON does not support sparse or custom arrays.");
221
+ for (const key of keys) {
222
+ if (typeof key !== "string" || (key !== "length" && parseArrayIndex(key) === undefined)) {
223
+ throw new TypeError("Canonical JSON does not support sparse or custom arrays.");
224
+ }
225
+ }
226
+ const result = [];
227
+ for (let index = 0; index < length; index += 1) {
228
+ const descriptor = descriptorValue(descriptors, String(index));
229
+ assertDataDescriptor(descriptor);
230
+ if (descriptor.enumerable !== true)
231
+ throw new TypeError("Canonical JSON supports only enumerable array entries.");
232
+ consumeProperty(budget, String(index));
233
+ result.push(canonicalValue(descriptor.value, ancestors, budget, depth + 1));
234
+ }
235
+ return result;
236
+ }
237
+ function canonicalDate(value, budget) {
238
+ const descriptors = safeDescriptors(value);
239
+ if (descriptorKeys(descriptors).length !== 0)
240
+ throw new TypeError("Canonical JSON does not support custom date properties.");
241
+ let iso;
242
+ try {
243
+ iso = Date.prototype.toISOString.call(value);
244
+ }
245
+ catch {
246
+ throw new TypeError("Canonical JSON contains an invalid date.");
247
+ }
248
+ consumeBytes(budget, iso);
249
+ return { $date: iso };
250
+ }
251
+ function canonicalBytes(value, budget) {
252
+ if (TYPED_ARRAY_BYTE_LENGTH_GETTER === undefined)
253
+ throw new TypeError(SAFE_CANONICAL_ERROR);
254
+ let byteLength;
255
+ try {
256
+ // This internal-slot check rejects a Proxy around a typed array without
257
+ // reading any caller-controlled property or invoking a getter.
258
+ byteLength = TYPED_ARRAY_BYTE_LENGTH_GETTER.call(value);
259
+ }
260
+ catch {
261
+ throw new TypeError(SAFE_CANONICAL_ERROR);
262
+ }
263
+ if (!Number.isSafeInteger(byteLength) || byteLength < 0 || byteLength > MAX_CANONICAL_BYTES) {
264
+ throw new TypeError("Canonical JSON contains an oversized byte array.");
265
+ }
266
+ const descriptors = safeDescriptors(value);
267
+ const keys = descriptorKeys(descriptors);
268
+ if (keys.length !== byteLength)
269
+ throw new TypeError("Canonical JSON does not support custom byte-array properties.");
270
+ const bytes = new Uint8Array(byteLength);
271
+ for (let index = 0; index < byteLength; index += 1) {
272
+ const key = String(index);
273
+ const descriptor = descriptorValue(descriptors, key);
274
+ assertDataDescriptor(descriptor);
275
+ if (descriptor.enumerable !== true || typeof descriptor.value !== "number" || !Number.isInteger(descriptor.value) || descriptor.value < 0 || descriptor.value > 255) {
276
+ throw new TypeError("Canonical JSON contains an invalid byte-array entry.");
277
+ }
278
+ bytes[index] = descriptor.value;
279
+ consumeProperty(budget, key);
280
+ }
281
+ const encoded = Buffer.from(bytes).toString("base64");
282
+ consumeBytes(budget, encoded);
283
+ return { $bytes: encoded };
284
+ }
285
+ function safeRecordValues(value, allowed) {
286
+ if (value === null || typeof value !== "object")
287
+ throw new TypeError(SAFE_CANONICAL_ERROR);
288
+ const prototype = safeGetPrototype(value);
289
+ if (prototype !== Object.prototype && prototype !== null)
290
+ throw new TypeError(SAFE_CANONICAL_ERROR);
291
+ const descriptors = safeDescriptors(value);
292
+ const allowedSet = new Set(allowed);
293
+ const values = new Map();
294
+ for (const key of descriptorKeys(descriptors)) {
295
+ if (typeof key !== "string")
296
+ throw new TypeError("Canonical JSON does not support symbol properties.");
297
+ if (!allowedSet.has(key))
298
+ throw new TypeError("Canonical JSON contains an unsupported field.");
299
+ const descriptor = descriptorValue(descriptors, key);
300
+ assertDataDescriptor(descriptor);
301
+ if (descriptor.enumerable !== true)
302
+ throw new TypeError(SAFE_CANONICAL_ERROR);
303
+ values.set(key, descriptor.value);
304
+ }
305
+ return values;
306
+ }
307
+ function safeArrayElements(value) {
308
+ if (value === null || typeof value !== "object")
309
+ throw new TypeError(SAFE_CANONICAL_ERROR);
310
+ let isArray = false;
311
+ try {
312
+ isArray = Array.isArray(value);
313
+ }
314
+ catch {
315
+ throw new TypeError(SAFE_CANONICAL_ERROR);
316
+ }
317
+ if (!isArray || safeGetPrototype(value) !== Array.prototype)
318
+ throw new TypeError(SAFE_CANONICAL_ERROR);
319
+ const descriptors = safeDescriptors(value);
320
+ const lengthDescriptor = descriptorValue(descriptors, "length");
321
+ assertDataDescriptor(lengthDescriptor);
322
+ if (typeof lengthDescriptor.value !== "number" || !Number.isSafeInteger(lengthDescriptor.value) || lengthDescriptor.value < 0 || lengthDescriptor.value > MAX_CANONICAL_ARRAY_LENGTH) {
323
+ throw new TypeError(SAFE_CANONICAL_ERROR);
324
+ }
325
+ const length = lengthDescriptor.value;
326
+ const keys = descriptorKeys(descriptors);
327
+ if (keys.length !== length + 1)
328
+ throw new TypeError(SAFE_CANONICAL_ERROR);
329
+ for (const key of keys) {
330
+ if (typeof key !== "string" || (key !== "length" && parseArrayIndex(key) === undefined)) {
331
+ throw new TypeError(SAFE_CANONICAL_ERROR);
332
+ }
333
+ }
334
+ const values = [];
335
+ for (let index = 0; index < length; index += 1) {
336
+ const descriptor = descriptorValue(descriptors, String(index));
337
+ assertDataDescriptor(descriptor);
338
+ if (descriptor.enumerable !== true)
339
+ throw new TypeError(SAFE_CANONICAL_ERROR);
340
+ values.push(descriptor.value);
341
+ }
342
+ return values;
343
+ }
344
+ function safeGetPrototype(value) {
345
+ try {
346
+ return Object.getPrototypeOf(value);
347
+ }
348
+ catch {
349
+ throw new TypeError(SAFE_CANONICAL_ERROR);
350
+ }
351
+ }
352
+ function safeDescriptors(value) {
353
+ let descriptors;
354
+ try {
355
+ descriptors = Object.getOwnPropertyDescriptors(value);
356
+ }
357
+ catch {
358
+ throw new TypeError(SAFE_CANONICAL_ERROR);
359
+ }
360
+ return descriptors;
361
+ }
362
+ function descriptorKeys(descriptors) {
363
+ try {
364
+ return Reflect.ownKeys(descriptors);
365
+ }
366
+ catch {
367
+ throw new TypeError(SAFE_CANONICAL_ERROR);
368
+ }
369
+ }
370
+ function descriptorValue(descriptors, key) {
371
+ let descriptor;
372
+ try {
373
+ descriptor = Object.getOwnPropertyDescriptor(descriptors, key);
374
+ }
375
+ catch {
376
+ throw new TypeError(SAFE_CANONICAL_ERROR);
377
+ }
378
+ if (descriptor === undefined || !("value" in descriptor))
379
+ throw new TypeError(SAFE_CANONICAL_ERROR);
380
+ return descriptor.value;
381
+ }
382
+ function assertDataDescriptor(descriptor) {
383
+ if (!("value" in descriptor) || descriptor.get !== undefined || descriptor.set !== undefined) {
384
+ throw new TypeError("Canonical JSON supports only own data properties.");
385
+ }
386
+ }
387
+ function parseArrayIndex(key) {
388
+ if (!/^(?:0|[1-9][0-9]*)$/u.test(key))
389
+ return undefined;
390
+ const index = Number(key);
391
+ if (!Number.isSafeInteger(index) || index < 0 || index > 4_294_967_294 || String(index) !== key)
392
+ return undefined;
393
+ return index;
394
+ }
395
+ function consumeNode(budget, depth) {
396
+ if (depth > MAX_CANONICAL_DEPTH || ++budget.nodes > MAX_CANONICAL_NODES) {
397
+ throw new TypeError("Canonical JSON exceeds the bounded graph limit.");
398
+ }
399
+ }
400
+ function consumeProperty(budget, key) {
401
+ if (++budget.properties > MAX_CANONICAL_PROPERTIES)
402
+ throw new TypeError("Canonical JSON exceeds the bounded property limit.");
403
+ const bytes = Buffer.byteLength(key, "utf8");
404
+ if (bytes > MAX_CANONICAL_KEY_BYTES)
405
+ throw new TypeError("Canonical JSON contains an oversized property name.");
406
+ consumeBytes(budget, key);
407
+ }
408
+ function consumeBytes(budget, value) {
409
+ budget.bytes += Buffer.byteLength(value, "utf8");
410
+ if (budget.bytes > MAX_CANONICAL_BYTES)
411
+ throw new TypeError("Canonical JSON exceeds the bounded byte limit.");
412
+ }
@@ -0,0 +1,72 @@
1
+ import type { PageLike, RuntimeEnv } from "../types.js";
2
+ import { type CoordinatorOwner, type ProcessTabCoordinator } from "../runtime/tab-coordinator.js";
3
+ import type { OperationRuntimeCapabilities } from "../runtime/operation-context.js";
4
+ import { type OperationRuntimeBrowserPrimitives } from "./runtime-adapter.js";
5
+ import type { BrowserTargetEvidenceDigest } from "./browser-target.js";
6
+ import type { OperationAdapterFactory, OperationAdapterFactoryContext, OperationHandleAdapterFactory, OperationControlAdapterFactory } from "./client.js";
7
+ import type { OperationConfigurationRequestV1, OperationSurface, OperationTargetBindingV1 } from "./types.js";
8
+ /**
9
+ * Configuration for the default ChatGPT browser runtime.
10
+ *
11
+ * The environment is copied once when this factory is created. Browser
12
+ * attachment itself remains inside the per-request capture callback, which
13
+ * OperationClient invokes only after the journal has created the operation
14
+ * record. A caller may supply provider-specific primitives later without
15
+ * changing target binding or recovery semantics.
16
+ */
17
+ export type ChatGPTRuntimeFactoryOptions = Readonly<{
18
+ env: RuntimeEnv;
19
+ owner: CoordinatorOwner;
20
+ evidenceDigest: BrowserTargetEvidenceDigest;
21
+ coordinator?: ProcessTabCoordinator;
22
+ transactionTimeoutMs?: number;
23
+ surfaceTimeoutMs?: number;
24
+ /**
25
+ * Provider-advertised, integration-tested concurrency capabilities. Missing
26
+ * fields are false. The default ChatGPT bridge deliberately does not claim
27
+ * different-tab overlap until its embedding supplies this evidence.
28
+ */
29
+ capabilities?: Partial<OperationRuntimeCapabilities>;
30
+ /** Optional request-local augmentation for provider primitives under active integration. */
31
+ primitives?: (context: ChatGPTPrimitiveFactoryContext) => Partial<OperationRuntimeBrowserPrimitives> | undefined;
32
+ }>;
33
+ export type ChatGPTPrimitiveFactoryContext = Readonly<{
34
+ operationId: string;
35
+ requestDigest: string;
36
+ surface: OperationSurface;
37
+ prompt?: string;
38
+ configuration?: OperationConfigurationRequestV1;
39
+ files: OperationAdapterFactoryContext["files"];
40
+ signal: AbortSignal;
41
+ page: Readonly<PageLike>;
42
+ target?: OperationTargetBindingV1;
43
+ }>;
44
+ /**
45
+ * Create a fresh, prompt-bearing control adapter. The prompt is accepted only
46
+ * for this invocation and is never cached or forwarded through durable phase
47
+ * records. The factory binds the authenticated parent target by tab ID.
48
+ */
49
+ export declare function createChatGPTOperationControlAdapterFactory(options: ChatGPTRuntimeFactoryOptions): OperationControlAdapterFactory;
50
+ /** Alias for callers that use the shorter control-factory name. */
51
+ export declare const createChatGPTControlAdapterFactory: typeof createChatGPTOperationControlAdapterFactory;
52
+ export declare class ChatGPTRuntimeFactoryError extends Error {
53
+ readonly code: "chatgpt_runtime_unavailable";
54
+ constructor();
55
+ }
56
+ /**
57
+ * Create the normal request-scoped adapter factory for `ChatGPTClient`.
58
+ *
59
+ * The returned factory performs no browser work until its capture callback is
60
+ * reached by `resolveTarget`. It is therefore safe to construct while a
61
+ * client is being initialized or while the browser bridge is unavailable.
62
+ */
63
+ export declare function createChatGPTOperationAdapterFactory(options: ChatGPTRuntimeFactoryOptions): OperationAdapterFactory;
64
+ /** Alias for integrations that use the "runtime" naming first. */
65
+ export declare const createChatGPTOperationRuntimeFactory: typeof createChatGPTOperationAdapterFactory;
66
+ /**
67
+ * Create the restart-safe handle factory. Recovery always attaches by the
68
+ * durable tab id; it never falls back to the selected tab or a replacement.
69
+ */
70
+ export declare function createChatGPTOperationHandleAdapterFactory(options: ChatGPTRuntimeFactoryOptions): OperationHandleAdapterFactory;
71
+ /** Alias retained for callers that call the restart path a recovery factory. */
72
+ export declare const createChatGPTOperationRecoveryFactory: typeof createChatGPTOperationHandleAdapterFactory;