@astrale-os/sdk 0.5.0-beta.95 → 0.5.0-beta.96
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/dist/application/action/context.d.ts +11 -0
- package/dist/application/requirements/index.d.ts +4 -1
- package/dist/application/requirements/index.js +5 -2
- package/dist/application/requirements/profiles.d.ts +12 -0
- package/dist/application/requirements/profiles.js +41 -0
- package/dist/application/requirements/requirement.d.ts +8 -1
- package/dist/deployment/build/compile.js +31 -0
- package/dist/execution/identity/authentication.js +1 -1
- package/dist/execution/identity/exchange.d.ts +1 -10
- package/dist/execution/identity/exchange.js +6 -33
- package/dist/execution/identity/identity.js +2 -5
- package/dist/execution/identity/index.d.ts +1 -1
- package/dist/execution/identity/index.js +1 -1
- package/dist/execution/index.d.ts +1 -1
- package/dist/execution/invocation/admission/authentication.d.ts +1 -0
- package/dist/execution/invocation/admission/authentication.js +3 -2
- package/dist/execution/invocation/dispatch/context.d.ts +1 -0
- package/dist/execution/invocation/dispatch/context.js +1 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0-beta.96](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.95...sdk-v0.5.0-beta.96) (2026-08-31)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* keep external token exchange caller-only ([#366](https://github.com/astrale-os/sdk/issues/366)) ([45d39de](https://github.com/astrale-os/sdk/commit/45d39debce782d1d4f76cf75e9ecf214ca57ddba))
|
|
9
|
+
|
|
3
10
|
## [0.5.0-beta.95](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.94...sdk-v0.5.0-beta.95) (2026-08-30)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -34,25 +34,36 @@ export interface DomainGraphExecutor<DomainValue extends Domain = Domain> {
|
|
|
34
34
|
readonly mutate: MutationExecutor<DomainValue>;
|
|
35
35
|
}
|
|
36
36
|
export type DomainGraphExecutors<DomainValue extends Domain = Domain> = Readonly<Record<'caller' | 'self' | 'union', DomainGraphExecutor<DomainValue>>>;
|
|
37
|
+
/** Explicit full Kernel sessions. No authority mode is selected implicitly. */
|
|
38
|
+
export type DomainKernelSessions = Readonly<Record<'caller' | 'self' | 'union', BoundClientSession>>;
|
|
37
39
|
type AuthorityOf<Callable, DomainValue extends Domain> = Callable extends {
|
|
38
40
|
readonly auth: 'anonymous';
|
|
39
41
|
} ? {
|
|
40
42
|
readonly caller: AnonymousCaller;
|
|
41
43
|
readonly client: null;
|
|
44
|
+
readonly kernel: null;
|
|
42
45
|
readonly graph: null;
|
|
43
46
|
readonly query?: never;
|
|
44
47
|
readonly mutate?: never;
|
|
45
48
|
} | {
|
|
46
49
|
readonly caller: AuthenticatedCaller;
|
|
50
|
+
/** Caller-only Kernel client. Privileged Domain work must select kernel.self explicitly. */
|
|
47
51
|
readonly client: BoundClientSession;
|
|
52
|
+
readonly kernel: DomainKernelSessions;
|
|
48
53
|
readonly graph: DomainGraphExecutors<DomainValue>;
|
|
54
|
+
/** Caller-only convenience executor. */
|
|
49
55
|
readonly query: QueryExecutor<DomainValue>;
|
|
56
|
+
/** Caller-only convenience executor. */
|
|
50
57
|
readonly mutate: MutationExecutor<DomainValue>;
|
|
51
58
|
} : {
|
|
52
59
|
readonly caller: AuthenticatedCaller;
|
|
60
|
+
/** Caller-only Kernel client. Privileged Domain work must select kernel.self explicitly. */
|
|
53
61
|
readonly client: BoundClientSession;
|
|
62
|
+
readonly kernel: DomainKernelSessions;
|
|
54
63
|
readonly graph: DomainGraphExecutors<DomainValue>;
|
|
64
|
+
/** Caller-only convenience executor. */
|
|
55
65
|
readonly query: QueryExecutor<DomainValue>;
|
|
66
|
+
/** Caller-only convenience executor. */
|
|
56
67
|
readonly mutate: MutationExecutor<DomainValue>;
|
|
57
68
|
};
|
|
58
69
|
type SelfOf<Callable> = Callable extends ResolvedMethod<unknown, unknown, false> ? {
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import type { AuthorityRequirementsInput } from './authority.js';
|
|
2
2
|
import type { ClassRequirementInput } from './classes.js';
|
|
3
3
|
import type { FunctionRequirementTarget } from './functions.js';
|
|
4
|
+
import type { CapabilityProfileRequirementInput } from './profiles.js';
|
|
4
5
|
import type { Requirements } from './requirement.js';
|
|
5
|
-
export type { AuthorityRequirements, ClassRequirement, Requirements } from './requirement.js';
|
|
6
|
+
export type { AuthorityRequirements, CapabilityProfileRequirement, ClassRequirement, Requirements, } from './requirement.js';
|
|
6
7
|
export { ClassOperationOrder, type ClassOperation, type ClassRequirementInput } from './classes.js';
|
|
7
8
|
export type { FunctionRequirementTarget } from './functions.js';
|
|
8
9
|
export type { AuthorityRequirementsInput } from './authority.js';
|
|
10
|
+
export type { CapabilityProfileRequirementInput } from './profiles.js';
|
|
9
11
|
export interface RequirementsInput {
|
|
10
12
|
readonly functions?: readonly FunctionRequirementTarget[];
|
|
11
13
|
readonly classes?: readonly ClassRequirementInput[];
|
|
12
14
|
readonly authority?: AuthorityRequirementsInput;
|
|
15
|
+
readonly profiles?: readonly CapabilityProfileRequirementInput[];
|
|
13
16
|
}
|
|
14
17
|
/** Capture canonical dependency requirements; Build proves the pinned dependency closure. */
|
|
15
18
|
export declare function requirements(input?: RequirementsInput): Requirements;
|
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { captureAuthority } from './authority.js';
|
|
2
2
|
import { captureClasses } from './classes.js';
|
|
3
3
|
import { captureFunctions } from './functions.js';
|
|
4
|
+
import { captureProfiles } from './profiles.js';
|
|
4
5
|
export { ClassOperationOrder } from './classes.js';
|
|
5
6
|
const admittedRequirements = new WeakSet();
|
|
6
7
|
/** Capture canonical dependency requirements; Build proves the pinned dependency closure. */
|
|
7
8
|
export function requirements(input = {}) {
|
|
8
9
|
if (input === null || typeof input !== 'object' || Array.isArray(input))
|
|
9
10
|
invalid();
|
|
10
|
-
if (Reflect.ownKeys(input).some((key) => key !== 'functions' && key !== 'classes' && key !== 'authority')) {
|
|
11
|
+
if (Reflect.ownKeys(input).some((key) => key !== 'functions' && key !== 'classes' && key !== 'authority' && key !== 'profiles')) {
|
|
11
12
|
invalid();
|
|
12
13
|
}
|
|
13
14
|
const functions = captureFunctions(input.functions);
|
|
14
15
|
const classes = captureClasses(input.classes);
|
|
15
16
|
const authority = captureAuthority(input.authority);
|
|
17
|
+
const profiles = captureProfiles(input.profiles);
|
|
16
18
|
const value = Object.freeze({
|
|
17
19
|
functions,
|
|
18
20
|
classes,
|
|
21
|
+
profiles,
|
|
19
22
|
...(authority === undefined ? {} : { authority }),
|
|
20
23
|
});
|
|
21
24
|
admittedRequirements.add(value);
|
|
@@ -25,5 +28,5 @@ export function isRequirements(input) {
|
|
|
25
28
|
return input !== null && typeof input === 'object' && admittedRequirements.has(input);
|
|
26
29
|
}
|
|
27
30
|
function invalid() {
|
|
28
|
-
throw new TypeError('Requirements definition may contain only functions, classes, and
|
|
31
|
+
throw new TypeError('Requirements definition may contain only functions, classes, authority, and profiles.');
|
|
29
32
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ResolvedCoreDefinition } from '../../platform/schema/index.js';
|
|
2
|
+
import type { AuthorityRequirementsInput } from './authority.js';
|
|
3
|
+
import type { ClassRequirementInput } from './classes.js';
|
|
4
|
+
import type { FunctionRequirementTarget } from './functions.js';
|
|
5
|
+
import type { CapabilityProfileRequirement } from './requirement.js';
|
|
6
|
+
export interface CapabilityProfileRequirementInput {
|
|
7
|
+
readonly subject: Pick<ResolvedCoreDefinition, 'ref'>;
|
|
8
|
+
readonly functions?: readonly FunctionRequirementTarget[];
|
|
9
|
+
readonly classes?: readonly ClassRequirementInput[];
|
|
10
|
+
readonly authority?: AuthorityRequirementsInput;
|
|
11
|
+
}
|
|
12
|
+
export declare function captureProfiles(input: readonly CapabilityProfileRequirementInput[] | undefined): readonly CapabilityProfileRequirement[];
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { acceptDefinitionRef, Key } from '../../platform/schema/index.js';
|
|
2
|
+
import { captureAuthority } from './authority.js';
|
|
3
|
+
import { captureClasses } from './classes.js';
|
|
4
|
+
import { captureFunctions } from './functions.js';
|
|
5
|
+
export function captureProfiles(input) {
|
|
6
|
+
if (input === undefined)
|
|
7
|
+
return Object.freeze([]);
|
|
8
|
+
if (!Array.isArray(input))
|
|
9
|
+
throw new TypeError('Requirement profiles must be an array.');
|
|
10
|
+
const profiles = input.map((entry) => {
|
|
11
|
+
if (entry === null || typeof entry !== 'object' || Array.isArray(entry))
|
|
12
|
+
invalid();
|
|
13
|
+
if (Reflect.ownKeys(entry).some((key) => key !== 'subject' && key !== 'functions' && key !== 'classes' && key !== 'authority')) {
|
|
14
|
+
invalid();
|
|
15
|
+
}
|
|
16
|
+
const admitted = acceptDefinitionRef(entry.subject?.ref);
|
|
17
|
+
if (admitted.kind !== 'core')
|
|
18
|
+
invalid();
|
|
19
|
+
const subject = admitted;
|
|
20
|
+
const functions = captureFunctions(entry.functions);
|
|
21
|
+
const classes = captureClasses(entry.classes);
|
|
22
|
+
const authority = captureAuthority(entry.authority);
|
|
23
|
+
if (functions.length === 0 && classes.length === 0 && authority === undefined)
|
|
24
|
+
invalid();
|
|
25
|
+
return Object.freeze({
|
|
26
|
+
subject,
|
|
27
|
+
functions,
|
|
28
|
+
classes,
|
|
29
|
+
...(authority === undefined ? {} : { authority }),
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
if (new Set(profiles.map(({ subject }) => Key.of(subject))).size !== profiles.length)
|
|
33
|
+
invalid();
|
|
34
|
+
return Object.freeze([...profiles].sort((left, right) => compare(Key.of(left.subject), Key.of(right.subject))));
|
|
35
|
+
}
|
|
36
|
+
function invalid() {
|
|
37
|
+
throw new TypeError('Capability profile requirement is invalid.');
|
|
38
|
+
}
|
|
39
|
+
function compare(left, right) {
|
|
40
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
41
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AuthorityOperation } from '../../platform/schema/index.js';
|
|
2
|
-
import type { ClassRef, Key } from '../../platform/schema/index.js';
|
|
2
|
+
import type { ClassRef, CoreRef, Key } from '../../platform/schema/index.js';
|
|
3
3
|
import type { ClassOperation } from './classes.js';
|
|
4
4
|
export interface ClassRequirement {
|
|
5
5
|
readonly class: ClassRef;
|
|
@@ -14,4 +14,11 @@ export interface Requirements {
|
|
|
14
14
|
readonly functions: readonly Key.Callable[];
|
|
15
15
|
readonly classes: readonly ClassRequirement[];
|
|
16
16
|
readonly authority?: AuthorityRequirements;
|
|
17
|
+
readonly profiles: readonly CapabilityProfileRequirement[];
|
|
18
|
+
}
|
|
19
|
+
export interface CapabilityProfileRequirement {
|
|
20
|
+
readonly subject: CoreRef;
|
|
21
|
+
readonly functions: readonly Key.Callable[];
|
|
22
|
+
readonly classes: readonly ClassRequirement[];
|
|
23
|
+
readonly authority?: AuthorityRequirements;
|
|
17
24
|
}
|
|
@@ -54,6 +54,27 @@ function compileRequirements(domain, input, sourceBundle) {
|
|
|
54
54
|
throw new TypeError('Class requirement is absent from the dependency closure.');
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
for (const profile of input?.profiles ?? []) {
|
|
58
|
+
const subject = domain.core.nodes[profile.subject.name];
|
|
59
|
+
if (profile.subject.origin !== domain.origin || subject === undefined) {
|
|
60
|
+
throw new TypeError('Capability profile subject must name one local Core Node.');
|
|
61
|
+
}
|
|
62
|
+
for (const key of profile.functions) {
|
|
63
|
+
requireDirectDependency(domain, key, 'Capability profile Function');
|
|
64
|
+
if (domain.callable(key) === undefined) {
|
|
65
|
+
throw new TypeError(`Capability profile Function ${key} is absent from the dependency closure.`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const requirement of profile.classes) {
|
|
69
|
+
const key = Key.of(requirement.class);
|
|
70
|
+
if (requirement.class.origin !== domain.origin) {
|
|
71
|
+
requireDirectDependency(domain, key, 'Capability profile Class');
|
|
72
|
+
}
|
|
73
|
+
if (domain.definition(requirement.class) === undefined) {
|
|
74
|
+
throw new TypeError('Capability profile Class is absent from the dependency closure.');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
57
78
|
const candidate = publication.admitRequirements({
|
|
58
79
|
capabilities: {
|
|
59
80
|
...(input === undefined || input.functions.length === 0
|
|
@@ -61,6 +82,16 @@ function compileRequirements(domain, input, sourceBundle) {
|
|
|
61
82
|
: { functions: input.functions }),
|
|
62
83
|
...(input === undefined || input.classes.length === 0 ? {} : { classes: input.classes }),
|
|
63
84
|
...(input?.authority === undefined ? {} : { authority: input.authority }),
|
|
85
|
+
...(input === undefined || input.profiles.length === 0
|
|
86
|
+
? {}
|
|
87
|
+
: {
|
|
88
|
+
profiles: input.profiles.map((profile) => ({
|
|
89
|
+
subject: profile.subject,
|
|
90
|
+
...(profile.functions.length === 0 ? {} : { functions: profile.functions }),
|
|
91
|
+
...(profile.classes.length === 0 ? {} : { classes: profile.classes }),
|
|
92
|
+
...(profile.authority === undefined ? {} : { authority: profile.authority }),
|
|
93
|
+
})),
|
|
94
|
+
}),
|
|
64
95
|
},
|
|
65
96
|
});
|
|
66
97
|
publication.validateRequirements(sourceBundle.root, sourceBundle.closure, candidate);
|
|
@@ -4,15 +4,6 @@ import type { IdentityNetworkPolicy, VerificationBasisResolver } from './jwks.js
|
|
|
4
4
|
import type { SigningMaterial } from './signing.js';
|
|
5
5
|
export interface ExchangeOptions {
|
|
6
6
|
readonly maximumTtlSeconds?: number;
|
|
7
|
-
/** Authority carried by the exchanged Domain credential. Defaults to the authenticated caller. */
|
|
8
|
-
readonly grantMode?: ExchangeGrantMode;
|
|
9
|
-
}
|
|
10
|
-
export type ExchangeGrantMode = 'caller' | 'union';
|
|
11
|
-
interface AcceptedExchangeOptions {
|
|
12
|
-
readonly maximumTtlSeconds: number;
|
|
13
|
-
readonly grantMode: ExchangeGrantMode;
|
|
14
7
|
}
|
|
15
8
|
export declare function maximumExchangeTtl(input: ExchangeOptions | undefined): number;
|
|
16
|
-
export declare function tokenExchange(issuer: IssuerId, subject: string, signing: SigningMaterial, policy: IdentityNetworkPolicy, verification: VerificationBasisResolver, maximumTtlSeconds: number
|
|
17
|
-
export declare function exchangeOptions(input: ExchangeOptions | undefined): AcceptedExchangeOptions;
|
|
18
|
-
export {};
|
|
9
|
+
export declare function tokenExchange(issuer: IssuerId, subject: string, signing: SigningMaterial, policy: IdentityNetworkPolicy, verification: VerificationBasisResolver, maximumTtlSeconds: number): exchange.Provider;
|
|
@@ -8,27 +8,21 @@ import { CredentialRejected, IssuerUnavailable } from './errors.js';
|
|
|
8
8
|
import { verifyCredential, verifyCredentialAgainst } from './jwks.js';
|
|
9
9
|
const DEFAULT_MAXIMUM_TTL_SECONDS = 300;
|
|
10
10
|
export function maximumExchangeTtl(input) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
function acceptExchangeOptions(input) {
|
|
14
|
-
if (input === undefined) {
|
|
15
|
-
return Object.freeze({ maximumTtlSeconds: DEFAULT_MAXIMUM_TTL_SECONDS, grantMode: 'caller' });
|
|
16
|
-
}
|
|
11
|
+
if (input === undefined)
|
|
12
|
+
return DEFAULT_MAXIMUM_TTL_SECONDS;
|
|
17
13
|
if (input === null ||
|
|
18
14
|
typeof input !== 'object' ||
|
|
19
15
|
Array.isArray(input) ||
|
|
20
|
-
Reflect.ownKeys(input).some((key) => key !== 'maximumTtlSeconds'
|
|
16
|
+
Reflect.ownKeys(input).some((key) => key !== 'maximumTtlSeconds')) {
|
|
21
17
|
throw new TypeError('Execution identity tokenExchange options are invalid.');
|
|
22
18
|
}
|
|
23
19
|
const value = input.maximumTtlSeconds ?? DEFAULT_MAXIMUM_TTL_SECONDS;
|
|
24
20
|
if (!Number.isSafeInteger(value) || value < 1) {
|
|
25
21
|
throw new TypeError('tokenExchange.maximumTtlSeconds must be a positive safe integer.');
|
|
26
22
|
}
|
|
27
|
-
|
|
28
|
-
return Object.freeze({ maximumTtlSeconds: value, grantMode: acceptExchangeGrantMode(grantMode) });
|
|
23
|
+
return value;
|
|
29
24
|
}
|
|
30
|
-
export function tokenExchange(issuer, subject, signing, policy, verification, maximumTtlSeconds
|
|
31
|
-
const acceptedGrantMode = acceptExchangeGrantMode(grantMode);
|
|
25
|
+
export function tokenExchange(issuer, subject, signing, policy, verification, maximumTtlSeconds) {
|
|
32
26
|
return Object.freeze({
|
|
33
27
|
async exchange(request, context) {
|
|
34
28
|
try {
|
|
@@ -51,7 +45,7 @@ export function tokenExchange(issuer, subject, signing, policy, verification, ma
|
|
|
51
45
|
const token = await new SignJWT({
|
|
52
46
|
grant: {
|
|
53
47
|
v: 1,
|
|
54
|
-
expr:
|
|
48
|
+
expr: { kind: 'identity', credential: carried.credential },
|
|
55
49
|
},
|
|
56
50
|
})
|
|
57
51
|
.setProtectedHeader({
|
|
@@ -87,27 +81,6 @@ export function tokenExchange(issuer, subject, signing, policy, verification, ma
|
|
|
87
81
|
},
|
|
88
82
|
});
|
|
89
83
|
}
|
|
90
|
-
export function exchangeOptions(input) {
|
|
91
|
-
return acceptExchangeOptions(input);
|
|
92
|
-
}
|
|
93
|
-
function exchangeGrant(mode, credential) {
|
|
94
|
-
const caller = Object.freeze({ kind: 'identity', credential });
|
|
95
|
-
if (mode === 'caller')
|
|
96
|
-
return caller;
|
|
97
|
-
return Object.freeze({
|
|
98
|
-
kind: 'union',
|
|
99
|
-
operands: Object.freeze([
|
|
100
|
-
Object.freeze({ kind: 'identity', self: true }),
|
|
101
|
-
caller,
|
|
102
|
-
]),
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
function acceptExchangeGrantMode(input) {
|
|
106
|
-
if (input !== 'caller' && input !== 'union') {
|
|
107
|
-
throw new TypeError('tokenExchange.grantMode must be caller or union.');
|
|
108
|
-
}
|
|
109
|
-
return input;
|
|
110
|
-
}
|
|
111
84
|
function requireProfile(input, profile) {
|
|
112
85
|
const expected = ['aud', 'delegation', 'exp', 'iat', 'iss', 'sub'];
|
|
113
86
|
const actual = Object.keys(input.claims).sort();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { admit, authenticate } from './authentication.js';
|
|
2
2
|
import { publicationDelivery } from './delivery.js';
|
|
3
3
|
import { httpIssuer } from './errors.js';
|
|
4
|
-
import {
|
|
4
|
+
import { maximumExchangeTtl, tokenExchange } from './exchange.js';
|
|
5
5
|
import { createVerificationBasisResolver } from './jwks.js';
|
|
6
6
|
import { signing } from './signing.js';
|
|
7
7
|
/** Create one stateless execution identity backed by an asymmetric private JWK. */
|
|
@@ -37,10 +37,7 @@ export function createIdentity(input) {
|
|
|
37
37
|
});
|
|
38
38
|
const exchangeProvider = input.tokenExchange === false
|
|
39
39
|
? undefined
|
|
40
|
-
: (()
|
|
41
|
-
const options = exchangeOptions(input.tokenExchange);
|
|
42
|
-
return tokenExchange(issuer, input.subject, material, policy, verification, options.maximumTtlSeconds, options.grantMode);
|
|
43
|
-
})();
|
|
40
|
+
: tokenExchange(issuer, input.subject, material, policy, verification, maximumExchangeTtl(input.tokenExchange));
|
|
44
41
|
return identity({
|
|
45
42
|
issuer,
|
|
46
43
|
subject: input.subject,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { createIdentity, identity, type Identity, type IdentityInput } from './identity.js';
|
|
2
|
-
export { maximumExchangeTtl, tokenExchange, type
|
|
2
|
+
export { maximumExchangeTtl, tokenExchange, type ExchangeOptions } from './exchange.js';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { createIdentity, identity } from './identity.js';
|
|
2
|
-
export { maximumExchangeTtl, tokenExchange
|
|
2
|
+
export { maximumExchangeTtl, tokenExchange } from './exchange.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { serve } from './serve.js';
|
|
2
2
|
export type { ExecutionContext, ServedApplication, ServeInput } from './serve.js';
|
|
3
|
-
export { createIdentity, type
|
|
3
|
+
export { createIdentity, type ExchangeOptions, type Identity, type IdentityInput, } from './identity/index.js';
|
|
4
4
|
export { InvocationError } from './invocation/index.js';
|
|
5
5
|
export type { InvocationErrorCode } from './invocation/index.js';
|
|
@@ -6,6 +6,7 @@ import { requireVia } from './authority.js';
|
|
|
6
6
|
const ANONYMOUS = Object.freeze({
|
|
7
7
|
caller: Object.freeze({ kind: 'anonymous' }),
|
|
8
8
|
client: null,
|
|
9
|
+
kernel: null,
|
|
9
10
|
graph: null,
|
|
10
11
|
close() { },
|
|
11
12
|
});
|
|
@@ -37,14 +38,14 @@ export async function authentication(callable, request, release, domain, authori
|
|
|
37
38
|
}
|
|
38
39
|
const caller = admitCaller(authenticated.caller);
|
|
39
40
|
const graphInput = admitGraph(authenticated.graph);
|
|
40
|
-
if (authenticated.client !== graphInput.
|
|
41
|
+
if (authenticated.client !== graphInput.caller)
|
|
41
42
|
invalid();
|
|
42
43
|
const graph = Object.freeze({
|
|
43
44
|
caller: bindSession(graphInput.caller),
|
|
44
45
|
self: bindSession(graphInput.self),
|
|
45
46
|
union: bindSession(graphInput.union),
|
|
46
47
|
});
|
|
47
|
-
return Object.freeze({ caller, client: graph.
|
|
48
|
+
return Object.freeze({ caller, client: graph.caller, graph, close });
|
|
48
49
|
}
|
|
49
50
|
catch (cause) {
|
|
50
51
|
if (close === undefined)
|
|
@@ -12,6 +12,7 @@ export interface DispatchContext {
|
|
|
12
12
|
readonly input: unknown;
|
|
13
13
|
readonly caller: Caller;
|
|
14
14
|
readonly client: BoundClientSession | null;
|
|
15
|
+
readonly kernel: Readonly<Record<'caller' | 'self' | 'union', BoundClientSession>> | null;
|
|
15
16
|
readonly graph: DomainGraphExecutors | null;
|
|
16
17
|
readonly query?: QueryExecutor;
|
|
17
18
|
readonly mutate?: MutationExecutor;
|
|
@@ -18,6 +18,7 @@ export function context(request, runtime, authentication, self) {
|
|
|
18
18
|
input: request.call.input,
|
|
19
19
|
caller: authentication.caller,
|
|
20
20
|
client,
|
|
21
|
+
kernel: authentication.graph,
|
|
21
22
|
graph: authentication.graph === null ? null : bindGraph(authentication.graph, runtime.loaded.domain),
|
|
22
23
|
...(client === null
|
|
23
24
|
? {}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/sdk",
|
|
3
|
-
"version": "0.5.0-beta.
|
|
3
|
+
"version": "0.5.0-beta.96",
|
|
4
4
|
"description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"astrale",
|
|
@@ -217,11 +217,11 @@
|
|
|
217
217
|
"registry": "https://registry.npmjs.org/"
|
|
218
218
|
},
|
|
219
219
|
"dependencies": {
|
|
220
|
-
"@astrale-os/kernel-client": "0.6.0-beta.
|
|
221
|
-
"@astrale-os/kernel-core": "0.9.0-beta.
|
|
222
|
-
"@astrale-os/kernel-dsl": "0.2.0-beta.
|
|
223
|
-
"@astrale-os/kernel-protocol": "0.5.0-beta.
|
|
224
|
-
"@astrale-os/kernel-server": "0.5.0-beta.
|
|
220
|
+
"@astrale-os/kernel-client": "0.6.0-beta.39",
|
|
221
|
+
"@astrale-os/kernel-core": "0.9.0-beta.29",
|
|
222
|
+
"@astrale-os/kernel-dsl": "0.2.0-beta.22",
|
|
223
|
+
"@astrale-os/kernel-protocol": "0.5.0-beta.32",
|
|
224
|
+
"@astrale-os/kernel-server": "0.5.0-beta.34",
|
|
225
225
|
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
226
226
|
"hono": "^4.13.2",
|
|
227
227
|
"jose": "^6.2.9",
|