@cuna_labs/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/NOTICE +9 -0
- package/README.md +169 -0
- package/THIRD_PARTY_NOTICES.md +29 -0
- package/dist/api/capability-evidence.d.ts +19 -0
- package/dist/api/capability-evidence.d.ts.map +1 -0
- package/dist/api/capability-evidence.js +38 -0
- package/dist/api/capability-evidence.js.map +1 -0
- package/dist/api/client.d.ts +167 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +937 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/contracts.d.ts +345 -0
- package/dist/api/contracts.d.ts.map +1 -0
- package/dist/api/contracts.js +976 -0
- package/dist/api/contracts.js.map +1 -0
- package/dist/api/execution-workspaces.d.ts +17 -0
- package/dist/api/execution-workspaces.d.ts.map +1 -0
- package/dist/api/execution-workspaces.js +46 -0
- package/dist/api/execution-workspaces.js.map +1 -0
- package/dist/api/http.d.ts +76 -0
- package/dist/api/http.d.ts.map +1 -0
- package/dist/api/http.js +838 -0
- package/dist/api/http.js.map +1 -0
- package/dist/api/managed-executions.d.ts +37 -0
- package/dist/api/managed-executions.d.ts.map +1 -0
- package/dist/api/managed-executions.js +80 -0
- package/dist/api/managed-executions.js.map +1 -0
- package/dist/api/observer-v2-schema.d.ts +206 -0
- package/dist/api/observer-v2-schema.d.ts.map +1 -0
- package/dist/api/observer-v2-schema.js +264 -0
- package/dist/api/observer-v2-schema.js.map +1 -0
- package/dist/api/observer-v2.d.ts +33 -0
- package/dist/api/observer-v2.d.ts.map +1 -0
- package/dist/api/observer-v2.js +60 -0
- package/dist/api/observer-v2.js.map +1 -0
- package/dist/api/owner-observe-grants-v2-schema.d.ts +678 -0
- package/dist/api/owner-observe-grants-v2-schema.d.ts.map +1 -0
- package/dist/api/owner-observe-grants-v2-schema.js +887 -0
- package/dist/api/owner-observe-grants-v2-schema.js.map +1 -0
- package/dist/api/owner-observe-grants-v2.d.ts +268 -0
- package/dist/api/owner-observe-grants-v2.d.ts.map +1 -0
- package/dist/api/owner-observe-grants-v2.js +604 -0
- package/dist/api/owner-observe-grants-v2.js.map +1 -0
- package/dist/api/provider-v2-schema.d.ts +293 -0
- package/dist/api/provider-v2-schema.d.ts.map +1 -0
- package/dist/api/provider-v2-schema.js +381 -0
- package/dist/api/provider-v2-schema.js.map +1 -0
- package/dist/api/provider-v2.d.ts +55 -0
- package/dist/api/provider-v2.d.ts.map +1 -0
- package/dist/api/provider-v2.js +54 -0
- package/dist/api/provider-v2.js.map +1 -0
- package/dist/api/remote-workspace.d.ts +29 -0
- package/dist/api/remote-workspace.d.ts.map +1 -0
- package/dist/api/remote-workspace.js +62 -0
- package/dist/api/remote-workspace.js.map +1 -0
- package/dist/api/supervisor-live-update.d.ts +248 -0
- package/dist/api/supervisor-live-update.d.ts.map +1 -0
- package/dist/api/supervisor-live-update.js +434 -0
- package/dist/api/supervisor-live-update.js.map +1 -0
- package/dist/api/terminal-reason.d.ts +5 -0
- package/dist/api/terminal-reason.d.ts.map +1 -0
- package/dist/api/terminal-reason.js +12 -0
- package/dist/api/terminal-reason.js.map +1 -0
- package/dist/auth/browser-handoff.d.ts +59 -0
- package/dist/auth/browser-handoff.d.ts.map +1 -0
- package/dist/auth/browser-handoff.js +33 -0
- package/dist/auth/browser-handoff.js.map +1 -0
- package/dist/auth/browser.d.ts +11 -0
- package/dist/auth/browser.d.ts.map +1 -0
- package/dist/auth/browser.js +47 -0
- package/dist/auth/browser.js.map +1 -0
- package/dist/auth/human-client.d.ts +39 -0
- package/dist/auth/human-client.d.ts.map +1 -0
- package/dist/auth/human-client.js +66 -0
- package/dist/auth/human-client.js.map +1 -0
- package/dist/auth/human-contracts.d.ts +52 -0
- package/dist/auth/human-contracts.d.ts.map +1 -0
- package/dist/auth/human-contracts.js +229 -0
- package/dist/auth/human-contracts.js.map +1 -0
- package/dist/auth/human-session.d.ts +48 -0
- package/dist/auth/human-session.d.ts.map +1 -0
- package/dist/auth/human-session.js +902 -0
- package/dist/auth/human-session.js.map +1 -0
- package/dist/auth/onboarding-state.d.ts +31 -0
- package/dist/auth/onboarding-state.d.ts.map +1 -0
- package/dist/auth/onboarding-state.js +52 -0
- package/dist/auth/onboarding-state.js.map +1 -0
- package/dist/auth/pkce.d.ts +15 -0
- package/dist/auth/pkce.d.ts.map +1 -0
- package/dist/auth/pkce.js +19 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/bin/cuna.d.ts +3 -0
- package/dist/bin/cuna.d.ts.map +1 -0
- package/dist/bin/cuna.js +4 -0
- package/dist/bin/cuna.js.map +1 -0
- package/dist/build-identity.d.ts +20 -0
- package/dist/build-identity.d.ts.map +1 -0
- package/dist/build-identity.js +77 -0
- package/dist/build-identity.js.map +1 -0
- package/dist/cli/command-help.d.ts +9 -0
- package/dist/cli/command-help.d.ts.map +1 -0
- package/dist/cli/command-help.js +324 -0
- package/dist/cli/command-help.js.map +1 -0
- package/dist/cli/help.d.ts +40 -0
- package/dist/cli/help.d.ts.map +1 -0
- package/dist/cli/help.js +256 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/output.d.ts +28 -0
- package/dist/cli/output.d.ts.map +1 -0
- package/dist/cli/output.js +95 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/parser.d.ts +65 -0
- package/dist/cli/parser.d.ts.map +1 -0
- package/dist/cli/parser.js +294 -0
- package/dist/cli/parser.js.map +1 -0
- package/dist/cli/process-entrypoint.d.ts +18 -0
- package/dist/cli/process-entrypoint.d.ts.map +1 -0
- package/dist/cli/process-entrypoint.js +26 -0
- package/dist/cli/process-entrypoint.js.map +1 -0
- package/dist/cli/run.d.ts +114 -0
- package/dist/cli/run.d.ts.map +1 -0
- package/dist/cli/run.js +1969 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/commands/commands.d.ts +74 -0
- package/dist/commands/commands.d.ts.map +1 -0
- package/dist/commands/commands.js +2814 -0
- package/dist/commands/commands.js.map +1 -0
- package/dist/config/config.d.ts +86 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +323 -0
- package/dist/config/config.js.map +1 -0
- package/dist/config/infra-contract-witness.d.ts +29 -0
- package/dist/config/infra-contract-witness.d.ts.map +1 -0
- package/dist/config/infra-contract-witness.js +30 -0
- package/dist/config/infra-contract-witness.js.map +1 -0
- package/dist/core/browser-url.d.ts +2 -0
- package/dist/core/browser-url.d.ts.map +1 -0
- package/dist/core/browser-url.js +20 -0
- package/dist/core/browser-url.js.map +1 -0
- package/dist/core/deployed-wire-compatibility.d.ts +15 -0
- package/dist/core/deployed-wire-compatibility.d.ts.map +1 -0
- package/dist/core/deployed-wire-compatibility.js +15 -0
- package/dist/core/deployed-wire-compatibility.js.map +1 -0
- package/dist/core/errors.d.ts +59 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js +82 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/exit-codes.d.ts +68 -0
- package/dist/core/exit-codes.d.ts.map +1 -0
- package/dist/core/exit-codes.js +84 -0
- package/dist/core/exit-codes.js.map +1 -0
- package/dist/core/instant.d.ts +60 -0
- package/dist/core/instant.d.ts.map +1 -0
- package/dist/core/instant.js +90 -0
- package/dist/core/instant.js.map +1 -0
- package/dist/core/namespace.d.ts +171 -0
- package/dist/core/namespace.d.ts.map +1 -0
- package/dist/core/namespace.js +227 -0
- package/dist/core/namespace.js.map +1 -0
- package/dist/core/observation-budget.d.ts +185 -0
- package/dist/core/observation-budget.d.ts.map +1 -0
- package/dist/core/observation-budget.js +209 -0
- package/dist/core/observation-budget.js.map +1 -0
- package/dist/core/product-web.d.ts +81 -0
- package/dist/core/product-web.d.ts.map +1 -0
- package/dist/core/product-web.js +87 -0
- package/dist/core/product-web.js.map +1 -0
- package/dist/core/validation.d.ts +90 -0
- package/dist/core/validation.d.ts.map +1 -0
- package/dist/core/validation.js +199 -0
- package/dist/core/validation.js.map +1 -0
- package/dist/credentials/contracts.d.ts +82 -0
- package/dist/credentials/contracts.d.ts.map +1 -0
- package/dist/credentials/contracts.js +2 -0
- package/dist/credentials/contracts.js.map +1 -0
- package/dist/credentials/errors.d.ts +19 -0
- package/dist/credentials/errors.d.ts.map +1 -0
- package/dist/credentials/errors.js +16 -0
- package/dist/credentials/errors.js.map +1 -0
- package/dist/credentials/index.d.ts +6 -0
- package/dist/credentials/index.d.ts.map +1 -0
- package/dist/credentials/index.js +6 -0
- package/dist/credentials/index.js.map +1 -0
- package/dist/credentials/local-session.d.ts +101 -0
- package/dist/credentials/local-session.d.ts.map +1 -0
- package/dist/credentials/local-session.js +839 -0
- package/dist/credentials/local-session.js.map +1 -0
- package/dist/credentials/secret-material.d.ts +17 -0
- package/dist/credentials/secret-material.d.ts.map +1 -0
- package/dist/credentials/secret-material.js +49 -0
- package/dist/credentials/secret-material.js.map +1 -0
- package/dist/credentials/vault.d.ts +41 -0
- package/dist/credentials/vault.d.ts.map +1 -0
- package/dist/credentials/vault.js +719 -0
- package/dist/credentials/vault.js.map +1 -0
- package/dist/daemon/endpoint.d.ts +29 -0
- package/dist/daemon/endpoint.d.ts.map +1 -0
- package/dist/daemon/endpoint.js +66 -0
- package/dist/daemon/endpoint.js.map +1 -0
- package/dist/daemon/journal.d.ts +62 -0
- package/dist/daemon/journal.d.ts.map +1 -0
- package/dist/daemon/journal.js +299 -0
- package/dist/daemon/journal.js.map +1 -0
- package/dist/daemon/lease.d.ts +25 -0
- package/dist/daemon/lease.d.ts.map +1 -0
- package/dist/daemon/lease.js +94 -0
- package/dist/daemon/lease.js.map +1 -0
- package/dist/daemon/lifecycle.d.ts +14 -0
- package/dist/daemon/lifecycle.d.ts.map +1 -0
- package/dist/daemon/lifecycle.js +29 -0
- package/dist/daemon/lifecycle.js.map +1 -0
- package/dist/daemon/protocol.d.ts +65 -0
- package/dist/daemon/protocol.d.ts.map +1 -0
- package/dist/daemon/protocol.js +194 -0
- package/dist/daemon/protocol.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +29 -0
- package/dist/daemon/supervisor.d.ts.map +1 -0
- package/dist/daemon/supervisor.js +87 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/daemon/views.d.ts +31 -0
- package/dist/daemon/views.d.ts.map +1 -0
- package/dist/daemon/views.js +86 -0
- package/dist/daemon/views.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +38 -0
- package/dist/index.js.map +1 -0
- package/dist/journey/api-effects.d.ts +59 -0
- package/dist/journey/api-effects.d.ts.map +1 -0
- package/dist/journey/api-effects.js +386 -0
- package/dist/journey/api-effects.js.map +1 -0
- package/dist/journey/derived-identity.d.ts +91 -0
- package/dist/journey/derived-identity.d.ts.map +1 -0
- package/dist/journey/derived-identity.js +123 -0
- package/dist/journey/derived-identity.js.map +1 -0
- package/dist/journey/index.d.ts +6 -0
- package/dist/journey/index.d.ts.map +1 -0
- package/dist/journey/index.js +6 -0
- package/dist/journey/index.js.map +1 -0
- package/dist/journey/intent.d.ts +36 -0
- package/dist/journey/intent.d.ts.map +1 -0
- package/dist/journey/intent.js +191 -0
- package/dist/journey/intent.js.map +1 -0
- package/dist/journey/orchestrator.d.ts +140 -0
- package/dist/journey/orchestrator.d.ts.map +1 -0
- package/dist/journey/orchestrator.js +415 -0
- package/dist/journey/orchestrator.js.map +1 -0
- package/dist/journey/provider-launch-intent.d.ts +12 -0
- package/dist/journey/provider-launch-intent.d.ts.map +1 -0
- package/dist/journey/provider-launch-intent.js +40 -0
- package/dist/journey/provider-launch-intent.js.map +1 -0
- package/dist/journey/remote-workspace.d.ts +34 -0
- package/dist/journey/remote-workspace.d.ts.map +1 -0
- package/dist/journey/remote-workspace.js +91 -0
- package/dist/journey/remote-workspace.js.map +1 -0
- package/dist/journey/root-entry.d.ts +56 -0
- package/dist/journey/root-entry.d.ts.map +1 -0
- package/dist/journey/root-entry.js +19 -0
- package/dist/journey/root-entry.js.map +1 -0
- package/dist/journey/selection.d.ts +165 -0
- package/dist/journey/selection.d.ts.map +1 -0
- package/dist/journey/selection.js +565 -0
- package/dist/journey/selection.js.map +1 -0
- package/dist/journey/session-failure.d.ts +4 -0
- package/dist/journey/session-failure.d.ts.map +1 -0
- package/dist/journey/session-failure.js +28 -0
- package/dist/journey/session-failure.js.map +1 -0
- package/dist/journey/workspace-effects.d.ts +30 -0
- package/dist/journey/workspace-effects.d.ts.map +1 -0
- package/dist/journey/workspace-effects.js +348 -0
- package/dist/journey/workspace-effects.js.map +1 -0
- package/dist/local-actions/broker.d.ts +32 -0
- package/dist/local-actions/broker.d.ts.map +1 -0
- package/dist/local-actions/broker.js +400 -0
- package/dist/local-actions/broker.js.map +1 -0
- package/dist/local-actions/browser-action.d.ts +78 -0
- package/dist/local-actions/browser-action.d.ts.map +1 -0
- package/dist/local-actions/browser-action.js +307 -0
- package/dist/local-actions/browser-action.js.map +1 -0
- package/dist/local-actions/callback-relay.d.ts +45 -0
- package/dist/local-actions/callback-relay.d.ts.map +1 -0
- package/dist/local-actions/callback-relay.js +265 -0
- package/dist/local-actions/callback-relay.js.map +1 -0
- package/dist/local-actions/clipboard.d.ts +3 -0
- package/dist/local-actions/clipboard.d.ts.map +1 -0
- package/dist/local-actions/clipboard.js +18 -0
- package/dist/local-actions/clipboard.js.map +1 -0
- package/dist/local-actions/contracts.d.ts +63 -0
- package/dist/local-actions/contracts.d.ts.map +1 -0
- package/dist/local-actions/contracts.js +18 -0
- package/dist/local-actions/contracts.js.map +1 -0
- package/dist/local-actions/desktop-presentation.d.ts +141 -0
- package/dist/local-actions/desktop-presentation.d.ts.map +1 -0
- package/dist/local-actions/desktop-presentation.js +253 -0
- package/dist/local-actions/desktop-presentation.js.map +1 -0
- package/dist/local-actions/device-selection.d.ts +43 -0
- package/dist/local-actions/device-selection.d.ts.map +1 -0
- package/dist/local-actions/device-selection.js +154 -0
- package/dist/local-actions/device-selection.js.map +1 -0
- package/dist/local-actions/executor.d.ts +49 -0
- package/dist/local-actions/executor.d.ts.map +1 -0
- package/dist/local-actions/executor.js +329 -0
- package/dist/local-actions/executor.js.map +1 -0
- package/dist/local-actions/file-transfers.d.ts +141 -0
- package/dist/local-actions/file-transfers.d.ts.map +1 -0
- package/dist/local-actions/file-transfers.js +446 -0
- package/dist/local-actions/file-transfers.js.map +1 -0
- package/dist/local-actions/foreground-notifications.d.ts +45 -0
- package/dist/local-actions/foreground-notifications.d.ts.map +1 -0
- package/dist/local-actions/foreground-notifications.js +163 -0
- package/dist/local-actions/foreground-notifications.js.map +1 -0
- package/dist/local-actions/git-signing.d.ts +39 -0
- package/dist/local-actions/git-signing.d.ts.map +1 -0
- package/dist/local-actions/git-signing.js +135 -0
- package/dist/local-actions/git-signing.js.map +1 -0
- package/dist/local-actions/index.d.ts +19 -0
- package/dist/local-actions/index.d.ts.map +1 -0
- package/dist/local-actions/index.js +19 -0
- package/dist/local-actions/index.js.map +1 -0
- package/dist/local-actions/local-service-actions.d.ts +87 -0
- package/dist/local-actions/local-service-actions.d.ts.map +1 -0
- package/dist/local-actions/local-service-actions.js +347 -0
- package/dist/local-actions/local-service-actions.js.map +1 -0
- package/dist/local-actions/loopback.d.ts +5 -0
- package/dist/local-actions/loopback.d.ts.map +1 -0
- package/dist/local-actions/loopback.js +15 -0
- package/dist/local-actions/loopback.js.map +1 -0
- package/dist/local-actions/policy-store.d.ts +7 -0
- package/dist/local-actions/policy-store.d.ts.map +1 -0
- package/dist/local-actions/policy-store.js +70 -0
- package/dist/local-actions/policy-store.js.map +1 -0
- package/dist/local-actions/policy.d.ts +21 -0
- package/dist/local-actions/policy.d.ts.map +1 -0
- package/dist/local-actions/policy.js +43 -0
- package/dist/local-actions/policy.js.map +1 -0
- package/dist/local-actions/private-port-forward.d.ts +36 -0
- package/dist/local-actions/private-port-forward.d.ts.map +1 -0
- package/dist/local-actions/private-port-forward.js +154 -0
- package/dist/local-actions/private-port-forward.js.map +1 -0
- package/dist/local-actions/provider-mcp-config.d.ts +101 -0
- package/dist/local-actions/provider-mcp-config.d.ts.map +1 -0
- package/dist/local-actions/provider-mcp-config.js +166 -0
- package/dist/local-actions/provider-mcp-config.js.map +1 -0
- package/dist/local-actions/providers.d.ts +12 -0
- package/dist/local-actions/providers.d.ts.map +1 -0
- package/dist/local-actions/providers.js +42 -0
- package/dist/local-actions/providers.js.map +1 -0
- package/dist/local-actions/schemas.d.ts +4 -0
- package/dist/local-actions/schemas.d.ts.map +1 -0
- package/dist/local-actions/schemas.js +314 -0
- package/dist/local-actions/schemas.js.map +1 -0
- package/dist/local-actions/sensitive-consent.d.ts +32 -0
- package/dist/local-actions/sensitive-consent.d.ts.map +1 -0
- package/dist/local-actions/sensitive-consent.js +47 -0
- package/dist/local-actions/sensitive-consent.js.map +1 -0
- package/dist/machines/command-launch.d.ts +17 -0
- package/dist/machines/command-launch.d.ts.map +1 -0
- package/dist/machines/command-launch.js +52 -0
- package/dist/machines/command-launch.js.map +1 -0
- package/dist/machines/execution-receipt.d.ts +18 -0
- package/dist/machines/execution-receipt.d.ts.map +1 -0
- package/dist/machines/execution-receipt.js +87 -0
- package/dist/machines/execution-receipt.js.map +1 -0
- package/dist/machines/executions-screen.d.ts +6 -0
- package/dist/machines/executions-screen.d.ts.map +1 -0
- package/dist/machines/executions-screen.js +410 -0
- package/dist/machines/executions-screen.js.map +1 -0
- package/dist/machines/explorer.d.ts +75 -0
- package/dist/machines/explorer.d.ts.map +1 -0
- package/dist/machines/explorer.js +1726 -0
- package/dist/machines/explorer.js.map +1 -0
- package/dist/machines/live-supervisor-update.d.ts +325 -0
- package/dist/machines/live-supervisor-update.d.ts.map +1 -0
- package/dist/machines/live-supervisor-update.js +513 -0
- package/dist/machines/live-supervisor-update.js.map +1 -0
- package/dist/machines/machine-first.d.ts +123 -0
- package/dist/machines/machine-first.d.ts.map +1 -0
- package/dist/machines/machine-first.js +119 -0
- package/dist/machines/machine-first.js.map +1 -0
- package/dist/machines/opencode-supervisor.d.ts +51 -0
- package/dist/machines/opencode-supervisor.d.ts.map +1 -0
- package/dist/machines/opencode-supervisor.js +124 -0
- package/dist/machines/opencode-supervisor.js.map +1 -0
- package/dist/machines/pagination.d.ts +4 -0
- package/dist/machines/pagination.d.ts.map +1 -0
- package/dist/machines/pagination.js +7 -0
- package/dist/machines/pagination.js.map +1 -0
- package/dist/machines/provider-availability.d.ts +42 -0
- package/dist/machines/provider-availability.d.ts.map +1 -0
- package/dist/machines/provider-availability.js +82 -0
- package/dist/machines/provider-availability.js.map +1 -0
- package/dist/machines/provider-screen.d.ts +12 -0
- package/dist/machines/provider-screen.d.ts.map +1 -0
- package/dist/machines/provider-screen.js +129 -0
- package/dist/machines/provider-screen.js.map +1 -0
- package/dist/machines/session-actionability.d.ts +86 -0
- package/dist/machines/session-actionability.d.ts.map +1 -0
- package/dist/machines/session-actionability.js +125 -0
- package/dist/machines/session-actionability.js.map +1 -0
- package/dist/machines/session-visibility.d.ts +139 -0
- package/dist/machines/session-visibility.d.ts.map +1 -0
- package/dist/machines/session-visibility.js +109 -0
- package/dist/machines/session-visibility.js.map +1 -0
- package/dist/platform/adapter.d.ts +62 -0
- package/dist/platform/adapter.d.ts.map +1 -0
- package/dist/platform/adapter.js +240 -0
- package/dist/platform/adapter.js.map +1 -0
- package/dist/platform/support.d.ts +12 -0
- package/dist/platform/support.d.ts.map +1 -0
- package/dist/platform/support.js +25 -0
- package/dist/platform/support.js.map +1 -0
- package/dist/pty/contracts.d.ts +45 -0
- package/dist/pty/contracts.d.ts.map +1 -0
- package/dist/pty/contracts.js +2 -0
- package/dist/pty/contracts.js.map +1 -0
- package/dist/pty/evidence-gate.d.ts +14 -0
- package/dist/pty/evidence-gate.d.ts.map +1 -0
- package/dist/pty/evidence-gate.js +35 -0
- package/dist/pty/evidence-gate.js.map +1 -0
- package/dist/pty/index.d.ts +5 -0
- package/dist/pty/index.d.ts.map +1 -0
- package/dist/pty/index.js +5 -0
- package/dist/pty/index.js.map +1 -0
- package/dist/pty/node-host-terminal.d.ts +14 -0
- package/dist/pty/node-host-terminal.d.ts.map +1 -0
- package/dist/pty/node-host-terminal.js +173 -0
- package/dist/pty/node-host-terminal.js.map +1 -0
- package/dist/pty/node-process.d.ts +26 -0
- package/dist/pty/node-process.d.ts.map +1 -0
- package/dist/pty/node-process.js +102 -0
- package/dist/pty/node-process.js.map +1 -0
- package/dist/runtime/api-terminal-control-plane.d.ts +7 -0
- package/dist/runtime/api-terminal-control-plane.d.ts.map +1 -0
- package/dist/runtime/api-terminal-control-plane.js +95 -0
- package/dist/runtime/api-terminal-control-plane.js.map +1 -0
- package/dist/runtime/backoff.d.ts +17 -0
- package/dist/runtime/backoff.d.ts.map +1 -0
- package/dist/runtime/backoff.js +61 -0
- package/dist/runtime/backoff.js.map +1 -0
- package/dist/runtime/boundary.d.ts +171 -0
- package/dist/runtime/boundary.d.ts.map +1 -0
- package/dist/runtime/boundary.js +1858 -0
- package/dist/runtime/boundary.js.map +1 -0
- package/dist/runtime/capability-gate.d.ts +25 -0
- package/dist/runtime/capability-gate.d.ts.map +1 -0
- package/dist/runtime/capability-gate.js +77 -0
- package/dist/runtime/capability-gate.js.map +1 -0
- package/dist/runtime/contracts.d.ts +25 -0
- package/dist/runtime/contracts.d.ts.map +1 -0
- package/dist/runtime/contracts.js +66 -0
- package/dist/runtime/contracts.js.map +1 -0
- package/dist/runtime/errors.d.ts +20 -0
- package/dist/runtime/errors.d.ts.map +1 -0
- package/dist/runtime/errors.js +22 -0
- package/dist/runtime/errors.js.map +1 -0
- package/dist/runtime/index.d.ts +9 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +9 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/node-foreground-session.d.ts +50 -0
- package/dist/runtime/node-foreground-session.d.ts.map +1 -0
- package/dist/runtime/node-foreground-session.js +431 -0
- package/dist/runtime/node-foreground-session.js.map +1 -0
- package/dist/runtime/node-websocket-connector.d.ts +6 -0
- package/dist/runtime/node-websocket-connector.d.ts.map +1 -0
- package/dist/runtime/node-websocket-connector.js +344 -0
- package/dist/runtime/node-websocket-connector.js.map +1 -0
- package/dist/runtime/observer-screen.d.ts +6 -0
- package/dist/runtime/observer-screen.d.ts.map +1 -0
- package/dist/runtime/observer-screen.js +144 -0
- package/dist/runtime/observer-screen.js.map +1 -0
- package/dist/runtime/owner-grant-operations.d.ts +136 -0
- package/dist/runtime/owner-grant-operations.d.ts.map +1 -0
- package/dist/runtime/owner-grant-operations.js +216 -0
- package/dist/runtime/owner-grant-operations.js.map +1 -0
- package/dist/runtime/owner-grants-screen.d.ts +40 -0
- package/dist/runtime/owner-grants-screen.d.ts.map +1 -0
- package/dist/runtime/owner-grants-screen.js +987 -0
- package/dist/runtime/owner-grants-screen.js.map +1 -0
- package/dist/runtime/terminal-transport.d.ts +85 -0
- package/dist/runtime/terminal-transport.d.ts.map +1 -0
- package/dist/runtime/terminal-transport.js +152 -0
- package/dist/runtime/terminal-transport.js.map +1 -0
- package/dist/sync/continuous-sync-supervisor.d.ts +107 -0
- package/dist/sync/continuous-sync-supervisor.d.ts.map +1 -0
- package/dist/sync/continuous-sync-supervisor.js +1117 -0
- package/dist/sync/continuous-sync-supervisor.js.map +1 -0
- package/dist/sync/index.d.ts +9 -0
- package/dist/sync/index.d.ts.map +1 -0
- package/dist/sync/index.js +9 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/sync/journal.d.ts +57 -0
- package/dist/sync/journal.d.ts.map +1 -0
- package/dist/sync/journal.js +685 -0
- package/dist/sync/journal.js.map +1 -0
- package/dist/sync/revisions.d.ts +118 -0
- package/dist/sync/revisions.d.ts.map +1 -0
- package/dist/sync/revisions.js +364 -0
- package/dist/sync/revisions.js.map +1 -0
- package/dist/sync/supervisor.d.ts +107 -0
- package/dist/sync/supervisor.d.ts.map +1 -0
- package/dist/sync/supervisor.js +246 -0
- package/dist/sync/supervisor.js.map +1 -0
- package/dist/sync/workspace-sync-client.d.ts +18 -0
- package/dist/sync/workspace-sync-client.d.ts.map +1 -0
- package/dist/sync/workspace-sync-client.js +150 -0
- package/dist/sync/workspace-sync-client.js.map +1 -0
- package/dist/sync/workspace-sync-coordinator.d.ts +76 -0
- package/dist/sync/workspace-sync-coordinator.d.ts.map +1 -0
- package/dist/sync/workspace-sync-coordinator.js +621 -0
- package/dist/sync/workspace-sync-coordinator.js.map +1 -0
- package/dist/sync/workspace-sync-product-service.d.ts +79 -0
- package/dist/sync/workspace-sync-product-service.d.ts.map +1 -0
- package/dist/sync/workspace-sync-product-service.js +398 -0
- package/dist/sync/workspace-sync-product-service.js.map +1 -0
- package/dist/sync/workspace-sync-protocol.d.ts +145 -0
- package/dist/sync/workspace-sync-protocol.d.ts.map +1 -0
- package/dist/sync/workspace-sync-protocol.js +347 -0
- package/dist/sync/workspace-sync-protocol.js.map +1 -0
- package/dist/terminal/appbar.d.ts +40 -0
- package/dist/terminal/appbar.d.ts.map +1 -0
- package/dist/terminal/appbar.js +55 -0
- package/dist/terminal/appbar.js.map +1 -0
- package/dist/terminal/cell-width.d.ts +3 -0
- package/dist/terminal/cell-width.d.ts.map +1 -0
- package/dist/terminal/cell-width.js +53 -0
- package/dist/terminal/cell-width.js.map +1 -0
- package/dist/terminal/codec.d.ts +107 -0
- package/dist/terminal/codec.d.ts.map +1 -0
- package/dist/terminal/codec.js +538 -0
- package/dist/terminal/codec.js.map +1 -0
- package/dist/terminal/foreground.d.ts +135 -0
- package/dist/terminal/foreground.d.ts.map +1 -0
- package/dist/terminal/foreground.js +2097 -0
- package/dist/terminal/foreground.js.map +1 -0
- package/dist/terminal/generated/terminal-wire-v1.d.ts +26 -0
- package/dist/terminal/generated/terminal-wire-v1.d.ts.map +1 -0
- package/dist/terminal/generated/terminal-wire-v1.js +27 -0
- package/dist/terminal/generated/terminal-wire-v1.js.map +1 -0
- package/dist/terminal/mode.d.ts +33 -0
- package/dist/terminal/mode.d.ts.map +1 -0
- package/dist/terminal/mode.js +99 -0
- package/dist/terminal/mode.js.map +1 -0
- package/dist/terminal/passthrough.d.ts +47 -0
- package/dist/terminal/passthrough.d.ts.map +1 -0
- package/dist/terminal/passthrough.js +666 -0
- package/dist/terminal/passthrough.js.map +1 -0
- package/dist/terminal/resume.d.ts +58 -0
- package/dist/terminal/resume.d.ts.map +1 -0
- package/dist/terminal/resume.js +185 -0
- package/dist/terminal/resume.js.map +1 -0
- package/dist/terminal/viewport.d.ts +93 -0
- package/dist/terminal/viewport.d.ts.map +1 -0
- package/dist/terminal/viewport.js +266 -0
- package/dist/terminal/viewport.js.map +1 -0
- package/dist/terminal/workbench.d.ts +32 -0
- package/dist/terminal/workbench.d.ts.map +1 -0
- package/dist/terminal/workbench.js +316 -0
- package/dist/terminal/workbench.js.map +1 -0
- package/dist/terminal/xterm-vte.d.ts +49 -0
- package/dist/terminal/xterm-vte.d.ts.map +1 -0
- package/dist/terminal/xterm-vte.js +602 -0
- package/dist/terminal/xterm-vte.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/workspace/binding-path.d.ts +17 -0
- package/dist/workspace/binding-path.d.ts.map +1 -0
- package/dist/workspace/binding-path.js +91 -0
- package/dist/workspace/binding-path.js.map +1 -0
- package/dist/workspace/binding-store.d.ts +107 -0
- package/dist/workspace/binding-store.d.ts.map +1 -0
- package/dist/workspace/binding-store.js +783 -0
- package/dist/workspace/binding-store.js.map +1 -0
- package/dist/workspace/binding.d.ts +35 -0
- package/dist/workspace/binding.d.ts.map +1 -0
- package/dist/workspace/binding.js +70 -0
- package/dist/workspace/binding.js.map +1 -0
- package/dist/workspace/errors.d.ts +4 -0
- package/dist/workspace/errors.d.ts.map +1 -0
- package/dist/workspace/errors.js +19 -0
- package/dist/workspace/errors.js.map +1 -0
- package/dist/workspace/exclusion.d.ts +21 -0
- package/dist/workspace/exclusion.d.ts.map +1 -0
- package/dist/workspace/exclusion.js +243 -0
- package/dist/workspace/exclusion.js.map +1 -0
- package/dist/workspace/index.d.ts +8 -0
- package/dist/workspace/index.d.ts.map +1 -0
- package/dist/workspace/index.js +8 -0
- package/dist/workspace/index.js.map +1 -0
- package/dist/workspace/lifecycle.d.ts +56 -0
- package/dist/workspace/lifecycle.d.ts.map +1 -0
- package/dist/workspace/lifecycle.js +94 -0
- package/dist/workspace/lifecycle.js.map +1 -0
- package/dist/workspace/manifest.d.ts +47 -0
- package/dist/workspace/manifest.d.ts.map +1 -0
- package/dist/workspace/manifest.js +243 -0
- package/dist/workspace/manifest.js.map +1 -0
- package/dist/workspace/paths.d.ts +14 -0
- package/dist/workspace/paths.d.ts.map +1 -0
- package/dist/workspace/paths.js +67 -0
- package/dist/workspace/paths.js.map +1 -0
- package/dist/workspace/schema.d.ts +15 -0
- package/dist/workspace/schema.d.ts.map +1 -0
- package/dist/workspace/schema.js +33 -0
- package/dist/workspace/schema.js.map +1 -0
- package/dist/workspace/selection-screen.d.ts +4 -0
- package/dist/workspace/selection-screen.d.ts.map +1 -0
- package/dist/workspace/selection-screen.js +216 -0
- package/dist/workspace/selection-screen.js.map +1 -0
- package/dist/workspace/selection-service.d.ts +16 -0
- package/dist/workspace/selection-service.d.ts.map +1 -0
- package/dist/workspace/selection-service.js +65 -0
- package/dist/workspace/selection-service.js.map +1 -0
- package/node_modules/@xterm/headless/README.md +31 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.js +2 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.js.map +1 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.mjs +46 -0
- package/node_modules/@xterm/headless/lib-headless/xterm-headless.mjs.map +7 -0
- package/node_modules/@xterm/headless/package.json +29 -0
- package/node_modules/@xterm/headless/typings/xterm-headless.d.ts +1385 -0
- package/package.json +75 -0
|
@@ -0,0 +1,604 @@
|
|
|
1
|
+
import { ownerObserveGrantSchemas, ownerObserveGrantOperations } from './owner-observe-grants-v2-schema.js';
|
|
2
|
+
import { assertCanonicalUuid } from '../core/validation.js';
|
|
3
|
+
import { CunaError, EXIT_CODES } from '../core/errors.js';
|
|
4
|
+
// One implementation of the producer's order over a run, shared with the durable
|
|
5
|
+
// store that carries it between processes. Two copies of this rule would drift.
|
|
6
|
+
import { audienceFactIsOlder } from '../runtime/owner-grant-operations.js';
|
|
7
|
+
const schemas = ownerObserveGrantSchemas;
|
|
8
|
+
function valid(v, s) {
|
|
9
|
+
if (s.$ref)
|
|
10
|
+
return valid(v, schemas[s.$ref.split('/').at(-1)]);
|
|
11
|
+
if (s.allOf && !s.allOf.every(x => valid(v, x)))
|
|
12
|
+
return false;
|
|
13
|
+
if (s.anyOf && !s.anyOf.some(x => valid(v, x)))
|
|
14
|
+
return false;
|
|
15
|
+
// Exactly one branch, not at least one. The canonical contract uses `oneOf`
|
|
16
|
+
// where a discriminating field decides the shape -- an operation's `status`
|
|
17
|
+
// decides whether the five accompanying fields and a non-null `response` are
|
|
18
|
+
// present -- and a body satisfying two branches is one the producer cannot
|
|
19
|
+
// emit. Reading it as `anyOf` would have accepted a schema keyword this file
|
|
20
|
+
// does not implement as no constraint at all.
|
|
21
|
+
if (s.oneOf && s.oneOf.filter(x => valid(v, x)).length !== 1)
|
|
22
|
+
return false;
|
|
23
|
+
if (s.if) {
|
|
24
|
+
const branch = valid(v, s.if) ? s.then : s.else;
|
|
25
|
+
if (branch && !valid(v, branch))
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (s.const !== undefined && v !== s.const || s.enum && !s.enum.includes(v))
|
|
29
|
+
return false;
|
|
30
|
+
if (Array.isArray(s.type))
|
|
31
|
+
return s.type.some(type => valid(v, { ...s, type }));
|
|
32
|
+
if (s.type === 'null')
|
|
33
|
+
return v === null;
|
|
34
|
+
if (s.type === 'string')
|
|
35
|
+
return typeof v === 'string' && v.length >= (s.minLength ?? 0) && v.length <= (s.maxLength ?? Infinity) && (!s.pattern || new RegExp(s.pattern).test(v));
|
|
36
|
+
if (s.type === 'integer')
|
|
37
|
+
return typeof v === 'number' && Number.isSafeInteger(v) && v >= (s.minimum ?? -Infinity) && v <= (s.maximum ?? Infinity);
|
|
38
|
+
if (s.type === 'array')
|
|
39
|
+
return Array.isArray(v) && v.length <= (s.maxItems ?? Infinity) && v.every(x => s.items && valid(x, s.items));
|
|
40
|
+
if (s.type === 'object' || s.properties || s.required) {
|
|
41
|
+
if (!v || typeof v !== 'object' || Array.isArray(v))
|
|
42
|
+
return false;
|
|
43
|
+
const row = v;
|
|
44
|
+
const descriptors = Object.getOwnPropertyDescriptors(row);
|
|
45
|
+
if (Reflect.ownKeys(row).some(k => typeof k !== 'string' || !descriptors[k]?.enumerable || !('value' in descriptors[k])))
|
|
46
|
+
return false;
|
|
47
|
+
return !(s.required ?? []).some(k => !Object.hasOwn(row, k)) && Object.keys(row).every(k => s.properties?.[k] ? valid(row[k], s.properties[k]) : s.additionalProperties !== false);
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
export class OwnerGrantError extends CunaError {
|
|
52
|
+
kind;
|
|
53
|
+
/**
|
|
54
|
+
* True when the server-side effect of this attempt is UNDETERMINED.
|
|
55
|
+
*
|
|
56
|
+
* A refusal the server issued before acting (denied, stale revision, unknown
|
|
57
|
+
* grant, rejected credential) settles the outcome: nothing changed. A lost
|
|
58
|
+
* answer, a local cancellation after dispatch, or a receipt this CLI refused
|
|
59
|
+
* to trust does NOT: the authority may exist. Only the first kind may drop a
|
|
60
|
+
* durable operation record.
|
|
61
|
+
*/
|
|
62
|
+
effectUnknown;
|
|
63
|
+
constructor(kind, message, cause, reason, effectUnknown = false) {
|
|
64
|
+
super({ code: `cuna.share.${kind}`, message, exitCode: kind === 'denied' || kind === 'identity_mismatch' || kind === 'malformed_receipt' ? EXIT_CODES.policy : kind === 'stale_revision' || kind === 'operation_conflict' ? EXIT_CODES.conflict : kind === 'auth' ? EXIT_CODES.auth : kind === 'not_found' || kind === 'grant_unavailable' ? EXIT_CODES.remote : EXIT_CODES.network, retryable: kind === 'unavailable', ...(reason === undefined ? {} : { details: { reason } }), ...(cause === undefined ? {} : { cause }) });
|
|
65
|
+
this.kind = kind;
|
|
66
|
+
this.effectUnknown = effectUnknown;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/** Re-mint a failure raised after a mutation left this process: its effect is not settled, whatever the reason reads like. */
|
|
70
|
+
export function withUnknownEffect(error) {
|
|
71
|
+
return error.effectUnknown ? error : new OwnerGrantError(error.kind, error.message, error.cause, typeof error.details?.reason === 'string' ? error.details.reason : undefined, true);
|
|
72
|
+
}
|
|
73
|
+
const malformed = (what) => new OwnerGrantError('malformed_receipt', `Cuna answered with a ${what} that does not match the collaboration contract. Nothing was trusted from it.`);
|
|
74
|
+
const mismatch = (what) => new OwnerGrantError('identity_mismatch', `Cuna answered about a different ${what}. The receipt was refused.`);
|
|
75
|
+
function check(value, name, what) { if (!valid(value, schemas[name]))
|
|
76
|
+
throw malformed(what); }
|
|
77
|
+
const GRANT_UNAVAILABLE = Object.freeze({
|
|
78
|
+
create: "Cuna refused this grant and created nothing. The member is no longer an active observer at the membership revision that was read, this account is no longer the Project's active owner, the session is not one it owns, or the requested expiry is outside the window Cuna accepts. Reread the members and decide again.",
|
|
79
|
+
revoke: "Cuna refused this revocation and changed nothing. The grant is no longer active at the revision that was read - it may already be revoked or expired - or this account is no longer the Project's active owner. Inspect the grant to read its current state.",
|
|
80
|
+
inspect: 'Cuna does not know this grant for this account. It may never have existed, or this account is neither its owner nor its subject.',
|
|
81
|
+
members: "Cuna would not list this Project's members. This account is not the Project's present active owner, or the Project's authority is not in a state Cuna can read members from.",
|
|
82
|
+
});
|
|
83
|
+
/**
|
|
84
|
+
* What a 409 `operation_conflict` actually means, per operation.
|
|
85
|
+
*
|
|
86
|
+
* The Edge maps two producer facts onto this one code: the explicit
|
|
87
|
+
* `collab_v2_observe_operation_conflict` raised when an operation ID is
|
|
88
|
+
* replayed with a different actor, action or request tuple, and PostgreSQL
|
|
89
|
+
* `23505`, which on create is the partial unique index
|
|
90
|
+
* `collab_v2_one_active_observe_grant(agent_session_id, session_incarnation,
|
|
91
|
+
* subject_id) where state='active'`. Both abort the transaction, so this
|
|
92
|
+
* attempt applied nothing -- but the second says an equivalent authority
|
|
93
|
+
* already exists, which the owner must be told.
|
|
94
|
+
*/
|
|
95
|
+
const OPERATION_CONFLICT = Object.freeze({
|
|
96
|
+
create: 'Cuna refused this as a conflict and this attempt created nothing. Either this exact operation ID was already used for a different request, or an active grant for this member on this session already exists.',
|
|
97
|
+
revoke: 'Cuna refused this as a conflict and this attempt changed nothing. This exact operation ID was already used for a different revocation request. Inspect the grant to read its current state.',
|
|
98
|
+
inspect: 'Cuna answered this read with a conflict. A read carries no operation identity and applies nothing, so read again.',
|
|
99
|
+
members: 'Cuna answered this read with a conflict. A read carries no operation identity and applies nothing, so read again.',
|
|
100
|
+
});
|
|
101
|
+
const pick = (table, operation, fallback) => operation === undefined || operation === 'audience' || operation === 'audience-state' ? fallback : table[operation];
|
|
102
|
+
/**
|
|
103
|
+
* What the publication route actually answers, per Problem code.
|
|
104
|
+
*
|
|
105
|
+
* Read at infra `2d61dd11494e76e5b48623b57aa99d3649dee2ff`. `edge/src/api.ts`
|
|
106
|
+
* validates the body (422 `audience_request_invalid`), reads the AgentSession as
|
|
107
|
+
* the signed-in account (a session this account does not own is a 404
|
|
108
|
+
* `resource_not_found` from `translateDatabaseError`), refuses before asking the
|
|
109
|
+
* session when there is no current control fence or runtime lease (503
|
|
110
|
+
* `audience_runtime_unavailable`), and otherwise renders
|
|
111
|
+
* `coordinateSessionAudienceV2`'s non-observed result as 503
|
|
112
|
+
* `audience_<reason>`. Where that coordinator gives up decides everything below:
|
|
113
|
+
* `invalid_scope`, `request_unavailable` and `request_expired` all return BEFORE
|
|
114
|
+
* `registry.controlSessionAudienceV2` is called, so the session was asked
|
|
115
|
+
* nothing; `producer_unavailable` means the session answered `unavailable` and
|
|
116
|
+
* that answer was recorded, so the transition did not happen; and the three
|
|
117
|
+
* remaining reasons are raised at or after the moment the session was asked, so
|
|
118
|
+
* the change may have been made.
|
|
119
|
+
*
|
|
120
|
+
* `effectUnknown` here is a statement about THIS attempt, and on a REPLAY that
|
|
121
|
+
* is exactly the problem: a refusal of the re-raise describes the re-raise. It
|
|
122
|
+
* cannot describe the attempt being replayed, whose answer was never seen. So
|
|
123
|
+
* every refusal that is settled on a first dispatch because the session was
|
|
124
|
+
* asked nothing is re-minted as uncertain on a replay, with its own sentence
|
|
125
|
+
* (`replay`) -- settling there would destroy the only identity that could ever
|
|
126
|
+
* finish the original.
|
|
127
|
+
*
|
|
128
|
+
* `settledCanResend` says whether sending this exact request again could still
|
|
129
|
+
* settle it. It is false where the producer has closed the door: after
|
|
130
|
+
* `request_expired` the stored request's deadline has passed and
|
|
131
|
+
* `coordinateSessionAudienceV2` returns before the session is reached, and after
|
|
132
|
+
* `producer_unavailable` Cuna has RECORDED a result for that request, so a
|
|
133
|
+
* differing later answer is refused `collab_v2_audience_conflict`. Offering a
|
|
134
|
+
* resend there would steer an owner into the one path that can desynchronise the
|
|
135
|
+
* runtime from Cuna.
|
|
136
|
+
*/
|
|
137
|
+
const AUDIENCE_REFUSAL = Object.freeze({
|
|
138
|
+
audience_request_invalid: { message: 'Cuna rejected this as not a valid sharing request and never passed it to the session, so nothing about sharing changed.', effectUnknown: false },
|
|
139
|
+
audience_runtime_unavailable: { message: 'This session is not connected to Cuna right now, so Cuna asked it nothing and nothing about sharing changed. Once the session is running again, decide again.', effectUnknown: false },
|
|
140
|
+
audience_invalid_scope: { message: 'Cuna would not raise this with the session: what it knows about the session is not current enough to act on. The session was asked nothing and nothing about sharing changed.', effectUnknown: false,
|
|
141
|
+
replay: 'Cuna would not raise this with the session again: what it knows about the session is not current enough to act on. That refusal is about this attempt only - what the earlier one did is still unknown.' },
|
|
142
|
+
audience_request_unavailable: { message: 'Cuna could not raise this with the session, so the session was asked nothing and nothing about sharing changed. Another sharing change on this session may still be in flight; wait a few seconds and decide again.', effectUnknown: false,
|
|
143
|
+
replay: 'Cuna could not raise this with the session again, so the session was asked nothing this time. That says nothing about what the earlier attempt did, which is still unknown. Another sharing change on this session may still be in flight; waiting a few seconds and sending this same request again may still settle it.' },
|
|
144
|
+
// The producer's own reason is collapsed into one code by the Edge, so the CLI
|
|
145
|
+
// cannot know WHY the session refused. `audience_stale` -- what a session that
|
|
146
|
+
// has already moved past the generation Cuna asked about returns -- is one of
|
|
147
|
+
// the possibilities, and it is precisely the case where something did change.
|
|
148
|
+
// Recording the refusal is itself an effect: `consume_collab_v2_session_audience_response`
|
|
149
|
+
// retires every pending observer attachment for this session's dispatch and
|
|
150
|
+
// closes every active observer endpoint, whether the result was observed or
|
|
151
|
+
// unavailable.
|
|
152
|
+
audience_producer_unavailable: { message: 'The session refused this change and Cuna recorded the refusal, so the change you asked for was not applied. Cuna does not pass on why the session refused, so this is not evidence that nothing else changed: recording a refusal also disconnects anyone currently watching this session.', effectUnknown: false, settledCanResend: false,
|
|
153
|
+
replay: 'The session refused this attempt and Cuna recorded that refusal. It is an answer about this attempt only - what the earlier one did is still unknown - and sending this same request again cannot settle it, because Cuna has now recorded an answer for it.' },
|
|
154
|
+
audience_request_expired: { message: 'Cuna ran out of time for this request before the session answered, so the session was asked nothing and nothing about sharing changed.', effectUnknown: false, settledCanResend: false,
|
|
155
|
+
replay: 'Cuna ran out of time for this request before the session answered, and it will answer the same way every time from now on: this exact request can no longer be sent. What the first attempt did is still unknown.' },
|
|
156
|
+
audience_transport_unavailable: { message: 'Cuna asked the session and no answer came back. This change may or may not have been made.', effectUnknown: true },
|
|
157
|
+
audience_response_unavailable: { message: 'The session answered something Cuna would not accept, so Cuna recorded nothing. This change may or may not have been made.', effectUnknown: true },
|
|
158
|
+
audience_receipt_unavailable: { message: 'The session answered, but Cuna could not record the answer. The session may now be in the state you asked for while Cuna does not know it.', effectUnknown: true },
|
|
159
|
+
});
|
|
160
|
+
/**
|
|
161
|
+
* What a refusal of the READING route means, per Problem code.
|
|
162
|
+
*
|
|
163
|
+
* Every entry settles this attempt and nothing else. A reading issues no
|
|
164
|
+
* transition: `consume_collab_v2_session_audience_response` returns before it
|
|
165
|
+
* retires an attachment or closes an endpoint when the action is `observe`, so
|
|
166
|
+
* even a refusal Cuna recorded leaves the audience, the observers and the
|
|
167
|
+
* streams exactly as they were. That is why none of these is `effectUnknown`
|
|
168
|
+
* and why none of them may say anything about an earlier transition: a question
|
|
169
|
+
* Cuna could not put to the session is not a verdict on a change it asked about
|
|
170
|
+
* minutes ago.
|
|
171
|
+
*
|
|
172
|
+
* `transport_unavailable` is the one that deserves its own sentence. The Edge
|
|
173
|
+
* registry refuses an `observe` request to a supervisor that does not advertise
|
|
174
|
+
* `session_audience_state_v2` -- every Machine created before that asset
|
|
175
|
+
* existed -- and a genuinely lost answer arrives as the same code. Nothing
|
|
176
|
+
* distinguishes them from here, so both are named instead of one being guessed.
|
|
177
|
+
*/
|
|
178
|
+
const READING_REFUSAL = Object.freeze({
|
|
179
|
+
audience_request_invalid: 'Cuna rejected this as not a valid question about sharing, so it asked the session nothing.',
|
|
180
|
+
audience_runtime_unavailable: 'This session is not connected to Cuna right now, so Cuna could not ask it what it is sharing.',
|
|
181
|
+
audience_invalid_scope: 'Cuna would not raise this with the session: what it knows about the session is not current enough to ask.',
|
|
182
|
+
audience_request_unavailable: 'Cuna could not raise this question with the session. Another sharing change on this session may still be in flight; wait a few seconds and ask again.',
|
|
183
|
+
audience_request_expired: 'Cuna ran out of time before it could put this question to the session.',
|
|
184
|
+
audience_producer_unavailable: 'The session refused to answer. Refusing to answer changes nothing about what it is sharing; it only leaves it unread.',
|
|
185
|
+
audience_transport_unavailable: 'Cuna asked the session and no answer came back. A session on a Machine created before this question existed can never answer it, and that is indistinguishable from a lost answer.',
|
|
186
|
+
audience_response_unavailable: 'The session answered something Cuna would not accept, so nothing was read.',
|
|
187
|
+
audience_receipt_unavailable: 'The session answered, but Cuna could not record the answer, so nothing was read.',
|
|
188
|
+
audience_history_unavailable: 'Cuna could not look up what that earlier change is recorded to have done, so it asked the session nothing either.',
|
|
189
|
+
});
|
|
190
|
+
/** True when resending this exact request could still settle it; false where the producer has closed that door. */
|
|
191
|
+
export function audienceRefusalCanResend(reason) {
|
|
192
|
+
return typeof reason !== 'string' || !Object.hasOwn(AUDIENCE_REFUSAL, reason) || AUDIENCE_REFUSAL[reason].settledCanResend !== false;
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Map a transport failure to one typed owner failure.
|
|
196
|
+
*
|
|
197
|
+
* A mutation whose answer never arrived is uncertain, never assumed failed or
|
|
198
|
+
* applied. Beyond that, the status is only believed as a collaboration answer
|
|
199
|
+
* when the Problem document names the collaboration code that produces it: a
|
|
200
|
+
* 404 that names no reason is a different event from `grant_unavailable`, and
|
|
201
|
+
* saying "Cuna does not know this grant" about it would invent a cause.
|
|
202
|
+
*/
|
|
203
|
+
export function classifyTransportFailure(error, mutation, operation) {
|
|
204
|
+
if (error instanceof OwnerGrantError)
|
|
205
|
+
return error;
|
|
206
|
+
if (error instanceof CunaError) {
|
|
207
|
+
const status = typeof error.details?.http_status === 'number' ? error.details.http_status : undefined;
|
|
208
|
+
const reason = typeof error.details?.reason === 'string' ? error.details.reason : error.code;
|
|
209
|
+
if (error.code === 'cuna.auth.rejected')
|
|
210
|
+
return new OwnerGrantError('auth', 'Cuna rejected the current sign-in. Run `cuna login` and retry.', error, reason);
|
|
211
|
+
// The publication route shares none of the grant route's collaboration codes,
|
|
212
|
+
// so its answers are read from its own table before the grant mapping below
|
|
213
|
+
// could give one of them a meaning it does not have.
|
|
214
|
+
if (operation === 'audience' && typeof reason === 'string' && Object.hasOwn(AUDIENCE_REFUSAL, reason)) {
|
|
215
|
+
const refusal = AUDIENCE_REFUSAL[reason];
|
|
216
|
+
return new OwnerGrantError(refusal.effectUnknown ? 'uncertain' : 'unavailable', refusal.message, error, reason, refusal.effectUnknown);
|
|
217
|
+
}
|
|
218
|
+
// A reading changes nothing, so every refusal of it is settled for the reading
|
|
219
|
+
// and silent about every other request. It is read before the grant mapping
|
|
220
|
+
// for the same reason the publication route is.
|
|
221
|
+
if (operation === 'audience-state' && typeof reason === 'string' && Object.hasOwn(READING_REFUSAL, reason))
|
|
222
|
+
return new OwnerGrantError('unavailable', READING_REFUSAL[reason], error, reason);
|
|
223
|
+
if (operation === 'audience-state' && status === 404 && error.code === 'cuna.remote.operation_not_served')
|
|
224
|
+
return new OwnerGrantError('unavailable', `This Cuna deployment does not serve the sharing-state question this build asks, so it could not be asked. ${error.message}`, error, reason);
|
|
225
|
+
if (operation === 'audience-state' && status === 404)
|
|
226
|
+
return new OwnerGrantError('not_found', 'Cuna does not know this session for this account, so it read nothing.', error, reason);
|
|
227
|
+
if (operation === 'audience' && status === 404 && error.code !== 'cuna.remote.operation_not_served')
|
|
228
|
+
return new OwnerGrantError('not_found', 'Cuna does not know this session for this account, so it asked nothing and nothing about sharing changed.', error, reason);
|
|
229
|
+
// 403 is the Edge's own principal check -- auth class plus `collaboration:manage`.
|
|
230
|
+
// Project ownership is proved later, inside the transaction, and its failure
|
|
231
|
+
// is a 404. Naming ownership here would send the owner after the wrong thing.
|
|
232
|
+
if (status === 403 || error.code === 'cuna.policy.denied')
|
|
233
|
+
return new OwnerGrantError('denied', 'Cuna denied this action for this sign-in: it does not carry collaboration:manage. Project ownership is checked separately and is not what this answer reports.', error, reason);
|
|
234
|
+
if (status === 409)
|
|
235
|
+
return new OwnerGrantError('operation_conflict', reason === 'operation_conflict' ? pick(OPERATION_CONFLICT, operation, 'Cuna refused this as a conflict. This attempt applied nothing.') : 'Cuna answered with a conflict but named no collaboration reason. This attempt applied nothing; nothing further can be concluded from it.', error, reason);
|
|
236
|
+
// A deployment that does not implement the route is not a missing grant.
|
|
237
|
+
if (status === 404 && error.code === 'cuna.remote.operation_not_served')
|
|
238
|
+
return new OwnerGrantError('unavailable', `This Cuna deployment does not serve the collaboration grant operations this build uses. ${error.message}`, error, reason);
|
|
239
|
+
if (status === 404)
|
|
240
|
+
return new OwnerGrantError(reason === 'grant_unavailable' ? 'grant_unavailable' : 'not_found', reason === 'grant_unavailable' ? pick(GRANT_UNAVAILABLE, operation, 'Cuna refused this: the grant, session, membership or Project authority it needs is not available to this account.') : 'Cuna answered 404 and named no collaboration reason, so which grant, session, membership or Project it means is unknown.', error, reason);
|
|
241
|
+
if (status === 422)
|
|
242
|
+
return new OwnerGrantError('unavailable', 'Cuna rejected the request as invalid for the collaboration contract and never reached the grant store, so nothing changed.', error, reason);
|
|
243
|
+
if (status !== undefined && status >= 400 && status < 500)
|
|
244
|
+
return new OwnerGrantError('unavailable', 'Cuna rejected the request without a collaboration answer.', error, reason);
|
|
245
|
+
if (mutation)
|
|
246
|
+
return new OwnerGrantError('uncertain', 'The answer to this change never arrived. Its outcome is unknown until reconciled.', error, reason, true);
|
|
247
|
+
return new OwnerGrantError('unavailable', 'Cuna could not be reached for this read.', error, reason);
|
|
248
|
+
}
|
|
249
|
+
if (error instanceof Error && error.name === 'AbortError')
|
|
250
|
+
return new OwnerGrantError('aborted', 'The action was cancelled locally.', error, undefined, mutation);
|
|
251
|
+
return mutation ? new OwnerGrantError('uncertain', 'The answer to this change never arrived. Its outcome is unknown until reconciled.', error, undefined, true) : new OwnerGrantError('unavailable', 'Cuna could not be reached for this read.', error);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* The plain-language meaning of one receipt. `revoking`/`effective_pending`
|
|
255
|
+
* MUST NOT read as "revoked": the endpoint may still be serving frames.
|
|
256
|
+
*/
|
|
257
|
+
export function describeGrantState(g, now = Date.now()) {
|
|
258
|
+
if (g.state === 'active' && g.expires_at <= now)
|
|
259
|
+
return { label: 'Expired', detail: 'The grant reached its expiry. No new observation admission is possible.', final: true };
|
|
260
|
+
if (g.state === 'active')
|
|
261
|
+
return { label: 'Active', detail: `Read-only observation may be admitted until ${new Date(g.expires_at).toISOString()}. No keyboard, resize or signal is granted.`, final: false };
|
|
262
|
+
if (g.state === 'revoking')
|
|
263
|
+
return { label: 'Revocation requested, not yet effective', detail: 'Cuna accepted the revocation but has not confirmed the stream endpoint is retired. The observer may still see output. Inspect again to learn when it is effective.', final: false };
|
|
264
|
+
if (g.state === 'revoked')
|
|
265
|
+
return { label: g.revocation_state === 'effective' ? 'Revoked, effective' : 'Revoked, endpoint retirement pending', detail: g.revocation_state === 'effective' ? 'Observation access ended and the stream endpoint is retired.' : 'The grant is revoked but endpoint retirement is not yet confirmed. Inspect again.', final: g.revocation_state === 'effective' };
|
|
266
|
+
return { label: 'Expired', detail: 'The grant reached its expiry. No new observation admission is possible.', final: true };
|
|
267
|
+
}
|
|
268
|
+
export function decodeOwnerGrant(value, owner, project, reference) {
|
|
269
|
+
check(value, 'SessionObserveGrantV2Receipt', 'grant receipt');
|
|
270
|
+
const g = value;
|
|
271
|
+
if (g.owner_principal_id !== owner)
|
|
272
|
+
throw mismatch('owner');
|
|
273
|
+
if (g.project_id !== project)
|
|
274
|
+
throw mismatch('Project');
|
|
275
|
+
if (g.subject_principal_id === owner)
|
|
276
|
+
throw new OwnerGrantError('identity_mismatch', 'Cuna answered with a grant to your own account. Observation grants are for a distinct member.');
|
|
277
|
+
if (reference) {
|
|
278
|
+
if (g.grant_id !== reference.grant_id)
|
|
279
|
+
throw mismatch('grant');
|
|
280
|
+
if (reference.agent_session_id !== undefined && g.agent_session_id !== reference.agent_session_id)
|
|
281
|
+
throw mismatch('session');
|
|
282
|
+
if (reference.subject_principal_id !== undefined && g.subject_principal_id !== reference.subject_principal_id)
|
|
283
|
+
throw mismatch('member');
|
|
284
|
+
if (reference.revision !== undefined && g.revision < reference.revision)
|
|
285
|
+
throw new OwnerGrantError('stale_revision', 'Cuna answered with an older revision than the one already read. The receipt was refused.');
|
|
286
|
+
}
|
|
287
|
+
return structuredClone(g);
|
|
288
|
+
}
|
|
289
|
+
export function decodeProjectObserverPage(value, project, after) {
|
|
290
|
+
check(value, 'ProjectObserversV2Receipt', 'member page');
|
|
291
|
+
const page = value;
|
|
292
|
+
if (page.project_id !== project)
|
|
293
|
+
throw mismatch('Project');
|
|
294
|
+
if (page.items.some((m, i) => m.principal_id <= (i ? page.items[i - 1].principal_id : after ?? '')) || page.next_after_principal_id !== null && (page.next_after_principal_id <= (after ?? '') || page.items.some(m => m.principal_id > page.next_after_principal_id)))
|
|
295
|
+
throw malformed('member page order');
|
|
296
|
+
return structuredClone(page);
|
|
297
|
+
}
|
|
298
|
+
/** Run a receipt check that happens after a mutation was sent, so any refusal reports an undetermined effect. */
|
|
299
|
+
function afterDispatch(decode) {
|
|
300
|
+
try {
|
|
301
|
+
return decode();
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
throw error instanceof OwnerGrantError ? withUnknownEffect(error) : error;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
export function ownerObserveGrantsApi(transport, owner, project, verifyPrincipal) {
|
|
308
|
+
assertCanonicalUuid(project, 'Project ID');
|
|
309
|
+
assertCanonicalUuid(owner, 'Principal ID');
|
|
310
|
+
/**
|
|
311
|
+
* What this client has already had confirmed about each session's audience.
|
|
312
|
+
*
|
|
313
|
+
* The generation alone CANNOT order these decisions, and an earlier version of
|
|
314
|
+
* this module claimed it could. `_run_audience_v2` answers a publish with
|
|
315
|
+
* `expected_generation + 1` and a return to private with `expected_generation`,
|
|
316
|
+
* so a publish TO generation G and a private AT generation G carry the same
|
|
317
|
+
* number: `generation < seen` is false at equality and a stored public receipt
|
|
318
|
+
* replayed after a confirmed private was admitted and rendered as the current
|
|
319
|
+
* state. The generation check below is kept, because a strictly lower one is
|
|
320
|
+
* still definitely older, but it is a floor and not an ordering.
|
|
321
|
+
*
|
|
322
|
+
* What does order them is this client's own record of which requests it has
|
|
323
|
+
* already had answered. `issue_collab_v2_session_audience_request` mints one
|
|
324
|
+
* `request_id` per operation and returns that same stored request on a replay,
|
|
325
|
+
* so the request identity is stable and a receipt naming a request already
|
|
326
|
+
* answered here is a REPEAT of that answer, not a new decision. The ordering
|
|
327
|
+
* comes from the sequence in which this client first saw each request answered
|
|
328
|
+
* -- never from comparing UUIDs, which carry no order at all.
|
|
329
|
+
*/
|
|
330
|
+
const answeredRequest = new Map();
|
|
331
|
+
// A reading belongs here too, and it is why `action` carries `'observe'`: a
|
|
332
|
+
// fresh reading is the newest thing this client knows about the session, so a
|
|
333
|
+
// journaled receipt replayed after one cannot describe the session now either.
|
|
334
|
+
const confirmedAudience = new Map();
|
|
335
|
+
let audienceOrder = 0;
|
|
336
|
+
const current = async () => { if (verifyPrincipal && await verifyPrincipal() !== owner)
|
|
337
|
+
throw new OwnerGrantError('identity_mismatch', 'The signed-in account changed while this action was in flight. Nothing from the answer was trusted.'); };
|
|
338
|
+
const send = async (path, body, mutation, signal, operation) => {
|
|
339
|
+
await current();
|
|
340
|
+
let value;
|
|
341
|
+
try {
|
|
342
|
+
value = await transport.request({ method: 'POST', path, body, signal });
|
|
343
|
+
}
|
|
344
|
+
catch (error) {
|
|
345
|
+
throw classifyTransportFailure(error, mutation, operation);
|
|
346
|
+
}
|
|
347
|
+
// The principal re-check below runs after the request was answered, so a
|
|
348
|
+
// mutation that fails it has already reached the server.
|
|
349
|
+
try {
|
|
350
|
+
await current();
|
|
351
|
+
}
|
|
352
|
+
catch (error) {
|
|
353
|
+
throw mutation && error instanceof OwnerGrantError ? withUnknownEffect(error) : error;
|
|
354
|
+
}
|
|
355
|
+
return value;
|
|
356
|
+
};
|
|
357
|
+
return {
|
|
358
|
+
/** Members who currently hold observer membership; membership alone grants nothing. */
|
|
359
|
+
async listMembers(after, signal) { const body = { version: '2', after_principal_id: after, limit: 50 }; check(body, 'ListProjectObserversV2Request', 'member request'); return decodeProjectObserverPage(await send(ownerObserveGrantOperations.listProjectObserversV2.path.replace('{id}', project), body, false, signal, 'members'), project, after); },
|
|
360
|
+
/** Create with a caller-owned operation ID so an uncertain outcome can be reconciled by replaying the SAME identity, never by minting a second grant. */
|
|
361
|
+
async create(input, operationId, signal) {
|
|
362
|
+
assertCanonicalUuid(input.agentSessionId, 'AgentSession ID');
|
|
363
|
+
assertCanonicalUuid(input.subjectPrincipalId, 'Principal ID');
|
|
364
|
+
if (input.subjectPrincipalId === owner)
|
|
365
|
+
throw new OwnerGrantError('identity_mismatch', 'You cannot grant observation to your own account. Select a distinct member.');
|
|
366
|
+
const body = { version: '2', operation_id: operationId, subject_principal_id: input.subjectPrincipalId, expected_membership_revision: input.expectedMembershipRevision, expires_at_ms: input.expiresAtMs };
|
|
367
|
+
check(body, 'CreateSessionObserveGrantV2Request', 'grant request');
|
|
368
|
+
// Past this line the request has left. Every refusal below is about an answer
|
|
369
|
+
// we would not trust, which says nothing about whether the grant now exists.
|
|
370
|
+
const answer = await send(ownerObserveGrantOperations.createSessionObserveGrantV2.path.replace('{id}', input.agentSessionId), body, true, signal, 'create');
|
|
371
|
+
return afterDispatch(() => {
|
|
372
|
+
const g = decodeOwnerGrant(answer, owner, project);
|
|
373
|
+
if (g.agent_session_id !== input.agentSessionId)
|
|
374
|
+
throw mismatch('session');
|
|
375
|
+
if (g.subject_principal_id !== input.subjectPrincipalId)
|
|
376
|
+
throw mismatch('member');
|
|
377
|
+
if (g.membership_revision !== input.expectedMembershipRevision)
|
|
378
|
+
throw new OwnerGrantError('stale_revision', 'Cuna created the grant under a different membership revision than the one read. Inspect the grant before relying on it.');
|
|
379
|
+
if (g.expires_at > input.expiresAtMs)
|
|
380
|
+
throw mismatch('expiry');
|
|
381
|
+
return g;
|
|
382
|
+
});
|
|
383
|
+
},
|
|
384
|
+
/** A read. Safe to repeat; the only way to learn whether a pending revocation became effective. */
|
|
385
|
+
async inspect(reference, signal) { assertCanonicalUuid(reference.grant_id, 'Grant ID'); const body = { version: '2' }; check(body, 'InspectSessionObserveGrantV2Request', 'inspect request'); return decodeOwnerGrant(await send(ownerObserveGrantOperations.inspectSessionObserveGrantV2.path.replace('{id}', reference.grant_id), body, false, signal, 'inspect'), owner, project, reference); },
|
|
386
|
+
/**
|
|
387
|
+
* Revoke against the exact revision read. A receipt that still says active
|
|
388
|
+
* contradicts the write and is refused.
|
|
389
|
+
*
|
|
390
|
+
* The target is an identity, not a receipt: grant, session, member and the
|
|
391
|
+
* revision this decision was made against. A full `OwnerGrant` satisfies it,
|
|
392
|
+
* and so does a durable operation record recovered from an earlier process,
|
|
393
|
+
* which is the whole point -- replaying a lost revocation must not require
|
|
394
|
+
* fabricating a server receipt nobody ever sent.
|
|
395
|
+
*/
|
|
396
|
+
async revoke(grant, operationId, signal) {
|
|
397
|
+
for (const [label, value] of [['Grant ID', grant.grant_id], ['AgentSession ID', grant.agent_session_id], ['Principal ID', grant.subject_principal_id]])
|
|
398
|
+
assertCanonicalUuid(value, label);
|
|
399
|
+
if (!Number.isSafeInteger(grant.revision) || grant.revision < 1)
|
|
400
|
+
throw new OwnerGrantError('stale_revision', 'The grant revision to revoke against is not a revision Cuna could have issued.');
|
|
401
|
+
const body = { version: '2', operation_id: operationId, expected_revision: grant.revision };
|
|
402
|
+
check(body, 'RevokeSessionObserveGrantV2Request', 'revoke request');
|
|
403
|
+
const answer = await send(ownerObserveGrantOperations.revokeSessionObserveGrantV2.path.replace('{id}', grant.grant_id), body, true, signal, 'revoke');
|
|
404
|
+
return afterDispatch(() => {
|
|
405
|
+
const g = decodeOwnerGrant(answer, owner, project, { grant_id: grant.grant_id, agent_session_id: grant.agent_session_id, subject_principal_id: grant.subject_principal_id, revision: grant.revision });
|
|
406
|
+
if (g.state === 'active')
|
|
407
|
+
throw new OwnerGrantError('malformed_receipt', 'Cuna acknowledged the revocation with a receipt that still says active. The contradiction was refused; inspect the grant.');
|
|
408
|
+
return g;
|
|
409
|
+
});
|
|
410
|
+
},
|
|
411
|
+
/**
|
|
412
|
+
* Publish this session's screen, or take it back to private.
|
|
413
|
+
*
|
|
414
|
+
* Both actions of the canonical enum are here on purpose: shipping only
|
|
415
|
+
* `publish` would give an owner a way to start disclosing a terminal and no
|
|
416
|
+
* way to stop it from the same surface.
|
|
417
|
+
*
|
|
418
|
+
* The operation ID is the whole reconciliation story.
|
|
419
|
+
* `issue_collab_v2_session_audience_request` is keyed on it: the same ID
|
|
420
|
+
* re-raises the SAME stored request with the session, and the supervisor
|
|
421
|
+
* journals its answer per request and returns the journaled one instead of
|
|
422
|
+
* transitioning twice. So replaying one identity cannot publish twice, and it
|
|
423
|
+
* is the only thing that can settle an answer Cuna failed to record. A NEW
|
|
424
|
+
* identity would be issued against Cuna's last known generation, which the
|
|
425
|
+
* session has already moved past -- the session would refuse it, and the
|
|
426
|
+
* earlier outcome would stay unknown forever. Nothing here ever mints one.
|
|
427
|
+
*/
|
|
428
|
+
async setAudience(input, operationId, signal) {
|
|
429
|
+
assertCanonicalUuid(input.agentSessionId, 'AgentSession ID');
|
|
430
|
+
assertCanonicalUuid(operationId, 'Operation ID');
|
|
431
|
+
const body = { version: '2', operation_id: operationId, action: input.action };
|
|
432
|
+
check(body, 'PrepareSessionAudienceV2Request', 'sharing request');
|
|
433
|
+
let answer;
|
|
434
|
+
try {
|
|
435
|
+
answer = await send(ownerObserveGrantOperations.prepareSessionAudienceV2.path.replace('{id}', input.agentSessionId), body, true, signal, 'audience');
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
// A dispatch that reuses an identity an earlier attempt already sent learns
|
|
439
|
+
// nothing about that earlier attempt from a refusal of the re-raise. Every
|
|
440
|
+
// refusal that is settled only because the session was asked nothing is
|
|
441
|
+
// therefore uncertain here: settling would destroy the only identity that
|
|
442
|
+
// can ever finish the original.
|
|
443
|
+
const reason = error instanceof OwnerGrantError && typeof error.details?.reason === 'string' ? error.details.reason : undefined;
|
|
444
|
+
const refusal = reason !== undefined && Object.hasOwn(AUDIENCE_REFUSAL, reason) ? AUDIENCE_REFUSAL[reason] : undefined;
|
|
445
|
+
if (input.replay === true && refusal?.replay !== undefined)
|
|
446
|
+
throw new OwnerGrantError('uncertain', refusal.replay, error.cause, reason, true);
|
|
447
|
+
throw error;
|
|
448
|
+
}
|
|
449
|
+
// Raised outside `afterDispatch` on purpose. That wrapper exists because a
|
|
450
|
+
// receipt this CLI would not TRUST says nothing about what the server did --
|
|
451
|
+
// but a repeat of an answer already given is the opposite case: the producer
|
|
452
|
+
// stores one result per request and returns it unchanged, so the re-raise
|
|
453
|
+
// demonstrably applied nothing and the operation it belongs to is answered.
|
|
454
|
+
// Marking it uncertain would keep a record whose outcome is already known.
|
|
455
|
+
let superseded;
|
|
456
|
+
const decided = afterDispatch(() => {
|
|
457
|
+
check(answer, 'PrepareSessionAudienceV2Receipt', 'sharing receipt');
|
|
458
|
+
const receipt = answer;
|
|
459
|
+
const r = receipt.response;
|
|
460
|
+
if (r.agent_session_id !== input.agentSessionId)
|
|
461
|
+
throw mismatch('session');
|
|
462
|
+
if (input.sessionIncarnation !== undefined && r.session_incarnation !== input.sessionIncarnation)
|
|
463
|
+
throw mismatch('run of this session');
|
|
464
|
+
if (r.action !== input.action)
|
|
465
|
+
throw mismatch('sharing action');
|
|
466
|
+
if (r.result.state !== (input.action === 'publish' ? 'public' : 'private'))
|
|
467
|
+
throw new OwnerGrantError('malformed_receipt', `Cuna answered a request to ${input.action === 'publish' ? 'start' : 'stop'} sharing with the opposite state. The contradiction was refused.`);
|
|
468
|
+
// The producer's own arithmetic, asserted rather than assumed: a publish is
|
|
469
|
+
// exactly one step past the generation it was issued against, and a return
|
|
470
|
+
// to private stays on it. Anything else is a receipt about a different
|
|
471
|
+
// transition than the one this request asked for.
|
|
472
|
+
const generation = BigInt(r.result.generation), expected = BigInt(r.expected_generation);
|
|
473
|
+
if (generation !== expected + (input.action === 'publish' ? 1n : 0n))
|
|
474
|
+
throw mismatch('sharing transition');
|
|
475
|
+
const key = `${r.agent_session_id}/${r.session_incarnation}/${r.process_epoch}`, confirmed = confirmedAudience.get(key);
|
|
476
|
+
// A floor, not an ordering: see the note on `answeredRequest`.
|
|
477
|
+
if (confirmed !== undefined && generation < confirmed.generation)
|
|
478
|
+
throw new OwnerGrantError('stale_revision', 'Cuna answered with an older sharing state than one already confirmed here. The receipt was refused; it cannot describe how the session is shared now.');
|
|
479
|
+
const decision = { action: r.action, state: r.result.state, agentSessionId: r.agent_session_id, sessionIncarnation: r.session_incarnation, processEpoch: r.process_epoch, logicalTerminalId: r.logical_terminal_id, requestId: r.request_id, generation: r.result.generation, ...(r.result.state === 'public' ? { streamId: r.result.stream_id, firstSequence: r.result.first_sequence } : {}) };
|
|
480
|
+
const prior = answeredRequest.get(r.request_id);
|
|
481
|
+
if (prior !== undefined) {
|
|
482
|
+
// The same request answered two different ways is a contradiction, not a
|
|
483
|
+
// decision: `consume_collab_v2_session_audience_response` stores one result
|
|
484
|
+
// per request and returns it unchanged, so this cannot be the producer
|
|
485
|
+
// changing its mind.
|
|
486
|
+
if (prior.key !== key || prior.action !== r.action || prior.state !== r.result.state || prior.generation !== r.result.generation || prior.streamId !== decision.streamId)
|
|
487
|
+
throw new OwnerGrantError('malformed_receipt', 'Cuna answered the same sharing request two different ways. The contradiction was refused; neither answer is trusted.');
|
|
488
|
+
// A repeat of an answer this client already has. If a different decision
|
|
489
|
+
// has been confirmed for this session since, the repeat describes a request
|
|
490
|
+
// that decision has already replaced. It is refused rather than returned:
|
|
491
|
+
// an answer that cannot describe the session now must not be able to reach
|
|
492
|
+
// a screen at all, and the refusal names the decision that replaced it so
|
|
493
|
+
// the history is still readable.
|
|
494
|
+
if (confirmed !== undefined && confirmed.order > prior.order) {
|
|
495
|
+
const since = confirmed.action === 'observe'
|
|
496
|
+
? `Cuna has since read this session's current sharing state directly, and it says ${confirmed.state === 'public' ? 'the session is sharing live' : 'the session is not sharing live'}`
|
|
497
|
+
: `you asked Cuna to ${confirmed.action === 'publish' ? 'start' : 'stop'} live sharing, and Cuna confirmed it`;
|
|
498
|
+
superseded = `Cuna answered this with the answer it already gave to an earlier request, which ${prior.state === 'public' ? 'started' : 'stopped'} live sharing. Something newer is known since - ${since}. This answer describes the earlier request, so it cannot say how the session is shared now, and it was refused.`;
|
|
499
|
+
return Object.freeze(decision);
|
|
500
|
+
}
|
|
501
|
+
return Object.freeze(decision);
|
|
502
|
+
}
|
|
503
|
+
audienceOrder += 1;
|
|
504
|
+
answeredRequest.set(r.request_id, { order: audienceOrder, key, action: r.action, state: r.result.state, generation: r.result.generation, streamId: decision.streamId });
|
|
505
|
+
confirmedAudience.set(key, { order: audienceOrder, action: r.action, state: r.result.state, generation });
|
|
506
|
+
return Object.freeze(decision);
|
|
507
|
+
});
|
|
508
|
+
if (superseded !== undefined)
|
|
509
|
+
throw new OwnerGrantError('stale_revision', superseded);
|
|
510
|
+
return decided;
|
|
511
|
+
},
|
|
512
|
+
/**
|
|
513
|
+
* Ask what this session IS sharing, and optionally what one earlier change is
|
|
514
|
+
* recorded to have done.
|
|
515
|
+
*
|
|
516
|
+
* This is the question `setAudience` cannot ask. A publication whose
|
|
517
|
+
* acknowledgement was lost leaves the runtime one generation ahead of Cuna and
|
|
518
|
+
* fenced: every later transition is issued at the last RECORDED generation,
|
|
519
|
+
* the session refuses it as stale, and the owner can neither share again nor
|
|
520
|
+
* be told that sharing stopped. `issue_collab_v2_session_audience_request`
|
|
521
|
+
* computes `expected_generation` from the latest OBSERVED result of any
|
|
522
|
+
* action, so once a reading is recorded the next publish or private is issued
|
|
523
|
+
* against the live counter -- which is what makes a fresh decision possible
|
|
524
|
+
* again without restarting the session.
|
|
525
|
+
*
|
|
526
|
+
* Every reading mints its OWN identity. A stored request keeps its original
|
|
527
|
+
* twenty-second deadline, so reusing one can only ever answer
|
|
528
|
+
* `audience_request_expired`; there is nothing here to make idempotent across
|
|
529
|
+
* minutes, because the reading is a query. `reconcile` names the EARLIER
|
|
530
|
+
* uncertain change and may never be this reading's own identity.
|
|
531
|
+
*
|
|
532
|
+
* It admits nobody. `consume_collab_v2_session_audience_response` returns
|
|
533
|
+
* before it retires an attachment or closes an endpoint when the action is
|
|
534
|
+
* `observe`, so neither a reading nor a refusal of one ends anyone's
|
|
535
|
+
* observation, and no stream identity is created.
|
|
536
|
+
*
|
|
537
|
+
* The two halves are returned side by side and never merged: `current` is the
|
|
538
|
+
* only statement about now, and `operation` is history even when it is the
|
|
539
|
+
* history of the very change the owner is trying to finish.
|
|
540
|
+
*/
|
|
541
|
+
async readAudience(input, operationId, signal) {
|
|
542
|
+
assertCanonicalUuid(input.agentSessionId, 'AgentSession ID');
|
|
543
|
+
assertCanonicalUuid(operationId, 'Operation ID');
|
|
544
|
+
if (input.reconcile !== undefined) {
|
|
545
|
+
assertCanonicalUuid(input.reconcile.operationId, 'Operation ID');
|
|
546
|
+
if (input.reconcile.operationId === operationId)
|
|
547
|
+
throw new OwnerGrantError('identity_mismatch', 'A question about an earlier change cannot name itself as that change. Nothing was sent.');
|
|
548
|
+
}
|
|
549
|
+
const body = { version: '2', operation_id: operationId, ...(input.reconcile === undefined ? {} : { reconcile_operation_id: input.reconcile.operationId }) };
|
|
550
|
+
check(body, 'ReadSessionAudienceStateV2Request', 'sharing question');
|
|
551
|
+
const answer = await send(ownerObserveGrantOperations.readSessionAudienceStateV2.path.replace('{id}', input.agentSessionId), body, false, signal, 'audience-state');
|
|
552
|
+
check(answer, 'SessionAudienceStateV2Receipt', 'sharing state');
|
|
553
|
+
const receipt = answer;
|
|
554
|
+
const c = receipt.current;
|
|
555
|
+
if (c.agent_session_id !== input.agentSessionId)
|
|
556
|
+
throw mismatch('session');
|
|
557
|
+
if (input.sessionIncarnation !== undefined && c.session_incarnation !== input.sessionIncarnation)
|
|
558
|
+
throw mismatch('run of this session');
|
|
559
|
+
const key = `${c.agent_session_id}/${c.session_incarnation}/${c.process_epoch}`, confirmed = confirmedAudience.get(key);
|
|
560
|
+
const generation = BigInt(c.result.generation);
|
|
561
|
+
// An answer below what this client already had confirmed describes a moment
|
|
562
|
+
// that has passed. The comparison is on `(generation, state)`, not the
|
|
563
|
+
// generation alone: `public@G` and `private@G` both exist, and the producer's
|
|
564
|
+
// arithmetic puts the publish that CREATED G before every `private@G`, so a
|
|
565
|
+
// reading of `public@G` after a confirmed `private@G` is strictly older. An
|
|
566
|
+
// answer ABOVE every recorded generation is the repaired case, not an error.
|
|
567
|
+
if (confirmed !== undefined && audienceFactIsOlder({ state: c.result.state, generation: c.result.generation }, { state: confirmed.state, generation: confirmed.generation.toString() }))
|
|
568
|
+
throw new OwnerGrantError('stale_revision', 'Cuna answered with a sharing state from earlier in this session run than one already confirmed here. The answer was refused; it describes a moment that has passed.');
|
|
569
|
+
const raw = receipt.operation;
|
|
570
|
+
if ((raw === undefined) !== (input.reconcile === undefined))
|
|
571
|
+
throw malformed(input.reconcile === undefined ? 'sharing state carrying history nobody asked for' : 'sharing state with no answer about the change that was named');
|
|
572
|
+
let operation;
|
|
573
|
+
if (raw !== undefined && input.reconcile !== undefined) {
|
|
574
|
+
if (raw.operation_id !== input.reconcile.operationId)
|
|
575
|
+
throw mismatch('change');
|
|
576
|
+
if (raw.status === 'unknown')
|
|
577
|
+
operation = { status: 'unknown', operationId: raw.operation_id };
|
|
578
|
+
else {
|
|
579
|
+
if (raw.agent_session_id !== input.agentSessionId)
|
|
580
|
+
throw mismatch('session');
|
|
581
|
+
// The producer refuses one operation identity replayed with a different
|
|
582
|
+
// action, so history naming another action is history about something this
|
|
583
|
+
// CLI never sent under that identity.
|
|
584
|
+
if (raw.action !== input.reconcile.action)
|
|
585
|
+
throw mismatch('sharing action');
|
|
586
|
+
const revision = raw.request_revision;
|
|
587
|
+
if (raw.status === 'recorded') {
|
|
588
|
+
const result = raw.response.result;
|
|
589
|
+
operation = result.status === 'observed'
|
|
590
|
+
? { status: 'recorded', operationId: raw.operation_id, action: raw.action, requestRevision: revision, outcome: { kind: 'observed', state: result.state, generation: result.generation, ...(result.state === 'public' ? { streamId: result.stream_id } : {}) } }
|
|
591
|
+
: { status: 'recorded', operationId: raw.operation_id, action: raw.action, requestRevision: revision, outcome: { kind: 'refused' } };
|
|
592
|
+
}
|
|
593
|
+
else
|
|
594
|
+
operation = { status: raw.status, operationId: raw.operation_id, action: raw.action, requestRevision: revision };
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
audienceOrder += 1;
|
|
598
|
+
confirmedAudience.set(key, { order: audienceOrder, action: 'observe', state: c.result.state, generation });
|
|
599
|
+
const current = { agentSessionId: c.agent_session_id, sessionIncarnation: c.session_incarnation, processEpoch: c.process_epoch, logicalTerminalId: c.logical_terminal_id, requestId: c.request_id, state: c.result.state, generation: c.result.generation, ...(c.result.state === 'public' ? { streamId: c.result.stream_id } : {}) };
|
|
600
|
+
return Object.freeze({ current, ...(operation === undefined ? {} : { operation }) });
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
//# sourceMappingURL=owner-observe-grants-v2.js.map
|