@opengeni/contracts 0.44.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-authored-durable-text.d.ts +70 -0
- package/dist/agent-config.d.ts +869 -0
- package/dist/agent-instruction-changes.d.ts +110 -0
- package/dist/agent-learning.d.ts +243 -0
- package/dist/agent-topology.d.ts +292 -0
- package/dist/allowance-refusal.d.ts +9 -0
- package/dist/allowance-refusal.js +50 -0
- package/dist/allowance-refusal.js.map +1 -0
- package/dist/analytics-consent-report.d.ts +19 -0
- package/dist/analytics-consent-report.js +10 -0
- package/dist/analytics-consent-report.js.map +1 -0
- package/dist/api-key-presets.d.ts +19 -0
- package/dist/artifact-catalog.d.ts +161 -0
- package/dist/artifacts.d.ts +135 -11
- package/dist/atlassian-native-retirement.d.ts +16 -0
- package/dist/atlassian-native-retirement.js +30 -0
- package/dist/atlassian-native-retirement.js.map +1 -0
- package/dist/atlassian.d.ts +2 -0
- package/dist/atlassian.js +27 -11
- package/dist/browser-storage.d.ts +5 -0
- package/dist/browser-storage.js +9 -0
- package/dist/browser-storage.js.map +1 -0
- package/dist/bundled-skills.d.ts +40 -0
- package/dist/canonical-human-identities.d.ts +157 -0
- package/dist/canonical-human-identities.js +23 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/chunk-2ACYHZFB.js +292 -0
- package/dist/chunk-2ACYHZFB.js.map +1 -0
- package/dist/chunk-2VORLN2R.js +353 -0
- package/dist/chunk-2VORLN2R.js.map +1 -0
- package/dist/{chunk-Y3MLSLB4.js → chunk-3SIZGL3O.js} +42 -30
- package/dist/chunk-3SIZGL3O.js.map +1 -0
- package/dist/chunk-46KLD2UH.js +186 -0
- package/dist/chunk-46KLD2UH.js.map +1 -0
- package/dist/chunk-4JGHSSB7.js +11 -0
- package/dist/chunk-4JGHSSB7.js.map +1 -0
- package/dist/{chunk-52SGB2QO.js → chunk-5IXYF6XN.js} +50 -10
- package/dist/chunk-5IXYF6XN.js.map +1 -0
- package/dist/chunk-BCS7WHCK.js +139 -0
- package/dist/chunk-BCS7WHCK.js.map +1 -0
- package/dist/chunk-EK7NDGFR.js +128 -0
- package/dist/chunk-EK7NDGFR.js.map +1 -0
- package/dist/{chunk-5UDNP7AO.js → chunk-FZ6BXQHL.js} +78 -38
- package/dist/chunk-FZ6BXQHL.js.map +1 -0
- package/dist/chunk-GRG7PHWQ.js +25 -0
- package/dist/chunk-GRG7PHWQ.js.map +1 -0
- package/dist/chunk-JUFK3T4Q.js +80 -0
- package/dist/chunk-JUFK3T4Q.js.map +1 -0
- package/dist/chunk-KHHZTBP7.js +11 -0
- package/dist/chunk-KHHZTBP7.js.map +1 -0
- package/dist/chunk-KR2V42UZ.js +187 -0
- package/dist/chunk-KR2V42UZ.js.map +1 -0
- package/dist/chunk-MZLBPKFE.js +168 -0
- package/dist/chunk-MZLBPKFE.js.map +1 -0
- package/dist/{chunk-H5BVCZKF.js → chunk-NRMCVHAU.js} +6 -5
- package/dist/chunk-NRMCVHAU.js.map +1 -0
- package/dist/{chunk-TZ6YEYN4.js → chunk-NVJMJWLL.js} +3 -1
- package/dist/chunk-NVJMJWLL.js.map +1 -0
- package/dist/chunk-O77VSFYZ.js +70 -0
- package/dist/chunk-O77VSFYZ.js.map +1 -0
- package/dist/chunk-PX3VCKAU.js +29 -0
- package/dist/chunk-PX3VCKAU.js.map +1 -0
- package/dist/chunk-QR5D2IQC.js +61 -0
- package/dist/chunk-QR5D2IQC.js.map +1 -0
- package/dist/chunk-RJ76DRPO.js +117 -0
- package/dist/chunk-RJ76DRPO.js.map +1 -0
- package/dist/chunk-RKX3NQYS.js +28 -0
- package/dist/chunk-RKX3NQYS.js.map +1 -0
- package/dist/{chunk-FJBG5E4O.js → chunk-SIOU2K4U.js} +45 -22
- package/dist/chunk-SIOU2K4U.js.map +1 -0
- package/dist/chunk-TSCDAGET.js +75 -0
- package/dist/chunk-TSCDAGET.js.map +1 -0
- package/dist/{chunk-LSB7GRLG.js → chunk-TXTQIYCV.js} +15 -11
- package/dist/chunk-TXTQIYCV.js.map +1 -0
- package/dist/chunk-X7ETVO4P.js +26544 -0
- package/dist/chunk-X7ETVO4P.js.map +1 -0
- package/dist/{chunk-CADSX6UN.js → chunk-Y3KNXVTD.js} +2 -2
- package/dist/chunk-YBW5JSA3.js +251 -0
- package/dist/chunk-YBW5JSA3.js.map +1 -0
- package/dist/chunk-YRXAWWCU.js +45 -0
- package/dist/chunk-YRXAWWCU.js.map +1 -0
- package/dist/claude-provider-account-authority.d.ts +18 -0
- package/dist/claude-subscription-oauth.d.ts +42 -0
- package/dist/claude-subscription-usage.d.ts +159 -0
- package/dist/client-error-report.d.ts +109 -0
- package/dist/client-error-report.js +87 -0
- package/dist/client-error-report.js.map +1 -0
- package/dist/code-search.d.ts +52 -0
- package/dist/code-search.js +40 -0
- package/dist/code-search.js.map +1 -0
- package/dist/codex-provider-account-authority.d.ts +23 -0
- package/dist/codex-provider-account-authority.js +23 -0
- package/dist/codex-provider-account-authority.js.map +1 -0
- package/dist/company-brain-governed-writes.d.ts +475 -0
- package/dist/company-brain.d.ts +336 -0
- package/dist/company-profile.d.ts +566 -0
- package/dist/connect.d.ts +325 -0
- package/dist/connect.js +191 -0
- package/dist/connect.js.map +1 -0
- package/dist/connection-account-label.d.ts +2 -0
- package/dist/connection-account-label.js +35 -0
- package/dist/connection-account-label.js.map +1 -0
- package/dist/connection-authority.d.ts +193 -0
- package/dist/connection-authority.js +50 -0
- package/dist/connection-authority.js.map +1 -0
- package/dist/connector-attachments.d.ts +95 -0
- package/dist/connector-attachments.js +51 -0
- package/dist/connector-attachments.js.map +1 -0
- package/dist/connector-tool-permissions.d.ts +73 -0
- package/dist/direct-model-provider.d.ts +36 -0
- package/dist/editable-artifact-codec-registry.d.ts +16 -7
- package/dist/editable-artifact-codec-registry.js +19 -9
- package/dist/editable-artifact-committed-transaction.d.ts +2 -2
- package/dist/editable-artifact-committed-transaction.js +2 -2
- package/dist/editable-artifact-live.d.ts +11 -12
- package/dist/editable-artifact-live.js +110 -45
- package/dist/editable-artifact-live.js.map +1 -1
- package/dist/editable-artifact-serialized-commit.d.ts +2 -1
- package/dist/editable-artifact-serialized-commit.js +8 -7
- package/dist/editable-artifact-versions.d.ts +20 -5
- package/dist/editable-artifact-versions.js +23 -5
- package/dist/editable-artifacts.d.ts +2 -0
- package/dist/editable-artifacts.js +48 -36
- package/dist/external-identities.d.ts +784 -0
- package/dist/external-identities.js +44 -0
- package/dist/external-identities.js.map +1 -0
- package/dist/feedback.d.ts +51 -0
- package/dist/github-repository-contracts.d.ts +36 -0
- package/dist/github-repository-contracts.js +59 -0
- package/dist/github-repository-contracts.js.map +1 -0
- package/dist/github-repository.d.ts +14 -0
- package/dist/github-repository.js +36 -0
- package/dist/github-repository.js.map +1 -0
- package/dist/google-drive.d.ts +90 -1
- package/dist/google-drive.js +91 -15
- package/dist/google-drive.js.map +1 -1
- package/dist/governed-learning-activation.d.ts +154 -0
- package/dist/governed-learning-evaluator.d.ts +152 -0
- package/dist/host-mcp-bindings.d.ts +326 -0
- package/dist/host-mcp-bindings.js +252 -0
- package/dist/host-mcp-bindings.js.map +1 -0
- package/dist/image-generation.d.ts +1 -0
- package/dist/index.d.ts +27574 -5374
- package/dist/index.js +2531 -177
- package/dist/insights-usage.d.ts +877 -0
- package/dist/insights-usage.js +509 -0
- package/dist/insights-usage.js.map +1 -0
- package/dist/interaction.d.ts +1752 -13
- package/dist/knowledge-entries.d.ts +982 -0
- package/dist/knowledge-preparation.d.ts +237 -0
- package/dist/knowledge.d.ts +740 -0
- package/dist/managed-auth-session-sets.d.ts +241 -0
- package/dist/managed-auth-session-sets.js +191 -0
- package/dist/managed-auth-session-sets.js.map +1 -0
- package/dist/managed-sign-in-methods.d.ts +56 -0
- package/dist/managed-sign-in-methods.js +46 -0
- package/dist/managed-sign-in-methods.js.map +1 -0
- package/dist/mcp-catalog-limits.d.ts +2 -0
- package/dist/mcp-endpoint.d.ts +7 -0
- package/dist/mcp-endpoint.js +9 -0
- package/dist/mcp-endpoint.js.map +1 -0
- package/dist/mcp-oauth.d.ts +71 -0
- package/dist/modal-native-proof-v2.d.ts +587 -0
- package/dist/modal-native-proof-v2.js +37 -0
- package/dist/modal-native-proof-v2.js.map +1 -0
- package/dist/model-availability.d.ts +15 -0
- package/dist/model-connection-access.d.ts +24 -0
- package/dist/model-context-inspector.d.ts +329 -0
- package/dist/model-display.d.ts +38 -0
- package/dist/model-display.js +134 -0
- package/dist/model-display.js.map +1 -0
- package/dist/model-picker-order.d.ts +25 -0
- package/dist/model-picker-order.js +42 -0
- package/dist/model-picker-order.js.map +1 -0
- package/dist/organization-access.d.ts +231 -0
- package/dist/organization-access.js +34 -0
- package/dist/organization-access.js.map +1 -0
- package/dist/organization-integration-policy.d.ts +27 -0
- package/dist/organization-membership-lifecycle.d.ts +1022 -0
- package/dist/organization-model-usage.d.ts +146 -0
- package/dist/organization-model-usage.js +67 -0
- package/dist/organization-model-usage.js.map +1 -0
- package/dist/organization-recovery.d.ts +337 -0
- package/dist/organization-recovery.js +37 -0
- package/dist/organization-recovery.js.map +1 -0
- package/dist/organization-usage.d.ts +138 -0
- package/dist/permissions.d.ts +54 -0
- package/dist/personal-github.d.ts +320 -0
- package/dist/personal-github.js +222 -0
- package/dist/personal-github.js.map +1 -0
- package/dist/plugin-discovery.d.ts +35 -0
- package/dist/plugin-discovery.js +7 -0
- package/dist/plugin-discovery.js.map +1 -0
- package/dist/preference-registry.d.ts +44 -1
- package/dist/product-analytics.d.ts +113 -0
- package/dist/product-lifecycle-facts.d.ts +73 -0
- package/dist/remember.d.ts +350 -0
- package/dist/retained-output.d.ts +8 -0
- package/dist/sandbox-file-artifacts.d.ts +57 -0
- package/dist/sandbox-provider-command.d.ts +113 -0
- package/dist/sandbox-recovery.d.ts +146 -0
- package/dist/sandbox-snapshots.d.ts +39 -0
- package/dist/session-final-reply.d.ts +6 -0
- package/dist/session-final-reply.js +9 -0
- package/dist/session-final-reply.js.map +1 -0
- package/dist/session-goal-reports.d.ts +21 -0
- package/dist/session-history-import.d.ts +947 -0
- package/dist/session-list-entries.d.ts +4 -0
- package/dist/session-list-entries.js +51 -0
- package/dist/session-list-entries.js.map +1 -0
- package/dist/session-mcp-projections.d.ts +215 -0
- package/dist/session-message-search.d.ts +68 -0
- package/dist/session-titles.d.ts +68 -0
- package/dist/session-titles.js +25 -0
- package/dist/session-titles.js.map +1 -0
- package/dist/session-topology-primitives.d.ts +22 -0
- package/dist/signup-attribution.d.ts +39 -0
- package/dist/site-request-headers.test.d.ts +1 -0
- package/dist/site-session-http.d.ts +11 -0
- package/dist/site-session-http.js +11 -0
- package/dist/site-session-http.js.map +1 -0
- package/dist/skill-catalog-context.d.ts +7 -0
- package/dist/skill-files.d.ts +12 -0
- package/dist/skill-metadata.d.ts +9 -0
- package/dist/skill-use.d.ts +61 -0
- package/dist/skills.d.ts +185 -0
- package/dist/slack-bot-scopes.d.ts +46 -21
- package/dist/slack-bot-scopes.js +14 -3
- package/dist/slack-rest-mcp.d.ts +31 -0
- package/dist/slack-rest-mcp.js +19 -0
- package/dist/slack-rest-mcp.js.map +1 -0
- package/dist/slack-task-policy.d.ts +294 -0
- package/dist/spreadsheet-artifact-commands.d.ts +2 -3
- package/dist/spreadsheet-artifact-commands.js +4 -2
- package/dist/spreadsheet-artifact-query.js +3 -2
- package/dist/subscription-account-pools.d.ts +292 -0
- package/dist/task-notes.d.ts +169 -0
- package/dist/tool-catalog.d.ts +286 -0
- package/dist/tool-result-spill.d.ts +16 -0
- package/dist/usage-allowances.d.ts +285 -0
- package/dist/usage-allowances.js +49 -0
- package/dist/usage-allowances.js.map +1 -0
- package/dist/video-generation.d.ts +51 -0
- package/dist/video-generation.js +9 -1
- package/dist/work-claims.d.ts +411 -0
- package/dist/workspace-instruction-policies.d.ts +94 -0
- package/dist/workspace-integration-wire.d.ts +36 -0
- package/dist/workspace-integration-wire.js +23 -0
- package/dist/workspace-integration-wire.js.map +1 -0
- package/dist/workspace-integrations.d.ts +948 -0
- package/dist/workspace-learning-administration.d.ts +289 -0
- package/dist/workspace-learning-policy.d.ts +1 -1
- package/dist/workspace-state.d.ts +85 -416
- package/dist/xai-provider-account-authority.d.ts +26 -0
- package/dist/xai-provider-account-authority.js +9 -0
- package/dist/xai-provider-account-authority.js.map +1 -0
- package/package.json +146 -1
- package/src/agent-authored-durable-text.ts +116 -0
- package/src/agent-config.ts +1527 -0
- package/src/agent-instruction-changes.ts +98 -0
- package/src/agent-learning.ts +161 -0
- package/src/agent-topology.ts +69 -0
- package/src/allowance-refusal.ts +81 -0
- package/src/analytics-consent-report.ts +20 -0
- package/src/api-key-presets.ts +25 -0
- package/src/artifact-catalog.ts +60 -0
- package/src/artifacts.ts +146 -18
- package/src/atlassian-native-retirement.ts +33 -0
- package/src/browser-storage.ts +10 -0
- package/src/bundled-skills.ts +73 -0
- package/src/canonical-human-identities.ts +93 -0
- package/src/claude-provider-account-authority.ts +12 -0
- package/src/claude-subscription-oauth.ts +62 -0
- package/src/claude-subscription-usage.ts +59 -0
- package/src/client-error-report.ts +184 -0
- package/src/code-search.ts +105 -0
- package/src/codex-provider-account-authority.ts +37 -0
- package/src/company-brain-governed-writes.ts +356 -0
- package/src/company-brain.ts +201 -0
- package/src/company-profile.ts +167 -1
- package/src/connect.ts +202 -0
- package/src/connection-account-label.ts +46 -0
- package/src/connection-authority.ts +213 -0
- package/src/connector-attachments.ts +327 -0
- package/src/connector-tool-permissions.ts +60 -0
- package/src/direct-model-provider.ts +98 -0
- package/src/editable-artifact-codec-registry.ts +55 -17
- package/src/editable-artifact-committed-transaction.ts +44 -31
- package/src/editable-artifact-live.ts +123 -57
- package/src/editable-artifact-serialized-commit.ts +2 -1
- package/src/editable-artifact-versions.ts +26 -5
- package/src/editable-artifacts.ts +2 -0
- package/src/external-identities.ts +285 -0
- package/src/feedback.ts +39 -0
- package/src/github-repository-contracts.ts +85 -0
- package/src/github-repository.ts +59 -0
- package/src/google-drive.ts +76 -4
- package/src/governed-learning-activation.ts +191 -0
- package/src/governed-learning-evaluator.ts +176 -0
- package/src/host-mcp-bindings.ts +298 -0
- package/src/image-generation.ts +8 -2
- package/src/index.ts +8019 -1799
- package/src/insights-usage.ts +679 -0
- package/src/interaction.ts +1102 -6
- package/src/knowledge-entries.ts +375 -0
- package/src/knowledge-preparation.ts +50 -0
- package/src/knowledge.ts +335 -0
- package/src/managed-auth-session-sets.ts +253 -0
- package/src/managed-sign-in-methods.ts +37 -0
- package/src/mcp-catalog-limits.ts +2 -0
- package/src/mcp-endpoint.ts +30 -0
- package/src/mcp-oauth.ts +66 -0
- package/src/modal-native-proof-v2.ts +398 -0
- package/src/model-availability.ts +22 -0
- package/src/model-connection-access.ts +17 -0
- package/src/model-context-inspector.ts +139 -0
- package/src/model-display.ts +195 -0
- package/src/model-picker-order.ts +97 -0
- package/src/organization-access.ts +176 -0
- package/src/organization-integration-policy.ts +54 -0
- package/src/organization-membership-lifecycle.ts +559 -0
- package/src/organization-model-usage.ts +72 -0
- package/src/organization-recovery.ts +186 -0
- package/src/organization-usage.ts +79 -0
- package/src/permissions.ts +58 -0
- package/src/personal-github.ts +267 -0
- package/src/plugin-discovery.ts +33 -0
- package/src/preference-registry.ts +20 -1
- package/src/product-analytics.ts +253 -0
- package/src/product-lifecycle-facts.ts +121 -0
- package/src/remember.ts +243 -0
- package/src/retained-output.ts +20 -3
- package/src/sandbox-file-artifacts.ts +73 -0
- package/src/sandbox-provider-command.ts +82 -0
- package/src/sandbox-recovery.ts +116 -0
- package/src/sandbox-snapshots.ts +142 -0
- package/src/session-final-reply.ts +16 -0
- package/src/session-goal-reports.ts +55 -0
- package/src/session-history-import.ts +159 -0
- package/src/session-list-entries.ts +91 -0
- package/src/session-mcp-projections.ts +273 -0
- package/src/session-message-search.ts +54 -0
- package/src/session-titles.ts +467 -0
- package/src/session-topology-primitives.ts +21 -0
- package/src/signup-attribution.ts +81 -0
- package/src/site-request-headers.test.ts +28 -0
- package/src/site-session-http.ts +63 -0
- package/src/skill-catalog-context.ts +50 -0
- package/src/skill-files.ts +52 -0
- package/src/skill-metadata.ts +40 -0
- package/src/skill-use.ts +77 -0
- package/src/skills.ts +136 -0
- package/src/slack-bot-scopes.ts +106 -42
- package/src/slack-rest-mcp.ts +194 -0
- package/src/slack-task-policy.ts +215 -0
- package/src/spreadsheet-artifact-commands.ts +12 -13
- package/src/subscription-account-pools.ts +44 -0
- package/src/task-notes.ts +105 -0
- package/src/tool-catalog.ts +155 -0
- package/src/tool-result-spill.ts +35 -0
- package/src/usage-allowances.ts +187 -0
- package/src/video-generation.ts +43 -6
- package/src/work-claims.ts +266 -0
- package/src/workspace-instruction-policies.ts +31 -0
- package/src/workspace-integration-wire.ts +99 -0
- package/src/workspace-integrations.ts +640 -0
- package/src/workspace-learning-administration.ts +88 -0
- package/src/workspace-learning-policy.ts +4 -3
- package/src/workspace-state.ts +16 -126
- package/src/xai-provider-account-authority.ts +38 -0
- package/dist/chunk-52SGB2QO.js.map +0 -1
- package/dist/chunk-5UDNP7AO.js.map +0 -1
- package/dist/chunk-BVGIYW7D.js +0 -11
- package/dist/chunk-BVGIYW7D.js.map +0 -1
- package/dist/chunk-FJBG5E4O.js.map +0 -1
- package/dist/chunk-H5BVCZKF.js.map +0 -1
- package/dist/chunk-LSB7GRLG.js.map +0 -1
- package/dist/chunk-TZ6YEYN4.js.map +0 -1
- package/dist/chunk-VA22KRHS.js +0 -15177
- package/dist/chunk-VA22KRHS.js.map +0 -1
- package/dist/chunk-Y3MLSLB4.js.map +0 -1
- /package/dist/{chunk-CADSX6UN.js.map → chunk-Y3KNXVTD.js.map} +0 -0
package/src/interaction.ts
CHANGED
|
@@ -5,6 +5,7 @@ export const INTERACTION_PROTOCOL_VERSION = 1 as const;
|
|
|
5
5
|
export const BROWSER_CONTROL_PROTOCOL_VERSION = INTERACTION_PROTOCOL_VERSION;
|
|
6
6
|
export const BROWSER_CONTROL_WEBSOCKET_PROTOCOL = "opengeni.browser.v1" as const;
|
|
7
7
|
export const COMPUTER_CONTROL_WEBSOCKET_PROTOCOL = "opengeni.computer.v1" as const;
|
|
8
|
+
export const COMPUTER_RFB_WEBSOCKET_PROTOCOL = "opengeni.computer.rfb.v1" as const;
|
|
8
9
|
export const BROWSER_CONTROL_WEBSOCKET_BEARER_PREFIX = "opengeni.auth." as const;
|
|
9
10
|
export const BROWSER_CONTROL_MAX_JSON_BYTES = 40 * 1024 * 1024;
|
|
10
11
|
export const BROWSER_CONTROL_MAX_FRAME_HEADER_BYTES = 64 * 1024;
|
|
@@ -16,12 +17,41 @@ export const INTERACTION_MAX_SEMANTIC_NODES = 10_000;
|
|
|
16
17
|
export const INTERACTION_MAX_CHANGED_NODES = 2_000;
|
|
17
18
|
export const INTERACTION_MAX_DIAGNOSTIC_ENTRIES = 1_000;
|
|
18
19
|
export const INTERACTION_MAX_ACTIONS_PER_BATCH = 32;
|
|
20
|
+
export const INTERACTION_MAX_WORKSPACE_FILES_PER_COMMAND = 100;
|
|
21
|
+
export const INTERACTION_MAX_CLIPBOARD_BYTES = 1024 * 1024;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Latest-wins workspace invalidation for Browser/Computer resources. This is
|
|
25
|
+
* deliberately a cursor snapshot rather than a durable event-log entry:
|
|
26
|
+
* consumers refetch authoritative resource lists whenever `revision` advances.
|
|
27
|
+
*/
|
|
28
|
+
export const WorkspaceInteractionRevisionEvent = z
|
|
29
|
+
.object({
|
|
30
|
+
workspaceId: z.string().uuid(),
|
|
31
|
+
sequence: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
32
|
+
revision: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
33
|
+
type: z.literal("workspace.interaction.changed"),
|
|
34
|
+
occurredAt: z.string().datetime({ offset: true }),
|
|
35
|
+
})
|
|
36
|
+
.strict()
|
|
37
|
+
.refine((event) => event.sequence === event.revision, {
|
|
38
|
+
message: "interaction event sequence must equal revision",
|
|
39
|
+
path: ["sequence"],
|
|
40
|
+
});
|
|
41
|
+
export type WorkspaceInteractionRevisionEvent = z.infer<typeof WorkspaceInteractionRevisionEvent>;
|
|
19
42
|
|
|
20
43
|
const opaqueGeneration = z
|
|
21
44
|
.string()
|
|
22
45
|
.min(1)
|
|
23
46
|
.max(256)
|
|
24
47
|
.regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/u);
|
|
48
|
+
// Native bridge generations use unpadded base64url; both - and _ can lead.
|
|
49
|
+
// Keep the bytes unchanged: generation equality fences old connections.
|
|
50
|
+
const attachedBridgeGeneration = z
|
|
51
|
+
.string()
|
|
52
|
+
.min(1)
|
|
53
|
+
.max(256)
|
|
54
|
+
.regex(/^[A-Za-z0-9_-][A-Za-z0-9._:-]*$/u);
|
|
25
55
|
const boundedOpaqueId = z
|
|
26
56
|
.string()
|
|
27
57
|
.min(1)
|
|
@@ -168,6 +198,7 @@ export const BrowserSessionCapabilities = z
|
|
|
168
198
|
downloads: z.boolean(),
|
|
169
199
|
uploads: z.boolean(),
|
|
170
200
|
clipboard: z.boolean(),
|
|
201
|
+
permissions: z.boolean(),
|
|
171
202
|
diagnostics: z.boolean(),
|
|
172
203
|
rawCdp: z.boolean(),
|
|
173
204
|
linkedComputer: z.boolean(),
|
|
@@ -178,6 +209,11 @@ export const BrowserSessionCapabilities = z
|
|
|
178
209
|
.strict();
|
|
179
210
|
export type BrowserSessionCapabilities = z.infer<typeof BrowserSessionCapabilities>;
|
|
180
211
|
|
|
212
|
+
/** Versioned persistent discriminator for experimental disposable contexts. */
|
|
213
|
+
export { EPHEMERAL_CHROMIUM_DRIVER_ID, browserSessionStorageMode } from "./browser-storage";
|
|
214
|
+
export const BrowserStorageMode = z.enum(["private_profile", "ephemeral_context"]);
|
|
215
|
+
export type BrowserStorageMode = z.infer<typeof BrowserStorageMode>;
|
|
216
|
+
|
|
181
217
|
export const BrowserSession = z
|
|
182
218
|
.object({
|
|
183
219
|
id: z.string().uuid(),
|
|
@@ -205,6 +241,48 @@ export const BrowserSession = z
|
|
|
205
241
|
.strict();
|
|
206
242
|
export type BrowserSession = z.infer<typeof BrowserSession>;
|
|
207
243
|
|
|
244
|
+
/** Controller-private, BrowserSession-scoped clipboard. This is deliberately
|
|
245
|
+
* distinct from a ComputerSession/host OS clipboard so concurrent browsers do
|
|
246
|
+
* not exchange ambient machine state. */
|
|
247
|
+
export const BrowserClipboard = z
|
|
248
|
+
.object({
|
|
249
|
+
browserSessionId: z.string().uuid(),
|
|
250
|
+
controllerGeneration: opaqueGeneration,
|
|
251
|
+
revision: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
252
|
+
text: z
|
|
253
|
+
.string()
|
|
254
|
+
.max(INTERACTION_MAX_CLIPBOARD_BYTES)
|
|
255
|
+
.refine(
|
|
256
|
+
(value) => new TextEncoder().encode(value).byteLength <= INTERACTION_MAX_CLIPBOARD_BYTES,
|
|
257
|
+
{ message: "browser clipboard text exceeds its UTF-8 byte envelope" },
|
|
258
|
+
),
|
|
259
|
+
source: z.enum(["empty", "write", "clear", "copy", "paste"]),
|
|
260
|
+
sourceTargetId: boundedOpaqueId.nullable(),
|
|
261
|
+
updatedAt: z.string().datetime({ offset: true }).nullable(),
|
|
262
|
+
})
|
|
263
|
+
.strict()
|
|
264
|
+
.superRefine((clipboard, context) => {
|
|
265
|
+
if (clipboard.revision === 0) {
|
|
266
|
+
if (
|
|
267
|
+
clipboard.text !== "" ||
|
|
268
|
+
clipboard.source !== "empty" ||
|
|
269
|
+
clipboard.sourceTargetId !== null ||
|
|
270
|
+
clipboard.updatedAt !== null
|
|
271
|
+
) {
|
|
272
|
+
context.addIssue({
|
|
273
|
+
code: "custom",
|
|
274
|
+
message: "initial browser clipboard state must be empty",
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
} else if (clipboard.source === "empty" || clipboard.updatedAt === null) {
|
|
278
|
+
context.addIssue({
|
|
279
|
+
code: "custom",
|
|
280
|
+
message: "updated browser clipboard state requires a source and timestamp",
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
export type BrowserClipboard = z.infer<typeof BrowserClipboard>;
|
|
285
|
+
|
|
208
286
|
/** One live Chrome-profile bridge installed on an enrolled machine. This is a
|
|
209
287
|
* transport endpoint, not saved browser/login state: BrowserIdentity remains
|
|
210
288
|
* the immutable, reusable state abstraction. */
|
|
@@ -243,7 +321,7 @@ export type AttachedBrowserDeviceAnnouncement = z.infer<typeof AttachedBrowserDe
|
|
|
243
321
|
|
|
244
322
|
export const AttachedBrowserInventorySnapshot = z
|
|
245
323
|
.object({
|
|
246
|
-
bridgeGeneration:
|
|
324
|
+
bridgeGeneration: attachedBridgeGeneration,
|
|
247
325
|
revision: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
248
326
|
devices: z.array(AttachedBrowserDeviceAnnouncement).max(10_000),
|
|
249
327
|
})
|
|
@@ -298,9 +376,25 @@ export const AttachedBrowserDevice = z
|
|
|
298
376
|
});
|
|
299
377
|
export type AttachedBrowserDevice = z.infer<typeof AttachedBrowserDevice>;
|
|
300
378
|
|
|
379
|
+
/** One enrolled machine agent currently reporting its browser-bridge inventory.
|
|
380
|
+
* A bridge with zero devices is operational but has no Chrome profile connected
|
|
381
|
+
* through the OpenGeni extension yet. */
|
|
382
|
+
export const AttachedBrowserBridge = z
|
|
383
|
+
.object({
|
|
384
|
+
enrollmentId: z.string().uuid(),
|
|
385
|
+
state: z.enum(["online", "offline"]),
|
|
386
|
+
bridgeGeneration: attachedBridgeGeneration,
|
|
387
|
+
inventoryRevision: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
388
|
+
connectedProfileCount: z.number().int().nonnegative().max(10_000),
|
|
389
|
+
lastSeenAt: z.string().datetime({ offset: true }),
|
|
390
|
+
})
|
|
391
|
+
.strict();
|
|
392
|
+
export type AttachedBrowserBridge = z.infer<typeof AttachedBrowserBridge>;
|
|
393
|
+
|
|
301
394
|
export const AttachedBrowserDeviceListResponse = z
|
|
302
395
|
.object({
|
|
303
396
|
revision: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
397
|
+
bridges: z.array(AttachedBrowserBridge).max(10_000),
|
|
304
398
|
devices: z.array(AttachedBrowserDevice).max(10_000),
|
|
305
399
|
})
|
|
306
400
|
.strict();
|
|
@@ -444,6 +538,7 @@ export const BrowserIdentity = z
|
|
|
444
538
|
workspaceId: z.string().uuid(),
|
|
445
539
|
name: z.string().trim().min(1).max(200),
|
|
446
540
|
status: BrowserIdentityStatus,
|
|
541
|
+
version: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
447
542
|
defaultRevisionId: z.string().uuid().nullable(),
|
|
448
543
|
headGeneration: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
449
544
|
revisionCount: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -521,6 +616,93 @@ export const NetworkRouteConsistency = z
|
|
|
521
616
|
.strict();
|
|
522
617
|
export type NetworkRouteConsistency = z.infer<typeof NetworkRouteConsistency>;
|
|
523
618
|
|
|
619
|
+
export function interactionPlacementsEqual(
|
|
620
|
+
left: InteractionPlacement,
|
|
621
|
+
right: InteractionPlacement,
|
|
622
|
+
): boolean {
|
|
623
|
+
if (left.kind !== right.kind) return false;
|
|
624
|
+
switch (left.kind) {
|
|
625
|
+
case "sandbox_group":
|
|
626
|
+
return right.kind === "sandbox_group" && left.sandboxGroupId === right.sandboxGroupId;
|
|
627
|
+
case "connected_machine":
|
|
628
|
+
return right.kind === "connected_machine" && left.sandboxId === right.sandboxId;
|
|
629
|
+
case "attached_device":
|
|
630
|
+
return right.kind === "attached_device" && left.deviceId === right.deviceId;
|
|
631
|
+
case "external_provider":
|
|
632
|
+
return (
|
|
633
|
+
right.kind === "external_provider" &&
|
|
634
|
+
left.providerId === right.providerId &&
|
|
635
|
+
left.placementId === right.placementId
|
|
636
|
+
);
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
/** One secret-free compatibility rule shared by configuration, persistence,
|
|
641
|
+
* and launch. `null` placement means the ordinary managed sandbox default. */
|
|
642
|
+
export function networkRoutePlacementCompatibilityIssue(
|
|
643
|
+
configuration: NetworkRouteConfiguration,
|
|
644
|
+
consistency: NetworkRouteConsistency,
|
|
645
|
+
placement: InteractionPlacement | null,
|
|
646
|
+
): string | null {
|
|
647
|
+
if (configuration.kind === "tunnel") {
|
|
648
|
+
if (!placement || !interactionPlacementsEqual(configuration.placement, placement)) {
|
|
649
|
+
return "Tunnel route is bound to another placement";
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
if (configuration.kind === "managed") {
|
|
653
|
+
if (placement?.kind !== "external_provider") {
|
|
654
|
+
return "Managed NetworkRoutes require an external browser provider placement";
|
|
655
|
+
}
|
|
656
|
+
if (configuration.providerId !== placement.providerId) {
|
|
657
|
+
return "Managed NetworkRoute belongs to another external browser provider";
|
|
658
|
+
}
|
|
659
|
+
if (configuration.credential !== null) {
|
|
660
|
+
return "Managed provider routes cannot use a separate proxy credential";
|
|
661
|
+
}
|
|
662
|
+
if (consistency.dns !== "provider") {
|
|
663
|
+
return "Managed provider routes require provider DNS";
|
|
664
|
+
}
|
|
665
|
+
if (configuration.providerId === "browserbase") {
|
|
666
|
+
if (configuration.routeId !== "default" || configuration.egressClass !== "residential") {
|
|
667
|
+
return "Browserbase supports only its default managed residential route";
|
|
668
|
+
}
|
|
669
|
+
if (configuration.region !== null && !/^[A-Za-z]{2}$/u.test(configuration.region)) {
|
|
670
|
+
return "Browserbase managed route region must be a two-letter country code";
|
|
671
|
+
}
|
|
672
|
+
if (consistency.stability !== "session") {
|
|
673
|
+
return "Browserbase managed routing cannot promise a stable IP across sessions";
|
|
674
|
+
}
|
|
675
|
+
} else if (configuration.providerId !== "kernel") {
|
|
676
|
+
return `Managed NetworkRoute provider ${configuration.providerId} is unsupported`;
|
|
677
|
+
}
|
|
678
|
+
return null;
|
|
679
|
+
}
|
|
680
|
+
if (placement?.kind === "external_provider") {
|
|
681
|
+
return "External browser providers require a provider-managed NetworkRoute";
|
|
682
|
+
}
|
|
683
|
+
const expectedDns = configuration.kind === "proxy" ? "proxy" : "placement";
|
|
684
|
+
if (consistency.dns !== expectedDns) {
|
|
685
|
+
return `Network route ${configuration.kind} cannot provide ${consistency.dns} DNS`;
|
|
686
|
+
}
|
|
687
|
+
if (consistency.webRtc === "proxy_only" && configuration.kind !== "proxy") {
|
|
688
|
+
return "WebRTC proxy-only routing requires a proxy network route";
|
|
689
|
+
}
|
|
690
|
+
if (placement?.kind === "attached_device") {
|
|
691
|
+
if (configuration.kind === "proxy") {
|
|
692
|
+
return "Attached Chrome cannot change its process-scoped proxy configuration";
|
|
693
|
+
}
|
|
694
|
+
if (
|
|
695
|
+
consistency.locale !== null ||
|
|
696
|
+
consistency.timezone !== null ||
|
|
697
|
+
consistency.geolocation !== null ||
|
|
698
|
+
consistency.webRtc !== "default"
|
|
699
|
+
) {
|
|
700
|
+
return "Attached Chrome cannot change process-scoped route emulation";
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
|
|
524
706
|
export const NetworkRoute = z
|
|
525
707
|
.object({
|
|
526
708
|
id: z.string().uuid(),
|
|
@@ -637,6 +819,9 @@ export const SiteAuthAuthority = z.discriminatedUnion("kind", [
|
|
|
637
819
|
kind: z.literal("external_provider"),
|
|
638
820
|
label: z.string().trim().min(1).max(200),
|
|
639
821
|
adapterId: boundedOpaqueId,
|
|
822
|
+
/** Opaque provider-owned auth-connection reference. It is meaningful
|
|
823
|
+
* only to the named adapter and never treated as credential material. */
|
|
824
|
+
connectionId: boundedOpaqueId,
|
|
640
825
|
credential: InteractionCredentialAuthorityRef.nullable(),
|
|
641
826
|
})
|
|
642
827
|
.strict(),
|
|
@@ -673,6 +858,22 @@ export type SiteAuthHealthPolicy = z.infer<typeof SiteAuthHealthPolicy>;
|
|
|
673
858
|
export const SiteAuthVerificationState = z.enum(["unknown", "verified", "needs_repair", "failed"]);
|
|
674
859
|
export type SiteAuthVerificationState = z.infer<typeof SiteAuthVerificationState>;
|
|
675
860
|
|
|
861
|
+
export const SiteAuthMaintenance = z
|
|
862
|
+
.object({
|
|
863
|
+
action: z.enum(["health_check", "repair"]),
|
|
864
|
+
/** Hidden until the durable session start has been confirmed. */
|
|
865
|
+
sessionId: z.string().uuid().nullable(),
|
|
866
|
+
dueAt: z.string().datetime({ offset: true }),
|
|
867
|
+
startedAt: z.string().datetime({ offset: true }).nullable(),
|
|
868
|
+
})
|
|
869
|
+
.strict();
|
|
870
|
+
export type SiteAuthMaintenance = z.infer<typeof SiteAuthMaintenance>;
|
|
871
|
+
|
|
872
|
+
/** Trusted service provenance for scheduler-authored maintenance sessions. */
|
|
873
|
+
export const SITE_AUTH_MAINTENANCE_OPERATION_CONTEXT_KEY =
|
|
874
|
+
"opengeniSiteAuthMaintenanceOperationId" as const;
|
|
875
|
+
export const SITE_AUTH_MAINTENANCE_CONNECTION_CONTEXT_KEY = "opengeniSiteAuthConnectionId" as const;
|
|
876
|
+
|
|
676
877
|
const SiteAuthConnectionConfiguration = z
|
|
677
878
|
.object({
|
|
678
879
|
name: z.string().trim().min(1).max(200),
|
|
@@ -693,6 +894,17 @@ function validateSiteAuthConfiguration(
|
|
|
693
894
|
connection: z.infer<typeof SiteAuthConnectionConfiguration>,
|
|
694
895
|
context: z.RefinementCtx,
|
|
695
896
|
): void {
|
|
897
|
+
if (
|
|
898
|
+
connection.preferredIdentityId &&
|
|
899
|
+
(connection.preferredPlacement?.kind === "attached_device" ||
|
|
900
|
+
connection.preferredPlacement?.kind === "external_provider")
|
|
901
|
+
) {
|
|
902
|
+
context.addIssue({
|
|
903
|
+
code: "custom",
|
|
904
|
+
path: ["preferredIdentityId"],
|
|
905
|
+
message: "the preferred placement owns its live profile identity",
|
|
906
|
+
});
|
|
907
|
+
}
|
|
696
908
|
if (new Set(connection.origins).size !== connection.origins.length) {
|
|
697
909
|
context.addIssue({ code: "custom", path: ["origins"], message: "origins repeat" });
|
|
698
910
|
}
|
|
@@ -767,6 +979,9 @@ export const SiteAuthConnection = SiteAuthConnectionConfiguration.extend({
|
|
|
767
979
|
verificationState: SiteAuthVerificationState,
|
|
768
980
|
lastVerifiedAt: z.string().datetime({ offset: true }).nullable(),
|
|
769
981
|
lastVerifiedUrl: boundedUrl.nullable(),
|
|
982
|
+
lastCheckedAt: z.string().datetime({ offset: true }).nullable(),
|
|
983
|
+
nextCheckAt: z.string().datetime({ offset: true }).nullable(),
|
|
984
|
+
maintenance: SiteAuthMaintenance.nullable(),
|
|
770
985
|
repairCode: boundedOpaqueId.nullable(),
|
|
771
986
|
version: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
772
987
|
createdBySubjectId: z.string().min(1).max(1_024),
|
|
@@ -862,6 +1077,7 @@ export const AuthRun = z
|
|
|
862
1077
|
controllerGeneration: opaqueGeneration,
|
|
863
1078
|
targetGeneration: opaqueGeneration,
|
|
864
1079
|
documentGeneration: opaqueGeneration.nullable(),
|
|
1080
|
+
purpose: z.enum(["authenticate", "health_check", "repair"]),
|
|
865
1081
|
methodId: boundedOpaqueId.nullable(),
|
|
866
1082
|
authorityId: boundedOpaqueId.nullable(),
|
|
867
1083
|
state: AuthRunState,
|
|
@@ -945,15 +1161,15 @@ export const StartAuthRunRequest = z
|
|
|
945
1161
|
targetId: boundedOpaqueId,
|
|
946
1162
|
expectedTargetGeneration: opaqueGeneration,
|
|
947
1163
|
expectedDocumentGeneration: opaqueGeneration.nullable(),
|
|
1164
|
+
purpose: z.enum(["authenticate", "health_check", "repair"]).optional(),
|
|
948
1165
|
methodId: boundedOpaqueId.optional(),
|
|
949
1166
|
authorityId: boundedOpaqueId.optional(),
|
|
950
1167
|
})
|
|
951
1168
|
.strict();
|
|
952
1169
|
export type StartAuthRunRequest = z.infer<typeof StartAuthRunRequest>;
|
|
953
1170
|
|
|
954
|
-
export const
|
|
1171
|
+
export const ReportAuthRunPayload = z
|
|
955
1172
|
.object({
|
|
956
|
-
operationId: z.string().uuid(),
|
|
957
1173
|
expectedVersion: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
958
1174
|
methodId: boundedOpaqueId.optional(),
|
|
959
1175
|
authorityId: boundedOpaqueId.optional(),
|
|
@@ -1001,6 +1217,11 @@ export const ReportAuthRunRequest = z
|
|
|
1001
1217
|
});
|
|
1002
1218
|
}
|
|
1003
1219
|
});
|
|
1220
|
+
export type ReportAuthRunPayload = z.infer<typeof ReportAuthRunPayload>;
|
|
1221
|
+
|
|
1222
|
+
export const ReportAuthRunRequest = ReportAuthRunPayload.safeExtend({
|
|
1223
|
+
operationId: z.string().uuid(),
|
|
1224
|
+
});
|
|
1004
1225
|
export type ReportAuthRunRequest = z.infer<typeof ReportAuthRunRequest>;
|
|
1005
1226
|
|
|
1006
1227
|
export const ProtectedAuthField = z
|
|
@@ -1045,6 +1266,101 @@ export const ProtectedAuthFillResponse = z
|
|
|
1045
1266
|
.strict();
|
|
1046
1267
|
export type ProtectedAuthFillResponse = z.infer<typeof ProtectedAuthFillResponse>;
|
|
1047
1268
|
|
|
1269
|
+
/** Public request for advancing a provider-managed AuthRun. Provider secrets,
|
|
1270
|
+
* profile names, browser ids, and hosted-login URLs stay behind browserd. */
|
|
1271
|
+
export const ExternalAuthRunRequest = z
|
|
1272
|
+
.object({
|
|
1273
|
+
operationId: z.string().uuid(),
|
|
1274
|
+
expectedVersion: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
1275
|
+
action: z.enum(["start", "poll"]),
|
|
1276
|
+
})
|
|
1277
|
+
.strict();
|
|
1278
|
+
export type ExternalAuthRunRequest = z.infer<typeof ExternalAuthRunRequest>;
|
|
1279
|
+
|
|
1280
|
+
export const ExternalAuthRunResponse = z
|
|
1281
|
+
.object({
|
|
1282
|
+
run: AuthRun,
|
|
1283
|
+
status: z.enum(["working", "needs_human", "ready_to_verify", "failed"]),
|
|
1284
|
+
operationId: z.string().uuid(),
|
|
1285
|
+
replayed: z.boolean(),
|
|
1286
|
+
})
|
|
1287
|
+
.strict();
|
|
1288
|
+
export type ExternalAuthRunResponse = z.infer<typeof ExternalAuthRunResponse>;
|
|
1289
|
+
|
|
1290
|
+
/** Human-only request for opening the provider's ephemeral hosted login UI. */
|
|
1291
|
+
export const ExternalAuthInteractiveRequest = z
|
|
1292
|
+
.object({
|
|
1293
|
+
operationId: z.string().uuid(),
|
|
1294
|
+
expectedVersion: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
1295
|
+
})
|
|
1296
|
+
.strict();
|
|
1297
|
+
export type ExternalAuthInteractiveRequest = z.infer<typeof ExternalAuthInteractiveRequest>;
|
|
1298
|
+
|
|
1299
|
+
export const ExternalAuthInteractiveResponse = z
|
|
1300
|
+
.object({
|
|
1301
|
+
authRunId: z.string().uuid(),
|
|
1302
|
+
url: boundedHttpUrl,
|
|
1303
|
+
expiresAt: z.string().datetime({ offset: true }).nullable(),
|
|
1304
|
+
})
|
|
1305
|
+
.strict();
|
|
1306
|
+
export type ExternalAuthInteractiveResponse = z.infer<typeof ExternalAuthInteractiveResponse>;
|
|
1307
|
+
|
|
1308
|
+
/** Controller-private Kernel/host-adapter command. This crosses only the
|
|
1309
|
+
* authenticated API -> browserd control channel; it is not a model tool. */
|
|
1310
|
+
export const BrowserExternalAuthCommand = z
|
|
1311
|
+
.object({
|
|
1312
|
+
browserSessionId: z.string().uuid(),
|
|
1313
|
+
controllerGeneration: opaqueGeneration,
|
|
1314
|
+
operationId: z.string().uuid(),
|
|
1315
|
+
authRunId: z.string().uuid(),
|
|
1316
|
+
adapterId: boundedOpaqueId,
|
|
1317
|
+
connectionId: boundedOpaqueId,
|
|
1318
|
+
action: z.enum(["start", "poll", "interactive"]),
|
|
1319
|
+
})
|
|
1320
|
+
.strict();
|
|
1321
|
+
export type BrowserExternalAuthCommand = z.infer<typeof BrowserExternalAuthCommand>;
|
|
1322
|
+
|
|
1323
|
+
export const BrowserExternalAuthResult = z
|
|
1324
|
+
.object({
|
|
1325
|
+
state: z.enum(["authenticated", "in_progress", "needs_human", "failed"]),
|
|
1326
|
+
externalAction: AuthRunExternalAction.nullable(),
|
|
1327
|
+
interactiveUrl: boundedHttpUrl.nullable(),
|
|
1328
|
+
failureCode: boundedOpaqueId.nullable(),
|
|
1329
|
+
profileLoaded: z.boolean(),
|
|
1330
|
+
})
|
|
1331
|
+
.strict()
|
|
1332
|
+
.superRefine((result, context) => {
|
|
1333
|
+
if ((result.state === "needs_human") !== (result.externalAction !== null)) {
|
|
1334
|
+
context.addIssue({
|
|
1335
|
+
code: "custom",
|
|
1336
|
+
path: ["externalAction"],
|
|
1337
|
+
message: "human external-auth state requires an action",
|
|
1338
|
+
});
|
|
1339
|
+
}
|
|
1340
|
+
if ((result.state === "failed") !== (result.failureCode !== null)) {
|
|
1341
|
+
context.addIssue({
|
|
1342
|
+
code: "custom",
|
|
1343
|
+
path: ["failureCode"],
|
|
1344
|
+
message: "failed external-auth state requires a failure code",
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
if (result.interactiveUrl !== null && result.state !== "needs_human") {
|
|
1348
|
+
context.addIssue({
|
|
1349
|
+
code: "custom",
|
|
1350
|
+
path: ["interactiveUrl"],
|
|
1351
|
+
message: "interactive URL requires a human external-auth state",
|
|
1352
|
+
});
|
|
1353
|
+
}
|
|
1354
|
+
if (result.profileLoaded && result.state !== "authenticated") {
|
|
1355
|
+
context.addIssue({
|
|
1356
|
+
code: "custom",
|
|
1357
|
+
path: ["profileLoaded"],
|
|
1358
|
+
message: "only authenticated external auth can load a profile",
|
|
1359
|
+
});
|
|
1360
|
+
}
|
|
1361
|
+
});
|
|
1362
|
+
export type BrowserExternalAuthResult = z.infer<typeof BrowserExternalAuthResult>;
|
|
1363
|
+
|
|
1048
1364
|
export const VerifyAuthRunRequest = z
|
|
1049
1365
|
.object({
|
|
1050
1366
|
operationId: z.string().uuid(),
|
|
@@ -1140,6 +1456,38 @@ export type InteractionInterventionMutationResponse = z.infer<
|
|
|
1140
1456
|
typeof InteractionInterventionMutationResponse
|
|
1141
1457
|
>;
|
|
1142
1458
|
|
|
1459
|
+
/** Canonical model/Codemode input for one typed browser/computer human wait. */
|
|
1460
|
+
export const INTERACTION_REQUEST_HUMAN_MODEL_TOOL_NAME = "interaction__interaction_request_human";
|
|
1461
|
+
|
|
1462
|
+
export const RequestHumanInteractionToolInput = z.discriminatedUnion("operation", [
|
|
1463
|
+
z.object({ operation: z.literal("wait"), interventionId: z.string().uuid() }).strict(),
|
|
1464
|
+
z
|
|
1465
|
+
.object({
|
|
1466
|
+
operation: z.literal("request"),
|
|
1467
|
+
resourceKind: z.enum(["browser_session", "computer_session"]),
|
|
1468
|
+
resourceId: z.string().uuid(),
|
|
1469
|
+
targetId: boundedOpaqueId,
|
|
1470
|
+
expectedControllerGeneration: opaqueGeneration,
|
|
1471
|
+
expectedTargetGeneration: opaqueGeneration,
|
|
1472
|
+
expectedDocumentGeneration: opaqueGeneration.nullable(),
|
|
1473
|
+
kind: z.enum(["manual_login", "mfa", "external_action", "confirmation", "other"]),
|
|
1474
|
+
reason: z.string().trim().min(1).max(2_048),
|
|
1475
|
+
authRunId: z.string().uuid().optional(),
|
|
1476
|
+
expiresInSeconds: z.number().int().min(30).max(86_400).default(900),
|
|
1477
|
+
})
|
|
1478
|
+
.strict(),
|
|
1479
|
+
]);
|
|
1480
|
+
export type RequestHumanInteractionToolInput = z.infer<typeof RequestHumanInteractionToolInput>;
|
|
1481
|
+
|
|
1482
|
+
export const RequestHumanInteractionToolOutput = z
|
|
1483
|
+
.object({
|
|
1484
|
+
intervention: InteractionIntervention,
|
|
1485
|
+
observation: z.lazy(() => z.union([BrowserObservation, ComputerObservation])).nullable(),
|
|
1486
|
+
observationErrorCode: z.string().min(1).max(128).nullable(),
|
|
1487
|
+
})
|
|
1488
|
+
.strict();
|
|
1489
|
+
export type RequestHumanInteractionToolOutput = z.infer<typeof RequestHumanInteractionToolOutput>;
|
|
1490
|
+
|
|
1143
1491
|
export const BrowserIdentityListResponse = z
|
|
1144
1492
|
.object({
|
|
1145
1493
|
revision: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
@@ -1164,6 +1512,24 @@ export const CreateBrowserIdentityRequest = z
|
|
|
1164
1512
|
.strict();
|
|
1165
1513
|
export type CreateBrowserIdentityRequest = z.infer<typeof CreateBrowserIdentityRequest>;
|
|
1166
1514
|
|
|
1515
|
+
export const UpdateBrowserIdentityRequest = z
|
|
1516
|
+
.object({
|
|
1517
|
+
operationId: z.string().uuid(),
|
|
1518
|
+
expectedVersion: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
1519
|
+
name: z.string().trim().min(1).max(200).optional(),
|
|
1520
|
+
status: BrowserIdentityStatus.optional(),
|
|
1521
|
+
defaultRevisionId: z.string().uuid().optional(),
|
|
1522
|
+
})
|
|
1523
|
+
.strict()
|
|
1524
|
+
.refine(
|
|
1525
|
+
(value) =>
|
|
1526
|
+
value.name !== undefined ||
|
|
1527
|
+
value.status !== undefined ||
|
|
1528
|
+
value.defaultRevisionId !== undefined,
|
|
1529
|
+
{ message: "browser identity update is empty" },
|
|
1530
|
+
);
|
|
1531
|
+
export type UpdateBrowserIdentityRequest = z.infer<typeof UpdateBrowserIdentityRequest>;
|
|
1532
|
+
|
|
1167
1533
|
export const BrowserIdentityMutationResponse = z
|
|
1168
1534
|
.object({
|
|
1169
1535
|
identity: BrowserIdentity,
|
|
@@ -1212,6 +1578,155 @@ export const BrowserTarget = z
|
|
|
1212
1578
|
.strict();
|
|
1213
1579
|
export type BrowserTarget = z.infer<typeof BrowserTarget>;
|
|
1214
1580
|
|
|
1581
|
+
export const BrowserDownloadStatus = z.enum([
|
|
1582
|
+
"in_progress",
|
|
1583
|
+
"completed",
|
|
1584
|
+
"cancelled",
|
|
1585
|
+
"failed",
|
|
1586
|
+
"unavailable",
|
|
1587
|
+
]);
|
|
1588
|
+
export type BrowserDownloadStatus = z.infer<typeof BrowserDownloadStatus>;
|
|
1589
|
+
|
|
1590
|
+
/** One browser-produced file. Its bytes remain private to the exact controller
|
|
1591
|
+
* until an explicit save publishes and materializes them. No placement path or
|
|
1592
|
+
* source URL crosses this contract. */
|
|
1593
|
+
export const BrowserDownload = z
|
|
1594
|
+
.object({
|
|
1595
|
+
id: z.string().uuid(),
|
|
1596
|
+
browserSessionId: z.string().uuid(),
|
|
1597
|
+
controllerGeneration: opaqueGeneration,
|
|
1598
|
+
targetId: boundedOpaqueId.nullable(),
|
|
1599
|
+
filename: z
|
|
1600
|
+
.string()
|
|
1601
|
+
.min(1)
|
|
1602
|
+
.max(4_096)
|
|
1603
|
+
.regex(/^[^\u0000-\u001f\u007f]+$/u),
|
|
1604
|
+
status: BrowserDownloadStatus,
|
|
1605
|
+
receivedBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
1606
|
+
totalBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER).nullable(),
|
|
1607
|
+
sha256: sha256Hex.nullable(),
|
|
1608
|
+
version: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
1609
|
+
startedAt: z.string().datetime({ offset: true }),
|
|
1610
|
+
settledAt: z.string().datetime({ offset: true }).nullable(),
|
|
1611
|
+
failureCode: boundedOpaqueId.nullable(),
|
|
1612
|
+
})
|
|
1613
|
+
.strict()
|
|
1614
|
+
.superRefine((download, context) => {
|
|
1615
|
+
const terminal = download.status !== "in_progress";
|
|
1616
|
+
if (terminal !== (download.settledAt !== null)) {
|
|
1617
|
+
context.addIssue({
|
|
1618
|
+
code: "custom",
|
|
1619
|
+
path: ["settledAt"],
|
|
1620
|
+
message: "download settlement must match its terminal status",
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
if (
|
|
1624
|
+
(download.status === "failed" || download.status === "unavailable") !==
|
|
1625
|
+
(download.failureCode !== null)
|
|
1626
|
+
) {
|
|
1627
|
+
context.addIssue({
|
|
1628
|
+
code: "custom",
|
|
1629
|
+
path: ["failureCode"],
|
|
1630
|
+
message: "failed or unavailable downloads require one failure code",
|
|
1631
|
+
});
|
|
1632
|
+
}
|
|
1633
|
+
if (download.status === "completed") {
|
|
1634
|
+
if (download.sha256 === null || download.totalBytes !== download.receivedBytes) {
|
|
1635
|
+
context.addIssue({
|
|
1636
|
+
code: "custom",
|
|
1637
|
+
path: ["sha256"],
|
|
1638
|
+
message: "completed downloads require exact bytes and SHA-256",
|
|
1639
|
+
});
|
|
1640
|
+
}
|
|
1641
|
+
} else if (download.sha256 !== null) {
|
|
1642
|
+
context.addIssue({
|
|
1643
|
+
code: "custom",
|
|
1644
|
+
path: ["sha256"],
|
|
1645
|
+
message: "only completed downloads carry a SHA-256",
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
});
|
|
1649
|
+
export type BrowserDownload = z.infer<typeof BrowserDownload>;
|
|
1650
|
+
|
|
1651
|
+
export const BrowserDownloadListResponse = z
|
|
1652
|
+
.object({
|
|
1653
|
+
browserSessionId: z.string().uuid(),
|
|
1654
|
+
controllerGeneration: opaqueGeneration,
|
|
1655
|
+
downloads: z.array(BrowserDownload).max(10_000),
|
|
1656
|
+
})
|
|
1657
|
+
.strict();
|
|
1658
|
+
export type BrowserDownloadListResponse = z.infer<typeof BrowserDownloadListResponse>;
|
|
1659
|
+
|
|
1660
|
+
const workspaceRelativeFilePath = z
|
|
1661
|
+
.string()
|
|
1662
|
+
.min(1)
|
|
1663
|
+
.max(4_096)
|
|
1664
|
+
.refine((value) => {
|
|
1665
|
+
if (value !== value.trim() || value.startsWith("/") || /^[A-Za-z]:[\\/]/u.test(value)) {
|
|
1666
|
+
return false;
|
|
1667
|
+
}
|
|
1668
|
+
if (value.includes("\\") || value.includes("\0")) return false;
|
|
1669
|
+
const segments = value.split("/");
|
|
1670
|
+
return segments.every(
|
|
1671
|
+
(segment) =>
|
|
1672
|
+
segment.length > 0 &&
|
|
1673
|
+
segment !== "." &&
|
|
1674
|
+
segment !== ".." &&
|
|
1675
|
+
!/[<>:"|?*\u0000-\u001f\u007f]/u.test(segment) &&
|
|
1676
|
+
!/[ .]$/u.test(segment) &&
|
|
1677
|
+
!/^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(segment),
|
|
1678
|
+
);
|
|
1679
|
+
}, "destinationPath must be a portable workspace-relative file path");
|
|
1680
|
+
|
|
1681
|
+
export const BrowserDownloadSaveRequest = z
|
|
1682
|
+
.object({
|
|
1683
|
+
operationId: z.string().uuid(),
|
|
1684
|
+
destinationPath: workspaceRelativeFilePath,
|
|
1685
|
+
overwrite: z.boolean().default(false),
|
|
1686
|
+
})
|
|
1687
|
+
.strict();
|
|
1688
|
+
export type BrowserDownloadSaveRequest = z.infer<typeof BrowserDownloadSaveRequest>;
|
|
1689
|
+
|
|
1690
|
+
export const BrowserDownloadSaveResponse = z
|
|
1691
|
+
.object({
|
|
1692
|
+
download: BrowserDownload,
|
|
1693
|
+
destinationPath: workspaceRelativeFilePath,
|
|
1694
|
+
fileId: z.string().uuid(),
|
|
1695
|
+
operationId: z.string().uuid(),
|
|
1696
|
+
replayed: z.boolean(),
|
|
1697
|
+
})
|
|
1698
|
+
.strict();
|
|
1699
|
+
export type BrowserDownloadSaveResponse = z.infer<typeof BrowserDownloadSaveResponse>;
|
|
1700
|
+
|
|
1701
|
+
/** Controller-private, narrow object authority for publishing one exact
|
|
1702
|
+
* completed download. Signed URLs and headers never appear in public SDK or
|
|
1703
|
+
* durable controller receipts. */
|
|
1704
|
+
export const BrowserDownloadExportRequest = z
|
|
1705
|
+
.object({
|
|
1706
|
+
operationId: z.string().uuid(),
|
|
1707
|
+
downloadId: z.string().uuid(),
|
|
1708
|
+
upload: z
|
|
1709
|
+
.object({
|
|
1710
|
+
url: boundedHttpUrl,
|
|
1711
|
+
requiredHeaders: z.record(z.string().min(1).max(256), z.string().max(8_192)),
|
|
1712
|
+
expiresAt: z.string().datetime({ offset: true }),
|
|
1713
|
+
})
|
|
1714
|
+
.strict(),
|
|
1715
|
+
})
|
|
1716
|
+
.strict();
|
|
1717
|
+
export type BrowserDownloadExportRequest = z.infer<typeof BrowserDownloadExportRequest>;
|
|
1718
|
+
|
|
1719
|
+
export const BrowserDownloadExportReceipt = z
|
|
1720
|
+
.object({
|
|
1721
|
+
operationId: z.string().uuid(),
|
|
1722
|
+
downloadId: z.string().uuid(),
|
|
1723
|
+
sizeBytes: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
1724
|
+
sha256: sha256Hex,
|
|
1725
|
+
replayed: z.boolean(),
|
|
1726
|
+
})
|
|
1727
|
+
.strict();
|
|
1728
|
+
export type BrowserDownloadExportReceipt = z.infer<typeof BrowserDownloadExportReceipt>;
|
|
1729
|
+
|
|
1215
1730
|
export const InteractionRect = z
|
|
1216
1731
|
.object({
|
|
1217
1732
|
x: z.number().finite(),
|
|
@@ -1313,6 +1828,18 @@ export const BrowserObservation = z
|
|
|
1313
1828
|
frameId: opaqueGeneration.nullable(),
|
|
1314
1829
|
semantic: z.union([InteractionSemanticSnapshot, InteractionSemanticDiff]).nullable(),
|
|
1315
1830
|
screenshot: RetainedArtifactReferenceSchema.nullable(),
|
|
1831
|
+
viewport: z
|
|
1832
|
+
.object({
|
|
1833
|
+
width: z.number().int().positive(),
|
|
1834
|
+
height: z.number().int().positive(),
|
|
1835
|
+
visualWidth: z.number().positive(),
|
|
1836
|
+
visualHeight: z.number().positive(),
|
|
1837
|
+
deviceScaleFactor: z.number().positive(),
|
|
1838
|
+
maxTouchPoints: z.number().int().nonnegative(),
|
|
1839
|
+
})
|
|
1840
|
+
.strict()
|
|
1841
|
+
.nullable()
|
|
1842
|
+
.optional(),
|
|
1316
1843
|
focusedRef: boundedOpaqueId.nullable(),
|
|
1317
1844
|
changedRegions: z.array(InteractionRect).max(INTERACTION_MAX_CHANGED_NODES),
|
|
1318
1845
|
diagnostics: InteractionDiagnosticSummary,
|
|
@@ -1381,6 +1908,90 @@ export const BrowserLocator = z.discriminatedUnion("kind", [
|
|
|
1381
1908
|
]);
|
|
1382
1909
|
export type BrowserLocator = z.infer<typeof BrowserLocator>;
|
|
1383
1910
|
|
|
1911
|
+
/** Cheap causal state for a target. This is intentionally independent of an
|
|
1912
|
+
* accessibility observation, which can require a full tree for every frame. */
|
|
1913
|
+
export const BrowserTargetState = z
|
|
1914
|
+
.object({
|
|
1915
|
+
browserSessionId: z.string().uuid(),
|
|
1916
|
+
controllerGeneration: opaqueGeneration,
|
|
1917
|
+
targetId: boundedOpaqueId,
|
|
1918
|
+
targetGeneration: opaqueGeneration,
|
|
1919
|
+
documentGeneration: opaqueGeneration.nullable(),
|
|
1920
|
+
frameId: opaqueGeneration.nullable(),
|
|
1921
|
+
})
|
|
1922
|
+
.strict();
|
|
1923
|
+
export type BrowserTargetState = z.infer<typeof BrowserTargetState>;
|
|
1924
|
+
|
|
1925
|
+
export const BrowserDomSafeAttribute = z.enum([
|
|
1926
|
+
"href",
|
|
1927
|
+
"src",
|
|
1928
|
+
"alt",
|
|
1929
|
+
"title",
|
|
1930
|
+
"role",
|
|
1931
|
+
"aria-label",
|
|
1932
|
+
"aria-expanded",
|
|
1933
|
+
"aria-checked",
|
|
1934
|
+
"aria-selected",
|
|
1935
|
+
"placeholder",
|
|
1936
|
+
"type",
|
|
1937
|
+
"name",
|
|
1938
|
+
"data-testid",
|
|
1939
|
+
]);
|
|
1940
|
+
export type BrowserDomSafeAttribute = z.infer<typeof BrowserDomSafeAttribute>;
|
|
1941
|
+
|
|
1942
|
+
export const BrowserDomReadSelector = z
|
|
1943
|
+
.string()
|
|
1944
|
+
.min(1)
|
|
1945
|
+
.max(8_192)
|
|
1946
|
+
.regex(/^[A-Za-z0-9_#.,\s>*-]+$/u);
|
|
1947
|
+
|
|
1948
|
+
/** DOM extraction avoids content-matching locators, which can probe redacted text. */
|
|
1949
|
+
export const BrowserDomReadLocator = z.discriminatedUnion("kind", [
|
|
1950
|
+
z.object({ kind: z.literal("ref"), ref: boundedOpaqueId }).strict(),
|
|
1951
|
+
z.object({ kind: z.literal("placeholder"), text: z.string().min(1).max(8_192) }).strict(),
|
|
1952
|
+
z.object({ kind: z.literal("test_id"), value: z.string().min(1).max(2_048) }).strict(),
|
|
1953
|
+
z.object({ kind: z.literal("css"), selector: BrowserDomReadSelector }).strict(),
|
|
1954
|
+
]);
|
|
1955
|
+
export type BrowserDomReadLocator = z.infer<typeof BrowserDomReadLocator>;
|
|
1956
|
+
|
|
1957
|
+
const BrowserDomReadFence = z.object({
|
|
1958
|
+
expectedTargetGeneration: opaqueGeneration,
|
|
1959
|
+
expectedDocumentGeneration: opaqueGeneration,
|
|
1960
|
+
expectedFrameId: opaqueGeneration,
|
|
1961
|
+
});
|
|
1962
|
+
|
|
1963
|
+
/** A fixed, read-only query. The caller never supplies executable JavaScript.
|
|
1964
|
+
* CSS reads accept only simple tag, class, id, descendant, and child selectors
|
|
1965
|
+
* so predicate queries cannot probe protected attribute values. CSS count is
|
|
1966
|
+
* scoped to the target's main document; child frames and shadow roots are not
|
|
1967
|
+
* part of its count. */
|
|
1968
|
+
export const BrowserDomReadRequest = z.discriminatedUnion("kind", [
|
|
1969
|
+
BrowserDomReadFence.extend({
|
|
1970
|
+
kind: z.literal("element"),
|
|
1971
|
+
locator: BrowserDomReadLocator,
|
|
1972
|
+
attributes: z.array(BrowserDomSafeAttribute).max(13).optional(),
|
|
1973
|
+
maxChars: z.number().int().min(1).max(32_768).optional(),
|
|
1974
|
+
}).strict(),
|
|
1975
|
+
BrowserDomReadFence.extend({
|
|
1976
|
+
kind: z.literal("count"),
|
|
1977
|
+
selector: BrowserDomReadSelector,
|
|
1978
|
+
}).strict(),
|
|
1979
|
+
]);
|
|
1980
|
+
export type BrowserDomReadRequest = z.infer<typeof BrowserDomReadRequest>;
|
|
1981
|
+
|
|
1982
|
+
export const BrowserDomReadResponse = BrowserTargetState.extend({
|
|
1983
|
+
kind: z.enum(["element", "count"]),
|
|
1984
|
+
count: z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER),
|
|
1985
|
+
text: z.string().max(32_768).nullable().optional(),
|
|
1986
|
+
value: z.string().max(32_768).nullable().optional(),
|
|
1987
|
+
attributes: z
|
|
1988
|
+
.partialRecord(BrowserDomSafeAttribute, z.string().max(32_768).nullable())
|
|
1989
|
+
.optional(),
|
|
1990
|
+
redacted: z.enum(["password", "payment", "private", "policy"]).nullable().optional(),
|
|
1991
|
+
truncated: z.boolean(),
|
|
1992
|
+
}).strict();
|
|
1993
|
+
export type BrowserDomReadResponse = z.infer<typeof BrowserDomReadResponse>;
|
|
1994
|
+
|
|
1384
1995
|
/** Provider-neutral locator for native accessibility trees. Native automation
|
|
1385
1996
|
* identifiers are intentionally distinct from DOM selectors/test ids: AX,
|
|
1386
1997
|
* AT-SPI, and UIA adapters resolve them inside the exact observed target. */
|
|
@@ -1417,8 +2028,39 @@ export const ComputerLocator = z.discriminatedUnion("kind", [
|
|
|
1417
2028
|
]);
|
|
1418
2029
|
export type ComputerLocator = z.infer<typeof ComputerLocator>;
|
|
1419
2030
|
|
|
2031
|
+
/** Web-platform permissions which a managed browser can set for the exact
|
|
2032
|
+
* top-level origin currently fenced by a BrowserActionCommand. Names remain
|
|
2033
|
+
* provider-neutral; drivers map them to their native permission descriptors. */
|
|
2034
|
+
export const BrowserPermission = z.enum([
|
|
2035
|
+
"geolocation",
|
|
2036
|
+
"notifications",
|
|
2037
|
+
"camera",
|
|
2038
|
+
"microphone",
|
|
2039
|
+
"midi",
|
|
2040
|
+
"midi_sysex",
|
|
2041
|
+
"sensors",
|
|
2042
|
+
"idle_detection",
|
|
2043
|
+
"local_fonts",
|
|
2044
|
+
"window_management",
|
|
2045
|
+
]);
|
|
2046
|
+
export type BrowserPermission = z.infer<typeof BrowserPermission>;
|
|
2047
|
+
|
|
2048
|
+
export const BrowserPermissionSetting = z.enum(["granted", "denied", "prompt"]);
|
|
2049
|
+
export type BrowserPermissionSetting = z.infer<typeof BrowserPermissionSetting>;
|
|
2050
|
+
|
|
1420
2051
|
const browserActionVariants = [
|
|
1421
2052
|
z.object({ type: z.literal("navigate"), url: boundedUrl }).strict(),
|
|
2053
|
+
z.object({ type: z.literal("history"), direction: z.enum(["back", "forward"]) }).strict(),
|
|
2054
|
+
z.object({ type: z.literal("activate") }).strict(),
|
|
2055
|
+
z
|
|
2056
|
+
.object({
|
|
2057
|
+
type: z.literal("viewport"),
|
|
2058
|
+
width: z.number().int().min(240).max(4_096),
|
|
2059
|
+
height: z.number().int().min(240).max(4_096),
|
|
2060
|
+
mobile: z.boolean(),
|
|
2061
|
+
deviceScaleFactor: z.number().min(0.5).max(4).optional(),
|
|
2062
|
+
})
|
|
2063
|
+
.strict(),
|
|
1422
2064
|
z
|
|
1423
2065
|
.object({
|
|
1424
2066
|
type: z.literal("click"),
|
|
@@ -1489,6 +2131,7 @@ const browserActionVariants = [
|
|
|
1489
2131
|
deltaX: z.number().finite().min(-1_000_000).max(1_000_000).optional(),
|
|
1490
2132
|
deltaY: z.number().finite().min(-1_000_000).max(1_000_000).optional(),
|
|
1491
2133
|
button: z.enum(["left", "right", "middle"]).optional(),
|
|
2134
|
+
clickCount: z.union([z.literal(1), z.literal(2)]).optional(),
|
|
1492
2135
|
})
|
|
1493
2136
|
.strict()
|
|
1494
2137
|
.superRefine((action, context) => {
|
|
@@ -1522,6 +2165,12 @@ const browserActionVariants = [
|
|
|
1522
2165
|
message: "pointer deltas require scroll",
|
|
1523
2166
|
});
|
|
1524
2167
|
}
|
|
2168
|
+
if (action.action !== "click" && action.clickCount !== undefined) {
|
|
2169
|
+
context.addIssue({
|
|
2170
|
+
code: "custom",
|
|
2171
|
+
message: "pointer clickCount requires click",
|
|
2172
|
+
});
|
|
2173
|
+
}
|
|
1525
2174
|
}),
|
|
1526
2175
|
z
|
|
1527
2176
|
.object({
|
|
@@ -1537,6 +2186,84 @@ const browserActionVariants = [
|
|
|
1537
2186
|
workspaceFileIds: z.array(z.string().uuid()).min(1).max(100),
|
|
1538
2187
|
})
|
|
1539
2188
|
.strict(),
|
|
2189
|
+
z
|
|
2190
|
+
.object({
|
|
2191
|
+
type: z.literal("clipboard"),
|
|
2192
|
+
operation: z.enum(["write", "clear", "copy", "paste"]),
|
|
2193
|
+
text: z
|
|
2194
|
+
.string()
|
|
2195
|
+
.max(INTERACTION_MAX_CLIPBOARD_BYTES)
|
|
2196
|
+
.refine(
|
|
2197
|
+
(value) => new TextEncoder().encode(value).byteLength <= INTERACTION_MAX_CLIPBOARD_BYTES,
|
|
2198
|
+
{ message: "browser clipboard text exceeds its UTF-8 byte envelope" },
|
|
2199
|
+
)
|
|
2200
|
+
.optional(),
|
|
2201
|
+
locator: BrowserLocator.optional(),
|
|
2202
|
+
content: z.enum(["selection", "value", "text"]).optional(),
|
|
2203
|
+
})
|
|
2204
|
+
.strict()
|
|
2205
|
+
.superRefine((action, context) => {
|
|
2206
|
+
if (action.operation === "write") {
|
|
2207
|
+
if (action.text === undefined) {
|
|
2208
|
+
context.addIssue({
|
|
2209
|
+
code: "custom",
|
|
2210
|
+
path: ["text"],
|
|
2211
|
+
message: "clipboard write requires text",
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
if (action.locator !== undefined || action.content !== undefined) {
|
|
2215
|
+
context.addIssue({
|
|
2216
|
+
code: "custom",
|
|
2217
|
+
message: "clipboard write accepts only text",
|
|
2218
|
+
});
|
|
2219
|
+
}
|
|
2220
|
+
return;
|
|
2221
|
+
}
|
|
2222
|
+
if (action.operation === "clear") {
|
|
2223
|
+
if (
|
|
2224
|
+
action.text !== undefined ||
|
|
2225
|
+
action.locator !== undefined ||
|
|
2226
|
+
action.content !== undefined
|
|
2227
|
+
) {
|
|
2228
|
+
context.addIssue({
|
|
2229
|
+
code: "custom",
|
|
2230
|
+
message: "clipboard clear accepts no payload",
|
|
2231
|
+
});
|
|
2232
|
+
}
|
|
2233
|
+
return;
|
|
2234
|
+
}
|
|
2235
|
+
if (action.operation === "copy") {
|
|
2236
|
+
if (action.text !== undefined) {
|
|
2237
|
+
context.addIssue({
|
|
2238
|
+
code: "custom",
|
|
2239
|
+
path: ["text"],
|
|
2240
|
+
message: "clipboard copy does not accept text",
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
if (action.content !== undefined && action.content !== "selection" && !action.locator) {
|
|
2244
|
+
context.addIssue({
|
|
2245
|
+
code: "custom",
|
|
2246
|
+
path: ["locator"],
|
|
2247
|
+
message: "copying element value or text requires a locator",
|
|
2248
|
+
});
|
|
2249
|
+
}
|
|
2250
|
+
return;
|
|
2251
|
+
}
|
|
2252
|
+
if (action.content !== undefined) {
|
|
2253
|
+
context.addIssue({
|
|
2254
|
+
code: "custom",
|
|
2255
|
+
path: ["content"],
|
|
2256
|
+
message: "clipboard paste does not accept content",
|
|
2257
|
+
});
|
|
2258
|
+
}
|
|
2259
|
+
}),
|
|
2260
|
+
z
|
|
2261
|
+
.object({
|
|
2262
|
+
type: z.literal("permission"),
|
|
2263
|
+
permission: BrowserPermission,
|
|
2264
|
+
setting: BrowserPermissionSetting,
|
|
2265
|
+
})
|
|
2266
|
+
.strict(),
|
|
1540
2267
|
z
|
|
1541
2268
|
.object({
|
|
1542
2269
|
type: z.literal("wait"),
|
|
@@ -1554,10 +2281,59 @@ export const BrowserActionBatch = z
|
|
|
1554
2281
|
.object({
|
|
1555
2282
|
type: z.literal("batch"),
|
|
1556
2283
|
actions: z.array(BrowserAction).min(1).max(INTERACTION_MAX_ACTIONS_PER_BATCH),
|
|
2284
|
+
/** Revalidate the original document before each action; never follow navigation. */
|
|
2285
|
+
fenceEachAction: z.literal(true).optional(),
|
|
1557
2286
|
})
|
|
1558
|
-
.strict()
|
|
2287
|
+
.strict()
|
|
2288
|
+
.superRefine((batch, context) => {
|
|
2289
|
+
const fileIds = new Set(
|
|
2290
|
+
batch.actions.flatMap((action) => (action.type === "upload" ? action.workspaceFileIds : [])),
|
|
2291
|
+
);
|
|
2292
|
+
if (fileIds.size > INTERACTION_MAX_WORKSPACE_FILES_PER_COMMAND) {
|
|
2293
|
+
context.addIssue({
|
|
2294
|
+
code: "custom",
|
|
2295
|
+
path: ["actions"],
|
|
2296
|
+
message: "browser action references too many workspace files",
|
|
2297
|
+
});
|
|
2298
|
+
}
|
|
2299
|
+
});
|
|
1559
2300
|
export type BrowserActionBatch = z.infer<typeof BrowserActionBatch>;
|
|
1560
2301
|
|
|
2302
|
+
/** Secret-safe projection of a connected-machine control failure carried in a
|
|
2303
|
+
* standard API error envelope. The outer envelope owns HTTP status, retryability,
|
|
2304
|
+
* and public request correlation; this preserves the exact failing control class
|
|
2305
|
+
* and optional inner request id without exposing subjects, local paths, or tokens. */
|
|
2306
|
+
export const InteractionControlFailureCode = z.enum([
|
|
2307
|
+
"unknown",
|
|
2308
|
+
"unsupported",
|
|
2309
|
+
"os",
|
|
2310
|
+
"not_found",
|
|
2311
|
+
"consent_required",
|
|
2312
|
+
"timeout",
|
|
2313
|
+
"draining",
|
|
2314
|
+
"protocol",
|
|
2315
|
+
"stream",
|
|
2316
|
+
"agent_offline",
|
|
2317
|
+
"fenced",
|
|
2318
|
+
"payload_too_large",
|
|
2319
|
+
]);
|
|
2320
|
+
export type InteractionControlFailureCode = z.infer<typeof InteractionControlFailureCode>;
|
|
2321
|
+
|
|
2322
|
+
export const InteractionControlFailureDetails = z
|
|
2323
|
+
.object({
|
|
2324
|
+
interactionLayer: z.literal("connected_machine"),
|
|
2325
|
+
interactionSurface: z.enum(["browser", "computer"]),
|
|
2326
|
+
controlFailureCode: InteractionControlFailureCode,
|
|
2327
|
+
controlRequestId: z
|
|
2328
|
+
.string()
|
|
2329
|
+
.min(1)
|
|
2330
|
+
.max(128)
|
|
2331
|
+
.regex(/^[A-Za-z0-9._:-]+$/u)
|
|
2332
|
+
.optional(),
|
|
2333
|
+
})
|
|
2334
|
+
.strict();
|
|
2335
|
+
export type InteractionControlFailureDetails = z.infer<typeof InteractionControlFailureDetails>;
|
|
2336
|
+
|
|
1561
2337
|
export const InteractionError = z
|
|
1562
2338
|
.object({
|
|
1563
2339
|
code: z.enum([
|
|
@@ -1600,11 +2376,72 @@ export const BrowserActionCommand = z
|
|
|
1600
2376
|
expectedDocumentGeneration: opaqueGeneration.nullable(),
|
|
1601
2377
|
expectedFrameId: opaqueGeneration.nullable(),
|
|
1602
2378
|
actor: InteractionActor,
|
|
2379
|
+
/** Human live-control surfaces already receive the resulting pixels. They
|
|
2380
|
+
* may omit the expensive semantic snapshot; agent actions keep it. The
|
|
2381
|
+
* negotiated input mode only observes a focused native dropdown after a
|
|
2382
|
+
* pointer click, and otherwise returns no observation. */
|
|
2383
|
+
observationMode: z.enum(["full", "none", "input"]).optional(),
|
|
1603
2384
|
action: z.union([BrowserAction, BrowserActionBatch]),
|
|
1604
2385
|
})
|
|
1605
2386
|
.strict();
|
|
1606
2387
|
export type BrowserActionCommand = z.infer<typeof BrowserActionCommand>;
|
|
1607
2388
|
|
|
2389
|
+
/** Controller-private authority used to materialize immutable workspace files
|
|
2390
|
+
* beside a BrowserSession before an upload action dispatches. Signed URLs and
|
|
2391
|
+
* placement paths never appear in the public BrowserAction or its receipt. */
|
|
2392
|
+
export const BrowserWorkspaceFileAuthority = z
|
|
2393
|
+
.object({
|
|
2394
|
+
fileId: z.string().uuid(),
|
|
2395
|
+
safeFilename: z
|
|
2396
|
+
.string()
|
|
2397
|
+
.min(1)
|
|
2398
|
+
.max(240)
|
|
2399
|
+
.regex(/^[A-Za-z0-9._ -]+$/u)
|
|
2400
|
+
.refine((value) => value !== "." && value !== "..", {
|
|
2401
|
+
message: "safe filename must be one path segment",
|
|
2402
|
+
}),
|
|
2403
|
+
sizeBytes: z.number().int().nonnegative().max(5_000_000_000),
|
|
2404
|
+
sha256: sha256Hex.nullable(),
|
|
2405
|
+
download: z
|
|
2406
|
+
.object({
|
|
2407
|
+
url: boundedHttpUrl,
|
|
2408
|
+
expiresAt: z.string().datetime({ offset: true }),
|
|
2409
|
+
})
|
|
2410
|
+
.strict(),
|
|
2411
|
+
})
|
|
2412
|
+
.strict();
|
|
2413
|
+
export type BrowserWorkspaceFileAuthority = z.infer<typeof BrowserWorkspaceFileAuthority>;
|
|
2414
|
+
|
|
2415
|
+
export const BrowserWorkspaceFileStageRequest = z
|
|
2416
|
+
.object({
|
|
2417
|
+
operationId: z.string().uuid(),
|
|
2418
|
+
files: z.array(BrowserWorkspaceFileAuthority).min(1).max(100),
|
|
2419
|
+
})
|
|
2420
|
+
.strict()
|
|
2421
|
+
.superRefine((request, context) => {
|
|
2422
|
+
const seen = new Set<string>();
|
|
2423
|
+
for (const [index, file] of request.files.entries()) {
|
|
2424
|
+
if (seen.has(file.fileId)) {
|
|
2425
|
+
context.addIssue({
|
|
2426
|
+
code: "custom",
|
|
2427
|
+
path: ["files", index, "fileId"],
|
|
2428
|
+
message: "workspace file authority is duplicated",
|
|
2429
|
+
});
|
|
2430
|
+
}
|
|
2431
|
+
seen.add(file.fileId);
|
|
2432
|
+
}
|
|
2433
|
+
});
|
|
2434
|
+
export type BrowserWorkspaceFileStageRequest = z.infer<typeof BrowserWorkspaceFileStageRequest>;
|
|
2435
|
+
|
|
2436
|
+
export const BrowserWorkspaceFileStageResponse = z
|
|
2437
|
+
.object({
|
|
2438
|
+
operationId: z.string().uuid(),
|
|
2439
|
+
fileIds: z.array(z.string().uuid()).min(1).max(100),
|
|
2440
|
+
replayed: z.boolean(),
|
|
2441
|
+
})
|
|
2442
|
+
.strict();
|
|
2443
|
+
export type BrowserWorkspaceFileStageResponse = z.infer<typeof BrowserWorkspaceFileStageResponse>;
|
|
2444
|
+
|
|
1608
2445
|
export const InteractionOperationState = z.enum([
|
|
1609
2446
|
"prepared",
|
|
1610
2447
|
"dispatched",
|
|
@@ -1671,6 +2508,10 @@ export const CreateBrowserSessionRequest = z
|
|
|
1671
2508
|
name: z.string().trim().min(1).max(200).optional(),
|
|
1672
2509
|
initialUrl: boundedUrl.optional(),
|
|
1673
2510
|
headless: z.boolean().default(true),
|
|
2511
|
+
storageMode: BrowserStorageMode.default("private_profile"),
|
|
2512
|
+
/** Managed engine choice. Attached Chrome continues to derive its engine
|
|
2513
|
+
* from the selected device rather than accepting an impersonated value. */
|
|
2514
|
+
engine: z.enum(["chromium", "lightpanda"]).default("chromium"),
|
|
1674
2515
|
placement: InteractionPlacement.optional(),
|
|
1675
2516
|
identityId: z.string().uuid().optional(),
|
|
1676
2517
|
baseRevisionId: z.string().uuid().optional(),
|
|
@@ -1679,6 +2520,23 @@ export const CreateBrowserSessionRequest = z
|
|
|
1679
2520
|
})
|
|
1680
2521
|
.strict()
|
|
1681
2522
|
.superRefine((value, context) => {
|
|
2523
|
+
if (
|
|
2524
|
+
value.storageMode === "ephemeral_context" &&
|
|
2525
|
+
(!value.headless ||
|
|
2526
|
+
value.engine !== "chromium" ||
|
|
2527
|
+
value.identityId ||
|
|
2528
|
+
value.baseRevisionId ||
|
|
2529
|
+
value.networkRouteId ||
|
|
2530
|
+
value.linkedComputerSessionId ||
|
|
2531
|
+
(value.placement && value.placement.kind !== "sandbox_group"))
|
|
2532
|
+
) {
|
|
2533
|
+
context.addIssue({
|
|
2534
|
+
code: "custom",
|
|
2535
|
+
path: ["storageMode"],
|
|
2536
|
+
message:
|
|
2537
|
+
"ephemeral contexts require headless managed sandbox Chromium without identity, revision, route or Computer",
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
1682
2540
|
if (value.baseRevisionId && !value.identityId) {
|
|
1683
2541
|
context.addIssue({
|
|
1684
2542
|
code: "custom",
|
|
@@ -1693,12 +2551,42 @@ export const CreateBrowserSessionRequest = z
|
|
|
1693
2551
|
message: "a linked computer requires a headed browser",
|
|
1694
2552
|
});
|
|
1695
2553
|
}
|
|
1696
|
-
if (value.
|
|
2554
|
+
if (value.engine === "lightpanda") {
|
|
2555
|
+
if (!value.headless) {
|
|
2556
|
+
context.addIssue({
|
|
2557
|
+
code: "custom",
|
|
2558
|
+
path: ["headless"],
|
|
2559
|
+
message: "Lightpanda is a headless semantic browser",
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
if (value.identityId || value.baseRevisionId) {
|
|
2563
|
+
context.addIssue({
|
|
2564
|
+
code: "custom",
|
|
2565
|
+
path: ["identityId"],
|
|
2566
|
+
message: "Lightpanda does not support Chromium browser identities",
|
|
2567
|
+
});
|
|
2568
|
+
}
|
|
2569
|
+
if (value.networkRouteId) {
|
|
2570
|
+
context.addIssue({
|
|
2571
|
+
code: "custom",
|
|
2572
|
+
path: ["networkRouteId"],
|
|
2573
|
+
message: "Lightpanda network routes are not supported yet",
|
|
2574
|
+
});
|
|
2575
|
+
}
|
|
1697
2576
|
if (value.linkedComputerSessionId) {
|
|
1698
2577
|
context.addIssue({
|
|
1699
2578
|
code: "custom",
|
|
1700
2579
|
path: ["linkedComputerSessionId"],
|
|
1701
|
-
message: "
|
|
2580
|
+
message: "Lightpanda has no linked desktop window",
|
|
2581
|
+
});
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
if (value.placement?.kind === "attached_device") {
|
|
2585
|
+
if (value.engine !== "chromium") {
|
|
2586
|
+
context.addIssue({
|
|
2587
|
+
code: "custom",
|
|
2588
|
+
path: ["engine"],
|
|
2589
|
+
message: "attached browser placement uses the selected Chrome engine",
|
|
1702
2590
|
});
|
|
1703
2591
|
}
|
|
1704
2592
|
if (value.headless) {
|
|
@@ -1716,6 +2604,29 @@ export const CreateBrowserSessionRequest = z
|
|
|
1716
2604
|
});
|
|
1717
2605
|
}
|
|
1718
2606
|
}
|
|
2607
|
+
if (value.placement?.kind === "external_provider") {
|
|
2608
|
+
if (value.engine !== "chromium") {
|
|
2609
|
+
context.addIssue({
|
|
2610
|
+
code: "custom",
|
|
2611
|
+
path: ["engine"],
|
|
2612
|
+
message: "external browser providers use their Chromium-compatible engine",
|
|
2613
|
+
});
|
|
2614
|
+
}
|
|
2615
|
+
if (value.identityId || value.baseRevisionId) {
|
|
2616
|
+
context.addIssue({
|
|
2617
|
+
code: "custom",
|
|
2618
|
+
path: ["identityId"],
|
|
2619
|
+
message: "external browser providers do not yet support portable BrowserIdentity state",
|
|
2620
|
+
});
|
|
2621
|
+
}
|
|
2622
|
+
if (value.linkedComputerSessionId) {
|
|
2623
|
+
context.addIssue({
|
|
2624
|
+
code: "custom",
|
|
2625
|
+
path: ["linkedComputerSessionId"],
|
|
2626
|
+
message: "external browser providers cannot link a placement desktop",
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
}
|
|
1719
2630
|
});
|
|
1720
2631
|
export type CreateBrowserSessionRequest = z.infer<typeof CreateBrowserSessionRequest>;
|
|
1721
2632
|
|
|
@@ -1783,6 +2694,19 @@ const DirectInteractionFrameStreamAttachment = z
|
|
|
1783
2694
|
})
|
|
1784
2695
|
.strict();
|
|
1785
2696
|
|
|
2697
|
+
/** Native tunnels offer `binary` + RFB + bearer (3). Docker and OpenSandbox
|
|
2698
|
+
* hide those on the API interaction frame-proxy, so the viewer sees `binary` +
|
|
2699
|
+
* the proxy grant (2). */
|
|
2700
|
+
const DirectComputerRfbAttachment = z
|
|
2701
|
+
.object({
|
|
2702
|
+
kind: z.literal("direct_rfb"),
|
|
2703
|
+
url: boundedUrl,
|
|
2704
|
+
protocols: z.array(z.string().min(1).max(2_048)).min(2).max(3),
|
|
2705
|
+
/** Absent on an older API means pixel viewing only. */
|
|
2706
|
+
inputAllowed: z.boolean().default(false),
|
|
2707
|
+
})
|
|
2708
|
+
.strict();
|
|
2709
|
+
|
|
1786
2710
|
function relayInteractionFrameStreamAttachment<const Kind extends 3 | 4>(kind: Kind) {
|
|
1787
2711
|
return z
|
|
1788
2712
|
.object({
|
|
@@ -1810,6 +2734,7 @@ export type BrowserFrameStreamAttachment = z.infer<typeof BrowserFrameStreamAtta
|
|
|
1810
2734
|
|
|
1811
2735
|
export const ComputerFrameStreamAttachment = z.discriminatedUnion("kind", [
|
|
1812
2736
|
DirectInteractionFrameStreamAttachment,
|
|
2737
|
+
DirectComputerRfbAttachment,
|
|
1813
2738
|
relayInteractionFrameStreamAttachment(4),
|
|
1814
2739
|
]);
|
|
1815
2740
|
export type ComputerFrameStreamAttachment = z.infer<typeof ComputerFrameStreamAttachment>;
|
|
@@ -1826,6 +2751,8 @@ export const BrowserSessionAttachment = z
|
|
|
1826
2751
|
controllerGeneration: opaqueGeneration,
|
|
1827
2752
|
targetId: boundedOpaqueId,
|
|
1828
2753
|
stream: BrowserFrameStreamAttachment,
|
|
2754
|
+
fencedInputBatches: z.literal(true).optional(),
|
|
2755
|
+
focusedInputObservations: z.literal(true).optional(),
|
|
1829
2756
|
expiresAt: z.string().datetime({ offset: true }),
|
|
1830
2757
|
})
|
|
1831
2758
|
.strict();
|
|
@@ -1850,6 +2777,7 @@ export const BrowserActionRequest = z
|
|
|
1850
2777
|
expectedTargetGeneration: opaqueGeneration,
|
|
1851
2778
|
expectedDocumentGeneration: opaqueGeneration.nullable(),
|
|
1852
2779
|
expectedFrameId: opaqueGeneration.nullable(),
|
|
2780
|
+
observationMode: z.enum(["full", "none", "input"]).default("full"),
|
|
1853
2781
|
action: z.union([BrowserAction, BrowserActionBatch]),
|
|
1854
2782
|
})
|
|
1855
2783
|
.strict();
|
|
@@ -1903,6 +2831,104 @@ export const BrowserActionReceipt = z
|
|
|
1903
2831
|
});
|
|
1904
2832
|
export type BrowserActionReceipt = z.infer<typeof BrowserActionReceipt>;
|
|
1905
2833
|
|
|
2834
|
+
/** Controller-private protected-fill wire contract. Secret values cross only
|
|
2835
|
+
* the credential broker -> exact placement controller boundary; this command
|
|
2836
|
+
* is never projected into model MCP, Codemode, public action history, or UI. */
|
|
2837
|
+
export const BrowserProtectedAuthFieldValue = ProtectedAuthField.extend({
|
|
2838
|
+
purpose: SiteAuthFieldPurpose,
|
|
2839
|
+
value: z.string().min(1).max(65_536),
|
|
2840
|
+
}).strict();
|
|
2841
|
+
export type BrowserProtectedAuthFieldValue = z.infer<typeof BrowserProtectedAuthFieldValue>;
|
|
2842
|
+
|
|
2843
|
+
export const BrowserProtectedAuthFillCommand = z
|
|
2844
|
+
.object({
|
|
2845
|
+
protocolVersion: z.literal(INTERACTION_PROTOCOL_VERSION),
|
|
2846
|
+
operationId: z.string().uuid(),
|
|
2847
|
+
browserSessionId: z.string().uuid(),
|
|
2848
|
+
controllerGeneration: opaqueGeneration,
|
|
2849
|
+
targetId: boundedOpaqueId,
|
|
2850
|
+
expectedTargetGeneration: opaqueGeneration,
|
|
2851
|
+
expectedDocumentGeneration: opaqueGeneration,
|
|
2852
|
+
expectedFrameId: opaqueGeneration,
|
|
2853
|
+
actor: InteractionActor,
|
|
2854
|
+
authorityId: boundedOpaqueId,
|
|
2855
|
+
credentialVersion: z.number().int().positive().max(Number.MAX_SAFE_INTEGER),
|
|
2856
|
+
allowedOrigins: z.array(canonicalWebOrigin).min(1).max(64),
|
|
2857
|
+
fields: z.array(BrowserProtectedAuthFieldValue).min(1).max(32),
|
|
2858
|
+
submit: ProtectedAuthSubmit,
|
|
2859
|
+
})
|
|
2860
|
+
.strict()
|
|
2861
|
+
.superRefine((command, context) => {
|
|
2862
|
+
if (new Set(command.allowedOrigins).size !== command.allowedOrigins.length) {
|
|
2863
|
+
context.addIssue({
|
|
2864
|
+
code: "custom",
|
|
2865
|
+
path: ["allowedOrigins"],
|
|
2866
|
+
message: "protected-fill origins repeat",
|
|
2867
|
+
});
|
|
2868
|
+
}
|
|
2869
|
+
const fieldIds = command.fields.map((field) => field.fieldId);
|
|
2870
|
+
if (new Set(fieldIds).size !== fieldIds.length) {
|
|
2871
|
+
context.addIssue({
|
|
2872
|
+
code: "custom",
|
|
2873
|
+
path: ["fields"],
|
|
2874
|
+
message: "protected-fill field ids repeat",
|
|
2875
|
+
});
|
|
2876
|
+
}
|
|
2877
|
+
});
|
|
2878
|
+
export type BrowserProtectedAuthFillCommand = z.infer<typeof BrowserProtectedAuthFillCommand>;
|
|
2879
|
+
|
|
2880
|
+
export const BrowserProtectedAuthObservation = z
|
|
2881
|
+
.object({
|
|
2882
|
+
target: BrowserTarget,
|
|
2883
|
+
status: z.enum(["submitted", "working"]),
|
|
2884
|
+
})
|
|
2885
|
+
.strict();
|
|
2886
|
+
export type BrowserProtectedAuthObservation = z.infer<typeof BrowserProtectedAuthObservation>;
|
|
2887
|
+
|
|
2888
|
+
/** Secret-free placement receipt. It can be journaled, replayed, and returned
|
|
2889
|
+
* to the broker without retaining any field value or model-visible page tree. */
|
|
2890
|
+
export const BrowserProtectedAuthFillReceipt = z
|
|
2891
|
+
.object({
|
|
2892
|
+
protocolVersion: z.literal(INTERACTION_PROTOCOL_VERSION),
|
|
2893
|
+
operationId: z.string().uuid(),
|
|
2894
|
+
browserSessionId: z.string().uuid(),
|
|
2895
|
+
controllerGeneration: opaqueGeneration,
|
|
2896
|
+
targetId: boundedOpaqueId,
|
|
2897
|
+
state: InteractionOperationState,
|
|
2898
|
+
dispatchedAt: z.string().datetime({ offset: true }).nullable(),
|
|
2899
|
+
settledAt: z.string().datetime({ offset: true }).nullable(),
|
|
2900
|
+
observation: BrowserProtectedAuthObservation.nullable(),
|
|
2901
|
+
error: InteractionError.nullable(),
|
|
2902
|
+
})
|
|
2903
|
+
.strict()
|
|
2904
|
+
.superRefine((receipt, context) => {
|
|
2905
|
+
if (
|
|
2906
|
+
receipt.state === "completed" &&
|
|
2907
|
+
(receipt.error !== null || receipt.observation === null || receipt.settledAt === null)
|
|
2908
|
+
) {
|
|
2909
|
+
context.addIssue({
|
|
2910
|
+
code: "custom",
|
|
2911
|
+
message: "completed protected-fill receipt requires a result and no error",
|
|
2912
|
+
});
|
|
2913
|
+
}
|
|
2914
|
+
if (
|
|
2915
|
+
(receipt.state === "failed" || receipt.state === "outcome_unknown") &&
|
|
2916
|
+
(receipt.error === null || receipt.observation !== null || receipt.settledAt === null)
|
|
2917
|
+
) {
|
|
2918
|
+
context.addIssue({
|
|
2919
|
+
code: "custom",
|
|
2920
|
+
message: "terminal protected-fill error requires error, no result, and time",
|
|
2921
|
+
});
|
|
2922
|
+
}
|
|
2923
|
+
if (receipt.state === "dispatched" && receipt.dispatchedAt === null) {
|
|
2924
|
+
context.addIssue({
|
|
2925
|
+
code: "custom",
|
|
2926
|
+
message: "dispatched protected-fill receipt requires dispatch time",
|
|
2927
|
+
});
|
|
2928
|
+
}
|
|
2929
|
+
});
|
|
2930
|
+
export type BrowserProtectedAuthFillReceipt = z.infer<typeof BrowserProtectedAuthFillReceipt>;
|
|
2931
|
+
|
|
1906
2932
|
export const ComputerSessionCapabilities = z
|
|
1907
2933
|
.object({
|
|
1908
2934
|
semanticObservation: z.boolean(),
|
|
@@ -1913,12 +2939,45 @@ export const ComputerSessionCapabilities = z
|
|
|
1913
2939
|
semanticActions: z.boolean(),
|
|
1914
2940
|
pointerInput: z.boolean(),
|
|
1915
2941
|
keyboardInput: z.boolean(),
|
|
2942
|
+
clipboard: z.boolean(),
|
|
1916
2943
|
backgroundActions: z.boolean(),
|
|
2944
|
+
/** Raw window input stays in the background. Absent means foreground-only. */
|
|
2945
|
+
backgroundInput: z.boolean().optional(),
|
|
1917
2946
|
parallelApps: z.boolean(),
|
|
1918
2947
|
})
|
|
1919
2948
|
.strict();
|
|
1920
2949
|
export type ComputerSessionCapabilities = z.infer<typeof ComputerSessionCapabilities>;
|
|
1921
2950
|
|
|
2951
|
+
/** A fresh bounded read of the native clipboard for the ComputerSession's
|
|
2952
|
+
* graphical seat. Physical ComputerSessions on the same login seat intentionally
|
|
2953
|
+
* observe the same OS clipboard; BrowserSession private clipboards never do. */
|
|
2954
|
+
export const ComputerClipboard = z
|
|
2955
|
+
.object({
|
|
2956
|
+
computerSessionId: z.string().uuid(),
|
|
2957
|
+
controllerGeneration: opaqueGeneration,
|
|
2958
|
+
text: z
|
|
2959
|
+
.string()
|
|
2960
|
+
.max(INTERACTION_MAX_CLIPBOARD_BYTES)
|
|
2961
|
+
.refine(
|
|
2962
|
+
(value) => new TextEncoder().encode(value).byteLength <= INTERACTION_MAX_CLIPBOARD_BYTES,
|
|
2963
|
+
{ message: "computer clipboard text exceeds its UTF-8 byte envelope" },
|
|
2964
|
+
)
|
|
2965
|
+
.nullable(),
|
|
2966
|
+
truncated: z.boolean(),
|
|
2967
|
+
observedAt: z.string().datetime({ offset: true }),
|
|
2968
|
+
})
|
|
2969
|
+
.strict()
|
|
2970
|
+
.superRefine((clipboard, context) => {
|
|
2971
|
+
if (clipboard.text === null && clipboard.truncated) {
|
|
2972
|
+
context.addIssue({
|
|
2973
|
+
code: "custom",
|
|
2974
|
+
path: ["truncated"],
|
|
2975
|
+
message: "an unavailable computer clipboard value cannot be truncated",
|
|
2976
|
+
});
|
|
2977
|
+
}
|
|
2978
|
+
});
|
|
2979
|
+
export type ComputerClipboard = z.infer<typeof ComputerClipboard>;
|
|
2980
|
+
|
|
1922
2981
|
export const ComputerSession = z
|
|
1923
2982
|
.object({
|
|
1924
2983
|
id: z.string().uuid(),
|
|
@@ -2079,6 +3138,29 @@ export const ComputerAction = z.discriminatedUnion("type", [
|
|
|
2079
3138
|
value: z.string().max(1_000_000),
|
|
2080
3139
|
})
|
|
2081
3140
|
.strict(),
|
|
3141
|
+
z
|
|
3142
|
+
.object({
|
|
3143
|
+
type: z.literal("clipboard"),
|
|
3144
|
+
operation: z.enum(["write", "clear", "copy", "paste"]),
|
|
3145
|
+
text: z
|
|
3146
|
+
.string()
|
|
3147
|
+
.max(INTERACTION_MAX_CLIPBOARD_BYTES)
|
|
3148
|
+
.refine(
|
|
3149
|
+
(value) => new TextEncoder().encode(value).byteLength <= INTERACTION_MAX_CLIPBOARD_BYTES,
|
|
3150
|
+
{ message: "computer clipboard text exceeds its UTF-8 byte envelope" },
|
|
3151
|
+
)
|
|
3152
|
+
.optional(),
|
|
3153
|
+
})
|
|
3154
|
+
.strict()
|
|
3155
|
+
.superRefine((action, context) => {
|
|
3156
|
+
if ((action.operation === "write") !== (action.text !== undefined)) {
|
|
3157
|
+
context.addIssue({
|
|
3158
|
+
code: "custom",
|
|
3159
|
+
path: ["text"],
|
|
3160
|
+
message: "computer clipboard text is required exactly for write",
|
|
3161
|
+
});
|
|
3162
|
+
}
|
|
3163
|
+
}),
|
|
2082
3164
|
z.object({ type: z.literal("focus"), targetId: boundedOpaqueId }).strict(),
|
|
2083
3165
|
z
|
|
2084
3166
|
.object({
|
|
@@ -2225,12 +3307,26 @@ export const ComputerSessionAttachment = z
|
|
|
2225
3307
|
computerSessionId: z.string().uuid(),
|
|
2226
3308
|
controllerGeneration: opaqueGeneration,
|
|
2227
3309
|
targetId: boundedOpaqueId,
|
|
3310
|
+
// Viewer posture only. Canonical actions still require live source authority.
|
|
3311
|
+
// Older API responses omit it; their existing action authorization remains.
|
|
3312
|
+
inputAllowed: z.boolean().optional(),
|
|
2228
3313
|
stream: ComputerFrameStreamAttachment,
|
|
2229
3314
|
expiresAt: z.string().datetime({ offset: true }),
|
|
2230
3315
|
})
|
|
2231
3316
|
.strict();
|
|
2232
3317
|
export type ComputerSessionAttachment = z.infer<typeof ComputerSessionAttachment>;
|
|
2233
3318
|
|
|
3319
|
+
/** Caller-specific human input posture, independent of media/native capability.
|
|
3320
|
+
* It is a current-controller hint; every action still reauthorizes. */
|
|
3321
|
+
export const ComputerSessionInputPosture = z
|
|
3322
|
+
.object({
|
|
3323
|
+
computerSessionId: z.string().uuid(),
|
|
3324
|
+
controllerGeneration: opaqueGeneration,
|
|
3325
|
+
inputAllowed: z.boolean(),
|
|
3326
|
+
})
|
|
3327
|
+
.strict();
|
|
3328
|
+
export type ComputerSessionInputPosture = z.infer<typeof ComputerSessionInputPosture>;
|
|
3329
|
+
|
|
2234
3330
|
export const ComputerSessionAttachmentRequest = z
|
|
2235
3331
|
.object({
|
|
2236
3332
|
targetId: boundedOpaqueId,
|