@astrale-os/sdk 0.5.0-beta.85 → 0.5.0-beta.87

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 CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.5.0-beta.87](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.86...sdk-v0.5.0-beta.87) (2026-08-30)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * expose managed Domain token exchange ([#354](https://github.com/astrale-os/sdk/issues/354)) ([f7d97bc](https://github.com/astrale-os/sdk/commit/f7d97bc4016d263ccb7f966509775c26368a350f))
9
+
10
+ ## [0.5.0-beta.86](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.85...sdk-v0.5.0-beta.86) (2026-08-30)
11
+
12
+
13
+ ### Features
14
+
15
+ * support trusted Domain token-exchange authority ([#352](https://github.com/astrale-os/sdk/issues/352)) ([8bec391](https://github.com/astrale-os/sdk/commit/8bec3915afad8aef6fab66d6e8906ea89ca8ad39))
16
+
3
17
  ## [0.5.0-beta.85](https://github.com/astrale-os/sdk/compare/sdk-v0.5.0-beta.84...sdk-v0.5.0-beta.85) (2026-08-30)
4
18
 
5
19
 
@@ -4,6 +4,15 @@ 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;
7
14
  }
8
15
  export declare function maximumExchangeTtl(input: ExchangeOptions | undefined): number;
9
- export declare function tokenExchange(issuer: IssuerId, subject: string, signing: SigningMaterial, policy: IdentityNetworkPolicy, verification: VerificationBasisResolver, maximumTtlSeconds: number): exchange.Provider;
16
+ export declare function tokenExchange(issuer: IssuerId, subject: string, signing: SigningMaterial, policy: IdentityNetworkPolicy, verification: VerificationBasisResolver, maximumTtlSeconds: number, grantMode?: ExchangeGrantMode): exchange.Provider;
17
+ export declare function exchangeOptions(input: ExchangeOptions | undefined): AcceptedExchangeOptions;
18
+ export {};
@@ -8,21 +8,27 @@ 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
- if (input === undefined)
12
- return DEFAULT_MAXIMUM_TTL_SECONDS;
11
+ return acceptExchangeOptions(input).maximumTtlSeconds;
12
+ }
13
+ function acceptExchangeOptions(input) {
14
+ if (input === undefined) {
15
+ return Object.freeze({ maximumTtlSeconds: DEFAULT_MAXIMUM_TTL_SECONDS, grantMode: 'caller' });
16
+ }
13
17
  if (input === null ||
14
18
  typeof input !== 'object' ||
15
19
  Array.isArray(input) ||
16
- Reflect.ownKeys(input).some((key) => key !== 'maximumTtlSeconds')) {
20
+ Reflect.ownKeys(input).some((key) => key !== 'maximumTtlSeconds' && key !== 'grantMode')) {
17
21
  throw new TypeError('Execution identity tokenExchange options are invalid.');
18
22
  }
19
23
  const value = input.maximumTtlSeconds ?? DEFAULT_MAXIMUM_TTL_SECONDS;
20
24
  if (!Number.isSafeInteger(value) || value < 1) {
21
25
  throw new TypeError('tokenExchange.maximumTtlSeconds must be a positive safe integer.');
22
26
  }
23
- return value;
27
+ const grantMode = input.grantMode ?? 'caller';
28
+ return Object.freeze({ maximumTtlSeconds: value, grantMode: acceptExchangeGrantMode(grantMode) });
24
29
  }
25
- export function tokenExchange(issuer, subject, signing, policy, verification, maximumTtlSeconds) {
30
+ export function tokenExchange(issuer, subject, signing, policy, verification, maximumTtlSeconds, grantMode = 'caller') {
31
+ const acceptedGrantMode = acceptExchangeGrantMode(grantMode);
26
32
  return Object.freeze({
27
33
  async exchange(request, context) {
28
34
  try {
@@ -45,7 +51,7 @@ export function tokenExchange(issuer, subject, signing, policy, verification, ma
45
51
  const token = await new SignJWT({
46
52
  grant: {
47
53
  v: 1,
48
- expr: { kind: 'identity', credential: carried.credential },
54
+ expr: exchangeGrant(acceptedGrantMode, carried.credential),
49
55
  },
50
56
  })
51
57
  .setProtectedHeader({
@@ -81,6 +87,27 @@ export function tokenExchange(issuer, subject, signing, policy, verification, ma
81
87
  },
82
88
  });
83
89
  }
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
+ }
84
111
  function requireProfile(input, profile) {
85
112
  const expected = ['aud', 'delegation', 'exp', 'iat', 'iss', 'sub'];
86
113
  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 { maximumExchangeTtl, tokenExchange } from './exchange.js';
4
+ import { exchangeOptions, 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,7 +37,10 @@ export function createIdentity(input) {
37
37
  });
38
38
  const exchangeProvider = input.tokenExchange === false
39
39
  ? undefined
40
- : tokenExchange(issuer, input.subject, material, policy, verification, maximumExchangeTtl(input.tokenExchange));
40
+ : (() => {
41
+ const options = exchangeOptions(input.tokenExchange);
42
+ return tokenExchange(issuer, input.subject, material, policy, verification, options.maximumTtlSeconds, options.grantMode);
43
+ })();
41
44
  return identity({
42
45
  issuer,
43
46
  subject: input.subject,
@@ -1,2 +1,2 @@
1
1
  export { createIdentity, identity, type Identity, type IdentityInput } from './identity.js';
2
- export { maximumExchangeTtl, tokenExchange, type ExchangeOptions } from './exchange.js';
2
+ export { maximumExchangeTtl, tokenExchange, type ExchangeGrantMode, type ExchangeOptions, } from './exchange.js';
@@ -1,2 +1,2 @@
1
1
  export { createIdentity, identity } from './identity.js';
2
- export { maximumExchangeTtl, tokenExchange } from './exchange.js';
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 Identity, type IdentityInput } from './identity/index.js';
3
+ export { createIdentity, type ExchangeGrantMode, 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';
@@ -1,3 +1,3 @@
1
1
  export { serve } from './serve.js';
2
- export { createIdentity } from './identity/index.js';
2
+ export { createIdentity, } from './identity/index.js';
3
3
  export { InvocationError } from './invocation/index.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.5.0-beta.85",
3
+ "version": "0.5.0-beta.87",
4
4
  "description": "Schema-first SDK for defining, composing, and deploying Astrale domains",
5
5
  "keywords": [
6
6
  "astrale",