@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,280 +0,0 @@
|
|
|
1
|
-
import type { IntentMessage, MountedWindow, ResolvedView, Shell } from '@astrale-os/shell'
|
|
2
|
-
|
|
3
|
-
import { NO_HOST_CAPABILITIES } from '@astrale-os/shell'
|
|
4
|
-
import { describe, expect, test } from 'bun:test'
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
handleOpenIntent,
|
|
8
|
-
installOpenIntentHandler,
|
|
9
|
-
type OpenIntentHost,
|
|
10
|
-
} from '../view/open-intent'
|
|
11
|
-
|
|
12
|
-
const digest = (character: string) => `sha256:${character.repeat(64)}` as const
|
|
13
|
-
const target = (value: string) => value as ResolvedView['target']
|
|
14
|
-
const issuer = (value: string) => value as ResolvedView['route']['issuer']
|
|
15
|
-
const revision = (character: string) => digest(character) as ResolvedView['route']['revision']
|
|
16
|
-
|
|
17
|
-
const profile: ResolvedView = {
|
|
18
|
-
target: target('@person-1'),
|
|
19
|
-
route: {
|
|
20
|
-
key: 'shell.test:view.profile',
|
|
21
|
-
declaration: {
|
|
22
|
-
target: {
|
|
23
|
-
kind: 'definition',
|
|
24
|
-
definitions: [{ origin: 'shell.test', kind: 'class', name: 'Person' }],
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
href: 'https://shell.test/profile',
|
|
28
|
-
handshake: 'shell',
|
|
29
|
-
issuer: issuer('https://shell.test'),
|
|
30
|
-
etag: digest('a'),
|
|
31
|
-
revision: revision('b'),
|
|
32
|
-
},
|
|
33
|
-
}
|
|
34
|
-
const card: ResolvedView = {
|
|
35
|
-
target: target('@person-1'),
|
|
36
|
-
route: {
|
|
37
|
-
key: 'shell.test:view.card',
|
|
38
|
-
declaration: {
|
|
39
|
-
target: {
|
|
40
|
-
kind: 'definition',
|
|
41
|
-
definitions: [{ origin: 'shell.test', kind: 'class', name: 'Person' }],
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
href: 'https://shell.test/card',
|
|
45
|
-
handshake: 'none',
|
|
46
|
-
issuer: issuer('https://shell.test'),
|
|
47
|
-
etag: digest('c'),
|
|
48
|
-
revision: revision('d'),
|
|
49
|
-
},
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function openMessage(viewId?: string, correlationId?: string): IntentMessage<'open'> {
|
|
53
|
-
return {
|
|
54
|
-
type: 'intent',
|
|
55
|
-
version: 1,
|
|
56
|
-
envelope: {
|
|
57
|
-
name: 'open',
|
|
58
|
-
payload: { nodeId: 'person-1', ...(viewId ? { viewId } : {}) },
|
|
59
|
-
sender: { windowId: 'old-window' },
|
|
60
|
-
...(correlationId ? { correlationId } : {}),
|
|
61
|
-
},
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function mounted(windowId: string, onClose?: () => void): MountedWindow {
|
|
66
|
-
return {
|
|
67
|
-
windowId,
|
|
68
|
-
window: {
|
|
69
|
-
windowId,
|
|
70
|
-
functionId: 'shell.test:view.profile',
|
|
71
|
-
targetNodeId: '@person-1',
|
|
72
|
-
children: [],
|
|
73
|
-
view: profile,
|
|
74
|
-
location: { target: '@person-1', params: {} },
|
|
75
|
-
presentation: { kind: 'inline', constrained: false },
|
|
76
|
-
isolation: 'shared',
|
|
77
|
-
state: 'ready',
|
|
78
|
-
credential: { state: 'none' },
|
|
79
|
-
capabilities: NO_HOST_CAPABILITIES,
|
|
80
|
-
},
|
|
81
|
-
handle: { element: {} as HTMLElement },
|
|
82
|
-
credential: { state: 'none' },
|
|
83
|
-
presentation: { kind: 'inline', constrained: false },
|
|
84
|
-
focus() {},
|
|
85
|
-
close: async () => {
|
|
86
|
-
onClose?.()
|
|
87
|
-
return { kind: 'closed' }
|
|
88
|
-
},
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function harness(views: readonly ResolvedView[] = [profile, card]) {
|
|
93
|
-
const events: string[] = []
|
|
94
|
-
const sent: { windowId: string; message: IntentMessage }[] = []
|
|
95
|
-
const old = mounted('old-window', () => events.push('close:old-window'))
|
|
96
|
-
let current: MountedWindow | null = old
|
|
97
|
-
const shell = {
|
|
98
|
-
views: {
|
|
99
|
-
resolve: async (node: string) => {
|
|
100
|
-
events.push(`resolve:${node}`)
|
|
101
|
-
return views
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
} as unknown as Pick<Shell, 'views'>
|
|
105
|
-
const host: OpenIntentHost = {
|
|
106
|
-
current: () => current,
|
|
107
|
-
setCurrent: (next) => {
|
|
108
|
-
events.push(`current:${next.windowId}`)
|
|
109
|
-
current = next
|
|
110
|
-
},
|
|
111
|
-
mount: async (view) => {
|
|
112
|
-
events.push(`mount:${view.route.key}:${view.target}`)
|
|
113
|
-
return mounted('new-window')
|
|
114
|
-
},
|
|
115
|
-
opened: (view) => events.push(`opened:${view.route.key}:${view.target}`),
|
|
116
|
-
failed: (error) => events.push(`failed:${error instanceof Error ? error.message : error}`),
|
|
117
|
-
reply: (message, windowId) => {
|
|
118
|
-
if (!message.envelope.correlationId) return
|
|
119
|
-
events.push(`reply:${message.envelope.sender.windowId}`)
|
|
120
|
-
sent.push({
|
|
121
|
-
windowId: message.envelope.sender.windowId,
|
|
122
|
-
message: {
|
|
123
|
-
type: 'intent',
|
|
124
|
-
version: 1,
|
|
125
|
-
envelope: {
|
|
126
|
-
name: 'intentReply',
|
|
127
|
-
payload: {
|
|
128
|
-
correlationId: message.envelope.correlationId,
|
|
129
|
-
result: { windowId },
|
|
130
|
-
},
|
|
131
|
-
sender: { windowId: 'root' },
|
|
132
|
-
},
|
|
133
|
-
},
|
|
134
|
-
})
|
|
135
|
-
},
|
|
136
|
-
reject: (message, error) => {
|
|
137
|
-
if (!message.envelope.correlationId) return
|
|
138
|
-
events.push(`reply:${message.envelope.sender.windowId}`)
|
|
139
|
-
sent.push({
|
|
140
|
-
windowId: message.envelope.sender.windowId,
|
|
141
|
-
message: {
|
|
142
|
-
type: 'intent',
|
|
143
|
-
version: 1,
|
|
144
|
-
envelope: {
|
|
145
|
-
name: 'intentReply',
|
|
146
|
-
payload: {
|
|
147
|
-
correlationId: message.envelope.correlationId,
|
|
148
|
-
error: { message: error instanceof Error ? error.message : String(error) },
|
|
149
|
-
},
|
|
150
|
-
sender: { windowId: 'root' },
|
|
151
|
-
},
|
|
152
|
-
},
|
|
153
|
-
})
|
|
154
|
-
},
|
|
155
|
-
}
|
|
156
|
-
return { events, sent, shell, host, current: () => current }
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
describe('open intent host', () => {
|
|
160
|
-
/** @evidence TEST-CLI-VIEW-OPEN-PRESERVES-RESOLVED-SELECTION */
|
|
161
|
-
test('uses the complete resolved placement and replies before retiring the requester', async () => {
|
|
162
|
-
const h = harness()
|
|
163
|
-
await handleOpenIntent(h.shell, h.host, openMessage(undefined, 'corr-1'))
|
|
164
|
-
|
|
165
|
-
expect(h.events).toEqual([
|
|
166
|
-
'resolve:person-1',
|
|
167
|
-
'mount:shell.test:view.profile:@person-1',
|
|
168
|
-
'current:new-window',
|
|
169
|
-
'opened:shell.test:view.profile:@person-1',
|
|
170
|
-
'reply:old-window',
|
|
171
|
-
'close:old-window',
|
|
172
|
-
])
|
|
173
|
-
expect(h.current()?.windowId).toBe('new-window')
|
|
174
|
-
expect(h.sent[0]).toMatchObject({
|
|
175
|
-
windowId: 'old-window',
|
|
176
|
-
message: {
|
|
177
|
-
envelope: {
|
|
178
|
-
payload: { correlationId: 'corr-1', result: { windowId: 'new-window' } },
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
})
|
|
182
|
-
})
|
|
183
|
-
|
|
184
|
-
test('selects an explicit canonical View key without flattening its placement', async () => {
|
|
185
|
-
const h = harness()
|
|
186
|
-
await handleOpenIntent(h.shell, h.host, openMessage('shell.test:view.card'))
|
|
187
|
-
|
|
188
|
-
expect(h.events).toContain('mount:shell.test:view.card:@person-1')
|
|
189
|
-
expect(h.sent).toEqual([])
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
test('keeps the current view and rejects a correlated resolution failure', async () => {
|
|
193
|
-
const h = harness([])
|
|
194
|
-
await handleOpenIntent(h.shell, h.host, openMessage(undefined, 'corr-fail'))
|
|
195
|
-
|
|
196
|
-
expect(h.current()?.windowId).toBe('old-window')
|
|
197
|
-
expect(h.events).toEqual([
|
|
198
|
-
'resolve:person-1',
|
|
199
|
-
'reply:old-window',
|
|
200
|
-
'failed:No view resolves for this node',
|
|
201
|
-
])
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
/** @evidence TEST-CLI-VIEW-HANDSHAKE-FAILS-CLOSED */
|
|
205
|
-
test('makes one replacement mount attempt and never retries as a different placement mode', async () => {
|
|
206
|
-
const h = harness([profile])
|
|
207
|
-
let attempts = 0
|
|
208
|
-
h.host.mount = async (view) => {
|
|
209
|
-
attempts++
|
|
210
|
-
h.events.push(`mount:${view.route.handshake}:failed`)
|
|
211
|
-
throw new Error('handshake failed')
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
await handleOpenIntent(h.shell, h.host, openMessage(undefined, 'corr-mount'))
|
|
215
|
-
|
|
216
|
-
expect(attempts).toBe(1)
|
|
217
|
-
expect(h.current()?.windowId).toBe('old-window')
|
|
218
|
-
expect(h.events).toEqual([
|
|
219
|
-
'resolve:person-1',
|
|
220
|
-
'mount:shell:failed',
|
|
221
|
-
'reply:old-window',
|
|
222
|
-
'failed:handshake failed',
|
|
223
|
-
])
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
test('serializes overlapping opens', async () => {
|
|
227
|
-
let handler: ((message: IntentMessage<'open'>) => Promise<void>) | undefined
|
|
228
|
-
let releaseFirst!: () => void
|
|
229
|
-
const firstGate = new Promise<void>((resolve) => {
|
|
230
|
-
releaseFirst = resolve
|
|
231
|
-
})
|
|
232
|
-
let resolveCount = 0
|
|
233
|
-
const base = harness([profile])
|
|
234
|
-
const events = base.events
|
|
235
|
-
const shell = {
|
|
236
|
-
...base.shell,
|
|
237
|
-
views: {
|
|
238
|
-
resolve: async () => {
|
|
239
|
-
resolveCount += 1
|
|
240
|
-
events.push(`resolve:${resolveCount}`)
|
|
241
|
-
if (resolveCount === 1) await firstGate
|
|
242
|
-
return [profile]
|
|
243
|
-
},
|
|
244
|
-
},
|
|
245
|
-
onIntent: (_name: 'open', next: typeof handler) => {
|
|
246
|
-
handler = next
|
|
247
|
-
return () => {}
|
|
248
|
-
},
|
|
249
|
-
} as unknown as Shell
|
|
250
|
-
const host = {
|
|
251
|
-
...base.host,
|
|
252
|
-
mount: async () => {
|
|
253
|
-
const id = `new-${resolveCount}`
|
|
254
|
-
events.push(`mount:${id}`)
|
|
255
|
-
return mounted(id, () => events.push(`close:${id}`))
|
|
256
|
-
},
|
|
257
|
-
}
|
|
258
|
-
installOpenIntentHandler(shell, host)
|
|
259
|
-
|
|
260
|
-
const first = handler!(openMessage())
|
|
261
|
-
const second = handler!(openMessage())
|
|
262
|
-
await Promise.resolve()
|
|
263
|
-
expect(events).toEqual(['resolve:1'])
|
|
264
|
-
releaseFirst()
|
|
265
|
-
await Promise.all([first, second])
|
|
266
|
-
expect(events).toEqual([
|
|
267
|
-
'resolve:1',
|
|
268
|
-
'mount:new-1',
|
|
269
|
-
'current:new-1',
|
|
270
|
-
'opened:shell.test:view.profile:@person-1',
|
|
271
|
-
'close:old-window',
|
|
272
|
-
'resolve:2',
|
|
273
|
-
'mount:new-2',
|
|
274
|
-
'current:new-2',
|
|
275
|
-
'opened:shell.test:view.profile:@person-1',
|
|
276
|
-
'close:new-1',
|
|
277
|
-
])
|
|
278
|
-
expect(base.current()?.windowId).toBe('new-2')
|
|
279
|
-
})
|
|
280
|
-
})
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
|
2
|
-
import { mkdtemp, rm } from 'node:fs/promises'
|
|
3
|
-
import net from 'node:net'
|
|
4
|
-
import { tmpdir } from 'node:os'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
|
|
7
|
-
import { findFreePort } from '../port'
|
|
8
|
-
import { withViewPortAllocationLock } from '../view/port-allocation'
|
|
9
|
-
|
|
10
|
-
let tmp: string
|
|
11
|
-
|
|
12
|
-
beforeEach(async () => {
|
|
13
|
-
tmp = await mkdtemp(join(tmpdir(), 'astrale-view-port-'))
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
afterEach(async () => {
|
|
17
|
-
await rm(tmp, { recursive: true, force: true })
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
function listen(port: number): Promise<net.Server> {
|
|
21
|
-
return new Promise((resolve, reject) => {
|
|
22
|
-
const server = net.createServer()
|
|
23
|
-
server.once('error', reject)
|
|
24
|
-
server.listen({ port, host: '127.0.0.1', exclusive: true }, () => resolve(server))
|
|
25
|
-
})
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function close(server: net.Server): Promise<void> {
|
|
29
|
-
return new Promise((resolve, reject) => {
|
|
30
|
-
server.close((error) => (error ? reject(error) : resolve()))
|
|
31
|
-
})
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
describe('view port allocation', () => {
|
|
35
|
-
test('never overlaps concurrent allocation critical sections', async () => {
|
|
36
|
-
const lockPath = join(tmp, 'ports.lock')
|
|
37
|
-
let active = 0
|
|
38
|
-
let maxActive = 0
|
|
39
|
-
|
|
40
|
-
const contender = () =>
|
|
41
|
-
withViewPortAllocationLock(async () => {
|
|
42
|
-
active++
|
|
43
|
-
maxActive = Math.max(maxActive, active)
|
|
44
|
-
await Bun.sleep(40)
|
|
45
|
-
active--
|
|
46
|
-
}, lockPath)
|
|
47
|
-
|
|
48
|
-
await Promise.all([contender(), contender()])
|
|
49
|
-
|
|
50
|
-
// Without the view-specific lock both contenders enter before either
|
|
51
|
-
// delay completes, making this 2 and recreating the probe/bind window.
|
|
52
|
-
expect(maxActive).toBe(1)
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
test('serializes concurrent probe-then-listen allocations', async () => {
|
|
56
|
-
const base = await findFreePort(48000, 200)
|
|
57
|
-
expect(base).not.toBeNull()
|
|
58
|
-
if (base === null) throw new Error('test port window exhausted')
|
|
59
|
-
const lockPath = join(tmp, 'ports.lock')
|
|
60
|
-
|
|
61
|
-
const allocate = () =>
|
|
62
|
-
withViewPortAllocationLock(async () => {
|
|
63
|
-
const port = await findFreePort(base, 4)
|
|
64
|
-
if (port === null) throw new Error('test port window exhausted')
|
|
65
|
-
|
|
66
|
-
// Widen the exact pre-fix race: both callers would finish the advisory
|
|
67
|
-
// probe before either one binds, then one would fail with EADDRINUSE.
|
|
68
|
-
await Bun.sleep(40)
|
|
69
|
-
const server = await listen(port)
|
|
70
|
-
return { port, server }
|
|
71
|
-
}, lockPath)
|
|
72
|
-
|
|
73
|
-
const allocations = await Promise.all([allocate(), allocate()])
|
|
74
|
-
try {
|
|
75
|
-
const ports = allocations.map(({ port }) => port).sort((a, b) => a - b)
|
|
76
|
-
expect(ports[0]).toBe(base)
|
|
77
|
-
expect(ports[1]).toBeGreaterThan(base)
|
|
78
|
-
} finally {
|
|
79
|
-
await Promise.all(allocations.map(({ server }) => close(server)))
|
|
80
|
-
}
|
|
81
|
-
})
|
|
82
|
-
})
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import type { AuthApi } from '@astrale-os/sdk/auth'
|
|
2
|
-
|
|
3
|
-
import { describe, expect, mock, test } from 'bun:test'
|
|
4
|
-
import { once } from 'node:events'
|
|
5
|
-
|
|
6
|
-
import type { ViewServeConfig } from '../view/session'
|
|
7
|
-
|
|
8
|
-
import { findFreePort } from '../port'
|
|
9
|
-
import { mintViewCredential, startViewServer } from '../view/server'
|
|
10
|
-
|
|
11
|
-
const digest = (character: string) => `sha256:${character.repeat(64)}` as const
|
|
12
|
-
const target = (value: string) => value as ViewServeConfig['session']['view']['target']
|
|
13
|
-
const issuer = (value: string) => value as ViewServeConfig['session']['view']['route']['issuer']
|
|
14
|
-
const revision = (character: string) =>
|
|
15
|
-
digest(character) as ViewServeConfig['session']['view']['route']['revision']
|
|
16
|
-
|
|
17
|
-
describe('view session server credentials', () => {
|
|
18
|
-
test('mints a proof-bounded credential for the Kernel audience', async () => {
|
|
19
|
-
const mint = mock(async () => 'minted-credential')
|
|
20
|
-
const auth = { mint } as unknown as Pick<AuthApi, 'mint'>
|
|
21
|
-
|
|
22
|
-
await expect(mintViewCredential(auth, issuer('https://kernel.test'))).resolves.toBe(
|
|
23
|
-
'minted-credential',
|
|
24
|
-
)
|
|
25
|
-
expect(mint).toHaveBeenCalledWith({
|
|
26
|
-
audience: 'https://kernel.test',
|
|
27
|
-
ttlSeconds: 240,
|
|
28
|
-
})
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
/** @evidence TEST-CLI-PLAIN-VIEW-RECEIVES-NO-CREDENTIAL */
|
|
32
|
-
test('refuses to mint a token for a handshake-none View', async () => {
|
|
33
|
-
const nonce = 'plain-view'
|
|
34
|
-
const port = await findFreePort(48_000, 200)
|
|
35
|
-
if (port === null) throw new Error('test port window exhausted')
|
|
36
|
-
const config = {
|
|
37
|
-
session: {
|
|
38
|
-
id: 'v-plain',
|
|
39
|
-
pid: 0,
|
|
40
|
-
port,
|
|
41
|
-
nonce,
|
|
42
|
-
pageUrl: `http://127.0.0.1:${port}/`,
|
|
43
|
-
view: {
|
|
44
|
-
target: target('/:example.test'),
|
|
45
|
-
route: {
|
|
46
|
-
key: 'example.test:view.public',
|
|
47
|
-
declaration: { target: { kind: 'domain' } },
|
|
48
|
-
href: 'https://example.test/ui/public',
|
|
49
|
-
handshake: 'none',
|
|
50
|
-
issuer: issuer('https://example.test'),
|
|
51
|
-
etag: digest('a'),
|
|
52
|
-
revision: revision('b'),
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
createdAt: '2026-08-20T00:00:00.000Z',
|
|
56
|
-
},
|
|
57
|
-
kernel: { creds: 'must-not-be-used' },
|
|
58
|
-
proxy: {
|
|
59
|
-
kernelUrl: 'https://kernel.test',
|
|
60
|
-
issuer: 'https://kernel.test',
|
|
61
|
-
direct: true,
|
|
62
|
-
},
|
|
63
|
-
externalOrigins: ['https://connect.nango.dev'],
|
|
64
|
-
idleMs: 60_000,
|
|
65
|
-
} satisfies ViewServeConfig
|
|
66
|
-
const server = startViewServer(config)
|
|
67
|
-
await once(server, 'listening')
|
|
68
|
-
|
|
69
|
-
try {
|
|
70
|
-
const configResponse = await fetch(`http://127.0.0.1:${port}/s/${nonce}/config.json`)
|
|
71
|
-
expect(configResponse.status).toBe(200)
|
|
72
|
-
expect(await configResponse.json()).toMatchObject({
|
|
73
|
-
sessionId: 'v-plain',
|
|
74
|
-
externalOrigins: ['https://connect.nango.dev'],
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
const response = await fetch(`http://127.0.0.1:${port}/s/${nonce}/token`, {
|
|
78
|
-
method: 'POST',
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
expect(response.status).toBe(403)
|
|
82
|
-
expect(await response.json()).toEqual({
|
|
83
|
-
error: 'plain views have no Astrale credential privilege',
|
|
84
|
-
})
|
|
85
|
-
} finally {
|
|
86
|
-
await new Promise<void>((resolve, reject) => {
|
|
87
|
-
server.close((error) => (error ? reject(error) : resolve()))
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
})
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { afterEach, describe, expect, test } from 'bun:test'
|
|
2
|
-
import { closeSync } from 'node:fs'
|
|
3
|
-
import { chmod, mkdir, mkdtemp, readFile, rm, stat } from 'node:fs/promises'
|
|
4
|
-
import { tmpdir } from 'node:os'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
|
|
7
|
-
import type { ViewServeConfig } from '../view/session'
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
configPath,
|
|
11
|
-
logPath,
|
|
12
|
-
openSessionLog,
|
|
13
|
-
recordPath,
|
|
14
|
-
removeSessionFiles,
|
|
15
|
-
saveRecord,
|
|
16
|
-
saveServeConfig,
|
|
17
|
-
} from '../view/session'
|
|
18
|
-
|
|
19
|
-
const temporaryDirectories: string[] = []
|
|
20
|
-
|
|
21
|
-
afterEach(async () => {
|
|
22
|
-
await Promise.all(
|
|
23
|
-
temporaryDirectories.splice(0).map((path) => rm(path, { recursive: true, force: true })),
|
|
24
|
-
)
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
function mode(value: Awaited<ReturnType<typeof stat>>): number {
|
|
28
|
-
return Number(value.mode) & 0o777
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const target = (value: string) => value as ViewServeConfig['session']['view']['target']
|
|
32
|
-
const issuer = (value: string) => value as ViewServeConfig['session']['view']['route']['issuer']
|
|
33
|
-
const revision = (character: string) =>
|
|
34
|
-
`sha256:${character.repeat(64)}` as ViewServeConfig['session']['view']['route']['revision']
|
|
35
|
-
|
|
36
|
-
describe('view session private state', () => {
|
|
37
|
-
/** @evidence TEST-CLI-VIEW-CREDENTIAL-CONFIG-IS-OWNER-ONLY */
|
|
38
|
-
test('repairs directory/log modes and atomically stores raw carriers as 0600', async () => {
|
|
39
|
-
const root = await mkdtemp(join(tmpdir(), 'astrale-view-state-'))
|
|
40
|
-
temporaryDirectories.push(root)
|
|
41
|
-
const directory = join(root, 'view')
|
|
42
|
-
await mkdir(directory, { mode: 0o755 })
|
|
43
|
-
await chmod(directory, 0o755)
|
|
44
|
-
|
|
45
|
-
const config = {
|
|
46
|
-
session: {
|
|
47
|
-
id: 'v-a1b2c3',
|
|
48
|
-
pid: 0,
|
|
49
|
-
port: 4419,
|
|
50
|
-
nonce: 'nonce',
|
|
51
|
-
pageUrl: 'http://127.0.0.1:4419/s/nonce/',
|
|
52
|
-
view: {
|
|
53
|
-
target: target('/:example.test'),
|
|
54
|
-
route: {
|
|
55
|
-
key: 'example.test:view.main',
|
|
56
|
-
href: 'https://example.test/ui',
|
|
57
|
-
handshake: 'shell',
|
|
58
|
-
issuer: issuer('https://example.test'),
|
|
59
|
-
etag: `sha256:${'a'.repeat(64)}`,
|
|
60
|
-
revision: revision('b'),
|
|
61
|
-
declaration: { target: { kind: 'domain' } },
|
|
62
|
-
},
|
|
63
|
-
},
|
|
64
|
-
createdAt: '2026-08-12T00:00:00.000Z',
|
|
65
|
-
},
|
|
66
|
-
kernel: { creds: 'raw-secret-carrier' },
|
|
67
|
-
proxy: {
|
|
68
|
-
kernelUrl: 'https://kernel.test',
|
|
69
|
-
issuer: 'https://kernel.test',
|
|
70
|
-
direct: true,
|
|
71
|
-
},
|
|
72
|
-
externalOrigins: [],
|
|
73
|
-
idleMs: 60_000,
|
|
74
|
-
} satisfies ViewServeConfig
|
|
75
|
-
|
|
76
|
-
await saveServeConfig(config, directory)
|
|
77
|
-
await saveRecord(config.session, directory)
|
|
78
|
-
const descriptor = await openSessionLog(config.session.id, directory)
|
|
79
|
-
closeSync(descriptor)
|
|
80
|
-
|
|
81
|
-
expect(mode(await stat(directory))).toBe(0o700)
|
|
82
|
-
expect(mode(await stat(configPath(config.session.id, directory)))).toBe(0o600)
|
|
83
|
-
expect(mode(await stat(recordPath(config.session.id, directory)))).toBe(0o600)
|
|
84
|
-
expect(mode(await stat(logPath(config.session.id, directory)))).toBe(0o600)
|
|
85
|
-
expect(await readFile(configPath(config.session.id, directory), 'utf8')).toContain(
|
|
86
|
-
'raw-secret-carrier',
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
await removeSessionFiles(config.session.id, directory)
|
|
90
|
-
await expect(stat(configPath(config.session.id, directory))).rejects.toMatchObject({
|
|
91
|
-
code: 'ENOENT',
|
|
92
|
-
})
|
|
93
|
-
await expect(stat(recordPath(config.session.id, directory))).rejects.toMatchObject({
|
|
94
|
-
code: 'ENOENT',
|
|
95
|
-
})
|
|
96
|
-
await expect(stat(logPath(config.session.id, directory))).rejects.toMatchObject({
|
|
97
|
-
code: 'ENOENT',
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
})
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
|
|
3
|
-
import type { AbResult } from '../browser'
|
|
4
|
-
|
|
5
|
-
import { snapshotText, waitForSettledSnapshot } from '../view/snapshot'
|
|
6
|
-
|
|
7
|
-
const pending = result('- paragraph\n - StaticText "Opening integrations…"')
|
|
8
|
-
const settled = result('- heading "Integrations" [level=1]\n- button "Connect Google" [ref=e4]')
|
|
9
|
-
|
|
10
|
-
function result(snapshot: string): AbResult {
|
|
11
|
-
return { ok: true, data: { snapshot }, error: null }
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function clock() {
|
|
15
|
-
let elapsed = 0
|
|
16
|
-
return {
|
|
17
|
-
now: () => elapsed,
|
|
18
|
-
sleep: async (ms: number) => {
|
|
19
|
-
elapsed += ms
|
|
20
|
-
},
|
|
21
|
-
elapsed: () => elapsed,
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
describe('view snapshot settling', () => {
|
|
26
|
-
test('waits through a late loading-to-content transition and a quiet window', async () => {
|
|
27
|
-
const fakeClock = clock()
|
|
28
|
-
let calls = 0
|
|
29
|
-
const takeSnapshot = async () => {
|
|
30
|
-
calls += 1
|
|
31
|
-
return fakeClock.elapsed() < 1_250 ? pending : settled
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const snapshot = await waitForSettledSnapshot(takeSnapshot, fakeClock, {
|
|
35
|
-
timeoutMs: 4_000,
|
|
36
|
-
quietWindowMs: 750,
|
|
37
|
-
pollMs: 250,
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
expect(snapshotText(snapshot)).toContain('Connect Google')
|
|
41
|
-
expect(fakeClock.elapsed()).toBe(2_000)
|
|
42
|
-
expect(calls).toBe(10)
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
test('returns the latest permanently pending snapshot at the bound', async () => {
|
|
46
|
-
const fakeClock = clock()
|
|
47
|
-
let calls = 0
|
|
48
|
-
const takeSnapshot = async () => {
|
|
49
|
-
calls += 1
|
|
50
|
-
return pending
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const snapshot = await waitForSettledSnapshot(takeSnapshot, fakeClock, {
|
|
54
|
-
timeoutMs: 1_000,
|
|
55
|
-
quietWindowMs: 500,
|
|
56
|
-
pollMs: 250,
|
|
57
|
-
})
|
|
58
|
-
|
|
59
|
-
expect(snapshot).toBe(pending)
|
|
60
|
-
expect(fakeClock.elapsed()).toBe(1_000)
|
|
61
|
-
expect(calls).toBe(6)
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
test('ignores changing agent-browser refs when measuring stability', async () => {
|
|
65
|
-
const fakeClock = clock()
|
|
66
|
-
let ref = 0
|
|
67
|
-
|
|
68
|
-
const snapshot = await waitForSettledSnapshot(
|
|
69
|
-
async () => result(`- button "Deploy" [ref=e${++ref}]`),
|
|
70
|
-
fakeClock,
|
|
71
|
-
{ timeoutMs: 2_000, quietWindowMs: 500, pollMs: 250 },
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
expect(snapshotText(snapshot)).toContain('Deploy')
|
|
75
|
-
expect(fakeClock.elapsed()).toBe(500)
|
|
76
|
-
})
|
|
77
|
-
})
|
package/src/lib/admin-domain.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import type { AdminConnectionOptions, ConnectionContext } from '../connection'
|
|
2
|
-
|
|
3
|
-
import { connectAdminCatalog, type DomainInfo, type PublishDomainInput } from '../admin/catalog'
|
|
4
|
-
import { connectAdminInstances, type OwnedInstanceInfo } from '../admin/instance'
|
|
5
|
-
import { withAdminClientSession } from '../connection'
|
|
6
|
-
|
|
7
|
-
export type { DomainInfo, InstallDomainResult, PublishDomainInput } from '../admin/catalog'
|
|
8
|
-
|
|
9
|
-
/** Read the caller-visible V2 Admin Domain catalog. */
|
|
10
|
-
export function listAdminDomains(options: AdminConnectionOptions): Promise<DomainInfo[]> {
|
|
11
|
-
return withAdminClientSession(options, async (context) =>
|
|
12
|
-
(await connectAdminCatalog(context)).list(),
|
|
13
|
-
)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** Reuse one open Admin session for catalog reads. */
|
|
17
|
-
export async function listAdminDomainsInContext(context: ConnectionContext): Promise<DomainInfo[]> {
|
|
18
|
-
return (await connectAdminCatalog(context)).list()
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Publish and optionally configure default installation through V2 receiver Methods. */
|
|
22
|
-
export function publishAdminDomain(options: AdminConnectionOptions, input: PublishDomainInput) {
|
|
23
|
-
return withAdminClientSession(options, async (context) =>
|
|
24
|
-
(await connectAdminCatalog(context)).publish(input),
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** Install one resolved catalog Domain on one caller-visible Instance. */
|
|
29
|
-
export async function installAdminDomainInContext(
|
|
30
|
-
context: ConnectionContext,
|
|
31
|
-
instance: OwnedInstanceInfo,
|
|
32
|
-
domain: DomainInfo,
|
|
33
|
-
) {
|
|
34
|
-
const receipt = await (await connectAdminInstances(context)).installDomain(instance.id, domain.id)
|
|
35
|
-
return Object.freeze({
|
|
36
|
-
name: domain.name,
|
|
37
|
-
origin: receipt.origin,
|
|
38
|
-
instanceId: instance.slug,
|
|
39
|
-
url: domain.url ?? '',
|
|
40
|
-
ok: receipt.ok,
|
|
41
|
-
...(receipt.error === undefined ? {} : { error: receipt.error }),
|
|
42
|
-
})
|
|
43
|
-
}
|