@astrale-os/kernel-client 0.6.0-beta.70 → 0.6.0-beta.71

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.
@@ -1,13 +1,25 @@
1
- import type { Identity, Authentication, IdentityId, MintedCredential, RegisterResult } from '@astrale-os/kernel-core/auth';
2
- import type { PathLike } from '@astrale-os/kernel-core/path';
3
- import type { Input } from '../client/index.js';
1
+ import type { Identity, Authentication, IdentityId, MintedCredential, RegisterResult, UnresolvedIdentityExpr } from '@astrale-os/kernel-core/auth';
2
+ import type { NodePath, PathLike } from '@astrale-os/kernel-core/path';
3
+ import type { Key } from '@astrale-os/kernel-dsl/v1/addressing';
4
+ import type { Call, Input } from '../client/index.js';
4
5
  import type { RequestOptions } from '../transport/index.js';
5
6
  import type { PolicyDecisionInput } from './authorization.js';
6
7
  import type { DelegateOptions, MintOptions, ImpersonateOptions } from './credential.js';
7
8
  import type { WhoisInput } from './identity.js';
8
9
  import type { RegisterRequest } from './register.js';
9
10
  export type AuthCall = (target: PathLike, input: Input, options?: RequestOptions) => Promise<Input>;
11
+ /** Current admission of one remote Call; the target has not been executed. */
12
+ export interface FunctionAdmission {
13
+ readonly callable: Key.Callable;
14
+ readonly receiver?: NodePath;
15
+ }
16
+ export interface AdmissionOptions extends RequestOptions {
17
+ /** Intersect the caller's Grant; defaults to explicit session attenuation, then self. */
18
+ readonly attenuation?: UnresolvedIdentityExpr;
19
+ }
10
20
  export interface AuthApi {
21
+ /** Check access and input without executing an installed remote callable. */
22
+ admit(call: Call, options?: AdmissionOptions): Promise<FunctionAdmission>;
11
23
  register(input: RegisterRequest, options?: RequestOptions): Promise<RegisterResult>;
12
24
  whoami(options?: RequestOptions): Promise<Identity & Authentication>;
13
25
  whois(input: WhoisInput, options?: RequestOptions): Promise<(Identity & Authentication) | null>;
@@ -18,5 +30,5 @@ export interface AuthApi {
18
30
  mint(input: MintOptions, options?: RequestOptions): Promise<MintedCredential>;
19
31
  delegate(identity: IdentityId, input: DelegateOptions, options?: RequestOptions): Promise<MintedCredential>;
20
32
  }
21
- /** Bind the current Core identity syscalls without recreating legacy grant-edge verbs. */
22
- export declare function createAuth(call: AuthCall): AuthApi;
33
+ /** Internal composition over callbacks owned by the Session or its bound view. */
34
+ export declare function createAuth(call: AuthCall, admit: AuthApi['admit']): AuthApi;
package/dist/auth/auth.js CHANGED
@@ -2,11 +2,10 @@ import { authorizationApi } from './authorization.js';
2
2
  import { credentialApi } from './credential.js';
3
3
  import { identityApi } from './identity.js';
4
4
  import { registerApi } from './register.js';
5
- /** Bind the current Core identity syscalls without recreating legacy grant-edge verbs. */
6
- export function createAuth(call) {
7
- if (typeof call !== 'function')
8
- throw new TypeError('Auth call capability is invalid.');
5
+ /** Internal composition over callbacks owned by the Session or its bound view. */
6
+ export function createAuth(call, admit) {
9
7
  return Object.freeze({
8
+ admit,
10
9
  ...registerApi(call),
11
10
  ...identityApi(call),
12
11
  ...authorizationApi(call),
@@ -1,4 +1,4 @@
1
- export { createAuth, type AuthApi, type AuthCall } from './auth.js';
1
+ export type { AuthApi, AdmissionOptions, FunctionAdmission } from './auth.js';
2
2
  export { IDENTITY_CAN_PATH, type PolicyDecisionInput } from './authorization.js';
3
3
  export { IDENTITY_MINT_PATH, IDENTITY_IMPERSONATE_PATH, type DelegateOptions, type MintOptions, type ImpersonateOptions, } from './credential.js';
4
4
  export { IDENTITY_WHOAMI_PATH, IDENTITY_WHOIS_PATH, type WhoisInput } from './identity.js';
@@ -1,4 +1,3 @@
1
- export { createAuth } from './auth.js';
2
1
  export { IDENTITY_CAN_PATH } from './authorization.js';
3
2
  export { IDENTITY_MINT_PATH, IDENTITY_IMPERSONATE_PATH, } from './credential.js';
4
3
  export { IDENTITY_WHOAMI_PATH, IDENTITY_WHOIS_PATH } from './identity.js';
@@ -0,0 +1,18 @@
1
+ import type { invocation } from '@astrale-os/kernel-protocol';
2
+ import type { AdmissionOptions, FunctionAdmission } from '../auth/index.js';
3
+ import type { Client } from '../client/index.js';
4
+ import type { SchemaOptions } from '../schema/schema.js';
5
+ import type { Fetch } from '../transport/http/index.js';
6
+ import type { SessionOperation, SessionPolicy } from './context/index.js';
7
+ import type { SessionAuth } from './routing/index.js';
8
+ export interface FunctionAdmissionDependencies {
9
+ readonly kernel: string;
10
+ readonly auth?: SessionAuth;
11
+ readonly source: () => Client;
12
+ readonly fetch: Fetch;
13
+ readonly policy: Readonly<SessionPolicy>;
14
+ readonly limits: SchemaOptions;
15
+ readonly maximumResponseBytes: number;
16
+ }
17
+ /** Check a remote Call through the existing Domain exchange and Kernel admission protocols. */
18
+ export declare function admitFunction(dependencies: FunctionAdmissionDependencies, call: invocation.Call, options: AdmissionOptions | undefined, operation: SessionOperation): Promise<FunctionAdmission>;
@@ -0,0 +1,117 @@
1
+ import { grant } from '@astrale-os/kernel-core/auth';
2
+ import { targetPath } from '@astrale-os/kernel-core/callable';
3
+ import { Path } from '@astrale-os/kernel-core/path';
4
+ import { admitOutput } from '@astrale-os/kernel-core/schema/kernel/syscalls/contracts';
5
+ import { function as functions } from '@astrale-os/kernel-core/schema/kernel/syscalls/references';
6
+ import { Key } from '@astrale-os/kernel-dsl/v1/addressing';
7
+ import { codecs, issuer } from '@astrale-os/kernel-protocol';
8
+ import { credentialApi } from '../auth/credential.js';
9
+ import { identityApi } from '../auth/identity.js';
10
+ import { ClientError } from '../errors/index.js';
11
+ import { createSchema } from '../schema/index.js';
12
+ import { allowEndpoint, runSessionOperation, sessionTransportOptions } from './context/index.js';
13
+ import { boundedResponse, requireExactResponse } from './discovery/index.js';
14
+ import { matchesCallable } from './reference.js';
15
+ import { requireResultKind, resolveAuth } from './routing/index.js';
16
+ const ADMIT = Path.staticMethod(Path.project(functions.admit.owner), functions.admit.name);
17
+ /** Check a remote Call through the existing Domain exchange and Kernel admission protocols. */
18
+ export async function admitFunction(dependencies, call, options, operation) {
19
+ const target = Path.parse(targetPath(call.target));
20
+ const origin = callableOrigin(target);
21
+ const attenuation = options?.attenuation === undefined
22
+ ? undefined
23
+ : grant.acceptUnresolved({ v: 1, expr: options.attenuation }).expr;
24
+ const effective = await resolveAuth(dependencies.auth, call, operation);
25
+ if (effective.credential === undefined || effective.delegate === undefined) {
26
+ throw new ClientError('Function admission requires an authenticated session.');
27
+ }
28
+ // Resolve once for the intended Call, then retain that exact caller across every helper syscall.
29
+ const client = dependencies.source();
30
+ const caller = client.as(effective.credential);
31
+ const dispatch = (input) => runSessionOperation(operation, () => caller.dispatch(input, {
32
+ ...sessionTransportOptions(operation),
33
+ delegate: effective.delegate,
34
+ }));
35
+ const callIdentity = async (target, input) => requireResultKind('value', await dispatch({ target, input })).value;
36
+ const identity = identityApi(callIdentity);
37
+ const credentials = credentialApi(callIdentity);
38
+ const schema = createSchema(dispatch, dependencies.limits);
39
+ const [domain, self] = await Promise.all([schema.inspect(origin), identity.whoami()]);
40
+ const remote = domain.publication;
41
+ if (remote === null || remote.identity.issuer === dependencies.kernel) {
42
+ throw new ClientError('Function admission through token exchange requires a remote Domain.');
43
+ }
44
+ const configuration = issuer.acceptConfiguration(await fetchJson(dependencies, new URL(issuer.paths(remote.identity.issuer).configuration, remote.identity.issuer).href, operation), remote.identity.issuer);
45
+ const endpoint = configuration.token_exchange_endpoint;
46
+ if (endpoint === undefined) {
47
+ throw new ClientError('The installed Domain does not advertise token exchange.');
48
+ }
49
+ allowEndpoint(endpoint, dependencies.policy);
50
+ const credential = await credentials.delegate(self.id, {
51
+ audience: remote.identity.issuer,
52
+ ttlSeconds: effective.delegate.ttlSeconds,
53
+ attenuation: attenuation ?? effective.delegate.attenuation ?? { kind: 'identity', self: true },
54
+ });
55
+ const exchanged = issuer.exchange.acceptResponse(await fetchJson(dependencies, endpoint, operation, credential));
56
+ if (exchanged.expiresAt * 1_000 <= Date.now()) {
57
+ throw new ClientError('Domain token exchange returned an expired credential.');
58
+ }
59
+ const result = await runSessionOperation(operation, () => client
60
+ .as(exchanged.token)
61
+ .dispatch({ target: ADMIT, input: { call, credential } }, { ...sessionTransportOptions(operation), delegate: effective.delegate }));
62
+ const output = admitOutput.parse(requireResultKind('value', result).value);
63
+ const callable = Key(output.callable);
64
+ if (!matchesCallable(target, callable)) {
65
+ throw new ClientError('Function admission returned a different callable.');
66
+ }
67
+ const receiver = output.receiver === undefined ? undefined : Path.parse(output.receiver);
68
+ const method = target.ast.steps.at(-1);
69
+ const instance = method?.kind === 'method' && method.dispatch === 'instance';
70
+ if (instance !== (receiver !== undefined) ||
71
+ (receiver !== undefined &&
72
+ (receiver.ast.anchor.kind !== 'id' ||
73
+ receiver.ast.steps.length !== 0 ||
74
+ (target.ast.anchor.kind === 'id' &&
75
+ target.ast.steps.length === 1 &&
76
+ receiver.ast.anchor.id !== target.ast.anchor.id)))) {
77
+ throw new ClientError('Function admission returned a different receiver.');
78
+ }
79
+ return Object.freeze({ callable, ...(receiver === undefined ? {} : { receiver: receiver.raw }) });
80
+ }
81
+ function callableOrigin(path) {
82
+ const last = path.ast.steps.at(-1);
83
+ if (last?.kind === 'method' && last.dispatch === 'instance')
84
+ return Key.origin(last.class);
85
+ if (path.ast.anchor.kind === 'domain')
86
+ return path.ast.anchor.origin;
87
+ throw new ClientError('Function admission requires a Domain-qualified callable target.');
88
+ }
89
+ async function fetchJson(dependencies, url, operation, credential) {
90
+ allowEndpoint(url, dependencies.policy);
91
+ return runSessionOperation(operation, async (signal) => {
92
+ const init = {
93
+ method: credential === undefined ? 'GET' : 'POST',
94
+ headers: {
95
+ accept: 'application/json',
96
+ ...(credential === undefined ? {} : { authorization: `Bearer ${credential}` }),
97
+ },
98
+ credentials: 'omit',
99
+ cache: 'no-store',
100
+ referrerPolicy: 'no-referrer',
101
+ redirect: 'manual',
102
+ signal,
103
+ };
104
+ const response = await dependencies.fetch(url, init);
105
+ try {
106
+ requireExactResponse(response, url, 'Domain token exchange');
107
+ if (!response.ok) {
108
+ throw new ClientError(`Domain ${credential === undefined ? 'discovery' : 'token exchange'} returned HTTP ${response.status}.`);
109
+ }
110
+ return codecs.json.decode(await boundedResponse(response, dependencies.maximumResponseBytes, signal));
111
+ }
112
+ finally {
113
+ // Also release unread bodies rejected by URL, status, or declared-size validation.
114
+ void response.body?.cancel().catch(() => undefined);
115
+ }
116
+ });
117
+ }
@@ -1,17 +1,18 @@
1
1
  import type { IssuerId } from '@astrale-os/kernel-core/auth';
2
+ import type { AuthApi } from '../auth/index.js';
2
3
  import type { SchemaApi } from '../schema/index.js';
3
4
  import type { SessionControlOptions } from './context/index.js';
4
5
  import type { CallableReference, InputOfReference, OutputOfReference } from './reference.js';
5
6
  import type { SessionRequestOptions } from './routing/index.js';
6
7
  import type { ClientSession } from './session.js';
7
8
  import type { ViewCatalog } from './views/index.js';
8
- import { type AuthApi } from '../auth/index.js';
9
9
  import { type Binary, type Call, type Input, type Result, type Stream } from '../client/index.js';
10
10
  import { type GraphApi } from '../graph/index.js';
11
11
  /** Exact live Session surface captured by one credential-bound Kernel view. */
12
12
  export interface BoundSessionSource {
13
13
  readonly kernel: IssuerId;
14
14
  readonly schema: SchemaApi;
15
+ readonly auth: Pick<AuthApi, 'admit'>;
15
16
  dispatch(call: Call, options?: SessionRequestOptions): Promise<Result>;
16
17
  call(call: Call, options?: SessionRequestOptions): Promise<Input>;
17
18
  invoke<const Reference extends CallableReference<unknown>>(reference: Reference, input: InputOfReference<Reference>, options?: SessionRequestOptions): Promise<OutputOfReference<Reference>>;
@@ -1,4 +1,4 @@
1
- import { createAuth } from '../auth/index.js';
1
+ import { createAuth } from '../auth/auth.js';
2
2
  import { call as createCall, } from '../client/index.js';
3
3
  import { createGraph } from '../graph/index.js';
4
4
  /** Capture one Session into the ordinary graph, auth, and invocation Kernel journey. */
@@ -7,6 +7,7 @@ export function bindSession(source, controls) {
7
7
  invalid();
8
8
  const admittedControls = admitControls(controls);
9
9
  const dispatchSource = capture(source, 'dispatch');
10
+ const admitSource = capture(source.auth, 'admit');
10
11
  const callSource = capture(source, 'call');
11
12
  const invokeSource = capture(source, 'invoke');
12
13
  const streamSource = capture(source, 'stream');
@@ -14,6 +15,7 @@ export function bindSession(source, controls) {
14
15
  const viewsForSource = capture(source, 'viewsFor');
15
16
  const schemaSource = captureSchema(source.schema);
16
17
  const dispatch = (input, options) => dispatchSource(input, requestOptions(options, admittedControls));
18
+ const admit = (input, options) => admitSource(input, mergeOptions(options, admittedControls));
17
19
  const call = (input, options) => callSource(input, requestOptions(options, admittedControls));
18
20
  const invoke = (reference, input, options) => invokeSource(reference, input, requestOptions(options, admittedControls));
19
21
  const stream = (input, options) => streamSource(input, requestOptions(options, admittedControls));
@@ -26,7 +28,7 @@ export function bindSession(source, controls) {
26
28
  const dependencies = (origin, options) => schemaSource.dependencies(origin, controlOptions(options, admittedControls));
27
29
  const schema = Object.freeze({ install, uninstall, inspect, bundle, dependencies });
28
30
  const graph = createGraph(call);
29
- const auth = createAuth((target, input, options) => call(createCall(target, input), options));
31
+ const auth = createAuth((target, input, options) => call(createCall(target, input), options), admit);
30
32
  return Object.freeze({
31
33
  ...graph,
32
34
  kernel: source.kernel,
@@ -4,6 +4,7 @@ import type { Fetch } from '../../transport/http/index.js';
4
4
  import type { SessionOperation, SessionPolicy } from '../context/index.js';
5
5
  import type { SessionSnapshot } from './snapshot.js';
6
6
  export type { SessionSnapshot } from './snapshot.js';
7
+ export { boundedResponse, requireExactResponse } from './publication.js';
7
8
  export interface SessionDiscovery {
8
9
  readonly kernel: IssuerId;
9
10
  publication(operation: SessionOperation): Promise<publication.Publication>;
@@ -1,6 +1,7 @@
1
1
  import { BundleDiscovery } from './bundle.js';
2
2
  import { SessionDiscovery as SessionDiscoveryImplementation } from './discovery.js';
3
3
  import { PublicationDiscovery } from './publication.js';
4
+ export { boundedResponse, requireExactResponse } from './publication.js';
4
5
  export function createSessionDiscovery(options) {
5
6
  return new SessionDiscoveryImplementation(options.kernel, options.policy, new PublicationDiscovery({
6
7
  kernel: options.kernel,
@@ -37,4 +37,5 @@ export declare function reference<const Callable extends ResolvedFunction | Exec
37
37
  /** Project one exact resolved instance Method into a receiver-bound typed Client reference. */
38
38
  export declare function reference<const Callable extends ExecutableInstanceMethod>(domain: Pick<Domain, 'origin' | 'revision'>, callable: Callable): InstanceCallableReference<ReferenceInput<Callable>, ReferenceOutput<Callable>>;
39
39
  export declare function admitReference(input: CallableReference<unknown>): CallableReference<unknown>;
40
+ export declare function matchesCallable(target: PathValue, callable: KeyType.Callable): boolean;
40
41
  export {};
@@ -52,7 +52,7 @@ export function admitReference(input) {
52
52
  outputMode: input.outputMode,
53
53
  });
54
54
  }
55
- function matchesCallable(target, callable) {
55
+ export function matchesCallable(target, callable) {
56
56
  const coordinate = callableAddress(callable);
57
57
  const { anchor, steps } = target.ast;
58
58
  const last = steps.at(-1);
@@ -2,6 +2,7 @@ import type { IssuerId } from '@astrale-os/kernel-core/auth/issuer';
2
2
  import type { PathLike } from '@astrale-os/kernel-core/path';
3
3
  import type { Domain } from '@astrale-os/kernel-dsl/v1/domain';
4
4
  import type { publication } from '@astrale-os/kernel-protocol';
5
+ import type { AuthApi } from '../auth/index.js';
5
6
  import type { Call, Input, Result } from '../client/index.js';
6
7
  import type { DomainBinding, GraphApi } from '../graph/index.js';
7
8
  import type { ClientFactory, ClientPool as ClientPoolType } from '../pool/index.js';
@@ -42,6 +43,7 @@ export declare class ClientSession {
42
43
  readonly kernel: IssuerId;
43
44
  readonly schema: SchemaApi;
44
45
  readonly graph: GraphApi;
46
+ readonly auth: AuthApi;
45
47
  private readonly ownedPool?;
46
48
  private readonly discovery;
47
49
  private readonly dispatcher;
@@ -1,6 +1,7 @@
1
1
  import { Path } from '@astrale-os/kernel-core/path';
2
2
  import { callableFingerprint } from '@astrale-os/kernel-dsl/v1/schema/fingerprint';
3
- import { Client } from '../client/index.js';
3
+ import { createAuth } from '../auth/auth.js';
4
+ import { Client, acceptCall } from '../client/index.js';
4
5
  import { SessionError } from '../errors/index.js';
5
6
  import { createDomainBinding } from '../graph/domain/binding.js';
6
7
  import { createGraph } from '../graph/index.js';
@@ -9,7 +10,8 @@ import { createSchema, DEFAULT_SCHEMA_LIFECYCLE_TIMEOUT_MS } from '../schema/ind
9
10
  import { AutoTransport } from '../transport/auto/index.js';
10
11
  import { HttpTransport } from '../transport/http/index.js';
11
12
  import { WebSocketTransport } from '../transport/websocket/index.js';
12
- import { admitControlOptions, admitPolicy, createSessionOperation, DEFAULT_MAXIMUM_BUNDLE_BYTES, DEFAULT_MAXIMUM_PUBLICATION_BYTES, DEFAULT_MAXIMUM_RESPONSE_BYTES, DEFAULT_TIMEOUT_MS, admitKernel, kernelInvocationEndpoint, platformDuration, positive, } from './context/index.js';
13
+ import { admitFunction } from './admission.js';
14
+ import { admitControlOptions, admitPolicy, createSessionOperation, DEFAULT_MAXIMUM_BUNDLE_BYTES, DEFAULT_MAXIMUM_PUBLICATION_BYTES, DEFAULT_MAXIMUM_RESPONSE_BYTES, DEFAULT_TIMEOUT_MS, admitKernel, allowEndpoint, kernelInvocationEndpoint, platformDuration, positive, } from './context/index.js';
13
15
  import { createSessionDiscovery } from './discovery/index.js';
14
16
  import { admitReference } from './reference.js';
15
17
  import { admitEnvelopeTransport, admitRequestOptions, admitSessionAuth, requireResultKind, RouteCache, SessionDispatcher, } from './routing/index.js';
@@ -20,6 +22,7 @@ export class ClientSession {
20
22
  kernel;
21
23
  schema;
22
24
  graph;
25
+ auth;
23
26
  ownedPool;
24
27
  discovery;
25
28
  dispatcher;
@@ -80,12 +83,25 @@ export class ClientSession {
80
83
  acquisitionOperation: () => this.operation(undefined),
81
84
  });
82
85
  this.routes = new RouteCache(policy.maximumRouteAgeMs, undefined, options.routeStore);
86
+ const auth = admitSessionAuth(options.auth);
87
+ const admission = {
88
+ kernel: this.kernel,
89
+ auth,
90
+ source: () => {
91
+ allowEndpoint(sourceEndpoint, policy);
92
+ return pool.clientFor({ transport: 'http', url: sourceEndpoint });
93
+ },
94
+ fetch: fetchImpl,
95
+ policy,
96
+ limits: { maximumPublicationBytes, maximumBundleBytes },
97
+ maximumResponseBytes,
98
+ };
83
99
  this.dispatcher = new SessionDispatcher({
84
100
  kernel: this.kernel,
85
101
  sourceEndpoint,
86
102
  pool,
87
103
  websocketAvailable,
88
- auth: admitSessionAuth(options.auth),
104
+ auth,
89
105
  cache: this.routes,
90
106
  policy,
91
107
  envelopeTransport: admitEnvelopeTransport(options.envelopeTransport ?? 'http'),
@@ -97,6 +113,10 @@ export class ClientSession {
97
113
  lifecycleTimeoutMs: schemaLifecycleTimeoutMs,
98
114
  });
99
115
  this.graph = createGraph((call, options) => this.call(call, options));
116
+ this.auth = createAuth((target, input, options) => this.call({ target, input }, options), (call, options) => {
117
+ const operation = this.operation(admitControlOptions(options));
118
+ return admitFunction(admission, acceptCall(call), options, operation);
119
+ });
100
120
  }
101
121
  /** Bind one admitted DSL Domain to authenticated graph projection and Method dispatch. */
102
122
  bind(domain) {
@@ -12,6 +12,13 @@ void request;
12
12
  void snapshot;
13
13
  const observedPublication = session.publication(control);
14
14
  void observedPublication;
15
+ const admitted = session.auth.admit({
16
+ target: Path.parse('/:example.test:function.write'),
17
+ input: {},
18
+ }, { attenuation: { kind: 'identity', self: true }, ...control });
19
+ void admitted;
20
+ // @ts-expect-error Admission belongs to Auth, not the top-level Session.
21
+ void session.admit({ target: Path.parse('/:example.test:function.write'), input: {} });
15
22
  const credentials = createSessionCredentialProvider({
16
23
  ttlSeconds: 60,
17
24
  mint: async () => minted,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/kernel-client",
3
- "version": "0.6.0-beta.70",
3
+ "version": "0.6.0-beta.71",
4
4
  "description": "Universal Client — protocol-first, transport-agnostic",
5
5
  "keywords": [
6
6
  "astrale",
@@ -65,18 +65,18 @@
65
65
  "access": "public"
66
66
  },
67
67
  "dependencies": {
68
- "@astrale-os/kernel-core": "0.9.0-beta.53",
69
- "@astrale-os/kernel-dsl": "0.2.0-beta.38",
70
- "@astrale-os/kernel-protocol": "0.5.0-beta.59",
68
+ "@astrale-os/kernel-core": "0.9.0-beta.54",
69
+ "@astrale-os/kernel-dsl": "0.2.0-beta.39",
70
+ "@astrale-os/kernel-protocol": "0.5.0-beta.60",
71
71
  "@tanstack/pacer": "0.20.1",
72
72
  "msgpackr": "^2.0.5"
73
73
  },
74
74
  "devDependencies": {
75
- "@astrale-os/kernel-server": "0.5.0-beta.61",
75
+ "@astrale-os/kernel-server": "0.5.0-beta.62",
76
76
  "@astrale/typescript-config": "npm:@jsr/astrale__typescript-config@~1.1.0",
77
77
  "@types/node": "^22.0.0",
78
78
  "typescript": "7.0.2",
79
- "vitest": "^4.1.10"
79
+ "vitest": "^5.0.1"
80
80
  },
81
81
  "scripts": {
82
82
  "build": "tsc",