@astrale-os/cli 1.0.0-beta.32 → 1.0.0-beta.43
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/CHANGELOG.md +928 -0
- package/README.md +53 -43
- package/THIRD-PARTY-NOTICES.md +37 -1
- package/dist/astrale.js +349631 -83669
- package/dist/public/connect-core.js +16 -47
- package/dist/public/keys/index.js +1 -1
- package/dist/types/admin/contract.d.ts +11 -0
- package/dist/types/admin/graph/index.d.ts +1 -0
- package/dist/types/admin/graph/nodes.d.ts +12 -0
- package/dist/types/admin/instance/client.d.ts +2 -0
- package/dist/types/connection/lifetime.d.ts +1 -1
- package/dist/types/errors.d.ts +3 -0
- package/dist/types/lib/proc.d.ts +1 -0
- package/dist/types/lib/update.d.ts +15 -7
- package/package.json +8 -6
- package/studio/client/dist/assets/index-5C1uT6ML.css +2 -0
- package/studio/client/dist/assets/index-C4kNlvwF.js +80 -0
- package/studio/client/dist/assets/schema-studio-BR9d0faB.js +8 -0
- package/studio/client/dist/index.html +13 -2
- package/studio/package.json +2 -1
- package/studio/server/agent/ask.test.ts +7 -1
- package/studio/server/agent/bridge/grant.ts +15 -3
- package/studio/server/agent/prompts/system.test.ts +5 -0
- package/studio/server/agent/prompts/system.ts +19 -4
- package/studio/server/agent/routes.test.ts +39 -1
- package/studio/server/agent/routes.ts +3 -0
- package/studio/server/agent/run/coordinator.test.ts +7 -1
- package/studio/server/agent/run/preparation.ts +1 -0
- package/studio/server/agent/run/transcript.test.ts +47 -2
- package/studio/server/agent/run/transcript.ts +32 -3
- package/studio/server/api/documents.test.ts +31 -0
- package/studio/server/api/documents.ts +35 -1
- package/studio/server/api-agent-loadout.test.ts +7 -1
- package/studio/server/api.test.ts +7 -1
- package/studio/server/cache.ts +4 -4
- package/studio/server/detect.ts +9 -12
- package/studio/server/domain.test.ts +83 -3
- package/studio/server/domain.ts +205 -27
- package/studio/server/handoff/service.ts +1 -1
- package/studio/server/index.ts +5 -8
- package/studio/server/introspect/extractor.ts +111 -17
- package/studio/server/introspect/overlay-tsmorph.test.ts +9 -9
- package/studio/server/introspect/overlay.ts +1 -1
- package/studio/server/introspect/runtime.ts +9 -1
- package/studio/server/introspect/source-overlay/spans.ts +2 -5
- package/studio/server/lifecycle.ts +1 -1
- package/studio/server/state/baseline.test.ts +14 -0
- package/studio/server/state/baseline.ts +16 -2
- package/studio/server/watch.test.ts +2 -1
- package/studio/server/watch.ts +5 -2
- package/studio/server/workspace/create.ts +9 -8
- package/studio/server/workspace-state.ts +4 -6
- package/studio/server/workspace-watch.ts +33 -22
- package/studio/shared/contracts/agent.ts +3 -0
- package/viewer/dist/main.js +12 -12
- package/src/__tests__/fixtures/publication.ts +0 -20
- package/src/admin/.spec/api.d.ts +0 -3
- package/src/admin/.spec/architecture.md +0 -22
- package/src/admin/.spec/icon.svg +0 -3
- package/src/admin/.spec/layout.ts +0 -6
- package/src/admin/__tests__/fixture.ts +0 -25
- package/src/admin/catalog/.spec/api.d.ts +0 -63
- package/src/admin/catalog/.spec/architecture.md +0 -7
- package/src/admin/catalog/.spec/icon.svg +0 -3
- package/src/admin/catalog/.spec/layout.ts +0 -6
- package/src/admin/catalog/__tests__/client.test.ts +0 -245
- package/src/admin/catalog/client.ts +0 -195
- package/src/admin/catalog/index.ts +0 -13
- package/src/admin/catalog/model.ts +0 -41
- package/src/admin/catalog/tsconfig.json +0 -8
- package/src/admin/contract.ts +0 -47
- package/src/admin/graph/.spec/api.d.ts +0 -22
- package/src/admin/graph/.spec/architecture.md +0 -5
- package/src/admin/graph/.spec/icon.svg +0 -3
- package/src/admin/graph/.spec/layout.ts +0 -3
- package/src/admin/graph/index.ts +0 -6
- package/src/admin/graph/nodes.ts +0 -56
- package/src/admin/index.ts +0 -2
- package/src/admin/instance/.spec/api.d.ts +0 -62
- package/src/admin/instance/.spec/architecture.md +0 -10
- package/src/admin/instance/.spec/icon.svg +0 -3
- package/src/admin/instance/.spec/layout.ts +0 -6
- package/src/admin/instance/__tests__/client.test.ts +0 -273
- package/src/admin/instance/client.ts +0 -191
- package/src/admin/instance/index.ts +0 -15
- package/src/admin/instance/model.ts +0 -59
- package/src/admin/instance/tsconfig.json +0 -8
- package/src/commands/__tests__/admin-instance.test.ts +0 -91
- package/src/commands/__tests__/auth-login.test.ts +0 -231
- package/src/commands/__tests__/auth-token.test.ts +0 -223
- package/src/commands/__tests__/call-describe.test.ts +0 -80
- package/src/commands/__tests__/call.test.ts +0 -63
- package/src/commands/__tests__/domain-install-operation.test.ts +0 -145
- package/src/commands/__tests__/domain-install-owned.test.ts +0 -191
- package/src/commands/__tests__/domain-list.test.ts +0 -133
- package/src/commands/__tests__/domain-uninstall.test.ts +0 -53
- package/src/commands/__tests__/install-direct.test.ts +0 -128
- package/src/commands/__tests__/install-identity-override.test.ts +0 -76
- package/src/commands/__tests__/instance-bookmark.test.ts +0 -166
- package/src/commands/__tests__/instance-list-admin.test.ts +0 -26
- package/src/commands/__tests__/instance-list-rows.test.ts +0 -64
- package/src/commands/__tests__/instance-status.test.ts +0 -139
- package/src/commands/__tests__/instance-use.test.ts +0 -67
- package/src/commands/__tests__/introspect-parse.test.ts +0 -100
- package/src/commands/__tests__/logs.test.ts +0 -345
- package/src/commands/__tests__/read-commands.test.ts +0 -377
- package/src/commands/__tests__/setup-plan.test.ts +0 -61
- package/src/commands/__tests__/studio-descriptor.test.ts +0 -22
- package/src/commands/__tests__/token-ttl.test.ts +0 -66
- package/src/commands/__tests__/update.test.ts +0 -95
- package/src/commands/__tests__/view-build.test.ts +0 -58
- package/src/commands/__tests__/view.test.ts +0 -197
- package/src/commands/admin/status.ts +0 -61
- package/src/commands/admin/use.ts +0 -100
- package/src/commands/auth/login.ts +0 -82
- package/src/commands/auth/logout.ts +0 -53
- package/src/commands/auth/status.ts +0 -86
- package/src/commands/auth/token.ts +0 -174
- package/src/commands/browser.ts +0 -236
- package/src/commands/call-describe.ts +0 -123
- package/src/commands/call.ts +0 -230
- package/src/commands/domain/install.ts +0 -575
- package/src/commands/domain/list.ts +0 -155
- package/src/commands/domain/publish.ts +0 -136
- package/src/commands/domain/uninstall.ts +0 -128
- package/src/commands/get.ts +0 -69
- package/src/commands/identity/__tests__/register.test.ts +0 -93
- package/src/commands/identity/create.ts +0 -35
- package/src/commands/identity/delete.ts +0 -24
- package/src/commands/identity/export.ts +0 -46
- package/src/commands/identity/import.ts +0 -61
- package/src/commands/identity/list.ts +0 -56
- package/src/commands/identity/register.ts +0 -195
- package/src/commands/identity/sync.ts +0 -38
- package/src/commands/identity/unsync.ts +0 -34
- package/src/commands/identity/use.ts +0 -24
- package/src/commands/identity/whoami.ts +0 -34
- package/src/commands/idp/add.ts +0 -150
- package/src/commands/idp/list.ts +0 -57
- package/src/commands/idp/refresh.ts +0 -38
- package/src/commands/idp/remove.ts +0 -36
- package/src/commands/idp/show.ts +0 -29
- package/src/commands/instance/active.ts +0 -73
- package/src/commands/instance/bookmark.ts +0 -101
- package/src/commands/instance/create.ts +0 -61
- package/src/commands/instance/delete.ts +0 -69
- package/src/commands/instance/forget.ts +0 -26
- package/src/commands/instance/list.ts +0 -197
- package/src/commands/instance/status.ts +0 -92
- package/src/commands/instance/use.ts +0 -263
- package/src/commands/introspect.ts +0 -129
- package/src/commands/logs.ts +0 -371
- package/src/commands/mutate.ts +0 -122
- package/src/commands/query.ts +0 -142
- package/src/commands/session/analyze.ts +0 -72
- package/src/commands/session/list.ts +0 -36
- package/src/commands/setup.ts +0 -54
- package/src/commands/status.ts +0 -60
- package/src/commands/studio.ts +0 -434
- package/src/commands/token.ts +0 -121
- package/src/commands/ui/__tests__/commands.test.ts +0 -152
- package/src/commands/ui/add.ts +0 -51
- package/src/commands/ui/doctor.ts +0 -21
- package/src/commands/ui/init.ts +0 -38
- package/src/commands/ui/list.ts +0 -26
- package/src/commands/ui/preset-apply.ts +0 -19
- package/src/commands/ui/preset-list.ts +0 -12
- package/src/commands/ui/shared.ts +0 -25
- package/src/commands/update.ts +0 -356
- package/src/commands/use.ts +0 -86
- package/src/commands/view-serve.ts +0 -26
- package/src/commands/view.ts +0 -658
- package/src/connect-core.test.ts +0 -38
- package/src/connect-core.ts +0 -42
- package/src/connection/.spec/api.d.ts +0 -110
- package/src/connection/.spec/architecture.md +0 -58
- package/src/connection/.spec/capabilities/connection.ts +0 -13
- package/src/connection/.spec/examples/call.ts +0 -7
- package/src/connection/.spec/flows/command.ts +0 -20
- package/src/connection/.spec/flows/session.ts +0 -62
- package/src/connection/.spec/laws/connection.ts +0 -213
- package/src/connection/.spec/layout.ts +0 -22
- package/src/connection/__tests__/auth.test.ts +0 -129
- package/src/connection/__tests__/ca-fetch.test.ts +0 -60
- package/src/connection/__tests__/call.test.ts +0 -17
- package/src/connection/__tests__/credential.test.ts +0 -254
- package/src/connection/__tests__/errors.test.ts +0 -577
- package/src/connection/__tests__/exchange.test.ts +0 -404
- package/src/connection/__tests__/failure-fixtures.ts +0 -39
- package/src/connection/__tests__/failure-safety.test.ts +0 -75
- package/src/connection/__tests__/fixtures/localhost-cert.pem +0 -19
- package/src/connection/__tests__/fixtures/localhost-key.base64 +0 -1
- package/src/connection/__tests__/managed.test.ts +0 -39
- package/src/connection/__tests__/reasons.test.ts +0 -78
- package/src/connection/__tests__/self.test.ts +0 -71
- package/src/connection/__tests__/session.test.ts +0 -144
- package/src/connection/__tests__/target.test.ts +0 -95
- package/src/connection/auth.ts +0 -265
- package/src/connection/call.ts +0 -7
- package/src/connection/command.ts +0 -67
- package/src/connection/credential.ts +0 -138
- package/src/connection/errors.ts +0 -1
- package/src/connection/exchange.ts +0 -394
- package/src/connection/failure/classify.ts +0 -110
- package/src/connection/failure/index.ts +0 -18
- package/src/connection/failure/model.ts +0 -28
- package/src/connection/failure/render.ts +0 -116
- package/src/connection/index.ts +0 -8
- package/src/connection/lifetime.ts +0 -25
- package/src/connection/reasons.ts +0 -209
- package/src/connection/self.ts +0 -138
- package/src/connection/session.ts +0 -203
- package/src/connection/target.ts +0 -112
- package/src/connection/tsconfig.json +0 -6
- package/src/errors.ts +0 -66
- package/src/graph/.spec/api.d.ts +0 -41
- package/src/graph/.spec/laws/documents.ts +0 -24
- package/src/graph/.spec/laws/projection.ts +0 -13
- package/src/graph/.spec/layout.ts +0 -14
- package/src/graph/__tests__/mutation.test.ts +0 -51
- package/src/graph/__tests__/projection.test.ts +0 -22
- package/src/graph/__tests__/query.test.ts +0 -180
- package/src/graph/class.ts +0 -30
- package/src/graph/index.ts +0 -4
- package/src/graph/mutation.ts +0 -46
- package/src/graph/projection.ts +0 -21
- package/src/graph/query.ts +0 -95
- package/src/graph/tsconfig.json +0 -6
- package/src/identity/.history/ard/bootstrap-root-transfer.md +0 -57
- package/src/identity/.history/ard/domain-mediated-registration.md +0 -36
- package/src/identity/.spec/api.d.ts +0 -124
- package/src/identity/.spec/architecture.md +0 -33
- package/src/identity/.spec/capabilities/identity.ts +0 -7
- package/src/identity/.spec/flows/bootstrap-root.ts +0 -79
- package/src/identity/.spec/flows/domain-mediated-registration.ts +0 -51
- package/src/identity/.spec/flows/import.ts +0 -29
- package/src/identity/.spec/laws/identity.ts +0 -56
- package/src/identity/.spec/layout.ts +0 -13
- package/src/identity/__tests__/fixtures/registry-journey.ts +0 -65
- package/src/identity/__tests__/registration.test.ts +0 -64
- package/src/identity/__tests__/registry.test.ts +0 -74
- package/src/identity/__tests__/transfer.test.ts +0 -198
- package/src/identity/index.ts +0 -23
- package/src/identity/registration.ts +0 -72
- package/src/identity/registry.ts +0 -181
- package/src/identity/transfer.ts +0 -187
- package/src/identity/tsconfig.json +0 -6
- package/src/index.ts +0 -1
- package/src/keys/.spec/api.d.ts +0 -74
- package/src/keys/.spec/architecture.md +0 -13
- package/src/keys/.spec/laws/keys.ts +0 -43
- package/src/keys/.spec/layout.ts +0 -6
- package/src/keys/__tests__/algorithm.test.ts +0 -39
- package/src/keys/__tests__/keys.test.ts +0 -172
- package/src/keys/algorithm.ts +0 -33
- package/src/keys/credential.ts +0 -113
- package/src/keys/index.ts +0 -14
- package/src/keys/pair.ts +0 -219
- package/src/keys/tsconfig.json +0 -6
- package/src/lib/__tests__/admin-target.test.ts +0 -184
- package/src/lib/__tests__/binary.test.ts +0 -70
- package/src/lib/__tests__/browser-retention.test.ts +0 -212
- package/src/lib/__tests__/command-dx.test.ts +0 -102
- package/src/lib/__tests__/concurrency.test.ts +0 -62
- package/src/lib/__tests__/config.test.ts +0 -81
- package/src/lib/__tests__/design.test.ts +0 -99
- package/src/lib/__tests__/domain-publication.test.ts +0 -138
- package/src/lib/__tests__/format.test.ts +0 -22
- package/src/lib/__tests__/idp-session.driver.ts +0 -60
- package/src/lib/__tests__/idp-session.test.ts +0 -404
- package/src/lib/__tests__/idp.test.ts +0 -415
- package/src/lib/__tests__/instance-candidates.test.ts +0 -146
- package/src/lib/__tests__/instance-target.test.ts +0 -213
- package/src/lib/__tests__/instance.test.ts +0 -192
- package/src/lib/__tests__/local-status.test.ts +0 -202
- package/src/lib/__tests__/log-errors.test.ts +0 -64
- package/src/lib/__tests__/log.test.ts +0 -31
- package/src/lib/__tests__/meta.test.ts +0 -55
- package/src/lib/__tests__/output.test.ts +0 -162
- package/src/lib/__tests__/panel.test.ts +0 -40
- package/src/lib/__tests__/port.test.ts +0 -44
- package/src/lib/__tests__/prompt.test.ts +0 -25
- package/src/lib/__tests__/sdk-deps.test.ts +0 -68
- package/src/lib/__tests__/self.test.ts +0 -50
- package/src/lib/__tests__/skills.test.ts +0 -834
- package/src/lib/__tests__/studio-server-deps.test.ts +0 -111
- package/src/lib/__tests__/table.test.ts +0 -53
- package/src/lib/__tests__/update.test.ts +0 -511
- package/src/lib/__tests__/use-target.test.ts +0 -56
- package/src/lib/__tests__/validation.test.ts +0 -34
- package/src/lib/__tests__/view-assets.test.ts +0 -171
- package/src/lib/__tests__/view-external-open-intent.test.ts +0 -150
- package/src/lib/__tests__/view-external-open-origins.test.ts +0 -27
- package/src/lib/__tests__/view-open-intent.test.ts +0 -280
- package/src/lib/__tests__/view-port-allocation.test.ts +0 -82
- package/src/lib/__tests__/view-server.test.ts +0 -91
- package/src/lib/__tests__/view-session.test.ts +0 -100
- package/src/lib/__tests__/view-snapshot.test.ts +0 -77
- package/src/lib/admin-domain.ts +0 -43
- package/src/lib/admin-instance.ts +0 -56
- package/src/lib/admin-target.ts +0 -290
- package/src/lib/binary.ts +0 -127
- package/src/lib/browser-retention.ts +0 -210
- package/src/lib/browser.ts +0 -150
- package/src/lib/ca-fetch.ts +0 -133
- package/src/lib/command-dx.ts +0 -191
- package/src/lib/concurrency.ts +0 -31
- package/src/lib/config.ts +0 -57
- package/src/lib/credential-lifetime.ts +0 -24
- package/src/lib/domain-publication.ts +0 -104
- package/src/lib/failure-debug.ts +0 -26
- package/src/lib/format.ts +0 -4
- package/src/lib/idp-session.ts +0 -156
- package/src/lib/idp.ts +0 -926
- package/src/lib/instance-candidates.ts +0 -49
- package/src/lib/instance-target.ts +0 -197
- package/src/lib/instance.ts +0 -468
- package/src/lib/invocation.ts +0 -11
- package/src/lib/local-status.ts +0 -152
- package/src/lib/log.ts +0 -143
- package/src/lib/login-flow.ts +0 -201
- package/src/lib/meta.ts +0 -90
- package/src/lib/output.ts +0 -238
- package/src/lib/panel.ts +0 -61
- package/src/lib/port.ts +0 -41
- package/src/lib/proc.ts +0 -87
- package/src/lib/prompt.ts +0 -136
- package/src/lib/provision-instance.ts +0 -139
- package/src/lib/sdk-deps.ts +0 -104
- package/src/lib/self.ts +0 -22
- package/src/lib/skills/lock.ts +0 -117
- package/src/lib/skills/sync.ts +0 -878
- package/src/lib/skills.ts +0 -120
- package/src/lib/table.ts +0 -62
- package/src/lib/update.ts +0 -568
- package/src/lib/use-target.ts +0 -24
- package/src/lib/validation.ts +0 -59
- package/src/lib/view/assets.ts +0 -87
- package/src/lib/view/external-open-intent.ts +0 -41
- package/src/lib/view/external-open-origins.ts +0 -37
- package/src/lib/view/host-capabilities.ts +0 -17
- package/src/lib/view/open-intent.ts +0 -67
- package/src/lib/view/port-allocation.ts +0 -19
- package/src/lib/view/resolve.ts +0 -111
- package/src/lib/view/server.ts +0 -259
- package/src/lib/view/session.ts +0 -154
- package/src/lib/view/snapshot.ts +0 -101
- package/src/paths/.spec/api.d.ts +0 -13
- package/src/paths/.spec/architecture.md +0 -5
- package/src/paths/.spec/layout.ts +0 -3
- package/src/paths/index.ts +0 -13
- package/src/program/.spec/api.d.ts +0 -43
- package/src/program/.spec/architecture.md +0 -18
- package/src/program/.spec/laws/program.ts +0 -29
- package/src/program/.spec/layout.ts +0 -14
- package/src/program/__tests__/program.test.ts +0 -556
- package/src/program/argv.ts +0 -14
- package/src/program/build.ts +0 -205
- package/src/program/command.ts +0 -43
- package/src/program/index.ts +0 -3
- package/src/program/options.ts +0 -41
- package/src/program/registry.ts +0 -64
- package/src/program/tsconfig.json +0 -6
- package/src/setup/__tests__/instance-step.test.ts +0 -256
- package/src/setup/__tests__/util.test.ts +0 -29
- package/src/setup/engine.ts +0 -83
- package/src/setup/render.ts +0 -107
- package/src/setup/steps/admin.ts +0 -93
- package/src/setup/steps/agent-browser.ts +0 -81
- package/src/setup/steps/auth.ts +0 -54
- package/src/setup/steps/domain.ts +0 -68
- package/src/setup/steps/index.ts +0 -18
- package/src/setup/steps/instance.ts +0 -206
- package/src/setup/steps/skills-bridge.ts +0 -70
- package/src/setup/steps/skills.ts +0 -61
- package/src/setup/types.ts +0 -61
- package/src/setup/util.ts +0 -34
- package/src/state/.spec/api.d.ts +0 -152
- package/src/state/.spec/architecture.md +0 -45
- package/src/state/.spec/capabilities/state.ts +0 -7
- package/src/state/.spec/flows/identity-update.ts +0 -22
- package/src/state/.spec/laws/state.ts +0 -73
- package/src/state/.spec/layout.ts +0 -15
- package/src/state/__tests__/exchange-credentials.test.ts +0 -341
- package/src/state/__tests__/files.test.ts +0 -136
- package/src/state/__tests__/fixtures/identity-transition.ts +0 -37
- package/src/state/__tests__/fixtures/session-route-process.ts +0 -93
- package/src/state/__tests__/identities.test.ts +0 -142
- package/src/state/__tests__/paths.test.ts +0 -28
- package/src/state/__tests__/session-routes.test.ts +0 -138
- package/src/state/exchange-credentials.ts +0 -250
- package/src/state/files.ts +0 -170
- package/src/state/identities.ts +0 -229
- package/src/state/index.ts +0 -31
- package/src/state/paths.ts +0 -64
- package/src/state/session-routes.ts +0 -34
- package/src/state/tsconfig.json +0 -6
- package/src/telemetry/__tests__/analyze-log.test.ts +0 -38
- package/src/telemetry/__tests__/gate.test.ts +0 -63
- package/src/telemetry/__tests__/recorder.test.ts +0 -111
- package/src/telemetry/__tests__/redact.test.ts +0 -79
- package/src/telemetry/__tests__/retention.test.ts +0 -267
- package/src/telemetry/__tests__/session.test.ts +0 -166
- package/src/telemetry/__tests__/settings.test.ts +0 -102
- package/src/telemetry/__tests__/store-scan.test.ts +0 -128
- package/src/telemetry/__tests__/trigger.test.ts +0 -78
- package/src/telemetry/adapters/__tests__/claude-code.test.ts +0 -89
- package/src/telemetry/adapters/__tests__/codex.test.ts +0 -138
- package/src/telemetry/adapters/__tests__/index.test.ts +0 -88
- package/src/telemetry/adapters/claude-code.ts +0 -90
- package/src/telemetry/adapters/codex.ts +0 -160
- package/src/telemetry/adapters/index.ts +0 -45
- package/src/telemetry/adapters/types.ts +0 -21
- package/src/telemetry/analyze.ts +0 -249
- package/src/telemetry/gate.ts +0 -79
- package/src/telemetry/recorder.ts +0 -68
- package/src/telemetry/redact.ts +0 -53
- package/src/telemetry/retention.ts +0 -176
- package/src/telemetry/session.ts +0 -94
- package/src/telemetry/settings.ts +0 -79
- package/src/telemetry/store.ts +0 -174
- package/src/telemetry/trigger.ts +0 -107
- package/src/telemetry/types.ts +0 -64
- package/src/test-utils.ts +0 -18
- package/src/ui/.spec/api.d.ts +0 -14
- package/src/ui/.spec/architecture.md +0 -14
- package/src/ui/.spec/laws.ts +0 -50
- package/src/ui/.spec/layout.ts +0 -16
- package/src/ui/__tests__/ui.test.ts +0 -1742
- package/src/ui/index.ts +0 -13
- package/src/ui/lock.ts +0 -89
- package/src/ui/model.ts +0 -83
- package/src/ui/operations.ts +0 -1044
- package/src/ui/project.ts +0 -333
- package/src/ui/release.ts +0 -398
- package/src/ui/runner.ts +0 -18
- package/studio/client/dist/assets/index-BFVFs_8x.js +0 -81
- package/studio/client/dist/assets/index-DuB9iUdu.css +0 -2
- package/studio/client/dist/assets/schema-studio-DH6oEWME.js +0 -8
- package/studio/tsconfig.json +0 -24
- package/viewer/tsconfig.json +0 -13
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import type { Fetch } from '@astrale-os/sdk/client'
|
|
2
|
-
import type { SessionAuth } from '@astrale-os/sdk/client/session'
|
|
3
|
-
|
|
4
|
-
import { credential, type IssuerId } from '@astrale-os/sdk/auth'
|
|
5
|
-
|
|
6
|
-
import type { AstraleConfig } from '../lib/config'
|
|
7
|
-
import type { ConnectionOptions, ConnectionTarget } from './target'
|
|
8
|
-
|
|
9
|
-
import { AstraleError } from '../errors'
|
|
10
|
-
import { remainingCredentialLifetimeSeconds } from '../lib/credential-lifetime'
|
|
11
|
-
import { resolveCredential } from './auth'
|
|
12
|
-
import { createExchangeCredentialResolver } from './exchange'
|
|
13
|
-
import { exchangeCredentialTtlSeconds, invocationCredentialTtlSeconds } from './lifetime'
|
|
14
|
-
import { registrationKeyForTarget } from './target'
|
|
15
|
-
|
|
16
|
-
const DELEGATION_TTL_SECONDS = 60
|
|
17
|
-
|
|
18
|
-
export interface SourceCredentialResolver {
|
|
19
|
-
resolve(audience: IssuerId, signal: AbortSignal): Promise<string>
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Resolve source authority; an omitted Session delegation preserves exact current authority. */
|
|
23
|
-
export function createConnectionCredential(
|
|
24
|
-
expectedSourceIssuer: IssuerId,
|
|
25
|
-
source: SourceCredentialResolver,
|
|
26
|
-
ttlSeconds = DELEGATION_TTL_SECONDS,
|
|
27
|
-
): SessionAuth {
|
|
28
|
-
if (!Number.isSafeInteger(ttlSeconds) || ttlSeconds < 1) {
|
|
29
|
-
throw new TypeError('Connection credential ttlSeconds must be a positive safe integer.')
|
|
30
|
-
}
|
|
31
|
-
const resolveSource = source.resolve.bind(source)
|
|
32
|
-
return Object.freeze({
|
|
33
|
-
ttlSeconds,
|
|
34
|
-
async resolve(
|
|
35
|
-
_call: Parameters<SessionAuth['resolve']>[0],
|
|
36
|
-
signal: Parameters<SessionAuth['resolve']>[1],
|
|
37
|
-
) {
|
|
38
|
-
const resolved = await resolveSource(expectedSourceIssuer, signal)
|
|
39
|
-
const delegatedTtlSeconds = sourceBoundDelegationTtl(resolved, ttlSeconds)
|
|
40
|
-
return Object.freeze({
|
|
41
|
-
credential: resolved,
|
|
42
|
-
...(delegatedTtlSeconds === undefined
|
|
43
|
-
? {}
|
|
44
|
-
: { delegate: { ttlSeconds: delegatedTtlSeconds } }),
|
|
45
|
-
})
|
|
46
|
-
},
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/** Never request a destination carrier that could outlive its current source bearer. */
|
|
51
|
-
function sourceBoundDelegationTtl(input: string, requestedTtlSeconds: number): number | undefined {
|
|
52
|
-
try {
|
|
53
|
-
const expiresAt = credential.inspect(input).claims.exp
|
|
54
|
-
if (typeof expiresAt !== 'number' || !Number.isSafeInteger(expiresAt)) return undefined
|
|
55
|
-
const remaining = remainingCredentialLifetimeSeconds(expiresAt)
|
|
56
|
-
if (remaining < requestedTtlSeconds) {
|
|
57
|
-
throw new AstraleError(
|
|
58
|
-
'CREDENTIAL_LIFETIME_INSUFFICIENT',
|
|
59
|
-
'The selected credential cannot cover the requested command timeout.',
|
|
60
|
-
`Use a fresh identity session or a shorter --timeout; ${Math.max(0, remaining)} seconds remain but ${requestedTtlSeconds} are required.`,
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
return Math.max(1, Math.min(requestedTtlSeconds, remaining))
|
|
64
|
-
} catch (cause) {
|
|
65
|
-
if (cause instanceof AstraleError) throw cause
|
|
66
|
-
// Preserve opaque explicit credentials; the Kernel remains their authority.
|
|
67
|
-
return undefined
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Bind CLI identity state and Core Auth delegation to one Session auth capability. */
|
|
72
|
-
export function createCliCredential(
|
|
73
|
-
target: ConnectionTarget,
|
|
74
|
-
options: ConnectionOptions,
|
|
75
|
-
config: AstraleConfig,
|
|
76
|
-
fetch: Fetch = globalThis.fetch,
|
|
77
|
-
timeoutMs = 30_000,
|
|
78
|
-
): SessionAuth | undefined {
|
|
79
|
-
validateCredentialSelection(options)
|
|
80
|
-
if (options.anonymous === true) return undefined
|
|
81
|
-
const authOptions = Object.freeze({
|
|
82
|
-
...(options.as === undefined ? {} : { as: options.as }),
|
|
83
|
-
...(options.creds === undefined ? {} : { creds: options.creds }),
|
|
84
|
-
...(target.defaultIdentity === undefined ? {} : { defaultIdentity: target.defaultIdentity }),
|
|
85
|
-
minimumRemainingSeconds:
|
|
86
|
-
target.domainIssuer === undefined
|
|
87
|
-
? invocationCredentialTtlSeconds(timeoutMs)
|
|
88
|
-
: exchangeCredentialTtlSeconds(timeoutMs),
|
|
89
|
-
})
|
|
90
|
-
const source: SourceCredentialResolver = {
|
|
91
|
-
async resolve(audience, signal) {
|
|
92
|
-
requireLive(signal)
|
|
93
|
-
const credential = await resolveCredential(
|
|
94
|
-
authOptions,
|
|
95
|
-
config,
|
|
96
|
-
audience,
|
|
97
|
-
registrationKeyForTarget(target),
|
|
98
|
-
)
|
|
99
|
-
requireLive(signal)
|
|
100
|
-
return credential
|
|
101
|
-
},
|
|
102
|
-
}
|
|
103
|
-
const effective =
|
|
104
|
-
target.domainIssuer === undefined || options.creds !== undefined
|
|
105
|
-
? source
|
|
106
|
-
: createExchangeCredentialResolver(
|
|
107
|
-
{ ...target, domainIssuer: target.domainIssuer },
|
|
108
|
-
source,
|
|
109
|
-
fetch,
|
|
110
|
-
timeoutMs,
|
|
111
|
-
)
|
|
112
|
-
const ttlSeconds = invocationCredentialTtlSeconds(timeoutMs)
|
|
113
|
-
return createConnectionCredential(target.kernelIssuer, effective, ttlSeconds)
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/** Reject contradictory explicit credential selections before identity or network access. */
|
|
117
|
-
export function validateCredentialSelection(options: ConnectionOptions): void {
|
|
118
|
-
if (options.as !== undefined && options.creds !== undefined) {
|
|
119
|
-
throw new AstraleError('INVALID_FLAG', '--as cannot be combined with --creds.')
|
|
120
|
-
}
|
|
121
|
-
if (options.anonymous !== true) return
|
|
122
|
-
const conflicting = [
|
|
123
|
-
...(options.as === undefined ? [] : ['--as']),
|
|
124
|
-
...(options.creds === undefined ? [] : ['--creds']),
|
|
125
|
-
]
|
|
126
|
-
if (conflicting.length === 0) return
|
|
127
|
-
throw new AstraleError(
|
|
128
|
-
'INVALID_FLAG',
|
|
129
|
-
`--anonymous cannot be combined with ${conflicting.join(' or ')}.`,
|
|
130
|
-
)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function requireLive(signal: AbortSignal): void {
|
|
134
|
-
if (!signal.aborted) return
|
|
135
|
-
throw signal.reason instanceof Error
|
|
136
|
-
? signal.reason
|
|
137
|
-
: new DOMException('The operation was aborted.', 'AbortError')
|
|
138
|
-
}
|
package/src/connection/errors.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { formatKernelError, functionInputIssues, schemaUpgradeHint } from './failure'
|
|
@@ -1,394 +0,0 @@
|
|
|
1
|
-
import type { IssuerId } from '@astrale-os/sdk/auth'
|
|
2
|
-
import type { Fetch } from '@astrale-os/sdk/client'
|
|
3
|
-
|
|
4
|
-
import { createAuth } from '@astrale-os/sdk/auth'
|
|
5
|
-
import { credential, exchange as exchangeProtocol, grant } from '@astrale-os/sdk/auth'
|
|
6
|
-
import { call, Client } from '@astrale-os/sdk/client'
|
|
7
|
-
|
|
8
|
-
import type { SourceCredentialResolver } from './credential'
|
|
9
|
-
import type { ConnectionTarget } from './target'
|
|
10
|
-
|
|
11
|
-
import { AstraleError } from '../errors'
|
|
12
|
-
import { remainingCredentialLifetimeSeconds } from '../lib/credential-lifetime'
|
|
13
|
-
import { ExchangeCredentialCache } from '../state/exchange-credentials'
|
|
14
|
-
import { cachedCredentialTtlSeconds, exchangeCredentialTtlSeconds } from './lifetime'
|
|
15
|
-
|
|
16
|
-
const MAXIMUM_RESPONSE_BYTES = 256 * 1024
|
|
17
|
-
|
|
18
|
-
/** Exchange exact authenticated User authority for a Domain bearer bound to this Kernel. */
|
|
19
|
-
export function createExchangeCredentialResolver(
|
|
20
|
-
target: ConnectionTarget & { readonly domainIssuer: IssuerId },
|
|
21
|
-
source: SourceCredentialResolver,
|
|
22
|
-
fetch: Fetch,
|
|
23
|
-
timeoutMs: number,
|
|
24
|
-
cache = new ExchangeCredentialCache(),
|
|
25
|
-
): SourceCredentialResolver {
|
|
26
|
-
requireExchangeTransport(target)
|
|
27
|
-
const cacheTtlSeconds = cachedCredentialTtlSeconds(timeoutMs)
|
|
28
|
-
const exchangeTtlSeconds = exchangeCredentialTtlSeconds(timeoutMs)
|
|
29
|
-
return Object.freeze({
|
|
30
|
-
async resolve(kernelIssuer: IssuerId, signal: AbortSignal): Promise<string> {
|
|
31
|
-
requireLive(signal)
|
|
32
|
-
const sourceToken = await source.resolve(kernelIssuer, signal)
|
|
33
|
-
const sourceIdentity = sourceCacheIdentity(sourceToken)
|
|
34
|
-
requireLive(signal)
|
|
35
|
-
|
|
36
|
-
return await cache.getOrRefresh(
|
|
37
|
-
Object.freeze({
|
|
38
|
-
kernelIssuer,
|
|
39
|
-
domainIssuer: target.domainIssuer,
|
|
40
|
-
sourceIssuer: sourceIdentity.issuer,
|
|
41
|
-
sourceSubject: sourceIdentity.subject,
|
|
42
|
-
}),
|
|
43
|
-
cacheTtlSeconds,
|
|
44
|
-
async () => {
|
|
45
|
-
const delegationTtlSeconds = delegationLifetime(sourceToken, exchangeTtlSeconds)
|
|
46
|
-
const client = new Client({ url: `${kernelIssuer}/invoke`, fetch, timeoutMs })
|
|
47
|
-
try {
|
|
48
|
-
const authenticated = client.as(sourceToken)
|
|
49
|
-
const auth = createAuth(async (path, input, options) => {
|
|
50
|
-
const result = await authenticated.call(call(path, input), {
|
|
51
|
-
...options,
|
|
52
|
-
delegate: { ttlSeconds: delegationTtlSeconds },
|
|
53
|
-
})
|
|
54
|
-
return result.value
|
|
55
|
-
})
|
|
56
|
-
const user = await auth.whoami({ signal })
|
|
57
|
-
let envelope: string | undefined
|
|
58
|
-
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
59
|
-
try {
|
|
60
|
-
envelope = await auth.delegate(
|
|
61
|
-
user.id,
|
|
62
|
-
{
|
|
63
|
-
audience: target.domainIssuer,
|
|
64
|
-
ttlSeconds: delegationTtlSeconds,
|
|
65
|
-
attenuation: { kind: 'identity', self: true },
|
|
66
|
-
},
|
|
67
|
-
{ signal },
|
|
68
|
-
)
|
|
69
|
-
break
|
|
70
|
-
} catch (cause) {
|
|
71
|
-
if (attempt === 2 || !unknownFunctionOutcome(cause)) throw cause
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (envelope === undefined) throw new Error('Token delegation returned no credential.')
|
|
75
|
-
return {
|
|
76
|
-
...(await exchange(
|
|
77
|
-
target.domainIssuer,
|
|
78
|
-
kernelIssuer,
|
|
79
|
-
envelope,
|
|
80
|
-
cacheTtlSeconds,
|
|
81
|
-
fetch,
|
|
82
|
-
signal,
|
|
83
|
-
)),
|
|
84
|
-
user: user.id,
|
|
85
|
-
sourceIssuer: sourceIdentity.issuer,
|
|
86
|
-
sourceSubject: sourceIdentity.subject,
|
|
87
|
-
}
|
|
88
|
-
} finally {
|
|
89
|
-
client.close()
|
|
90
|
-
}
|
|
91
|
-
},
|
|
92
|
-
)
|
|
93
|
-
},
|
|
94
|
-
})
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function sourceCacheIdentity(sourceToken: string): { issuer: string; subject: string } {
|
|
98
|
-
const inspected = credential.inspect(sourceToken)
|
|
99
|
-
if (
|
|
100
|
-
typeof inspected.iss !== 'string' ||
|
|
101
|
-
inspected.iss.length === 0 ||
|
|
102
|
-
typeof inspected.sub !== 'string' ||
|
|
103
|
-
inspected.sub.length === 0
|
|
104
|
-
) {
|
|
105
|
-
throw new AstraleError(
|
|
106
|
-
'TOKEN_EXCHANGE_SOURCE_INVALID',
|
|
107
|
-
'The source identity credential has no stable issuer and subject.',
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
return Object.freeze({ issuer: inspected.iss, subject: inspected.sub })
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function unknownFunctionOutcome(cause: unknown): boolean {
|
|
114
|
-
if (cause === null || typeof cause !== 'object') return false
|
|
115
|
-
const error = cause as { readonly code?: unknown; readonly reason?: unknown }
|
|
116
|
-
if (error.code === 5002) return true
|
|
117
|
-
if (error.reason === null || typeof error.reason !== 'object') return false
|
|
118
|
-
return (error.reason as { readonly code?: unknown }).code === 'FUNCTION_OUTCOME_UNKNOWN'
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function delegationLifetime(sourceToken: string, requiredTtlSeconds: number): number {
|
|
122
|
-
const expiresAt = credential.inspect(sourceToken).claims.exp
|
|
123
|
-
if (typeof expiresAt !== 'number' || !Number.isSafeInteger(expiresAt)) {
|
|
124
|
-
throw new AstraleError(
|
|
125
|
-
'TOKEN_EXCHANGE_SOURCE_INVALID',
|
|
126
|
-
'The source identity credential has no valid expiration.',
|
|
127
|
-
)
|
|
128
|
-
}
|
|
129
|
-
const remaining = remainingCredentialLifetimeSeconds(expiresAt)
|
|
130
|
-
if (!Number.isSafeInteger(remaining) || remaining < 1) {
|
|
131
|
-
throw new AstraleError(
|
|
132
|
-
'TOKEN_EXCHANGE_SOURCE_EXPIRED',
|
|
133
|
-
'The source identity credential has no lifetime available for token exchange.',
|
|
134
|
-
)
|
|
135
|
-
}
|
|
136
|
-
if (remaining < requiredTtlSeconds) {
|
|
137
|
-
throw new AstraleError(
|
|
138
|
-
'TOKEN_EXCHANGE_SOURCE_LIFETIME_INSUFFICIENT',
|
|
139
|
-
'The source credential cannot cover the requested command timeout.',
|
|
140
|
-
`Refresh the identity session or use a shorter --timeout; ${remaining} seconds remain but ${requiredTtlSeconds} are required.`,
|
|
141
|
-
)
|
|
142
|
-
}
|
|
143
|
-
return requiredTtlSeconds
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function exchange(
|
|
147
|
-
domainIssuer: IssuerId,
|
|
148
|
-
kernelIssuer: IssuerId,
|
|
149
|
-
envelope: string,
|
|
150
|
-
requiredTtlSeconds: number,
|
|
151
|
-
fetch: Fetch,
|
|
152
|
-
signal: AbortSignal,
|
|
153
|
-
): Promise<{ readonly credential: string; readonly expiresAt: number }> {
|
|
154
|
-
const configurationUrl = new URL(
|
|
155
|
-
exchangeProtocol.paths(domainIssuer).configuration,
|
|
156
|
-
domainIssuer,
|
|
157
|
-
).toString()
|
|
158
|
-
const configurationResponse = await fetchExchange(
|
|
159
|
-
fetch,
|
|
160
|
-
configurationUrl,
|
|
161
|
-
{
|
|
162
|
-
method: 'GET',
|
|
163
|
-
redirect: 'error',
|
|
164
|
-
credentials: 'omit',
|
|
165
|
-
cache: 'no-store',
|
|
166
|
-
referrerPolicy: 'no-referrer',
|
|
167
|
-
headers: { accept: 'application/json' },
|
|
168
|
-
signal,
|
|
169
|
-
},
|
|
170
|
-
'Domain issuer discovery could not be reached.',
|
|
171
|
-
)
|
|
172
|
-
if (!configurationResponse.ok) {
|
|
173
|
-
throw new AstraleError(
|
|
174
|
-
'TOKEN_EXCHANGE_DISCOVERY_FAILED',
|
|
175
|
-
`Domain issuer discovery failed with HTTP ${configurationResponse.status}.`,
|
|
176
|
-
)
|
|
177
|
-
}
|
|
178
|
-
const configuration = exchangeProtocol.acceptConfiguration(
|
|
179
|
-
await boundedJson(configurationResponse, signal),
|
|
180
|
-
domainIssuer,
|
|
181
|
-
)
|
|
182
|
-
const endpoint = configuration.token_exchange_endpoint
|
|
183
|
-
if (endpoint === undefined) {
|
|
184
|
-
throw new AstraleError(
|
|
185
|
-
'TOKEN_EXCHANGE_UNSUPPORTED',
|
|
186
|
-
`Domain issuer ${domainIssuer} does not advertise token exchange.`,
|
|
187
|
-
'This command has no legacy token fallback.',
|
|
188
|
-
)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const response = await fetchExchange(
|
|
192
|
-
fetch,
|
|
193
|
-
endpoint,
|
|
194
|
-
{
|
|
195
|
-
method: 'POST',
|
|
196
|
-
redirect: 'error',
|
|
197
|
-
credentials: 'omit',
|
|
198
|
-
cache: 'no-store',
|
|
199
|
-
referrerPolicy: 'no-referrer',
|
|
200
|
-
headers: {
|
|
201
|
-
authorization: `Bearer ${envelope}`,
|
|
202
|
-
accept: exchangeProtocol.MEDIA_TYPE,
|
|
203
|
-
},
|
|
204
|
-
signal,
|
|
205
|
-
},
|
|
206
|
-
'Domain token exchange could not be reached.',
|
|
207
|
-
)
|
|
208
|
-
const body = await boundedJson(response, signal)
|
|
209
|
-
if (!response.ok) {
|
|
210
|
-
let admitted: exchangeProtocol.ErrorResponse
|
|
211
|
-
try {
|
|
212
|
-
admitted = exchangeProtocol.acceptErrorResponse(body)
|
|
213
|
-
} catch (cause) {
|
|
214
|
-
if (!(cause instanceof TypeError)) throw cause
|
|
215
|
-
throw new AstraleError(
|
|
216
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
217
|
-
`Token exchange failed with HTTP ${response.status} and an invalid error response.`,
|
|
218
|
-
cause instanceof Error ? cause.message : undefined,
|
|
219
|
-
)
|
|
220
|
-
}
|
|
221
|
-
throw new AstraleError(String(admitted.error.code), admitted.error.message)
|
|
222
|
-
}
|
|
223
|
-
requireExchangeResponseHeaders(response)
|
|
224
|
-
let exchanged: exchangeProtocol.Response
|
|
225
|
-
let inspected: ReturnType<typeof credential.inspect>
|
|
226
|
-
try {
|
|
227
|
-
exchanged = exchangeProtocol.acceptResponse(body)
|
|
228
|
-
inspected = credential.inspect(exchanged.token)
|
|
229
|
-
} catch (cause) {
|
|
230
|
-
if (!(cause instanceof TypeError)) throw cause
|
|
231
|
-
throw new AstraleError(
|
|
232
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
233
|
-
'Token exchange returned an invalid success response.',
|
|
234
|
-
cause.message,
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
if (
|
|
238
|
-
inspected.iss !== domainIssuer ||
|
|
239
|
-
inspected.aud !== kernelIssuer ||
|
|
240
|
-
inspected.claims.exp !== exchanged.expiresAt
|
|
241
|
-
) {
|
|
242
|
-
throw new AstraleError(
|
|
243
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
244
|
-
'Token exchange returned a credential inconsistent with the requested Domain and Kernel.',
|
|
245
|
-
)
|
|
246
|
-
}
|
|
247
|
-
const remaining = effectiveExchangeLifetime(inspected, exchanged.expiresAt)
|
|
248
|
-
if (remaining < requiredTtlSeconds) {
|
|
249
|
-
throw new AstraleError(
|
|
250
|
-
'TOKEN_EXCHANGE_LIFETIME_INSUFFICIENT',
|
|
251
|
-
'The Domain exchange credential cannot cover the requested command timeout.',
|
|
252
|
-
`The Domain issuer returned ${Math.max(0, remaining)} seconds but ${requiredTtlSeconds} are required. Use a shorter --timeout or update the Domain execution service.`,
|
|
253
|
-
)
|
|
254
|
-
}
|
|
255
|
-
return Object.freeze({ credential: exchanged.token, expiresAt: exchanged.expiresAt })
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/** The outer Domain bearer and its carried Kernel proof must both survive the operation. */
|
|
259
|
-
function effectiveExchangeLifetime(
|
|
260
|
-
inspected: ReturnType<typeof credential.inspect>,
|
|
261
|
-
outerExpiresAt: number,
|
|
262
|
-
): number {
|
|
263
|
-
let proofExpiresAt: number
|
|
264
|
-
try {
|
|
265
|
-
const carried = grant.acceptUnresolved(inspected.claims.grant).expr
|
|
266
|
-
if (
|
|
267
|
-
carried.kind !== 'identity' ||
|
|
268
|
-
!('credential' in carried) ||
|
|
269
|
-
typeof carried.credential !== 'string'
|
|
270
|
-
) {
|
|
271
|
-
throw new TypeError('Domain credential does not carry an identity proof.')
|
|
272
|
-
}
|
|
273
|
-
const value = credential.inspect(carried.credential).claims.exp
|
|
274
|
-
if (typeof value !== 'number' || !Number.isSafeInteger(value)) {
|
|
275
|
-
throw new TypeError('Domain credential carries an identity proof without an expiration.')
|
|
276
|
-
}
|
|
277
|
-
proofExpiresAt = value
|
|
278
|
-
} catch (cause) {
|
|
279
|
-
if (!(cause instanceof TypeError)) throw cause
|
|
280
|
-
throw new AstraleError(
|
|
281
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
282
|
-
'Token exchange returned an invalid carried identity proof.',
|
|
283
|
-
cause.message,
|
|
284
|
-
)
|
|
285
|
-
}
|
|
286
|
-
return remainingCredentialLifetimeSeconds(Math.min(outerExpiresAt, proofExpiresAt))
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
async function fetchExchange(
|
|
290
|
-
fetch: Fetch,
|
|
291
|
-
input: string,
|
|
292
|
-
init: RequestInit,
|
|
293
|
-
message: string,
|
|
294
|
-
): Promise<Response> {
|
|
295
|
-
try {
|
|
296
|
-
return await fetch(input, init)
|
|
297
|
-
} catch (cause) {
|
|
298
|
-
if (init.signal?.aborted) throw cause
|
|
299
|
-
throw new AstraleError('TOKEN_EXCHANGE_UNAVAILABLE', message, undefined, { cause })
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
function requireExchangeTransport(
|
|
304
|
-
target: ConnectionTarget & { readonly domainIssuer: IssuerId },
|
|
305
|
-
): void {
|
|
306
|
-
const kernel = new URL(target.kernelIssuer)
|
|
307
|
-
const domain = new URL(target.domainIssuer)
|
|
308
|
-
if (domain.protocol === 'https:') return
|
|
309
|
-
if (domain.protocol === 'http:' && kernel.protocol === 'http:') return
|
|
310
|
-
throw new AstraleError(
|
|
311
|
-
'TOKEN_EXCHANGE_INSECURE',
|
|
312
|
-
'An HTTP Domain issuer is allowed only with an explicitly configured HTTP Kernel target.',
|
|
313
|
-
)
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function requireExchangeResponseHeaders(response: Response): void {
|
|
317
|
-
const contentType = response.headers.get('content-type')?.split(';', 1)[0]?.trim().toLowerCase()
|
|
318
|
-
if (contentType !== exchangeProtocol.MEDIA_TYPE) {
|
|
319
|
-
throw new AstraleError(
|
|
320
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
321
|
-
'Token exchange returned an unsupported Content-Type.',
|
|
322
|
-
)
|
|
323
|
-
}
|
|
324
|
-
if (
|
|
325
|
-
!response.headers
|
|
326
|
-
.get('cache-control')
|
|
327
|
-
?.toLowerCase()
|
|
328
|
-
.split(',')
|
|
329
|
-
.some((v) => v.trim() === 'no-store')
|
|
330
|
-
) {
|
|
331
|
-
throw new AstraleError(
|
|
332
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
333
|
-
'Token exchange response is missing Cache-Control: no-store.',
|
|
334
|
-
)
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
async function boundedJson(response: Response, signal: AbortSignal): Promise<unknown> {
|
|
339
|
-
const declared = response.headers.get('content-length')
|
|
340
|
-
if (
|
|
341
|
-
declared !== null &&
|
|
342
|
-
(!/^\d+$/u.test(declared) || Number(declared) > MAXIMUM_RESPONSE_BYTES)
|
|
343
|
-
) {
|
|
344
|
-
throw new AstraleError(
|
|
345
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
346
|
-
'Issuer response exceeds the size limit.',
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
if (response.body === null) {
|
|
350
|
-
throw new AstraleError('TOKEN_EXCHANGE_PROTOCOL_ERROR', 'Issuer response body is missing.')
|
|
351
|
-
}
|
|
352
|
-
const reader = response.body.getReader()
|
|
353
|
-
const chunks: Uint8Array[] = []
|
|
354
|
-
let size = 0
|
|
355
|
-
try {
|
|
356
|
-
for (;;) {
|
|
357
|
-
requireLive(signal)
|
|
358
|
-
const next = await reader.read()
|
|
359
|
-
if (next.done) break
|
|
360
|
-
size += next.value.byteLength
|
|
361
|
-
if (size > MAXIMUM_RESPONSE_BYTES) {
|
|
362
|
-
throw new AstraleError(
|
|
363
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
364
|
-
'Issuer response exceeds the size limit.',
|
|
365
|
-
)
|
|
366
|
-
}
|
|
367
|
-
chunks.push(next.value)
|
|
368
|
-
}
|
|
369
|
-
} finally {
|
|
370
|
-
reader.releaseLock()
|
|
371
|
-
}
|
|
372
|
-
const bytes = new Uint8Array(size)
|
|
373
|
-
let offset = 0
|
|
374
|
-
for (const chunk of chunks) {
|
|
375
|
-
bytes.set(chunk, offset)
|
|
376
|
-
offset += chunk.byteLength
|
|
377
|
-
}
|
|
378
|
-
try {
|
|
379
|
-
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes)) as unknown
|
|
380
|
-
} catch (cause) {
|
|
381
|
-
throw new AstraleError(
|
|
382
|
-
'TOKEN_EXCHANGE_PROTOCOL_ERROR',
|
|
383
|
-
'Issuer response is not valid UTF-8 JSON.',
|
|
384
|
-
cause instanceof Error ? cause.message : undefined,
|
|
385
|
-
)
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
function requireLive(signal: AbortSignal): void {
|
|
390
|
-
if (!signal.aborted) return
|
|
391
|
-
throw signal.reason instanceof Error
|
|
392
|
-
? signal.reason
|
|
393
|
-
: new DOMException('The operation was aborted.', 'AbortError')
|
|
394
|
-
}
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { AuthValueError } from '@astrale-os/sdk/auth'
|
|
2
|
-
import { ClientError, ProtocolError, ResponseError, TransportError } from '@astrale-os/sdk/client'
|
|
3
|
-
import { NodeUnavailableError } from '@astrale-os/sdk/client'
|
|
4
|
-
import { PathError } from '@astrale-os/sdk/graph/path'
|
|
5
|
-
|
|
6
|
-
import type { FailureDiagnostic, TransportDiagnosticContext } from './model'
|
|
7
|
-
|
|
8
|
-
import { AstraleError } from '../../errors'
|
|
9
|
-
|
|
10
|
-
export function classifyFailure(error: unknown): FailureDiagnostic {
|
|
11
|
-
if (error instanceof AstraleError) return simple(error.code, error.message, error.hint)
|
|
12
|
-
if (error instanceof TransportError) {
|
|
13
|
-
const context = transportContext(error)
|
|
14
|
-
if (context === undefined) return simple('TRANSPORT_ERROR', error.message)
|
|
15
|
-
return {
|
|
16
|
-
kind: 'transport',
|
|
17
|
-
code: lifecycleCode(error.phase),
|
|
18
|
-
message: error.message,
|
|
19
|
-
phase: error.phase,
|
|
20
|
-
context,
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
if (error instanceof ResponseError) {
|
|
24
|
-
return {
|
|
25
|
-
kind: 'response',
|
|
26
|
-
code: error.code,
|
|
27
|
-
message: error.message,
|
|
28
|
-
...(error.reason === undefined ? {} : { reason: error.reason }),
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
if (error instanceof ClientError) {
|
|
32
|
-
const failure = sessionFailure(error)
|
|
33
|
-
if (failure !== undefined) return simple(lifecycleCode(failure), error.message)
|
|
34
|
-
}
|
|
35
|
-
if (error instanceof ProtocolError) return simple('PROTOCOL_ERROR', error.message)
|
|
36
|
-
if (error instanceof NodeUnavailableError)
|
|
37
|
-
return simple(
|
|
38
|
-
'NODE_UNAVAILABLE',
|
|
39
|
-
error.message,
|
|
40
|
-
'If this is a callable Path, use `astrale call` or `astrale introspect`.',
|
|
41
|
-
)
|
|
42
|
-
if (error instanceof PathError) return simple('PATH_INVALID', error.message)
|
|
43
|
-
if (error instanceof AuthValueError) return simple('AUTH_VALUE_INVALID', error.message)
|
|
44
|
-
if (error instanceof ClientError) return simple('CLIENT_ERROR', error.message)
|
|
45
|
-
return simple('UNEXPECTED_ERROR', 'The CLI encountered an unexpected internal failure.')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
type TransportCode = Extract<FailureDiagnostic, { kind: 'transport' }>['code']
|
|
49
|
-
type SessionFailure = 'cancelled' | 'closed' | 'timeout'
|
|
50
|
-
|
|
51
|
-
function lifecycleCode(value: TransportError['phase']): TransportCode
|
|
52
|
-
function lifecycleCode(value: SessionFailure): string
|
|
53
|
-
function lifecycleCode(value: TransportError['phase'] | SessionFailure): string {
|
|
54
|
-
if (value === 'connect') return 'CONNECTION_ERROR'
|
|
55
|
-
if (value === 'timeout') return 'TIMEOUT'
|
|
56
|
-
if (value === 'closed') return 'DISCONNECTED'
|
|
57
|
-
return value === 'cancelled' ? 'CANCELLED' : 'TRANSPORT_ERROR'
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function transportContext(error: TransportError): TransportDiagnosticContext | undefined {
|
|
61
|
-
const evidence = error as TransportError & {
|
|
62
|
-
readonly context?: unknown
|
|
63
|
-
readonly delivery?: unknown
|
|
64
|
-
readonly invocation?: unknown
|
|
65
|
-
}
|
|
66
|
-
if (record(evidence.context)) {
|
|
67
|
-
if (
|
|
68
|
-
evidence.context.kind === 'acquisition' &&
|
|
69
|
-
(evidence.context.resource === 'publication' || evidence.context.resource === 'bundle')
|
|
70
|
-
) {
|
|
71
|
-
return { kind: 'acquisition', resource: evidence.context.resource }
|
|
72
|
-
}
|
|
73
|
-
if (
|
|
74
|
-
evidence.context.kind === 'invocation' &&
|
|
75
|
-
(evidence.context.delivery === 'not-sent' || evidence.context.delivery === 'unknown')
|
|
76
|
-
) {
|
|
77
|
-
return {
|
|
78
|
-
kind: 'invocation',
|
|
79
|
-
delivery: evidence.context.delivery,
|
|
80
|
-
...(evidence.context.invocation === undefined
|
|
81
|
-
? {}
|
|
82
|
-
: { invocation: evidence.context.invocation }),
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (evidence.delivery !== 'not-sent' && evidence.delivery !== 'unknown') return undefined
|
|
87
|
-
return {
|
|
88
|
-
kind: 'invocation',
|
|
89
|
-
delivery: evidence.delivery,
|
|
90
|
-
...(evidence.invocation === undefined ? {} : { invocation: evidence.invocation }),
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function sessionFailure(error: ClientError): SessionFailure | undefined {
|
|
95
|
-
const failure = (error as ClientError & { readonly failure?: unknown }).failure
|
|
96
|
-
return failure === 'cancelled' || failure === 'closed' || failure === 'timeout'
|
|
97
|
-
? failure
|
|
98
|
-
: undefined
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function record(input: unknown): input is Readonly<Record<string, unknown>> {
|
|
102
|
-
return input !== null && typeof input === 'object' && !Array.isArray(input)
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
const simple = (code: string, message: string, hint?: string): FailureDiagnostic => ({
|
|
106
|
-
kind: 'simple',
|
|
107
|
-
code,
|
|
108
|
-
message,
|
|
109
|
-
...(hint === undefined ? {} : { hint }),
|
|
110
|
-
})
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { OperationRecovery } from '../command'
|
|
2
|
-
|
|
3
|
-
import { printFailureDebug } from '../../lib/failure-debug'
|
|
4
|
-
import { classifyFailure } from './classify'
|
|
5
|
-
import { renderFailure } from './render'
|
|
6
|
-
|
|
7
|
-
export { functionInputIssues, schemaUpgradeHint } from '../reasons'
|
|
8
|
-
|
|
9
|
-
export async function formatKernelError(
|
|
10
|
-
error: unknown,
|
|
11
|
-
machine: boolean,
|
|
12
|
-
urlArg = '',
|
|
13
|
-
debug = false,
|
|
14
|
-
options: { recovery?: OperationRecovery } = {},
|
|
15
|
-
): Promise<void> {
|
|
16
|
-
renderFailure(classifyFailure(error), machine, urlArg, options.recovery)
|
|
17
|
-
if (debug) printFailureDebug(error, urlArg)
|
|
18
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
export type TransportDiagnosticContext =
|
|
2
|
-
| { readonly kind: 'acquisition'; readonly resource: 'publication' | 'bundle' }
|
|
3
|
-
| {
|
|
4
|
-
readonly kind: 'invocation'
|
|
5
|
-
readonly delivery: 'not-sent' | 'unknown'
|
|
6
|
-
readonly invocation?: unknown
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export type FailureDiagnostic =
|
|
10
|
-
| {
|
|
11
|
-
readonly kind: 'simple'
|
|
12
|
-
readonly code: string
|
|
13
|
-
readonly message: string
|
|
14
|
-
readonly hint?: string
|
|
15
|
-
}
|
|
16
|
-
| {
|
|
17
|
-
readonly kind: 'response'
|
|
18
|
-
readonly code: number
|
|
19
|
-
readonly message: string
|
|
20
|
-
readonly reason?: unknown
|
|
21
|
-
}
|
|
22
|
-
| {
|
|
23
|
-
readonly kind: 'transport'
|
|
24
|
-
readonly code: 'CONNECTION_ERROR' | 'DISCONNECTED' | 'TIMEOUT' | 'TRANSPORT_ERROR'
|
|
25
|
-
readonly message: string
|
|
26
|
-
readonly phase: string
|
|
27
|
-
readonly context: TransportDiagnosticContext
|
|
28
|
-
}
|