@astrale-os/cli 1.0.0-beta.8 → 1.0.0-beta.9
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 +1 -1
- package/dist/astrale.js +1486 -1314
- package/dist/public/connect-core.js +4 -4
- 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 +3 -9
- 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/lib/admin-instance.d.ts +17 -0
- package/dist/types/lib/instance.d.ts +7 -1
- package/dist/types/lib/self.d.ts +9 -0
- package/package.json +1 -1
- package/src/admin/instance/__tests__/client.test.ts +4 -104
- package/src/admin/instance/client.ts +2 -96
- package/src/admin/instance/index.ts +1 -2
- package/src/admin/instance/model.ts +4 -14
- package/src/commands/__tests__/admin-instance.test.ts +11 -8
- package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
- package/src/commands/call-describe.ts +1 -1
- package/src/commands/call.ts +2 -2
- package/src/commands/domain/list.ts +1 -1
- package/src/commands/domain/publish.ts +14 -11
- package/src/commands/get.ts +1 -1
- package/src/commands/instance/create.ts +8 -16
- package/src/commands/instance/delete.ts +7 -6
- package/src/commands/instance/list.ts +2 -2
- package/src/commands/instance/status.ts +4 -4
- package/src/commands/instance/use.ts +16 -12
- package/src/commands/introspect.ts +5 -5
- package/src/commands/view.ts +3 -3
- package/src/connection/__tests__/credential.test.ts +19 -0
- package/src/connection/__tests__/target.test.ts +1 -0
- package/src/connection/auth.ts +13 -0
- package/src/connection/session.ts +12 -1
- package/src/lib/__tests__/command-dx.test.ts +1 -1
- package/src/lib/__tests__/domain-publication.test.ts +6 -1
- package/src/lib/__tests__/instance-candidates.test.ts +1 -3
- package/src/lib/__tests__/instance-target.test.ts +1 -0
- package/src/lib/admin-instance.ts +14 -8
- package/src/lib/command-dx.ts +8 -5
- package/src/lib/domain-publication.ts +8 -6
- package/src/lib/instance-candidates.ts +2 -2
- package/src/lib/instance.ts +14 -10
- package/src/lib/provision-instance.ts +34 -57
- 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-Di4OXGNH.js → elk-api-ByzoDZWH.js} +1 -1
- package/studio/client/dist/assets/{index-DTjvkOUX.js → index-B0RCgUOT.js} +4 -4
- package/studio/client/dist/assets/{index-BLm6J11H.js → index-N8J8EKlB.js} +2 -2
- package/studio/client/dist/index.html +1 -1
- package/studio/server/introspect/runtime.test.ts +2 -2
- package/viewer/dist/main.js +28 -28
- package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
|
@@ -8203,14 +8203,14 @@ function isPidAlive(pid) {
|
|
|
8203
8203
|
function sleep(milliseconds) {
|
|
8204
8204
|
return new Promise((resolve) => setTimeout(resolve, milliseconds));
|
|
8205
8205
|
}
|
|
8206
|
-
// node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.
|
|
8206
|
+
// node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.8/node_modules/@astrale-os/kernel-dsl/dist/value/limits.js
|
|
8207
8207
|
var defaultLimits = Object.freeze({
|
|
8208
8208
|
maxBytes: 16 * 1024 * 1024,
|
|
8209
8209
|
maxDepth: 64,
|
|
8210
8210
|
maxMembers: 1e5,
|
|
8211
8211
|
maxStringBytes: 1024 * 1024
|
|
8212
8212
|
});
|
|
8213
|
-
// node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.
|
|
8213
|
+
// node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.8/node_modules/@astrale-os/kernel-dsl/dist/value/canonical.js
|
|
8214
8214
|
var encoder2 = new TextEncoder;
|
|
8215
8215
|
// node_modules/.pnpm/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
|
|
8216
8216
|
var CharacterCodes;
|
|
@@ -8390,7 +8390,7 @@ var ParseErrorCode;
|
|
|
8390
8390
|
ParseErrorCode2[ParseErrorCode2["InvalidCharacter"] = 16] = "InvalidCharacter";
|
|
8391
8391
|
})(ParseErrorCode || (ParseErrorCode = {}));
|
|
8392
8392
|
|
|
8393
|
-
// node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.
|
|
8393
|
+
// node_modules/.pnpm/@astrale-os+kernel-dsl@0.2.0-beta.8/node_modules/@astrale-os/kernel-dsl/dist/value/decode.js
|
|
8394
8394
|
var decoder2 = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
|
|
8395
8395
|
// node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
8396
8396
|
var exports_external = {};
|
|
@@ -27595,7 +27595,7 @@ var log = {
|
|
|
27595
27595
|
dim: (msg) => console.log(source_default.dim(msg))
|
|
27596
27596
|
};
|
|
27597
27597
|
var IS_CI = !!(process.env.CI || process.env.CONTINUOUS_INTEGRATION || process.env.NO_SPINNER);
|
|
27598
|
-
// node_modules/.pnpm/@astrale-os+kernel-core@0.9.0-beta.
|
|
27598
|
+
// node_modules/.pnpm/@astrale-os+kernel-core@0.9.0-beta.10/node_modules/@astrale-os/kernel-core/dist/dns-label.js
|
|
27599
27599
|
var DNS_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
27600
27600
|
function isDnsLabel(value) {
|
|
27601
27601
|
return DNS_LABEL_RE.test(value);
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Input } from '@astrale-os/sdk/client';
|
|
2
|
+
import type { ClientSession } from '@astrale-os/sdk/client/session';
|
|
3
|
+
import type { ResolvedClass, ResolvedProperty } from '@astrale-os/sdk/schema';
|
|
4
|
+
import type { DomainBinding } from '@astrale-os/shell';
|
|
5
|
+
import { Path } from '@astrale-os/sdk/graph/path';
|
|
6
|
+
export type AdminBinding = DomainBinding;
|
|
7
|
+
/** Bind the exact Admin revision installed on this source Kernel. */
|
|
8
|
+
export declare function bindAdmin(session: ClientSession): Promise<AdminBinding>;
|
|
9
|
+
/** Admit an injected dynamic binding as the Admin Domain. */
|
|
10
|
+
export declare function requireAdminBinding(binding: AdminBinding): AdminBinding;
|
|
11
|
+
/** Resolve one required Admin Class without rebuilding its schema contract. */
|
|
12
|
+
export declare function requireAdminClass(binding: AdminBinding, name: string, kind: 'node'): ResolvedClass<'node'>;
|
|
13
|
+
export declare function requireAdminClass(binding: AdminBinding, name: string, kind: 'edge'): ResolvedClass<'edge'>;
|
|
14
|
+
/** Resolve one required Admin Core Node as its canonical projection Path. */
|
|
15
|
+
export declare function requireAdminCore(binding: AdminBinding, name: string): Path;
|
|
16
|
+
/** Resolve one effective Property by unambiguous member name. */
|
|
17
|
+
export declare function requireAdminProperty(owner: ResolvedClass, name: string): ResolvedProperty<unknown>;
|
|
18
|
+
/** Invoke one resolved executable instance Method through Kernel Client. */
|
|
19
|
+
export declare function invokeAdminMethod(session: ClientSession, binding: AdminBinding, owner: ResolvedClass<'node'>, name: string, receiver: Path, input: Input): Promise<unknown>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ClientSession } from '@astrale-os/sdk/client/session';
|
|
2
|
+
import { type AdminBinding } from '../binding';
|
|
3
|
+
import { type DomainInstallReceipt, type InstanceInfo, type OwnedInstanceInfo } from './model';
|
|
4
|
+
export interface AdminInstanceContext {
|
|
5
|
+
readonly session: ClientSession;
|
|
6
|
+
}
|
|
7
|
+
export interface AdminInstanceApi {
|
|
8
|
+
list(): Promise<OwnedInstanceInfo[]>;
|
|
9
|
+
create(slug: string): Promise<InstanceInfo>;
|
|
10
|
+
status(identifier: string): Promise<InstanceInfo>;
|
|
11
|
+
delete(identifier: string): Promise<InstanceInfo>;
|
|
12
|
+
installDomain(identifier: string, domain: string): Promise<DomainInstallReceipt>;
|
|
13
|
+
}
|
|
14
|
+
export interface AdminInstanceDependencies {
|
|
15
|
+
readonly bind?: (session: ClientSession) => Promise<AdminBinding>;
|
|
16
|
+
readonly operationId?: (kind: 'create' | 'status' | 'delete' | 'install-domain') => string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Bind one discovered Admin root revision and expose only the public Instance
|
|
20
|
+
* product journey. No Host lifecycle method is present on this capability.
|
|
21
|
+
*/
|
|
22
|
+
export declare function connectAdminInstances(context: AdminInstanceContext, dependencies?: AdminInstanceDependencies): Promise<AdminInstanceApi>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { connectAdminInstances, type AdminInstanceApi, type AdminInstanceContext, type AdminInstanceDependencies, } from './client';
|
|
2
|
+
export { AdminInstanceNotFoundError, findOwnedInstance, formatInstanceState, type DomainInstallReceipt, type InstanceInfo, type InstanceState, type OwnedInstanceInfo, } from './model';
|
|
@@ -4,9 +4,7 @@ export interface InstanceInfo {
|
|
|
4
4
|
readonly id: string;
|
|
5
5
|
readonly slug: string;
|
|
6
6
|
readonly url: string;
|
|
7
|
-
readonly
|
|
8
|
-
readonly region?: string;
|
|
9
|
-
readonly state?: InstanceState;
|
|
7
|
+
readonly state: InstanceState;
|
|
10
8
|
readonly phase?: string;
|
|
11
9
|
readonly error?: string | null;
|
|
12
10
|
readonly createdAt?: string;
|
|
@@ -28,12 +26,8 @@ export declare class AdminInstanceNotFoundError extends AstraleError {
|
|
|
28
26
|
readonly identifier: string;
|
|
29
27
|
constructor(identifier: string);
|
|
30
28
|
}
|
|
31
|
-
export declare class AdminHostNotFoundError extends AstraleError {
|
|
32
|
-
readonly identifier: string;
|
|
33
|
-
constructor(identifier: string);
|
|
34
|
-
}
|
|
35
29
|
/** Match an owner-scoped Instance by slug, canonical Node Path, or bare Node id. */
|
|
36
30
|
export declare function findOwnedInstance(instances: readonly OwnedInstanceInfo[], identifier: string): OwnedInstanceInfo | undefined;
|
|
37
|
-
/** Human-readable
|
|
38
|
-
export declare function
|
|
31
|
+
/** Human-readable non-ready lifecycle state for one Instance. */
|
|
32
|
+
export declare function formatInstanceState(info: InstanceInfo): string;
|
|
39
33
|
import { AstraleError } from '../../errors';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AstraleConfig } from '../lib/config';
|
|
2
|
+
import type { ConnectionOptions, ConnectionTarget } from './target';
|
|
2
3
|
import { type Identity } from '../identity/registry';
|
|
3
4
|
import { IdpAudienceMismatchError } from '../lib/idp';
|
|
4
5
|
import { IdpSessionNoRefreshTokenError } from '../lib/idp-session';
|
|
@@ -7,6 +8,8 @@ export type KeyIdentityAuthOptions = {
|
|
|
7
8
|
subject?: string;
|
|
8
9
|
audience: string;
|
|
9
10
|
};
|
|
11
|
+
/** Pin the local identity label before a session performs any authenticated effect. */
|
|
12
|
+
export declare function bindCredentialIdentity<Options extends ConnectionOptions>(options: Options, target: ConnectionTarget): Promise<Options>;
|
|
10
13
|
/**
|
|
11
14
|
* Resolve a signed JWT credential from CLI options.
|
|
12
15
|
*
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { ConnectionContext } from './session';
|
|
2
|
+
import type { ConnectionOptions } from './target';
|
|
3
|
+
export interface KernelCommandOpts extends ConnectionOptions {
|
|
4
|
+
readonly raw?: boolean;
|
|
5
|
+
readonly json?: boolean;
|
|
6
|
+
readonly format?: 'yaml' | 'json';
|
|
7
|
+
readonly debug?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface OperationRecovery {
|
|
10
|
+
readonly operation: string;
|
|
11
|
+
readonly retry: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Encapsulates the standard kernel command lifecycle:
|
|
15
|
+
* spinner → connect → call → timing → output → error handling.
|
|
16
|
+
*
|
|
17
|
+
* Commands provide a `fn` that does the actual work and an optional
|
|
18
|
+
* `format` callback for custom output. If `format` is omitted, the
|
|
19
|
+
* result is passed to the standard `output()` function.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runKernelCommand<T>(input: {
|
|
22
|
+
readonly opts: KernelCommandOpts;
|
|
23
|
+
readonly label: string;
|
|
24
|
+
readonly recovery?: OperationRecovery;
|
|
25
|
+
readonly fn: (context: ConnectionContext) => Promise<T>;
|
|
26
|
+
readonly format?: (result: T, options: KernelCommandOpts, machine: boolean) => void | Promise<void>;
|
|
27
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Fetch } from '@astrale-os/sdk/client';
|
|
2
|
+
import type { SessionAuth } from '@astrale-os/sdk/client/session';
|
|
3
|
+
import { type IssuerId } from '@astrale-os/sdk/auth';
|
|
4
|
+
import type { AstraleConfig } from '../lib/config';
|
|
5
|
+
import type { ConnectionOptions, ConnectionTarget } from './target';
|
|
6
|
+
export interface SourceCredentialResolver {
|
|
7
|
+
resolve(audience: IssuerId, signal: AbortSignal): Promise<string>;
|
|
8
|
+
}
|
|
9
|
+
/** Resolve source authority; an omitted Session delegation preserves exact current authority. */
|
|
10
|
+
export declare function createConnectionCredential(expectedSourceIssuer: IssuerId, source: SourceCredentialResolver): SessionAuth;
|
|
11
|
+
/** Bind CLI identity state and Core Auth delegation to one Session auth capability. */
|
|
12
|
+
export declare function createCliCredential(target: ConnectionTarget, options: ConnectionOptions, config: AstraleConfig, fetch?: Fetch, timeoutMs?: number): SessionAuth | undefined;
|
|
13
|
+
/** Reject contradictory explicit credential selections before identity or network access. */
|
|
14
|
+
export declare function validateCredentialSelection(options: ConnectionOptions): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { formatKernelError, functionInputIssues, schemaUpgradeHint } from './failure';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { IssuerId } from '@astrale-os/sdk/auth';
|
|
2
|
+
import type { Fetch } from '@astrale-os/sdk/client';
|
|
3
|
+
import type { SourceCredentialResolver } from './credential';
|
|
4
|
+
import type { ConnectionTarget } from './target';
|
|
5
|
+
import { ExchangeCredentialCache } from '../state/exchange-credentials';
|
|
6
|
+
/** Exchange exact authenticated User authority for a Domain bearer bound to this Kernel. */
|
|
7
|
+
export declare function createExchangeCredentialResolver(target: ConnectionTarget & {
|
|
8
|
+
readonly domainIssuer: IssuerId;
|
|
9
|
+
}, source: SourceCredentialResolver, fetch: Fetch, timeoutMs: number, cache?: ExchangeCredentialCache): SourceCredentialResolver;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { OperationRecovery } from '../command';
|
|
2
|
+
export { functionInputIssues, schemaUpgradeHint } from '../reasons';
|
|
3
|
+
export declare function formatKernelError(error: unknown, machine: boolean, urlArg?: string, debug?: boolean, options?: {
|
|
4
|
+
recovery?: OperationRecovery;
|
|
5
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type TransportDiagnosticContext = {
|
|
2
|
+
readonly kind: 'acquisition';
|
|
3
|
+
readonly resource: 'publication' | 'bundle';
|
|
4
|
+
} | {
|
|
5
|
+
readonly kind: 'invocation';
|
|
6
|
+
readonly delivery: 'not-sent' | 'unknown';
|
|
7
|
+
readonly invocation?: unknown;
|
|
8
|
+
};
|
|
9
|
+
export type FailureDiagnostic = {
|
|
10
|
+
readonly kind: 'simple';
|
|
11
|
+
readonly code: string;
|
|
12
|
+
readonly message: string;
|
|
13
|
+
readonly hint?: string;
|
|
14
|
+
} | {
|
|
15
|
+
readonly kind: 'response';
|
|
16
|
+
readonly code: number;
|
|
17
|
+
readonly message: string;
|
|
18
|
+
readonly reason?: unknown;
|
|
19
|
+
} | {
|
|
20
|
+
readonly kind: 'transport';
|
|
21
|
+
readonly code: 'CONNECTION_ERROR' | 'DISCONNECTED' | 'TIMEOUT' | 'TRANSPORT_ERROR';
|
|
22
|
+
readonly message: string;
|
|
23
|
+
readonly phase: string;
|
|
24
|
+
readonly context: TransportDiagnosticContext;
|
|
25
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { createPathCall } from './call';
|
|
2
|
+
export { runKernelCommand } from './command';
|
|
3
|
+
export type { KernelCommandOpts, OperationRecovery } from './command';
|
|
4
|
+
export { expandSelfInCall, expandSelfInPath, withSelfHint } from './self';
|
|
5
|
+
export type { SelfExpansionMeta } from './self';
|
|
6
|
+
export { withAdminClientSession, withClientSession, type ConnectionContext } from './session';
|
|
7
|
+
export { registrationKeyForTarget } from './target';
|
|
8
|
+
export type { AdminConnectionOptions, ConnectionOptions, ConnectionTarget } from './target';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export type FunctionInputIssue = Readonly<{
|
|
2
|
+
code: string;
|
|
3
|
+
path?: string;
|
|
4
|
+
message: string;
|
|
5
|
+
}>;
|
|
6
|
+
export type QueryInputRepair = Readonly<{
|
|
7
|
+
phase: 'decode' | 'input';
|
|
8
|
+
path: string;
|
|
9
|
+
}> | Readonly<{
|
|
10
|
+
phase: 'plan';
|
|
11
|
+
issue: string;
|
|
12
|
+
path?: string;
|
|
13
|
+
}> | Readonly<{
|
|
14
|
+
phase: 'limit';
|
|
15
|
+
limit: string;
|
|
16
|
+
maximum: number;
|
|
17
|
+
actual: number;
|
|
18
|
+
path?: string;
|
|
19
|
+
}>;
|
|
20
|
+
export type SchemaUpgradeDetails = {
|
|
21
|
+
readonly origin?: string;
|
|
22
|
+
readonly issue?: undefined;
|
|
23
|
+
} | {
|
|
24
|
+
readonly origin: string;
|
|
25
|
+
readonly issue: 'issuer-changed';
|
|
26
|
+
readonly installedIssuer: string;
|
|
27
|
+
readonly replacementIssuer: string;
|
|
28
|
+
};
|
|
29
|
+
export declare function reasonCode(reason: unknown): string | undefined;
|
|
30
|
+
/** Admit only bounded caller-safe Function input issues established by the Kernel. */
|
|
31
|
+
export declare function functionInputIssues(reason: unknown): readonly FunctionInputIssue[];
|
|
32
|
+
/** Admit only public Query-input repair variants; unknown details remain machine-only. */
|
|
33
|
+
export declare function queryInputRepair(reason: unknown): QueryInputRepair | undefined;
|
|
34
|
+
/** Decode bounded recovery guidance while preserving the admitted reason itself elsewhere. */
|
|
35
|
+
export declare function schemaUpgradeDetails(reason: unknown): SchemaUpgradeDetails | undefined;
|
|
36
|
+
export declare function schemaUpgradeHint(details: SchemaUpgradeDetails): string;
|
|
37
|
+
export declare function schemaDataRemovalHint(reason: unknown): string | undefined;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ConnectionContext } from './session';
|
|
2
|
+
/** Metadata attached to errors after an authenticated caller-authored @self expansion. */
|
|
3
|
+
export interface SelfExpansionMeta {
|
|
4
|
+
readonly original: string;
|
|
5
|
+
readonly expanded: string;
|
|
6
|
+
readonly selfId: string;
|
|
7
|
+
readonly slug?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Run `action`; if it throws NodeUnavailableError, retain the authenticated
|
|
11
|
+
* expansion for precise diagnostics. The error is re-thrown either way.
|
|
12
|
+
*/
|
|
13
|
+
export declare function withSelfHint<T>(action: () => Promise<T>, meta: SelfExpansionMeta | undefined): Promise<T>;
|
|
14
|
+
type AuthenticatedSelf = {
|
|
15
|
+
readonly id?: unknown;
|
|
16
|
+
readonly slug?: string;
|
|
17
|
+
};
|
|
18
|
+
export type ResolveSelfIdDependencies = {
|
|
19
|
+
readonly whoami?: (context: ConnectionContext) => Promise<AuthenticatedSelf>;
|
|
20
|
+
};
|
|
21
|
+
/** Resolve @self only from the effective principal authenticated by the selected Kernel. */
|
|
22
|
+
export declare function resolveSelfIdAuthenticated(context: ConnectionContext, dependencies?: ResolveSelfIdDependencies): Promise<{
|
|
23
|
+
readonly id: string;
|
|
24
|
+
readonly slug?: string;
|
|
25
|
+
}>;
|
|
26
|
+
/** Expand @self in path-like commands and return metadata for NotFound diagnostics. */
|
|
27
|
+
export declare function expandSelfInPath(path: string, context: ConnectionContext): Promise<{
|
|
28
|
+
readonly path: string;
|
|
29
|
+
readonly meta?: SelfExpansionMeta;
|
|
30
|
+
}>;
|
|
31
|
+
/** Expand @self once across one Call path and its CLI-authored string parameters. */
|
|
32
|
+
export declare function expandSelfInCall(path: string, parameters: Readonly<Record<string, unknown>>, context: ConnectionContext): Promise<{
|
|
33
|
+
readonly path: string;
|
|
34
|
+
readonly parameters: Readonly<Record<string, unknown>>;
|
|
35
|
+
readonly meta?: SelfExpansionMeta;
|
|
36
|
+
}>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { AuthApi } from '@astrale-os/sdk/auth';
|
|
2
|
+
import type { GraphApi } from '@astrale-os/sdk/client';
|
|
3
|
+
import type { ClientSessionOptions, SessionAuth } from '@astrale-os/sdk/client/session';
|
|
4
|
+
import { ClientSession } from '@astrale-os/sdk/client/session';
|
|
5
|
+
import type { AstraleConfig } from '../lib/config';
|
|
6
|
+
import type { AdminConnectionOptions, ConnectionOptions, ConnectionTarget } from './target';
|
|
7
|
+
import { connectAdminInstances, type InstanceInfo } from '../admin/instance';
|
|
8
|
+
export interface ConnectionContext {
|
|
9
|
+
readonly session: ClientSession;
|
|
10
|
+
readonly graph: GraphApi;
|
|
11
|
+
readonly auth: AuthApi;
|
|
12
|
+
readonly target: ConnectionTarget;
|
|
13
|
+
/** Local identity label selected for this session; absent for raw credentials or anonymous use. */
|
|
14
|
+
readonly identity?: string;
|
|
15
|
+
}
|
|
16
|
+
interface OwnedConnection {
|
|
17
|
+
readonly context: ConnectionContext;
|
|
18
|
+
close(): void;
|
|
19
|
+
}
|
|
20
|
+
export type ConnectionFactory = (target: ConnectionTarget, timeoutMs: number, options: ConnectionOptions, config: AstraleConfig) => OwnedConnection;
|
|
21
|
+
/** Resolve one ordinary target, run a command action, then close terminally. */
|
|
22
|
+
export declare function withClientSession<Value>(options: ConnectionOptions, action: (context: ConnectionContext) => Promise<Value>): Promise<Value>;
|
|
23
|
+
/** Resolve the configured Admin Domain target under the same terminal lifecycle. */
|
|
24
|
+
export declare function withAdminClientSession<Value>(options: AdminConnectionOptions, action: (context: ConnectionContext) => Promise<Value>): Promise<Value>;
|
|
25
|
+
/** Owner-private seam used to prove validation order and cleanup without network I/O. */
|
|
26
|
+
export declare function withResolvedClientSession<Value>(target: ConnectionTarget, options: ConnectionOptions, config: AstraleConfig, action: (context: ConnectionContext) => Promise<Value>, open?: ConnectionFactory): Promise<Value>;
|
|
27
|
+
export declare function resolveTimeoutMs(raw: string | undefined): number;
|
|
28
|
+
/** Owner-private construction seam proving that transport and source identity stay distinct. */
|
|
29
|
+
export declare function createClientSessionOptions(target: ConnectionTarget, fetch: NonNullable<ClientSessionOptions['fetch']>, auth: SessionAuth | undefined, timeoutMs: number): ClientSessionOptions;
|
|
30
|
+
export declare function lookupManagedInstance(slug: string, options: ConnectionOptions, openAdmin?: typeof withAdminClientSession, connect?: typeof connectAdminInstances): Promise<InstanceInfo>;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { IssuerId } from '@astrale-os/sdk/auth';
|
|
2
|
+
import type { InstanceInfo } from '../lib/admin-instance';
|
|
3
|
+
import type { AdminTargetCommandOpts } from '../lib/admin-target';
|
|
4
|
+
import type { AstraleConfig } from '../lib/config';
|
|
5
|
+
import type { InstanceStore } from '../lib/instance';
|
|
6
|
+
export interface ConnectionOptions {
|
|
7
|
+
readonly url?: string;
|
|
8
|
+
readonly instance?: string;
|
|
9
|
+
readonly timeout?: string;
|
|
10
|
+
readonly as?: string;
|
|
11
|
+
readonly creds?: string;
|
|
12
|
+
readonly anonymous?: boolean;
|
|
13
|
+
readonly ci?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export interface AdminConnectionOptions extends ConnectionOptions {
|
|
16
|
+
readonly admin?: string;
|
|
17
|
+
readonly adminUrl?: string;
|
|
18
|
+
readonly domainIssuer?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ConnectionTarget {
|
|
21
|
+
readonly url: string;
|
|
22
|
+
readonly kernelIssuer: IssuerId;
|
|
23
|
+
readonly domainIssuer?: IssuerId;
|
|
24
|
+
readonly slug?: string;
|
|
25
|
+
readonly defaultIdentity?: string;
|
|
26
|
+
readonly caFile?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface TargetDependencies {
|
|
29
|
+
readonly instances?: InstanceStore;
|
|
30
|
+
readonly managed?: (slug: string) => Promise<InstanceInfo>;
|
|
31
|
+
}
|
|
32
|
+
/** Stable local identity-registration key for the exact selected source Kernel. */
|
|
33
|
+
export declare function registrationKeyForTarget(target: ConnectionTarget): string;
|
|
34
|
+
/** Resolve the existing URL / instance / active precedence into one exact source Kernel. */
|
|
35
|
+
export declare function resolveConnectionTarget(options: ConnectionOptions, config: AstraleConfig, dependencies?: TargetDependencies): Promise<ConnectionTarget>;
|
|
36
|
+
/** Resolve the configured Admin Domain target without entering managed-instance discovery. */
|
|
37
|
+
export declare function resolveAdminConnectionTarget(options: AdminConnectionOptions, config: AstraleConfig, instances?: InstanceStore): Promise<ConnectionTarget>;
|
|
38
|
+
export declare function adminLookupOptions(options: AdminConnectionOptions): AdminTargetCommandOpts;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AdminConnectionOptions, ConnectionContext } from '../connection';
|
|
2
|
+
export { AdminInstanceNotFoundError, findOwnedInstance, formatInstanceState, type InstanceInfo, type InstanceState, type OwnedInstanceInfo, } from '../admin/instance';
|
|
3
|
+
/** Resolve the Admin target and read only the caller-visible Instance inventory. */
|
|
4
|
+
export declare function listOwnedInstances(options: AdminConnectionOptions): Promise<import("./admin-instance").OwnedInstanceInfo[]>;
|
|
5
|
+
/** Read caller-visible inventory together with the exact local identity used for the Admin call. */
|
|
6
|
+
export declare function listOwnedInstancesWithIdentity(options: AdminConnectionOptions): Promise<Readonly<{
|
|
7
|
+
instances: import("./admin-instance").OwnedInstanceInfo[];
|
|
8
|
+
identity?: string | undefined;
|
|
9
|
+
}>>;
|
|
10
|
+
/** Reuse an already-open Admin session for a caller-visible Instance inventory. */
|
|
11
|
+
export declare function listOwnedInstancesInContext(context: ConnectionContext): Promise<import("./admin-instance").OwnedInstanceInfo[]>;
|
|
12
|
+
/** Request one managed Instance; Admin owns infrastructure placement. */
|
|
13
|
+
export declare function createOwnedInstance(options: AdminConnectionOptions, slug: string): Promise<import("./admin-instance").InstanceInfo>;
|
|
14
|
+
/** Refresh one exact caller-visible Instance through its V2 receiver Method. */
|
|
15
|
+
export declare function statusOwnedInstance(options: AdminConnectionOptions, identifier: string): Promise<import("./admin-instance").InstanceInfo>;
|
|
16
|
+
/** Delete one exact caller-visible Instance through its V2 receiver Method. */
|
|
17
|
+
export declare function deleteOwnedInstance(options: AdminConnectionOptions, identifier: string): Promise<import("./admin-instance").InstanceInfo>;
|
|
@@ -172,7 +172,13 @@ export declare function upsertInstance(key: string, opts?: AddInstanceOpts): Pro
|
|
|
172
172
|
* normalized kernel URL). Reports the previous URL when an existing
|
|
173
173
|
* bookmark was repointed to a different kernel so callers can warn.
|
|
174
174
|
*/
|
|
175
|
-
export declare function upsertManagedBookmark(
|
|
175
|
+
export declare function upsertManagedBookmark(input: Readonly<{
|
|
176
|
+
key: string;
|
|
177
|
+
slug: string;
|
|
178
|
+
url: string;
|
|
179
|
+
organizationId?: string;
|
|
180
|
+
defaultIdentity?: string;
|
|
181
|
+
}>): Promise<{
|
|
176
182
|
entry: InstanceEntry;
|
|
177
183
|
repointedFrom?: string;
|
|
178
184
|
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lexical `@self` helpers. Effective-principal resolution is deliberately not
|
|
3
|
+
* local: connection/self.ts asks the authenticated target Kernel through
|
|
4
|
+
* Identity.whoami before replacing any reference.
|
|
5
|
+
*/
|
|
6
|
+
/** Cheap pre-check before invoking authenticated principal resolution. */
|
|
7
|
+
export declare function containsSelfRef(input: string): boolean;
|
|
8
|
+
/** Replace every admitted `@self` token with one authenticated NodeId. */
|
|
9
|
+
export declare function expandSelfReferences(input: string, selfId: string): string;
|
package/package.json
CHANGED
|
@@ -1,50 +1,9 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { QueryAST } from '@astrale-os/sdk/query'
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
3
2
|
|
|
4
|
-
import {
|
|
5
|
-
import { Path } from '@astrale-os/sdk/graph/path'
|
|
6
|
-
import { describe, expect, mock, test } from 'bun:test'
|
|
7
|
-
|
|
8
|
-
import type { AdminGraphApi } from '../../graph'
|
|
9
|
-
|
|
10
|
-
import { AdminTestDomain, adminBinding, adminSession } from '../../__tests__/fixture'
|
|
3
|
+
import { adminBinding, adminSession } from '../../__tests__/fixture'
|
|
11
4
|
import { connectAdminInstances } from '../client'
|
|
12
5
|
|
|
13
|
-
function hostNode(id: string, props: { readonly id: string; readonly state: string }): Node {
|
|
14
|
-
return {
|
|
15
|
-
id: NodeId(id),
|
|
16
|
-
class: AdminTestDomain.classes.Host.key,
|
|
17
|
-
props: AdminTestDomain.classes.Host.properties.from(props),
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function instanceNode(id: string): Node {
|
|
22
|
-
return {
|
|
23
|
-
id: NodeId(id),
|
|
24
|
-
class: AdminTestDomain.classes.Instance.key,
|
|
25
|
-
props: AdminTestDomain.classes.Instance.properties.from({}),
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function graphResult(nodes: readonly Node[], cursor?: string) {
|
|
30
|
-
return {
|
|
31
|
-
result: {
|
|
32
|
-
kind: 'nodes' as const,
|
|
33
|
-
nodes: nodes.map((value) => ({ kind: 'value' as const, value })),
|
|
34
|
-
},
|
|
35
|
-
page: cursor === undefined ? {} : { next: cursor },
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function sourceName(ast: QueryAST): string | undefined {
|
|
40
|
-
const term = ast.source.terms[0]
|
|
41
|
-
return term?.kind === 'class' ? term.class.name : undefined
|
|
42
|
-
}
|
|
43
|
-
|
|
44
6
|
function fixture(input: {
|
|
45
|
-
instances?: readonly Node[]
|
|
46
|
-
hosts?: readonly Node[]
|
|
47
|
-
reserved?: Node | null
|
|
48
7
|
invoke?: (method: { owner: string; name: string }, receiver: unknown, input: unknown) => unknown
|
|
49
8
|
}) {
|
|
50
9
|
const calls: Array<{
|
|
@@ -57,26 +16,13 @@ function fixture(input: {
|
|
|
57
16
|
return input.invoke?.(method, receiver, value)
|
|
58
17
|
})
|
|
59
18
|
const binding = adminBinding()
|
|
60
|
-
const query = mock(async (ast: QueryAST) => {
|
|
61
|
-
const name = sourceName(ast)
|
|
62
|
-
if (name === 'Instance') return graphResult(input.instances ?? [])
|
|
63
|
-
if (name === 'Host') return graphResult(input.hosts ?? [])
|
|
64
|
-
throw new Error(`Unexpected graph query ${String(name)}`)
|
|
65
|
-
})
|
|
66
|
-
const neighbors = mock(async (source: unknown, edge: { name?: string }) => {
|
|
67
|
-
if (String(source) === '/:admin.astrale.ai:core.fleet') return page(input.reserved ?? null)
|
|
68
|
-
if (edge.name === 'instance_runs_on_host') return page(input.hosts?.[0] ?? null)
|
|
69
|
-
throw new Error(`Unexpected neighbor query ${String(source)} ${String(edge)}`)
|
|
70
|
-
})
|
|
71
|
-
const graph = { query, neighbors } as unknown as AdminGraphApi
|
|
72
19
|
return {
|
|
73
20
|
binding,
|
|
74
|
-
graph,
|
|
75
21
|
invoke: remote.invoke,
|
|
76
22
|
calls,
|
|
77
23
|
connect: () =>
|
|
78
24
|
connectAdminInstances(
|
|
79
|
-
{ session: remote.session
|
|
25
|
+
{ session: remote.session },
|
|
80
26
|
{
|
|
81
27
|
bind: async () => binding,
|
|
82
28
|
operationId: (kind) => `cli.instance.${kind}:test`,
|
|
@@ -85,15 +31,6 @@ function fixture(input: {
|
|
|
85
31
|
}
|
|
86
32
|
}
|
|
87
33
|
|
|
88
|
-
function page(item: Node | null) {
|
|
89
|
-
return {
|
|
90
|
-
nodes: item === null ? [] : [item],
|
|
91
|
-
first: item,
|
|
92
|
-
graph: { nodes: item === null ? [] : [item], edges: [] },
|
|
93
|
-
cursor: null,
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
34
|
describe('V2 Admin Instance adapter', () => {
|
|
98
35
|
test('lists caller-visible Instances through the Admin-owned Fleet operation', async () => {
|
|
99
36
|
const contract = fixture({
|
|
@@ -107,8 +44,6 @@ describe('V2 Admin Instance adapter', () => {
|
|
|
107
44
|
state: 'ready',
|
|
108
45
|
createdAt: '2026-08-12T00:00:00.000Z',
|
|
109
46
|
updatedAt: '2026-08-12T00:00:00.000Z',
|
|
110
|
-
hostId: '@host-node',
|
|
111
|
-
region: 'fr-par',
|
|
112
47
|
},
|
|
113
48
|
]
|
|
114
49
|
: undefined,
|
|
@@ -121,8 +56,6 @@ describe('V2 Admin Instance adapter', () => {
|
|
|
121
56
|
url: 'https://demo.eu.astrale.ai',
|
|
122
57
|
state: 'ready',
|
|
123
58
|
createdAt: '2026-08-12T00:00:00.000Z',
|
|
124
|
-
hostId: '@host-node',
|
|
125
|
-
region: 'fr-par',
|
|
126
59
|
},
|
|
127
60
|
])
|
|
128
61
|
expect(contract.calls).toEqual([
|
|
@@ -143,10 +76,7 @@ describe('V2 Admin Instance adapter', () => {
|
|
|
143
76
|
createdAt: '2026-08-12T00:00:00.000Z',
|
|
144
77
|
updatedAt: '2026-08-12T00:00:00.000Z',
|
|
145
78
|
}
|
|
146
|
-
const contract = fixture({
|
|
147
|
-
hosts: [hostNode('host-node', { id: 'host-paris', state: 'ready' })],
|
|
148
|
-
invoke: () => created,
|
|
149
|
-
})
|
|
79
|
+
const contract = fixture({ invoke: () => created })
|
|
150
80
|
|
|
151
81
|
await expect((await contract.connect()).create('demo')).resolves.toMatchObject({
|
|
152
82
|
id: created.id,
|
|
@@ -162,38 +92,10 @@ describe('V2 Admin Instance adapter', () => {
|
|
|
162
92
|
value: { operationId: 'cli.instance.create:test', slug: 'demo' },
|
|
163
93
|
},
|
|
164
94
|
])
|
|
165
|
-
expect(contract.graph.query).not.toHaveBeenCalled()
|
|
166
|
-
expect(contract.graph.neighbors).not.toHaveBeenCalled()
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
test('resolves --host-id to an exact Host receiver and rejects the reserved Admin Host', async () => {
|
|
170
|
-
const reserved = hostNode('admin-host', { id: 'admin', state: 'ready' })
|
|
171
|
-
const consumer = hostNode('consumer-host', { id: 'consumer-paris', state: 'ready' })
|
|
172
|
-
const contract = fixture({
|
|
173
|
-
hosts: [reserved, consumer],
|
|
174
|
-
reserved,
|
|
175
|
-
invoke: () => ({
|
|
176
|
-
id: '@instance-node',
|
|
177
|
-
slug: 'demo',
|
|
178
|
-
url: 'https://demo.eu.astrale.ai',
|
|
179
|
-
state: 'ready',
|
|
180
|
-
}),
|
|
181
|
-
})
|
|
182
|
-
const api = await contract.connect()
|
|
183
|
-
|
|
184
|
-
await expect(api.create('demo', 'admin')).rejects.toMatchObject({ code: 'HOST_NOT_FOUND' })
|
|
185
|
-
await expect(api.create('demo', 'consumer-paris')).resolves.toMatchObject({ slug: 'demo' })
|
|
186
|
-
expect(contract.calls.at(-1)).toEqual({
|
|
187
|
-
method: { owner: 'Host', name: 'createInstance' },
|
|
188
|
-
receiver: '@consumer-host::createInstance',
|
|
189
|
-
value: { operationId: 'cli.instance.create:test', slug: 'demo' },
|
|
190
|
-
})
|
|
191
95
|
})
|
|
192
96
|
|
|
193
97
|
test('refreshes and deletes through the resolved Instance receiver', async () => {
|
|
194
|
-
const instance = instanceNode('instance-node')
|
|
195
98
|
const contract = fixture({
|
|
196
|
-
instances: [instance],
|
|
197
99
|
invoke: (method) =>
|
|
198
100
|
method.name === 'listInstances'
|
|
199
101
|
? [
|
|
@@ -226,9 +128,7 @@ describe('V2 Admin Instance adapter', () => {
|
|
|
226
128
|
})
|
|
227
129
|
|
|
228
130
|
test('installs a resolved catalog Domain through Instance.installDomain', async () => {
|
|
229
|
-
const instance = instanceNode('instance-node')
|
|
230
131
|
const contract = fixture({
|
|
231
|
-
instances: [instance],
|
|
232
132
|
invoke: (method) =>
|
|
233
133
|
method.name === 'listInstances'
|
|
234
134
|
? [
|