@astrale-os/cli 1.0.0-beta.1 → 1.0.0-beta.11
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/README.md +23 -12
- package/dist/astrale.js +48048 -56798
- package/dist/public/connect-core.js +2011 -30765
- package/dist/public/keys/index.js +884 -29483
- package/dist/public/paths/index.js +13101 -41459
- package/dist/types/admin/binding.d.ts +19 -0
- package/dist/types/admin/instance/client.d.ts +22 -0
- package/dist/types/admin/instance/index.d.ts +2 -0
- package/dist/types/admin/instance/model.d.ts +5 -12
- package/dist/types/connection/auth.d.ts +3 -0
- package/dist/types/connection/call.d.ts +3 -0
- package/dist/types/connection/command.d.ts +27 -0
- package/dist/types/connection/credential.d.ts +14 -0
- package/dist/types/connection/errors.d.ts +1 -0
- package/dist/types/connection/exchange.d.ts +9 -0
- package/dist/types/connection/failure/classify.d.ts +2 -0
- package/dist/types/connection/failure/index.d.ts +5 -0
- package/dist/types/connection/failure/model.d.ts +25 -0
- package/dist/types/connection/failure/render.d.ts +3 -0
- package/dist/types/connection/index.d.ts +8 -0
- package/dist/types/connection/reasons.d.ts +37 -0
- package/dist/types/connection/self.d.ts +37 -0
- package/dist/types/connection/session.d.ts +31 -0
- package/dist/types/connection/target.d.ts +38 -0
- package/dist/types/errors.d.ts +1 -1
- package/dist/types/lib/admin-instance.d.ts +17 -0
- package/dist/types/lib/admin-target.d.ts +11 -36
- package/dist/types/lib/config.d.ts +7 -59
- package/dist/types/lib/failure-debug.d.ts +1 -0
- package/dist/types/lib/idp.d.ts +26 -168
- package/dist/types/lib/instance-target.d.ts +1 -1
- package/dist/types/lib/instance.d.ts +30 -88
- package/dist/types/lib/log.d.ts +5 -3
- package/dist/types/lib/meta.d.ts +2 -2
- package/dist/types/lib/proc.d.ts +43 -0
- package/dist/types/lib/self.d.ts +9 -0
- package/dist/types/lib/update.d.ts +91 -0
- package/dist/types/lib/validation.d.ts +4 -1
- package/package.json +16 -19
- package/src/__tests__/fixtures/publication.ts +20 -0
- package/src/admin/__tests__/binding.test.ts +31 -0
- package/src/admin/__tests__/fixture.ts +101 -0
- package/src/admin/binding.ts +98 -0
- package/src/admin/catalog/.spec/api.d.ts +2 -2
- package/src/admin/catalog/__tests__/client.test.ts +20 -49
- package/src/admin/catalog/client.ts +36 -32
- package/src/admin/catalog/model.ts +3 -4
- package/src/admin/graph/.spec/api.d.ts +4 -10
- package/src/admin/graph/nodes.ts +1 -1
- package/src/admin/instance/.spec/api.d.ts +2 -2
- package/src/admin/instance/__tests__/client.test.ts +39 -164
- package/src/admin/instance/client.ts +35 -124
- package/src/admin/instance/index.ts +1 -2
- package/src/admin/instance/model.ts +11 -20
- package/src/commands/__tests__/admin-instance.test.ts +11 -8
- package/src/commands/__tests__/auth-login.test.ts +54 -1
- package/src/commands/__tests__/call-describe.test.ts +46 -33
- package/src/commands/__tests__/call.test.ts +5 -1
- package/src/commands/__tests__/domain-install-operation.test.ts +12 -7
- package/src/commands/__tests__/domain-install-owned.test.ts +6 -2
- package/src/commands/__tests__/domain-list.test.ts +63 -4
- package/src/commands/__tests__/install-identity-override.test.ts +19 -19
- package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
- package/src/commands/__tests__/instance-status.test.ts +139 -0
- package/src/commands/__tests__/read-commands.test.ts +35 -10
- package/src/commands/__tests__/studio-descriptor.test.ts +22 -0
- package/src/commands/__tests__/update.test.ts +48 -19
- package/src/commands/call-describe.ts +60 -68
- package/src/commands/call.ts +43 -56
- package/src/commands/domain/install.ts +13 -17
- package/src/commands/domain/list.ts +18 -13
- package/src/commands/domain/publish.ts +14 -11
- package/src/commands/domain/uninstall.ts +2 -2
- package/src/commands/get.ts +14 -15
- package/src/commands/identity/__tests__/register.test.ts +3 -3
- package/src/commands/identity/register.ts +5 -4
- package/src/commands/instance/create.ts +8 -16
- package/src/commands/instance/delete.ts +12 -9
- package/src/commands/instance/list.ts +2 -2
- package/src/commands/instance/status.ts +66 -20
- package/src/commands/instance/use.ts +16 -12
- package/src/commands/introspect.ts +9 -16
- package/src/commands/logs.ts +24 -25
- package/src/commands/mutate.ts +6 -5
- package/src/commands/query.ts +27 -30
- package/src/commands/studio.ts +20 -0
- package/src/commands/token.ts +8 -7
- package/src/commands/update.ts +38 -14
- package/src/commands/view.ts +7 -6
- package/src/connection/.spec/api.d.ts +7 -8
- package/src/connection/.spec/architecture.md +5 -4
- package/src/connection/.spec/flows/session.ts +2 -2
- package/src/connection/.spec/laws/connection.ts +6 -2
- package/src/connection/.spec/layout.ts +1 -0
- package/src/connection/__tests__/credential.test.ts +20 -1
- package/src/connection/__tests__/errors.test.ts +43 -32
- package/src/connection/__tests__/exchange.test.ts +36 -6
- package/src/connection/__tests__/failure-fixtures.ts +39 -0
- package/src/connection/__tests__/failure-safety.test.ts +75 -0
- package/src/connection/__tests__/self.test.ts +31 -11
- package/src/connection/__tests__/session.test.ts +3 -3
- package/src/connection/__tests__/target.test.ts +1 -0
- package/src/connection/auth.ts +13 -0
- package/src/connection/call.ts +1 -1
- package/src/connection/credential.ts +2 -2
- package/src/connection/errors.ts +1 -355
- package/src/connection/exchange.ts +52 -27
- package/src/connection/failure/classify.ts +110 -0
- package/src/connection/failure/index.ts +18 -0
- package/src/connection/failure/model.ts +28 -0
- package/src/connection/failure/render.ts +116 -0
- package/src/connection/reasons.ts +16 -0
- package/src/connection/self.ts +39 -21
- package/src/connection/session.ts +19 -8
- package/src/errors.ts +3 -2
- package/src/graph/.spec/api.d.ts +12 -5
- package/src/graph/.spec/layout.ts +9 -1
- package/src/graph/__tests__/mutation.test.ts +2 -2
- package/src/graph/__tests__/query.test.ts +25 -6
- package/src/graph/class.ts +30 -0
- package/src/graph/index.ts +1 -0
- package/src/graph/query.ts +21 -32
- package/src/identity/.spec/api.d.ts +2 -2
- package/src/identity/__tests__/registration.test.ts +1 -1
- package/src/identity/registration.ts +3 -3
- package/src/keys/__tests__/keys.test.ts +4 -0
- package/src/keys/credential.ts +1 -0
- package/src/lib/__tests__/admin-target.test.ts +12 -0
- package/src/lib/__tests__/command-dx.test.ts +1 -1
- package/src/lib/__tests__/domain-publication.test.ts +138 -0
- package/src/lib/__tests__/idp-session.test.ts +22 -0
- package/src/lib/__tests__/idp.test.ts +36 -4
- package/src/lib/__tests__/instance-candidates.test.ts +1 -3
- package/src/lib/__tests__/instance-target.test.ts +7 -39
- package/src/lib/__tests__/instance.test.ts +6 -0
- package/src/lib/__tests__/log-errors.test.ts +64 -0
- package/src/lib/__tests__/studio-server-deps.test.ts +53 -16
- package/src/lib/__tests__/update.test.ts +113 -8
- package/src/lib/__tests__/view-open-intent.test.ts +0 -2
- package/src/lib/__tests__/view-server.test.ts +18 -3
- package/src/lib/__tests__/view-session.test.ts +1 -1
- package/src/lib/admin-instance.ts +14 -8
- package/src/lib/admin-target.ts +21 -2
- package/src/lib/command-dx.ts +9 -9
- package/src/lib/domain-publication.ts +104 -0
- package/src/lib/failure-debug.ts +26 -0
- package/src/lib/idp.ts +39 -4
- package/src/lib/instance-candidates.ts +2 -2
- package/src/lib/instance-target.ts +3 -14
- package/src/lib/instance.ts +22 -12
- package/src/lib/log.ts +16 -9
- package/src/lib/login-flow.ts +13 -3
- package/src/lib/meta.ts +2 -2
- package/src/lib/provision-instance.ts +34 -57
- package/src/lib/update.ts +124 -30
- package/src/lib/validation.ts +2 -2
- package/src/lib/view/resolve.ts +1 -1
- package/src/lib/view/server.ts +17 -3
- package/src/program/__tests__/program.test.ts +20 -4
- package/src/program/build.ts +2 -2
- package/src/setup/__tests__/instance-step.test.ts +27 -10
- package/src/setup/steps/instance.ts +22 -15
- package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
- package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
- package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
- package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
- package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
- package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
- package/studio/client/dist/index.html +3 -2
- package/studio/package.json +10 -14
- package/studio/server/agent/ask.test.ts +1 -1
- package/studio/server/agent/bridge/grant.test.ts +1 -1
- package/studio/server/agent/bridge/routes.test.ts +1 -1
- package/studio/server/agent/bridge/stdio.ts +8 -1
- package/studio/server/agent/conversation.test.ts +10 -5
- package/studio/server/agent/conversation.ts +56 -8
- package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
- package/studio/server/agent/harness/codex/loadout.ts +18 -21
- package/studio/server/agent/harness/gateway/config.ts +20 -18
- package/studio/server/agent/harness/selection.ts +9 -1
- package/studio/server/agent/prompts/anchors.test.ts +32 -36
- package/studio/server/agent/prompts/anchors.ts +20 -49
- package/studio/server/agent/prompts/system.test.ts +3 -2
- package/studio/server/agent/prompts/system.ts +6 -5
- package/studio/server/agent/prompts/turn.ts +13 -4
- package/studio/server/agent/routes.test.ts +1 -1
- package/studio/server/agent/run/completion.ts +2 -2
- package/studio/server/agent/run/coordinator.test.ts +1 -1
- package/studio/server/agent/run/preparation.ts +6 -5
- package/studio/server/agent/run/transcript.test.ts +35 -1
- package/studio/server/agent/run/transcript.ts +169 -3
- package/studio/server/agent/run/usage.test.ts +24 -0
- package/studio/server/agent/run/usage.ts +26 -1
- package/studio/server/api/canvas.ts +43 -0
- package/studio/server/api/comments.ts +85 -0
- package/studio/server/api/context.ts +61 -0
- package/studio/server/api/deployment.ts +39 -0
- package/studio/server/api/documents.ts +55 -0
- package/studio/server/api/domain.ts +59 -0
- package/studio/server/api/http.ts +45 -0
- package/studio/server/api/project.ts +57 -0
- package/studio/server/api/schema.ts +12 -0
- package/studio/server/api/views.ts +57 -0
- package/studio/server/api/workspace.ts +60 -0
- package/studio/server/api-agent-loadout.test.ts +1 -1
- package/studio/server/api.test.ts +147 -0
- package/studio/server/api.ts +20 -422
- package/studio/server/cache.test.ts +122 -0
- package/studio/server/cache.ts +162 -11
- package/studio/server/cli-consumers.test.ts +494 -0
- package/studio/server/cli.test.ts +88 -0
- package/studio/server/cli.ts +240 -0
- package/studio/server/client-package.ts +25 -1
- package/studio/server/domain.test.ts +50 -40
- package/studio/server/domain.ts +83 -52
- package/studio/server/environment/dotenv-preview.test.ts +39 -0
- package/studio/server/environment/dotenv-preview.ts +27 -0
- package/studio/server/environment/files.test.ts +53 -0
- package/studio/server/{state/env.ts → environment/files.ts} +7 -48
- package/studio/server/{state → handoff}/copy.ts +21 -6
- package/studio/server/handoff/service.test.ts +22 -0
- package/studio/server/{state/handoff.ts → handoff/service.ts} +21 -14
- package/studio/server/index.ts +1 -1
- package/studio/server/instances/active.ts +72 -0
- package/studio/server/instances/deploy-record.test.ts +31 -0
- package/studio/server/instances/deploy-record.ts +37 -0
- package/studio/server/instances/deploy.ts +56 -0
- package/studio/server/{state/instance.test.ts → instances/probe.test.ts} +25 -21
- package/studio/server/instances/probe.ts +67 -0
- package/studio/server/instances/status.test.ts +12 -0
- package/studio/server/instances/status.ts +49 -0
- package/studio/server/introspect/anatomy/client-tree.ts +57 -0
- package/studio/server/introspect/anatomy/env-fields.ts +66 -0
- package/studio/server/introspect/anatomy/schema-definition.ts +53 -0
- package/studio/server/introspect/anatomy/source.ts +181 -0
- package/studio/server/introspect/anatomy/views/routes.ts +114 -0
- package/studio/server/introspect/anatomy/views.ts +53 -0
- package/studio/server/introspect/anatomy-extras.test.ts +106 -35
- package/studio/server/introspect/anatomy-extras.ts +7 -726
- package/studio/server/introspect/anatomy.test.ts +22 -14
- package/studio/server/introspect/anatomy.ts +52 -28
- package/studio/server/introspect/bundle.ts +15 -9
- package/studio/server/introspect/canonical-schema.test.ts +93 -309
- package/studio/server/introspect/canonical-schema.ts +257 -425
- package/studio/server/introspect/config-preview.test.ts +32 -0
- package/studio/server/introspect/config-preview.ts +119 -0
- package/studio/server/introspect/core-extractor.ts +18 -127
- package/studio/server/introspect/core.ts +1 -2
- package/studio/server/introspect/diff.test.ts +18 -18
- package/studio/server/introspect/diff.ts +44 -90
- package/studio/server/introspect/extractor.ts +23 -116
- package/studio/server/introspect/hash.ts +5 -2
- package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
- package/studio/server/introspect/overlay-tsmorph.ts +7 -1305
- package/studio/server/introspect/overlay.test.ts +26 -54
- package/studio/server/introspect/overlay.ts +10 -37
- package/studio/server/introspect/revision.test.ts +54 -0
- package/studio/server/introspect/revision.ts +49 -0
- package/studio/server/introspect/runtime.test.ts +83 -143
- package/studio/server/introspect/runtime.ts +40 -11
- package/studio/server/introspect/schema-ir-json.test.ts +70 -0
- package/studio/server/introspect/schema-ir-json.ts +151 -0
- package/studio/server/introspect/schema-refs.test.ts +43 -88
- package/studio/server/introspect/schema-refs.ts +14 -49
- package/studio/server/introspect/source-overlay/annotations.ts +14 -0
- package/studio/server/introspect/source-overlay/handlers.ts +161 -0
- package/studio/server/introspect/source-overlay/kernel-calls.ts +46 -0
- package/studio/server/introspect/source-overlay/project.ts +248 -0
- package/studio/server/introspect/source-overlay/spans.ts +330 -0
- package/studio/server/json.ts +46 -0
- package/studio/server/lifecycle.ts +5 -1
- package/studio/server/sse.test.ts +26 -0
- package/studio/server/sse.ts +4 -1
- package/studio/server/state/baseline.test.ts +223 -7
- package/studio/server/state/baseline.ts +148 -34
- package/studio/server/state/comments.test.ts +66 -1
- package/studio/server/state/comments.ts +173 -10
- package/studio/server/state/context.ts +34 -2
- package/studio/server/state/documents.ts +42 -1
- package/studio/server/state/integrations.ts +27 -1
- package/studio/server/state/layout.test.ts +34 -0
- package/studio/server/state/layout.ts +44 -17
- package/studio/server/state/settings.ts +29 -22
- package/studio/server/state/store.test.ts +122 -0
- package/studio/server/state/store.ts +66 -17
- package/studio/server/state/visibility.ts +22 -11
- package/studio/server/views/model.test.ts +57 -0
- package/studio/server/views/model.ts +66 -0
- package/studio/server/views/runtime.ts +40 -0
- package/studio/server/views/selection-repository.test.ts +31 -0
- package/studio/server/views/selection-repository.ts +60 -0
- package/studio/server/views/session.test.ts +73 -0
- package/studio/server/views/session.ts +166 -0
- package/studio/server/views/target.test.ts +78 -0
- package/studio/server/views/target.ts +222 -0
- package/studio/server/watch.test.ts +11 -11
- package/studio/server/watch.ts +9 -5
- package/studio/server/workspace/catalog.test.ts +17 -0
- package/studio/server/workspace/catalog.ts +43 -0
- package/studio/server/{state → workspace}/create.test.ts +1 -1
- package/studio/server/{state → workspace}/create.ts +1 -1
- package/studio/server/{state → workspace}/git.ts +1 -1
- package/studio/server/workspace/updates.ts +83 -0
- package/studio/server/workspace-state.ts +1 -1
- package/studio/server/workspace-watch.ts +2 -2
- package/studio/shared/contracts/README.md +16 -0
- package/studio/shared/contracts/agent.ts +270 -0
- package/studio/shared/contracts/runtime.ts +50 -0
- package/studio/shared/contracts/schema.ts +393 -0
- package/studio/shared/contracts/surface.test.ts +317 -0
- package/studio/shared/contracts/workspace.ts +265 -0
- package/studio/shared/layout.test.ts +116 -0
- package/studio/shared/schema/identity.test.ts +34 -0
- package/studio/shared/schema/identity.ts +68 -0
- package/studio/shared/types.ts +11 -1099
- package/studio/tsconfig.json +1 -1
- package/viewer/dist/main.js +40 -61
- package/.check-workspace.cjs +0 -40
- package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
- package/studio/client/dist/assets/elk-api-D2xgMJvi.js +0 -1
- package/studio/client/dist/assets/index-BMdnsIJA.css +0 -1
- package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
- package/studio/client/dist/assets/index-D-vRV8w7.js +0 -8
- package/studio/client/dist/assets/index-LGSWRrk8.js +0 -81
- package/studio/server/state/catalog.ts +0 -117
- package/studio/server/state/instance.ts +0 -280
- package/studio/server/state/updates.ts +0 -63
- package/studio/server/state/views.test.ts +0 -286
- package/studio/server/state/views.ts +0 -535
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionAuth } from '@astrale-os/
|
|
1
|
+
import type { SessionAuth } from '@astrale-os/sdk/client/session'
|
|
2
2
|
|
|
3
3
|
import { issuer, type IssuerId } from '@astrale-os/sdk/auth'
|
|
4
4
|
import { Path } from '@astrale-os/sdk/graph/path'
|
|
@@ -6,6 +6,7 @@ import { describe, expect, test } from 'bun:test'
|
|
|
6
6
|
|
|
7
7
|
import type { AstraleConfig } from '../../lib/config'
|
|
8
8
|
|
|
9
|
+
import { bindCredentialIdentity } from '../auth'
|
|
9
10
|
import { createCliCredential, createConnectionCredential } from '../credential'
|
|
10
11
|
|
|
11
12
|
const SOURCE = issuer.accept('https://kernel.example')
|
|
@@ -20,6 +21,24 @@ const config: AstraleConfig = {
|
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
describe('connection credential', () => {
|
|
24
|
+
test('pins the bookmark identity while leaving explicit credentials unnamed', async () => {
|
|
25
|
+
const target = {
|
|
26
|
+
url: `${SOURCE}/invoke`,
|
|
27
|
+
kernelIssuer: SOURCE,
|
|
28
|
+
defaultIdentity: 'bookmark-owner',
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
await expect(bindCredentialIdentity({}, target)).resolves.toMatchObject({
|
|
32
|
+
as: 'bookmark-owner',
|
|
33
|
+
})
|
|
34
|
+
await expect(bindCredentialIdentity({ as: 'explicit-owner' }, target)).resolves.toEqual({
|
|
35
|
+
as: 'explicit-owner',
|
|
36
|
+
})
|
|
37
|
+
await expect(bindCredentialIdentity({ creds: 'opaque' }, target)).resolves.toEqual({
|
|
38
|
+
creds: 'opaque',
|
|
39
|
+
})
|
|
40
|
+
})
|
|
41
|
+
|
|
23
42
|
/** @evidence TEST-CLI-CONNECTION-RESOLVES-SOURCE-AUTH-BEFORE-ROUTING */
|
|
24
43
|
test('resolves source authority without destination knowledge', async () => {
|
|
25
44
|
const audiences: IssuerId[] = []
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { ResponseError
|
|
1
|
+
import { ResponseError } from '@astrale-os/sdk/client'
|
|
2
|
+
import { Path } from '@astrale-os/sdk/graph/path'
|
|
2
3
|
import { describe, expect, test } from 'bun:test'
|
|
3
4
|
|
|
4
5
|
import { formatKernelError, functionInputIssues, schemaUpgradeHint } from '../errors'
|
|
6
|
+
import { transportFailure } from './failure-fixtures'
|
|
5
7
|
|
|
6
8
|
const CONFLICT = 4001
|
|
7
9
|
const VALIDATION = 1003
|
|
10
|
+
const TEST_INVOCATION = {
|
|
11
|
+
source: 'https://kernel.test',
|
|
12
|
+
id: 'connection-errors',
|
|
13
|
+
} as ConstructorParameters<typeof ResponseError>[2]
|
|
8
14
|
|
|
9
15
|
describe('formatKernelError', () => {
|
|
10
16
|
/** @evidence TEST-CLI-CONNECTION-MAPS-TYPED-TRANSPORT */
|
|
@@ -15,24 +21,28 @@ describe('formatKernelError', () => {
|
|
|
15
21
|
writes.push(typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk))
|
|
16
22
|
return true
|
|
17
23
|
}) as typeof process.stderr.write
|
|
18
|
-
const error =
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
const error = Object.assign(
|
|
25
|
+
transportFailure('Publication discovery request failed.', 'unknown', {
|
|
26
|
+
kind: 'acquisition',
|
|
27
|
+
resource: 'publication',
|
|
28
|
+
}),
|
|
29
|
+
{
|
|
30
|
+
url: 'https://localhost:8443/kernel/host',
|
|
31
|
+
cause: Object.assign(new Error('connect ECONNREFUSED'), { code: 'ECONNREFUSED' }),
|
|
32
|
+
},
|
|
33
|
+
)
|
|
24
34
|
try {
|
|
25
|
-
await formatKernelError(error, true)
|
|
35
|
+
await formatKernelError(error, true, 'https://localhost:8443/kernel/host')
|
|
26
36
|
} finally {
|
|
27
37
|
process.stderr.write = original
|
|
28
38
|
}
|
|
29
39
|
|
|
30
40
|
expect(JSON.parse(writes[0]!)).toMatchObject({
|
|
31
|
-
error: '
|
|
41
|
+
error: 'TRANSPORT_ERROR',
|
|
32
42
|
message: 'Publication discovery request failed.',
|
|
33
43
|
url: 'https://localhost:8443/kernel/host',
|
|
34
|
-
phase: '
|
|
35
|
-
|
|
44
|
+
phase: 'unknown',
|
|
45
|
+
transport: { kind: 'acquisition', resource: 'publication' },
|
|
36
46
|
})
|
|
37
47
|
expect(writes[0]).not.toContain('ECONNREFUSED')
|
|
38
48
|
})
|
|
@@ -46,9 +56,8 @@ describe('formatKernelError', () => {
|
|
|
46
56
|
}) as typeof process.stderr.write
|
|
47
57
|
try {
|
|
48
58
|
await formatKernelError(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
phase: 'timeout',
|
|
59
|
+
transportFailure('Request timed out.', 'timeout', {
|
|
60
|
+
kind: 'invocation',
|
|
52
61
|
delivery: 'unknown',
|
|
53
62
|
}),
|
|
54
63
|
true,
|
|
@@ -70,7 +79,7 @@ describe('formatKernelError', () => {
|
|
|
70
79
|
expect(JSON.parse(writes[0]!)).toMatchObject({
|
|
71
80
|
error: 'TIMEOUT',
|
|
72
81
|
phase: 'timeout',
|
|
73
|
-
delivery: 'unknown',
|
|
82
|
+
transport: { kind: 'invocation', delivery: 'unknown' },
|
|
74
83
|
operation: '4a4c9a18-50f6-4d84-a7b7-2d83e3e45dc8',
|
|
75
84
|
retry:
|
|
76
85
|
'astrale domain install https://crm.test --direct --operation 4a4c9a18-50f6-4d84-a7b7-2d83e3e45dc8',
|
|
@@ -87,7 +96,7 @@ describe('formatKernelError', () => {
|
|
|
87
96
|
}) as typeof process.stderr.write
|
|
88
97
|
try {
|
|
89
98
|
await formatKernelError(
|
|
90
|
-
new ResponseError(CONFLICT, 'Schema change requires migration.', {
|
|
99
|
+
new ResponseError(CONFLICT, 'Schema change requires migration.', TEST_INVOCATION, {
|
|
91
100
|
code: 'DATA_MIGRATION_REQUIRED',
|
|
92
101
|
details: {
|
|
93
102
|
requirements: [
|
|
@@ -138,7 +147,7 @@ describe('formatKernelError', () => {
|
|
|
138
147
|
}) as typeof process.stderr.write
|
|
139
148
|
try {
|
|
140
149
|
await formatKernelError(
|
|
141
|
-
new ResponseError(CONFLICT, 'Schema change requires migration.', {
|
|
150
|
+
new ResponseError(CONFLICT, 'Schema change requires migration.', TEST_INVOCATION, {
|
|
142
151
|
code: 'DATA_MIGRATION_REQUIRED',
|
|
143
152
|
details: {
|
|
144
153
|
requirements: [
|
|
@@ -193,7 +202,7 @@ describe('formatKernelError', () => {
|
|
|
193
202
|
console.log = (...values: unknown[]) => hints.push(values.map(String).join(' '))
|
|
194
203
|
try {
|
|
195
204
|
await formatKernelError(
|
|
196
|
-
new ResponseError(CONFLICT, 'Schema change requires migration.', {
|
|
205
|
+
new ResponseError(CONFLICT, 'Schema change requires migration.', TEST_INVOCATION, {
|
|
197
206
|
code: 'DATA_MIGRATION_REQUIRED',
|
|
198
207
|
details: {
|
|
199
208
|
requirements: [
|
|
@@ -225,7 +234,7 @@ describe('formatKernelError', () => {
|
|
|
225
234
|
)
|
|
226
235
|
})
|
|
227
236
|
|
|
228
|
-
test('maps SDK
|
|
237
|
+
test('maps SDK error identities to stable CLI error codes', async () => {
|
|
229
238
|
const writes: string[] = []
|
|
230
239
|
const original = process.stderr.write
|
|
231
240
|
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
@@ -233,15 +242,17 @@ describe('formatKernelError', () => {
|
|
|
233
242
|
return true
|
|
234
243
|
}) as typeof process.stderr.write
|
|
235
244
|
try {
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
245
|
+
try {
|
|
246
|
+
Path.parse('not-a-path')
|
|
247
|
+
} catch (error) {
|
|
248
|
+
await formatKernelError(error, true)
|
|
249
|
+
}
|
|
239
250
|
} finally {
|
|
240
251
|
process.stderr.write = original
|
|
241
252
|
}
|
|
242
253
|
expect(JSON.parse(writes[0]!)).toEqual({
|
|
243
254
|
error: 'PATH_INVALID',
|
|
244
|
-
message:
|
|
255
|
+
message: expect.any(String),
|
|
245
256
|
})
|
|
246
257
|
})
|
|
247
258
|
|
|
@@ -254,7 +265,7 @@ describe('formatKernelError', () => {
|
|
|
254
265
|
console.log = (...values: unknown[]) => lines.push(values.join(' '))
|
|
255
266
|
try {
|
|
256
267
|
await formatKernelError(
|
|
257
|
-
new ResponseError(VALIDATION, 'Function input is invalid.', {
|
|
268
|
+
new ResponseError(VALIDATION, 'Function input is invalid.', TEST_INVOCATION, {
|
|
258
269
|
code: 'FUNCTION_INPUT_INVALID',
|
|
259
270
|
details: {
|
|
260
271
|
issues: [
|
|
@@ -279,7 +290,7 @@ describe('formatKernelError', () => {
|
|
|
279
290
|
false,
|
|
280
291
|
)
|
|
281
292
|
await formatKernelError(
|
|
282
|
-
new ResponseError(VALIDATION, 'Query input is invalid.', {
|
|
293
|
+
new ResponseError(VALIDATION, 'Query input is invalid.', TEST_INVOCATION, {
|
|
283
294
|
code: 'QUERY_INPUT_INVALID',
|
|
284
295
|
details: {
|
|
285
296
|
phase: 'plan',
|
|
@@ -310,7 +321,7 @@ describe('formatKernelError', () => {
|
|
|
310
321
|
}) as typeof process.stderr.write
|
|
311
322
|
try {
|
|
312
323
|
await formatKernelError(
|
|
313
|
-
new ResponseError(5001, 'Schema operation is not supported.', {
|
|
324
|
+
new ResponseError(5001, 'Schema operation is not supported.', TEST_INVOCATION, {
|
|
314
325
|
code: 'SCHEMA_UPGRADE_INCOMPATIBLE',
|
|
315
326
|
details: {
|
|
316
327
|
phase: 'upgrade',
|
|
@@ -358,7 +369,7 @@ describe('formatKernelError', () => {
|
|
|
358
369
|
console.log = (...values: unknown[]) => details.push(values.map(String).join(' '))
|
|
359
370
|
try {
|
|
360
371
|
await formatKernelError(
|
|
361
|
-
new ResponseError(5001, 'Schema operation is not supported.', {
|
|
372
|
+
new ResponseError(5001, 'Schema operation is not supported.', TEST_INVOCATION, {
|
|
362
373
|
code: 'SCHEMA_UPGRADE_INCOMPATIBLE',
|
|
363
374
|
details: {
|
|
364
375
|
phase: 'upgrade',
|
|
@@ -391,7 +402,7 @@ describe('formatKernelError', () => {
|
|
|
391
402
|
}) as typeof process.stderr.write
|
|
392
403
|
try {
|
|
393
404
|
await formatKernelError(
|
|
394
|
-
new ResponseError(1003, 'Function input is invalid.', {
|
|
405
|
+
new ResponseError(1003, 'Function input is invalid.', TEST_INVOCATION, {
|
|
395
406
|
code: 'SCHEMA_DOMAIN_ADDRESS_NOT_PUBLIC',
|
|
396
407
|
details: { phase: 'publication', requiredScope: 'public' },
|
|
397
408
|
}),
|
|
@@ -421,7 +432,7 @@ describe('formatKernelError', () => {
|
|
|
421
432
|
console.log = (...values: unknown[]) => hints.push(values.map(String).join(' '))
|
|
422
433
|
try {
|
|
423
434
|
await formatKernelError(
|
|
424
|
-
new ResponseError(1003, 'Function input is invalid.', {
|
|
435
|
+
new ResponseError(1003, 'Function input is invalid.', TEST_INVOCATION, {
|
|
425
436
|
code: 'SCHEMA_DOMAIN_ADDRESS_NOT_PUBLIC',
|
|
426
437
|
details: { phase: 'publication', requiredScope: 'public' },
|
|
427
438
|
}),
|
|
@@ -448,7 +459,7 @@ describe('formatKernelError', () => {
|
|
|
448
459
|
}) as typeof process.stderr.write
|
|
449
460
|
try {
|
|
450
461
|
await formatKernelError(
|
|
451
|
-
new ResponseError(1003, 'Function input is invalid.', {
|
|
462
|
+
new ResponseError(1003, 'Function input is invalid.', TEST_INVOCATION, {
|
|
452
463
|
code: 'FUNCTION_INPUT_INVALID',
|
|
453
464
|
details: {
|
|
454
465
|
issues: [
|
|
@@ -495,7 +506,7 @@ describe('formatKernelError', () => {
|
|
|
495
506
|
console.log = (...values: unknown[]) => details.push(values.map(String).join(' '))
|
|
496
507
|
try {
|
|
497
508
|
await formatKernelError(
|
|
498
|
-
new ResponseError(1003, 'Function input is invalid.', {
|
|
509
|
+
new ResponseError(1003, 'Function input is invalid.', TEST_INVOCATION, {
|
|
499
510
|
code: 'FUNCTION_INPUT_INVALID',
|
|
500
511
|
details: {
|
|
501
512
|
issues: [
|
|
@@ -530,7 +541,7 @@ describe('formatKernelError', () => {
|
|
|
530
541
|
}) as typeof process.stderr.write
|
|
531
542
|
try {
|
|
532
543
|
await formatKernelError(
|
|
533
|
-
new ResponseError(1003, 'Function input is invalid.', {
|
|
544
|
+
new ResponseError(1003, 'Function input is invalid.', TEST_INVOCATION, {
|
|
534
545
|
code: 'FUNCTION_INPUT_INVALID',
|
|
535
546
|
details: { issues: [{ code: 'INVALID_FORMAT', path: '/customer/email' }] },
|
|
536
547
|
}),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fetch } from '@astrale-os/
|
|
1
|
+
import type { Fetch } from '@astrale-os/sdk/client'
|
|
2
2
|
|
|
3
3
|
import { issuer } from '@astrale-os/sdk/auth'
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, test } from 'bun:test'
|
|
@@ -47,7 +47,7 @@ describe('Domain token exchange', () => {
|
|
|
47
47
|
observed.push({ url, init, body })
|
|
48
48
|
const index = observed.filter((entry) => entry.url === INVOCATION).length
|
|
49
49
|
return invocationResponse(
|
|
50
|
-
body.
|
|
50
|
+
body.requestId,
|
|
51
51
|
index === 1
|
|
52
52
|
? { id: 'user-1' }
|
|
53
53
|
: index === 2
|
|
@@ -121,7 +121,7 @@ describe('Domain token exchange', () => {
|
|
|
121
121
|
if (url === INVOCATION) {
|
|
122
122
|
const body = JSON.parse(await new Response(init?.body).text()) as Record<string, any>
|
|
123
123
|
return invocationResponse(
|
|
124
|
-
body.
|
|
124
|
+
body.requestId,
|
|
125
125
|
body.call.input && Object.keys(body.call.input).length === 0
|
|
126
126
|
? { id: 'user-1' }
|
|
127
127
|
: 'kernel-destination-envelope',
|
|
@@ -190,6 +190,35 @@ describe('Domain token exchange', () => {
|
|
|
190
190
|
message: 'Token exchange returned an invalid success response.',
|
|
191
191
|
})
|
|
192
192
|
})
|
|
193
|
+
|
|
194
|
+
test('normalizes native issuer Fetch failures without exposing their message', async () => {
|
|
195
|
+
const native = new AggregateError([new Error('private DNS state')], '')
|
|
196
|
+
const resolver = createExchangeCredentialResolver(
|
|
197
|
+
TARGET,
|
|
198
|
+
{ resolve: async () => SOURCE_TOKEN },
|
|
199
|
+
async (input, init) => {
|
|
200
|
+
if (String(input) === INVOCATION) {
|
|
201
|
+
const body = JSON.parse(await new Response(init?.body).text()) as Record<string, any>
|
|
202
|
+
return invocationResponse(
|
|
203
|
+
body.requestId,
|
|
204
|
+
body.call.input && Object.keys(body.call.input).length === 0
|
|
205
|
+
? { id: 'user-1' }
|
|
206
|
+
: 'kernel-destination-envelope',
|
|
207
|
+
new Headers(init?.headers).get('accept')!,
|
|
208
|
+
)
|
|
209
|
+
}
|
|
210
|
+
throw native
|
|
211
|
+
},
|
|
212
|
+
5_000,
|
|
213
|
+
new ExchangeCredentialCache(join(directory, 'native-failure.json')),
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
await expect(resolver.resolve(KERNEL, new AbortController().signal)).rejects.toMatchObject({
|
|
217
|
+
code: 'TOKEN_EXCHANGE_UNAVAILABLE',
|
|
218
|
+
message: 'Domain issuer discovery could not be reached.',
|
|
219
|
+
cause: native,
|
|
220
|
+
})
|
|
221
|
+
})
|
|
193
222
|
})
|
|
194
223
|
|
|
195
224
|
function exchangeFetch(
|
|
@@ -201,7 +230,7 @@ function exchangeFetch(
|
|
|
201
230
|
if (url === INVOCATION) {
|
|
202
231
|
const body = JSON.parse(await new Response(init?.body).text()) as Record<string, any>
|
|
203
232
|
return invocationResponse(
|
|
204
|
-
body.
|
|
233
|
+
body.requestId,
|
|
205
234
|
body.call.input && Object.keys(body.call.input).length === 0
|
|
206
235
|
? { id: 'user-1' }
|
|
207
236
|
: 'kernel-destination-envelope',
|
|
@@ -233,8 +262,9 @@ function configuration(enabled: boolean) {
|
|
|
233
262
|
}
|
|
234
263
|
}
|
|
235
264
|
|
|
236
|
-
function invocationResponse(
|
|
237
|
-
|
|
265
|
+
function invocationResponse(requestId: unknown, result: unknown, contentType: string): Response {
|
|
266
|
+
const invocation = { source: KERNEL, id: `exchange-${String(requestId)}` }
|
|
267
|
+
return new Response(JSON.stringify({ requestId, invocation, result }), {
|
|
238
268
|
headers: { 'content-type': contentType, 'cache-control': 'no-store' },
|
|
239
269
|
})
|
|
240
270
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { ClientError, TransportError } from '@astrale-os/sdk/client'
|
|
2
|
+
|
|
3
|
+
import type { TransportDiagnosticContext } from '../failure/model'
|
|
4
|
+
|
|
5
|
+
type CompatibleTransportPhase = TransportError['phase'] | 'unknown'
|
|
6
|
+
|
|
7
|
+
export function transportFailure(
|
|
8
|
+
message: string,
|
|
9
|
+
phase: CompatibleTransportPhase,
|
|
10
|
+
context: TransportDiagnosticContext,
|
|
11
|
+
): TransportError {
|
|
12
|
+
const error = new Error(message) as TransportError & {
|
|
13
|
+
context: TransportDiagnosticContext
|
|
14
|
+
}
|
|
15
|
+
Object.setPrototypeOf(error, TransportError.prototype)
|
|
16
|
+
Object.assign(error, { name: 'TransportError', phase, context })
|
|
17
|
+
return error
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function legacyTransportFailure(
|
|
21
|
+
message: string,
|
|
22
|
+
phase: CompatibleTransportPhase,
|
|
23
|
+
delivery: 'not-sent' | 'unknown',
|
|
24
|
+
): TransportError {
|
|
25
|
+
const error = new Error(message) as TransportError & { delivery: typeof delivery }
|
|
26
|
+
Object.setPrototypeOf(error, TransportError.prototype)
|
|
27
|
+
Object.assign(error, { name: 'TransportError', phase, delivery })
|
|
28
|
+
return error
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function sessionFailure(
|
|
32
|
+
message: string,
|
|
33
|
+
failure: 'cancelled' | 'closed' | 'timeout',
|
|
34
|
+
): ClientError {
|
|
35
|
+
const error = new Error(message) as ClientError & { failure: typeof failure }
|
|
36
|
+
Object.setPrototypeOf(error, ClientError.prototype)
|
|
37
|
+
Object.assign(error, { name: 'SessionError', failure })
|
|
38
|
+
return error
|
|
39
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
|
+
|
|
3
|
+
import { formatKernelError } from '../errors'
|
|
4
|
+
import { legacyTransportFailure, sessionFailure, transportFailure } from './failure-fixtures'
|
|
5
|
+
|
|
6
|
+
/** @evidence TEST-CLI-CONNECTION-FAILURE-SAFETY */
|
|
7
|
+
test('unknown and empty native failures never become ordinary diagnostics', async () => {
|
|
8
|
+
for (const failure of [new Error('private provider detail'), new Error(''), { secret: true }]) {
|
|
9
|
+
const output = await capture(() => formatKernelError(failure, true))
|
|
10
|
+
expect(JSON.parse(output)).toEqual({
|
|
11
|
+
error: 'UNEXPECTED_ERROR',
|
|
12
|
+
message: 'The CLI encountered an unexpected internal failure.',
|
|
13
|
+
})
|
|
14
|
+
expect(output).not.toContain('private provider detail')
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
|
|
18
|
+
test('Aggregate children are available only under explicit debug output', async () => {
|
|
19
|
+
const failure = new AggregateError([new Error('first private'), new Error('second private')], '')
|
|
20
|
+
const ordinary = await capture(() => formatKernelError(failure, true))
|
|
21
|
+
expect(ordinary).not.toContain('first private')
|
|
22
|
+
expect(ordinary).not.toContain('second private')
|
|
23
|
+
|
|
24
|
+
const debug = await capture(() => formatKernelError(failure, true, '', true))
|
|
25
|
+
expect(debug).toContain('aggregate: Error: first private')
|
|
26
|
+
expect(debug).toContain('aggregate: Error: second private')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('Session and acquisition failures remain typed without unsafe recovery advice', async () => {
|
|
30
|
+
const session = await capture(() =>
|
|
31
|
+
formatKernelError(sessionFailure('Session operation timed out.', 'timeout'), true),
|
|
32
|
+
)
|
|
33
|
+
expect(JSON.parse(session)).toEqual({ error: 'TIMEOUT', message: 'Session operation timed out.' })
|
|
34
|
+
|
|
35
|
+
const acquisition = await capture(() =>
|
|
36
|
+
formatKernelError(
|
|
37
|
+
transportFailure('Publication failed.', 'unknown', {
|
|
38
|
+
kind: 'acquisition',
|
|
39
|
+
resource: 'publication',
|
|
40
|
+
}),
|
|
41
|
+
true,
|
|
42
|
+
'',
|
|
43
|
+
false,
|
|
44
|
+
{ recovery: { operation: 'must-not-leak', retry: 'must-not-leak' } },
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
expect(JSON.parse(acquisition)).toMatchObject({
|
|
48
|
+
error: 'TRANSPORT_ERROR',
|
|
49
|
+
transport: { kind: 'acquisition', resource: 'publication' },
|
|
50
|
+
})
|
|
51
|
+
expect(acquisition).not.toContain('must-not-leak')
|
|
52
|
+
|
|
53
|
+
const legacy = await capture(() =>
|
|
54
|
+
formatKernelError(legacyTransportFailure('Legacy send failed.', 'send', 'not-sent'), true),
|
|
55
|
+
)
|
|
56
|
+
expect(JSON.parse(legacy)).toMatchObject({
|
|
57
|
+
error: 'TRANSPORT_ERROR',
|
|
58
|
+
transport: { kind: 'invocation', delivery: 'not-sent' },
|
|
59
|
+
})
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
async function capture(action: () => Promise<void>): Promise<string> {
|
|
63
|
+
const writes: string[] = []
|
|
64
|
+
const original = process.stderr.write
|
|
65
|
+
process.stderr.write = ((chunk: string | Uint8Array) => {
|
|
66
|
+
writes.push(typeof chunk === 'string' ? chunk : new TextDecoder().decode(chunk))
|
|
67
|
+
return true
|
|
68
|
+
}) as typeof process.stderr.write
|
|
69
|
+
try {
|
|
70
|
+
await action()
|
|
71
|
+
return writes.join('')
|
|
72
|
+
} finally {
|
|
73
|
+
process.stderr.write = original
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -2,7 +2,11 @@ import { describe, expect, test } from 'bun:test'
|
|
|
2
2
|
import { SignJWT } from 'jose'
|
|
3
3
|
import { webcrypto } from 'node:crypto'
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import type { ConnectionContext } from '../session'
|
|
6
|
+
|
|
7
|
+
import { expandSelfInCall, resolveSelfIdAuthenticated } from '../self'
|
|
8
|
+
|
|
9
|
+
const context = Object.freeze({}) as ConnectionContext
|
|
6
10
|
|
|
7
11
|
describe('resolveSelfIdAuthenticated', () => {
|
|
8
12
|
/** @evidence TEST-CLI-SELF-USES-AUTHENTICATED-EFFECTIVE-PRINCIPAL */
|
|
@@ -14,11 +18,9 @@ describe('resolveSelfIdAuthenticated', () => {
|
|
|
14
18
|
.setSubject('manager-principal')
|
|
15
19
|
.setAudience('https://child.example')
|
|
16
20
|
.sign(key)
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const resolved = await resolveSelfIdAuthenticated(opts, {
|
|
21
|
+
const resolved = await resolveSelfIdAuthenticated(context, {
|
|
20
22
|
whoami: async (received) => {
|
|
21
|
-
expect(received).toBe(
|
|
23
|
+
expect(received).toBe(context)
|
|
22
24
|
return { id: 'child-kernel-principal', slug: 'child' }
|
|
23
25
|
},
|
|
24
26
|
})
|
|
@@ -28,17 +30,35 @@ describe('resolveSelfIdAuthenticated', () => {
|
|
|
28
30
|
|
|
29
31
|
test('resolves an imported root without requiring a local registration', async () => {
|
|
30
32
|
await expect(
|
|
31
|
-
resolveSelfIdAuthenticated(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
),
|
|
33
|
+
resolveSelfIdAuthenticated(context, {
|
|
34
|
+
whoami: async () => ({ id: 'manager-kernel-principal' }),
|
|
35
|
+
}),
|
|
35
36
|
).resolves.toEqual({ id: 'manager-kernel-principal' })
|
|
36
37
|
})
|
|
37
38
|
|
|
38
39
|
test('fails closed when authenticated whoami returns no NodeId', async () => {
|
|
39
40
|
await expect(
|
|
40
|
-
resolveSelfIdAuthenticated(
|
|
41
|
-
).rejects.toMatchObject({
|
|
41
|
+
resolveSelfIdAuthenticated(context, { whoami: async () => ({ id: ' ' }) }),
|
|
42
|
+
).rejects.toMatchObject({ code: 'SELF_RESOLUTION_FAILED' })
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
describe('expandSelfInCall', () => {
|
|
47
|
+
test('expands only top-level string values after local parameter admission', async () => {
|
|
48
|
+
const callContext = {
|
|
49
|
+
auth: { whoami: async () => ({ id: 'caller-id' }) },
|
|
50
|
+
target: {},
|
|
51
|
+
} as ConnectionContext
|
|
52
|
+
const expanded = await expandSelfInCall(
|
|
53
|
+
'/:people.example.dev:class.Person:get',
|
|
54
|
+
{ owner: '@self', count: 2, nested: { owner: '@self' } },
|
|
55
|
+
callContext,
|
|
56
|
+
)
|
|
57
|
+
expect(expanded.parameters).toEqual({
|
|
58
|
+
owner: '@caller-id',
|
|
59
|
+
count: 2,
|
|
60
|
+
nested: { owner: '@self' },
|
|
61
|
+
})
|
|
42
62
|
})
|
|
43
63
|
})
|
|
44
64
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { AuthApi } from '@astrale-os/
|
|
2
|
-
import type { GraphApi } from '@astrale-os/
|
|
3
|
-
import type { ClientSession } from '@astrale-os/
|
|
1
|
+
import type { AuthApi } from '@astrale-os/sdk/auth'
|
|
2
|
+
import type { GraphApi } from '@astrale-os/sdk/client'
|
|
3
|
+
import type { ClientSession } from '@astrale-os/sdk/client/session'
|
|
4
4
|
|
|
5
5
|
import { issuer } from '@astrale-os/sdk/auth'
|
|
6
6
|
import { describe, expect, test } from 'bun:test'
|
package/src/connection/auth.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AstraleConfig } from '../lib/config'
|
|
2
|
+
import type { ConnectionOptions, ConnectionTarget } from './target'
|
|
2
3
|
|
|
3
4
|
import { AuthError } from '../errors'
|
|
4
5
|
import { getDefault, getIdentity, type Identity } from '../identity/registry'
|
|
@@ -21,6 +22,18 @@ export type KeyIdentityAuthOptions = {
|
|
|
21
22
|
audience: string
|
|
22
23
|
}
|
|
23
24
|
|
|
25
|
+
/** Pin the local identity label before a session performs any authenticated effect. */
|
|
26
|
+
export async function bindCredentialIdentity<Options extends ConnectionOptions>(
|
|
27
|
+
options: Options,
|
|
28
|
+
target: ConnectionTarget,
|
|
29
|
+
): Promise<Options> {
|
|
30
|
+
if (options.anonymous === true || options.creds !== undefined || options.as !== undefined) {
|
|
31
|
+
return options
|
|
32
|
+
}
|
|
33
|
+
const identity = target.defaultIdentity ?? (await getDefault()).name
|
|
34
|
+
return Object.freeze({ ...options, as: identity })
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
/**
|
|
25
38
|
* Resolve a signed JWT credential from CLI options.
|
|
26
39
|
*
|
package/src/connection/call.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { Fetch } from '@astrale-os/
|
|
2
|
-
import type { SessionAuth } from '@astrale-os/
|
|
1
|
+
import type { Fetch } from '@astrale-os/sdk/client'
|
|
2
|
+
import type { SessionAuth } from '@astrale-os/sdk/client/session'
|
|
3
3
|
|
|
4
4
|
import { credential, type IssuerId } from '@astrale-os/sdk/auth'
|
|
5
5
|
|