@astrale-os/sdk 0.1.1 → 0.1.3
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/dist/auth/authenticate.d.ts +24 -0
- package/dist/auth/authenticate.d.ts.map +1 -0
- package/dist/auth/authenticate.js +29 -0
- package/dist/auth/authenticate.js.map +1 -0
- package/dist/auth/check.d.ts +39 -0
- package/dist/auth/check.d.ts.map +1 -0
- package/dist/auth/check.js +54 -0
- package/dist/auth/check.js.map +1 -0
- package/dist/auth/compose.d.ts +41 -0
- package/dist/auth/compose.d.ts.map +1 -0
- package/dist/auth/compose.js +45 -0
- package/dist/auth/compose.js.map +1 -0
- package/dist/auth/errors.d.ts +16 -0
- package/dist/auth/errors.d.ts.map +1 -0
- package/dist/auth/errors.js +26 -0
- package/dist/auth/errors.js.map +1 -0
- package/dist/auth/identity.d.ts +16 -0
- package/dist/auth/identity.d.ts.map +1 -0
- package/dist/auth/identity.js +2 -0
- package/dist/auth/identity.js.map +1 -0
- package/dist/auth/index.d.ts +12 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +9 -0
- package/dist/auth/index.js.map +1 -0
- package/dist/auth/kernel-client.d.ts +43 -0
- package/dist/auth/kernel-client.d.ts.map +1 -0
- package/dist/auth/kernel-client.js +146 -0
- package/dist/auth/kernel-client.js.map +1 -0
- package/dist/auth/resolve.d.ts +19 -0
- package/dist/auth/resolve.d.ts.map +1 -0
- package/dist/auth/resolve.js +43 -0
- package/dist/auth/resolve.js.map +1 -0
- package/dist/auth/sign.d.ts +15 -0
- package/dist/auth/sign.d.ts.map +1 -0
- package/dist/auth/sign.js +24 -0
- package/dist/auth/sign.js.map +1 -0
- package/dist/auth/verify.d.ts +26 -0
- package/dist/auth/verify.d.ts.map +1 -0
- package/dist/auth/verify.js +96 -0
- package/dist/auth/verify.js.map +1 -0
- package/dist/define/index.d.ts +5 -0
- package/dist/define/index.d.ts.map +1 -0
- package/dist/define/index.js +3 -0
- package/dist/define/index.js.map +1 -0
- package/dist/define/remote-function.d.ts +96 -0
- package/dist/define/remote-function.d.ts.map +1 -0
- package/dist/define/remote-function.js +25 -0
- package/dist/define/remote-function.js.map +1 -0
- package/dist/define/view.d.ts +86 -0
- package/dist/define/view.d.ts.map +1 -0
- package/dist/define/view.js +28 -0
- package/dist/define/view.js.map +1 -0
- package/dist/deploy/check.d.ts +30 -0
- package/dist/deploy/check.d.ts.map +1 -0
- package/dist/deploy/check.js +82 -0
- package/dist/deploy/check.js.map +1 -0
- package/dist/deploy/hash-spec.d.ts +9 -0
- package/dist/deploy/hash-spec.d.ts.map +1 -0
- package/dist/deploy/hash-spec.js +29 -0
- package/dist/deploy/hash-spec.js.map +1 -0
- package/dist/deploy/index.d.ts +4 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js +4 -0
- package/dist/deploy/index.js.map +1 -0
- package/dist/deploy/meta.d.ts +18 -0
- package/dist/deploy/meta.d.ts.map +1 -0
- package/dist/deploy/meta.js +22 -0
- package/dist/deploy/meta.js.map +1 -0
- package/dist/dispatch/authorize.d.ts +14 -0
- package/dist/dispatch/authorize.d.ts.map +1 -0
- package/dist/dispatch/authorize.js +24 -0
- package/dist/dispatch/authorize.js.map +1 -0
- package/dist/dispatch/call-remote.d.ts +35 -0
- package/dist/dispatch/call-remote.d.ts.map +1 -0
- package/dist/dispatch/call-remote.js +37 -0
- package/dist/dispatch/call-remote.js.map +1 -0
- package/dist/dispatch/dispatcher.d.ts +60 -0
- package/dist/dispatch/dispatcher.d.ts.map +1 -0
- package/dist/dispatch/dispatcher.js +177 -0
- package/dist/dispatch/dispatcher.js.map +1 -0
- package/dist/dispatch/errors.d.ts +47 -0
- package/dist/dispatch/errors.d.ts.map +1 -0
- package/dist/dispatch/errors.js +76 -0
- package/dist/dispatch/errors.js.map +1 -0
- package/dist/dispatch/execute.d.ts +33 -0
- package/dist/dispatch/execute.d.ts.map +1 -0
- package/dist/dispatch/execute.js +24 -0
- package/dist/dispatch/execute.js.map +1 -0
- package/dist/dispatch/identity.d.ts +73 -0
- package/dist/dispatch/identity.d.ts.map +1 -0
- package/dist/dispatch/identity.js +106 -0
- package/dist/dispatch/identity.js.map +1 -0
- package/dist/dispatch/index.d.ts +8 -0
- package/dist/dispatch/index.d.ts.map +1 -0
- package/dist/dispatch/index.js +8 -0
- package/dist/dispatch/index.js.map +1 -0
- package/dist/dispatch/resolve.d.ts +27 -0
- package/dist/dispatch/resolve.d.ts.map +1 -0
- package/dist/dispatch/resolve.js +65 -0
- package/dist/dispatch/resolve.js.map +1 -0
- package/dist/dispatch/self.d.ts +27 -0
- package/dist/dispatch/self.d.ts.map +1 -0
- package/dist/dispatch/self.js +25 -0
- package/dist/dispatch/self.js.map +1 -0
- package/dist/dispatch/validate.d.ts +35 -0
- package/dist/dispatch/validate.d.ts.map +1 -0
- package/dist/dispatch/validate.js +27 -0
- package/dist/dispatch/validate.js.map +1 -0
- package/dist/domain/build-spec.d.ts +37 -0
- package/dist/domain/build-spec.d.ts.map +1 -0
- package/dist/domain/build-spec.js +95 -0
- package/dist/domain/build-spec.js.map +1 -0
- package/dist/domain/contract.d.ts +17 -0
- package/dist/domain/contract.d.ts.map +1 -0
- package/dist/domain/contract.js +26 -0
- package/dist/domain/contract.js.map +1 -0
- package/dist/domain/define.d.ts +82 -0
- package/dist/domain/define.d.ts.map +1 -0
- package/dist/domain/define.js +99 -0
- package/dist/domain/define.js.map +1 -0
- package/dist/domain/extend-core.d.ts +49 -0
- package/dist/domain/extend-core.d.ts.map +1 -0
- package/dist/domain/extend-core.js +182 -0
- package/dist/domain/extend-core.js.map +1 -0
- package/dist/domain/index.d.ts +5 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +4 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/method/class.d.ts +70 -0
- package/dist/method/class.d.ts.map +1 -0
- package/dist/method/class.js +26 -0
- package/dist/method/class.js.map +1 -0
- package/dist/method/context.d.ts +43 -0
- package/dist/method/context.d.ts.map +1 -0
- package/dist/method/context.js +10 -0
- package/dist/method/context.js.map +1 -0
- package/dist/method/index.d.ts +6 -0
- package/dist/method/index.d.ts.map +1 -0
- package/dist/method/index.js +3 -0
- package/dist/method/index.js.map +1 -0
- package/dist/method/single.d.ts +88 -0
- package/dist/method/single.d.ts.map +1 -0
- package/dist/method/single.js +18 -0
- package/dist/method/single.js.map +1 -0
- package/dist/server/auxiliary-routes.d.ts +44 -0
- package/dist/server/auxiliary-routes.d.ts.map +1 -0
- package/dist/server/auxiliary-routes.js +239 -0
- package/dist/server/auxiliary-routes.js.map +1 -0
- package/dist/server/config.d.ts +83 -0
- package/dist/server/config.d.ts.map +1 -0
- package/dist/server/config.js +8 -0
- package/dist/server/config.js.map +1 -0
- package/dist/server/create.d.ts +21 -0
- package/dist/server/create.d.ts.map +1 -0
- package/dist/server/create.js +210 -0
- package/dist/server/create.js.map +1 -0
- package/dist/server/handle.d.ts +35 -0
- package/dist/server/handle.d.ts.map +1 -0
- package/dist/server/handle.js +9 -0
- package/dist/server/handle.js.map +1 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/jwks.d.ts +11 -0
- package/dist/server/jwks.d.ts.map +1 -0
- package/dist/server/jwks.js +15 -0
- package/dist/server/jwks.js.map +1 -0
- package/dist/server/require-env.d.ts +15 -0
- package/dist/server/require-env.d.ts.map +1 -0
- package/dist/server/require-env.js +21 -0
- package/dist/server/require-env.js.map +1 -0
- package/dist/server/serving-url.d.ts +14 -0
- package/dist/server/serving-url.d.ts.map +1 -0
- package/dist/server/serving-url.js +28 -0
- package/dist/server/serving-url.js.map +1 -0
- package/dist/server/start.d.ts +11 -0
- package/dist/server/start.d.ts.map +1 -0
- package/dist/server/start.js +34 -0
- package/dist/server/start.js.map +1 -0
- package/dist/server/worker-entry.d.ts +60 -0
- package/dist/server/worker-entry.d.ts.map +1 -0
- package/dist/server/worker-entry.js +79 -0
- package/dist/server/worker-entry.js.map +1 -0
- package/dist/server/worker-meta.d.ts +6 -0
- package/dist/server/worker-meta.d.ts.map +1 -0
- package/dist/server/worker-meta.js +10 -0
- package/dist/server/worker-meta.js.map +1 -0
- package/package.json +5 -5
- package/src/auth/compose.ts +27 -2
- package/src/auth/kernel-client.ts +103 -11
- package/src/define/remote-function.ts +10 -0
- package/src/server/auxiliary-routes.ts +3 -1
- package/src/server/start.ts +5 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared inbound-credential resolution.
|
|
3
|
+
*
|
|
4
|
+
* Consumed by both `SdkDispatcher` (kernel envelope) and `mountAuxiliaryRoutes`
|
|
5
|
+
* (View / RemoteFunction routes). Centralises the auth-policy three-way
|
|
6
|
+
* (`'required'` / `'optional'` / `'public'`) and the wrap of underlying
|
|
7
|
+
* verification errors into canonical `AuthMissingError` / `AuthInvalidError`.
|
|
8
|
+
*/
|
|
9
|
+
import { isKernelErrorClassifiable } from '@astrale-os/kernel-api';
|
|
10
|
+
import { authenticateRequest } from './authenticate';
|
|
11
|
+
import { AuthInvalidError, AuthMissingError } from './errors';
|
|
12
|
+
export async function resolveInboundAuth(credential, policy, identity) {
|
|
13
|
+
const effective = policy ?? 'required';
|
|
14
|
+
if (effective === 'public')
|
|
15
|
+
return { auth: null, kernel: null };
|
|
16
|
+
if (effective === 'optional' && !credential)
|
|
17
|
+
return { auth: null, kernel: null };
|
|
18
|
+
if (effective === 'required' && !credential)
|
|
19
|
+
throw new AuthMissingError();
|
|
20
|
+
try {
|
|
21
|
+
const result = await authenticateRequest(credential, identity);
|
|
22
|
+
return { auth: buildAuthContext(result.authenticated), kernel: result.kernel };
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
// kernel-core auth errors (UntrustedIssuerError, TrustPolicyDeniedError, …)
|
|
26
|
+
// already self-classify with a discriminating `data.type`. Rethrow them
|
|
27
|
+
// unchanged so that classification survives to the wire; only wrap
|
|
28
|
+
// genuinely unclassified errors into the generic AuthInvalidError.
|
|
29
|
+
if (isKernelErrorClassifiable(err))
|
|
30
|
+
throw err;
|
|
31
|
+
throw new AuthInvalidError(err instanceof Error ? err.message : 'Authentication failed', err);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function buildAuthContext(authenticated) {
|
|
35
|
+
return {
|
|
36
|
+
credential: authenticated.credential,
|
|
37
|
+
principal: authenticated.credential.verified.sub,
|
|
38
|
+
grant: authenticated.grant,
|
|
39
|
+
attestation: authenticated.attestation,
|
|
40
|
+
delegation: authenticated.delegation,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/auth/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAA;AAKlE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAA;AACpD,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAO7D,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,UAA2B,EAC3B,MAA8B,EAC9B,QAA8B;IAE9B,MAAM,SAAS,GAAG,MAAM,IAAI,UAAU,CAAA;IAEtC,IAAI,SAAS,KAAK,QAAQ;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IAC/D,IAAI,SAAS,KAAK,UAAU,IAAI,CAAC,UAAU;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IAChF,IAAI,SAAS,KAAK,UAAU,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,gBAAgB,EAAE,CAAA;IAEzE,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAC9D,OAAO,EAAE,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAA;IAChF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,4EAA4E;QAC5E,wEAAwE;QACxE,mEAAmE;QACnE,mEAAmE;QACnE,IAAI,yBAAyB,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,CAAA;QAC7C,MAAM,IAAI,gBAAgB,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAA;IAC/F,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,aAA4B;IAC3D,OAAO;QACL,UAAU,EAAE,aAAa,CAAC,UAAU;QACpC,SAAS,EAAE,aAAa,CAAC,UAAU,CAAC,QAAQ,CAAC,GAA4B;QACzE,KAAK,EAAE,aAAa,CAAC,KAAM;QAC3B,WAAW,EAAE,aAAa,CAAC,WAAW;QACtC,UAAU,EAAE,aAAa,CAAC,UAAU;KACrC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT signing utilities for outbound composed credentials.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Sign a credential JWT with the given claims and identity config.
|
|
6
|
+
*/
|
|
7
|
+
export declare function signCredential(claims: Record<string, unknown>, config: {
|
|
8
|
+
issuer: string;
|
|
9
|
+
subject: string;
|
|
10
|
+
audience: string;
|
|
11
|
+
privateKey: JsonWebKey;
|
|
12
|
+
/** JWT lifetime as a jose-compatible string (e.g. '60s', '5m', '1h'). Default: '60s'. */
|
|
13
|
+
ttl?: string;
|
|
14
|
+
}): Promise<string>;
|
|
15
|
+
//# sourceMappingURL=sign.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../../src/auth/sign.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,MAAM,EAAE;IACN,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,UAAU,CAAA;IACtB,yFAAyF;IACzF,GAAG,CAAC,EAAE,MAAM,CAAA;CACb,GACA,OAAO,CAAC,MAAM,CAAC,CAejB"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT signing utilities for outbound composed credentials.
|
|
3
|
+
*/
|
|
4
|
+
import { deriveAllowedAlgorithms } from '@astrale-os/kernel-core';
|
|
5
|
+
import { SignJWT, importJWK } from 'jose';
|
|
6
|
+
/**
|
|
7
|
+
* Sign a credential JWT with the given claims and identity config.
|
|
8
|
+
*/
|
|
9
|
+
export async function signCredential(claims, config) {
|
|
10
|
+
const alg = deriveAllowedAlgorithms(config.privateKey)[0];
|
|
11
|
+
if (!alg) {
|
|
12
|
+
throw new Error(`Cannot derive algorithm from JWK: kty=${config.privateKey.kty}`);
|
|
13
|
+
}
|
|
14
|
+
const key = await importJWK(config.privateKey, alg);
|
|
15
|
+
return new SignJWT(claims)
|
|
16
|
+
.setProtectedHeader({ alg })
|
|
17
|
+
.setIssuer(config.issuer)
|
|
18
|
+
.setSubject(config.subject)
|
|
19
|
+
.setAudience(config.audience)
|
|
20
|
+
.setIssuedAt()
|
|
21
|
+
.setExpirationTime(config.ttl ?? '60s')
|
|
22
|
+
.sign(key);
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=sign.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sign.js","sourceRoot":"","sources":["../../src/auth/sign.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAA;AACjE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,MAAM,CAAA;AAEzC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAA+B,EAC/B,MAOC;IAED,MAAM,GAAG,GAAG,uBAAuB,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IACzD,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,yCAAyC,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,CAAA;IACnF,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,GAAG,CAAC,CAAA;IAEnD,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;SACvB,kBAAkB,CAAC,EAAE,GAAG,EAAE,CAAC;SAC3B,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC;SACxB,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC;SAC1B,WAAW,CAAC,MAAM,CAAC,QAAQ,CAAC;SAC5B,WAAW,EAAE;SACb,iBAAiB,CAAC,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC;SACtC,IAAI,CAAC,GAAG,CAAC,CAAA;AACd,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbound credential verification.
|
|
3
|
+
*
|
|
4
|
+
* Uses kernel-core's credential verification infrastructure
|
|
5
|
+
* (CredentialMethodResolver, MethodRegistry) instead of manual JWT handling.
|
|
6
|
+
* Not tied to JWT — supports any credential method kernel-core provides.
|
|
7
|
+
*/
|
|
8
|
+
import type { Attestation, CredentialInput, Delegation, VerifiedCredential } from '@astrale-os/kernel-core';
|
|
9
|
+
import type { RemoteIdentityConfig } from './identity';
|
|
10
|
+
export type VerifiedInbound = {
|
|
11
|
+
/** The full verified credential (iss, sub, aud, claims) */
|
|
12
|
+
verified: VerifiedCredential;
|
|
13
|
+
/** Issuer URL (from credential's iss claim) */
|
|
14
|
+
issuer: string;
|
|
15
|
+
/** Attestation — proves caller can invoke this function */
|
|
16
|
+
attestation: Attestation;
|
|
17
|
+
/** Delegation — scoped caller permissions as kernel-signed credential */
|
|
18
|
+
delegation: Delegation;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Verify an inbound delegation credential using kernel-core's verification.
|
|
22
|
+
*
|
|
23
|
+
* @throws AuthenticationError subclasses from kernel-core on verification failure
|
|
24
|
+
*/
|
|
25
|
+
export declare function verifyInboundCredential(credential: CredentialInput, config: RemoteIdentityConfig): Promise<VerifiedInbound>;
|
|
26
|
+
//# sourceMappingURL=verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/auth/verify.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,eAAe,EACf,UAAU,EAEV,kBAAkB,EACnB,MAAM,yBAAyB,CAAA;AAUhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAKtD,MAAM,MAAM,eAAe,GAAG;IAC5B,2DAA2D;IAC3D,QAAQ,EAAE,kBAAkB,CAAA;IAC5B,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAA;IACd,2DAA2D;IAC3D,WAAW,EAAE,WAAW,CAAA;IACxB,yEAAyE;IACzE,UAAU,EAAE,UAAU,CAAA;CACvB,CAAA;AA4DD;;;;GAIG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,eAAe,EAC3B,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,eAAe,CAAC,CA+B1B"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inbound credential verification.
|
|
3
|
+
*
|
|
4
|
+
* Uses kernel-core's credential verification infrastructure
|
|
5
|
+
* (CredentialMethodResolver, MethodRegistry) instead of manual JWT handling.
|
|
6
|
+
* Not tied to JWT — supports any credential method kernel-core provides.
|
|
7
|
+
*/
|
|
8
|
+
import { CredentialMethodResolver, MethodRegistry, verifyAudience, verifyCredential, } from '@astrale-os/kernel-core';
|
|
9
|
+
import { createLocalJWKSet, createRemoteJWKSet } from 'jose';
|
|
10
|
+
import { derivePublicJwk } from '../server/jwks';
|
|
11
|
+
import { canonicalizeServingUrl } from '../server/serving-url';
|
|
12
|
+
const methodResolver = new CredentialMethodResolver(new MethodRegistry());
|
|
13
|
+
/**
|
|
14
|
+
* Build the key resolver for one verifying server. Captures `config` so it can
|
|
15
|
+
* short-circuit the server's OWN issuer (`config.issuer`): a self-issued
|
|
16
|
+
* credential is verified against the in-memory public key, never fetched — a
|
|
17
|
+
* Worker can't fetch its own hostname, and it already holds the key. Every other
|
|
18
|
+
* issuer is resolved live via JWKS (`createRemoteJWKSet`).
|
|
19
|
+
*/
|
|
20
|
+
function makeResolveKeys(config) {
|
|
21
|
+
// The worker's own canonical iss. STRICT: `config.issuer` is the serving URL
|
|
22
|
+
// by contract (both producers — buildIdentityMap / buildAuxIdentityMap — feed
|
|
23
|
+
// it `canonicalizeServingUrl(config.url)`), so a value that doesn't parse is
|
|
24
|
+
// a construction-time config error. Swallowing it would silently disable
|
|
25
|
+
// self-verification and route self-issued credentials to a JWKS fetch on the
|
|
26
|
+
// worker's own hostname — which Cloudflare forbids — turning a config bug
|
|
27
|
+
// into an opaque per-call failure.
|
|
28
|
+
const selfIssuer = canonicalizeServingUrl(config.issuer);
|
|
29
|
+
// TODO(cache): Re-add JWKS caching with a short TTL or kid-miss retry.
|
|
30
|
+
// A prior implementation cached `createRemoteJWKSet` per issuer URL
|
|
31
|
+
// indefinitely. jose's internal cache (30s cooldown, 10min max-age) caused
|
|
32
|
+
// stale keys when the issuer restarted — the resolver served old keys and
|
|
33
|
+
// jose refused to refetch within the cooldown window. On CF Workers the
|
|
34
|
+
// module-level Map persisted across requests, making it worse. For now we
|
|
35
|
+
// create a fresh resolver per call (jose deduplicates concurrent fetches).
|
|
36
|
+
return async (issuer, _method, _kid) => {
|
|
37
|
+
const url = issuer;
|
|
38
|
+
// Self-issued credential (iss == this worker's own serving URL): resolve
|
|
39
|
+
// from the in-memory public key. Never fetch self — Cloudflare forbids a
|
|
40
|
+
// Worker fetching its own hostname, and the published JWKS is this key.
|
|
41
|
+
if (selfIssuer !== undefined) {
|
|
42
|
+
let canonical;
|
|
43
|
+
try {
|
|
44
|
+
canonical = canonicalizeServingUrl(url);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
canonical = undefined;
|
|
48
|
+
}
|
|
49
|
+
if (canonical === selfIssuer) {
|
|
50
|
+
return createLocalJWKSet({ keys: [derivePublicJwk(config.privateKey)] });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// M-28 fix: a bare-slug iss (`mails.localhost`) makes
|
|
54
|
+
// `new URL('mails.localhost/.well-known/jwks.json')` throw "Invalid
|
|
55
|
+
// URL string". The dispatcher's identity map normalizes the iss it
|
|
56
|
+
// signs with, but inbound creds from older clients may still carry
|
|
57
|
+
// the slug form. Coerce to a URL with a default `https://` scheme
|
|
58
|
+
// (matches kernel.astrale.ai canonical form). If the actual receiver
|
|
59
|
+
// is on http://localhost the receiver-side resolver still works
|
|
60
|
+
// because both endpoints are on localhost — but for prod targets
|
|
61
|
+
// requiring TLS this is the right default.
|
|
62
|
+
const normalized = /^https?:\/\//.test(url) ? url : `https://${url}`;
|
|
63
|
+
return createRemoteJWKSet(new URL(`${normalized}/.well-known/jwks.json`));
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Verify an inbound delegation credential using kernel-core's verification.
|
|
68
|
+
*
|
|
69
|
+
* @throws AuthenticationError subclasses from kernel-core on verification failure
|
|
70
|
+
*/
|
|
71
|
+
export async function verifyInboundCredential(credential, config) {
|
|
72
|
+
// Verify using kernel-core's credential verification pipeline
|
|
73
|
+
const verified = await verifyCredential({
|
|
74
|
+
methodResolver,
|
|
75
|
+
resolveKeys: makeResolveKeys(config),
|
|
76
|
+
}, credential);
|
|
77
|
+
// Validate audience matches this function's issuer (its serving URL).
|
|
78
|
+
// kernel-core's verifyAudience compares canonically.
|
|
79
|
+
verifyAudience(verified, config.issuer);
|
|
80
|
+
// Extract attestation and delegation from claims
|
|
81
|
+
const attestation = verified.claims.attestation;
|
|
82
|
+
if (!attestation?.expr) {
|
|
83
|
+
throw new Error('Credential missing attestation');
|
|
84
|
+
}
|
|
85
|
+
const delegation = verified.claims.delegation;
|
|
86
|
+
if (!delegation?.credential) {
|
|
87
|
+
throw new Error('Credential missing delegation');
|
|
88
|
+
}
|
|
89
|
+
return {
|
|
90
|
+
verified,
|
|
91
|
+
issuer: verified.iss,
|
|
92
|
+
attestation,
|
|
93
|
+
delegation,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/auth/verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { defineView } from './view';
|
|
2
|
+
export type { ViewDef, ViewRenderContext } from './view';
|
|
3
|
+
export { defineRemoteFunction } from './remote-function';
|
|
4
|
+
export type { AnyRemoteFunctionDef, RemoteFunctionContext, RemoteFunctionDef, } from './remote-function';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/define/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,YAAY,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAA;AAExD,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA;AACxD,YAAY,EACV,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/define/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AAGnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authoring a standalone remote function — a callable not bound to a class.
|
|
3
|
+
* (The verb keeps the `defineRemoteFunction` name; the node it materializes is
|
|
4
|
+
* the canonical kernel `Function` class, the former distribution `RemoteFunction`.)
|
|
5
|
+
*
|
|
6
|
+
* Each entry in `defineRemoteDomain({ remoteFunctions: { ... } })` becomes:
|
|
7
|
+
* - a graph node at `/${origin}/core/<functionsFolder>/<slug>`, materialized
|
|
8
|
+
* as the kernel `Function` class by `buildCorePath` so kernel discovery /
|
|
9
|
+
* `View.resolve` can list it. The `core/` anchor appears in the GRAPH path only.
|
|
10
|
+
* - a Hono route on the worker at the path implied by `binding`
|
|
11
|
+
* (`/<functionsFolder>/<slug>` POST by default — no `core/` in the URL).
|
|
12
|
+
*
|
|
13
|
+
* The slug = the map key (single source of truth, no duplication).
|
|
14
|
+
*
|
|
15
|
+
* `ref` is auto-derived as `function.<slug>` if omitted — used as
|
|
16
|
+
* `Function.ref` on the graph node and as the dispatch key.
|
|
17
|
+
*/
|
|
18
|
+
import type { AuthPolicy, FunctionBinding } from '@astrale-os/kernel-api/routed';
|
|
19
|
+
import type { FnMap } from '@astrale-os/kernel-client';
|
|
20
|
+
import type { BoundClientSessionView } from '@astrale-os/kernel-client/session';
|
|
21
|
+
import type { AuthContext } from '@astrale-os/kernel-core';
|
|
22
|
+
import type { Context } from 'hono';
|
|
23
|
+
import type { z } from 'zod';
|
|
24
|
+
import type { CallRemoteFn } from '../dispatch/call-remote';
|
|
25
|
+
export type RemoteFunctionContext<TParams, TDeps = unknown> = {
|
|
26
|
+
/** Validated params (Zod-checked against `inputSchema`). */
|
|
27
|
+
params: TParams;
|
|
28
|
+
/** Hono request context — escape hatch for headers, raw body, etc. */
|
|
29
|
+
c: Context;
|
|
30
|
+
/** Resolved auth context. `null` when `auth: 'public'` or absent. */
|
|
31
|
+
auth: AuthContext | null;
|
|
32
|
+
/** Typed dependency container injected at server startup. */
|
|
33
|
+
deps: TDeps;
|
|
34
|
+
/**
|
|
35
|
+
* `BoundClientSessionView` to the parent kernel, bound to the composed
|
|
36
|
+
* credential `union(delegation, self)` — same shape as `RemoteContext.kernel`
|
|
37
|
+
* for `remoteMethod`. `null` when `auth: 'public'`, or `auth: 'optional'`
|
|
38
|
+
* with no inbound credential.
|
|
39
|
+
*/
|
|
40
|
+
kernel: BoundClientSessionView<FnMap> | null;
|
|
41
|
+
/**
|
|
42
|
+
* Call another worker's remote method, re-minting the credential for the
|
|
43
|
+
* target's audience. Same contract as {@link RemoteContext.callRemote}: throws
|
|
44
|
+
* on a public/unauthenticated request; needs `USE` on
|
|
45
|
+
* `Identity.mintDelegationCredential` + the target method's grants.
|
|
46
|
+
*/
|
|
47
|
+
callRemote: CallRemoteFn;
|
|
48
|
+
/**
|
|
49
|
+
* Acquire a kernel session authenticated as THIS FUNCTION'S OWN identity —
|
|
50
|
+
* authority = the function's own grants only, no caller delegation. The
|
|
51
|
+
* webhook seam: when an `auth: 'public'` upstream can't carry an Astrale
|
|
52
|
+
* token (HMAC-signature webhooks, Stripe-style), VERIFY THE UPSTREAM'S
|
|
53
|
+
* SIGNATURE FIRST, then act on the graph as yourself. `kernelUrl` defaults
|
|
54
|
+
* to `deps.KERNEL_URL` (set automatically on managed deploys); pass it
|
|
55
|
+
* explicitly for other targets.
|
|
56
|
+
*/
|
|
57
|
+
selfKernel: (kernelUrl?: string) => Promise<BoundClientSessionView<FnMap>>;
|
|
58
|
+
};
|
|
59
|
+
export type RemoteFunctionDef<TParams = unknown, TResult = unknown, TDeps = unknown> = {
|
|
60
|
+
/**
|
|
61
|
+
* Canonical callable identity. Auto-derived as `function.<slug>` (where
|
|
62
|
+
* `<slug>` is the map key) when omitted. Stored as `Function.ref` on the
|
|
63
|
+
* graph node and used by the kernel dispatcher to route the call.
|
|
64
|
+
*/
|
|
65
|
+
ref?: string;
|
|
66
|
+
/** Zod schema for the call's parameters. */
|
|
67
|
+
inputSchema: z.ZodType<TParams>;
|
|
68
|
+
/** Zod schema for the call's result. */
|
|
69
|
+
outputSchema: z.ZodType<TResult>;
|
|
70
|
+
/**
|
|
71
|
+
* Override the binding (URL + route shape). When absent, SDK defaults to
|
|
72
|
+
* `{ remoteUrl: ${url}/<functionsFolder>/<slug> }`. The HTTP verb (POST
|
|
73
|
+
* for functions) is applied by the worker route mounter at mount time — it is
|
|
74
|
+
* NOT stored on the binding, so the materialized `Function.binding` carries
|
|
75
|
+
* `remoteUrl` only.
|
|
76
|
+
*
|
|
77
|
+
* Use this to bind to a custom host or REST-style path. Host + path
|
|
78
|
+
* placeholders both supported.
|
|
79
|
+
*/
|
|
80
|
+
binding?: FunctionBinding;
|
|
81
|
+
/** Authentication policy. Defaults to `'required'`. */
|
|
82
|
+
auth?: AuthPolicy;
|
|
83
|
+
/** Optional pre-execute authorization. Throw to deny. */
|
|
84
|
+
authorize?: (ctx: RemoteFunctionContext<TParams, TDeps>) => void | Promise<void>;
|
|
85
|
+
/** The function body. May be async. */
|
|
86
|
+
execute: (ctx: RemoteFunctionContext<TParams, TDeps>) => TResult | Promise<TResult>;
|
|
87
|
+
/** Optional human-readable description. */
|
|
88
|
+
description?: string;
|
|
89
|
+
};
|
|
90
|
+
export type AnyRemoteFunctionDef = RemoteFunctionDef<any, any, any>;
|
|
91
|
+
/**
|
|
92
|
+
* Identity helper for authoring a RemoteFunction. Returns its argument
|
|
93
|
+
* unchanged — `defineRemoteDomain` consumes the typed shape.
|
|
94
|
+
*/
|
|
95
|
+
export declare function defineRemoteFunction<TParams, TResult, TDeps = unknown>(def: RemoteFunctionDef<TParams, TResult, TDeps>): RemoteFunctionDef<TParams, TResult, TDeps>;
|
|
96
|
+
//# sourceMappingURL=remote-function.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-function.d.ts","sourceRoot":"","sources":["../../src/define/remote-function.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAChF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAA;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mCAAmC,CAAA;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACnC,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAE3D,MAAM,MAAM,qBAAqB,CAAC,OAAO,EAAE,KAAK,GAAG,OAAO,IAAI;IAC5D,4DAA4D;IAC5D,MAAM,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,CAAC,EAAE,OAAO,CAAA;IACV,qEAAqE;IACrE,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IACxB,6DAA6D;IAC7D,IAAI,EAAE,KAAK,CAAA;IACX;;;;;OAKG;IACH,MAAM,EAAE,sBAAsB,CAAC,KAAK,CAAC,GAAG,IAAI,CAAA;IAC5C;;;;;OAKG;IACH,UAAU,EAAE,YAAY,CAAA;IACxB;;;;;;;;OAQG;IACH,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,CAAA;CAC3E,CAAA;AAED,MAAM,MAAM,iBAAiB,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,OAAO,EAAE,KAAK,GAAG,OAAO,IAAI;IACrF;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,4CAA4C;IAC5C,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAC/B,wCAAwC;IACxC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAChC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,uDAAuD;IACvD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB,yDAAyD;IACzD,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAChF,uCAAuC;IACvC,OAAO,EAAE,CAAC,GAAG,EAAE,qBAAqB,CAAC,OAAO,EAAE,KAAK,CAAC,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACnF,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAGD,MAAM,MAAM,oBAAoB,GAAG,iBAAiB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;AAEnE;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,GAAG,OAAO,EACpE,GAAG,EAAE,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,GAC9C,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,CAE5C"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authoring a standalone remote function — a callable not bound to a class.
|
|
3
|
+
* (The verb keeps the `defineRemoteFunction` name; the node it materializes is
|
|
4
|
+
* the canonical kernel `Function` class, the former distribution `RemoteFunction`.)
|
|
5
|
+
*
|
|
6
|
+
* Each entry in `defineRemoteDomain({ remoteFunctions: { ... } })` becomes:
|
|
7
|
+
* - a graph node at `/${origin}/core/<functionsFolder>/<slug>`, materialized
|
|
8
|
+
* as the kernel `Function` class by `buildCorePath` so kernel discovery /
|
|
9
|
+
* `View.resolve` can list it. The `core/` anchor appears in the GRAPH path only.
|
|
10
|
+
* - a Hono route on the worker at the path implied by `binding`
|
|
11
|
+
* (`/<functionsFolder>/<slug>` POST by default — no `core/` in the URL).
|
|
12
|
+
*
|
|
13
|
+
* The slug = the map key (single source of truth, no duplication).
|
|
14
|
+
*
|
|
15
|
+
* `ref` is auto-derived as `function.<slug>` if omitted — used as
|
|
16
|
+
* `Function.ref` on the graph node and as the dispatch key.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* Identity helper for authoring a RemoteFunction. Returns its argument
|
|
20
|
+
* unchanged — `defineRemoteDomain` consumes the typed shape.
|
|
21
|
+
*/
|
|
22
|
+
export function defineRemoteFunction(def) {
|
|
23
|
+
return def;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=remote-function.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-function.js","sourceRoot":"","sources":["../../src/define/remote-function.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAiFH;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAClC,GAA+C;IAE/C,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authoring a `View` — iframe-mountable callable served by the domain worker.
|
|
3
|
+
*
|
|
4
|
+
* Each entry in `defineRemoteDomain({ views: { ... } })` becomes both:
|
|
5
|
+
* - a graph node at `/${origin}/core/<viewsFolder>/<slug>` (auto-materialized
|
|
6
|
+
* by the SDK; the `core/` segment is the universal anchor injected by
|
|
7
|
+
* `buildCorePath`. `<slug>` is the map key, so it lives in exactly one place)
|
|
8
|
+
* - a Hono route on the worker at the path implied by `binding`
|
|
9
|
+
* (`/<viewsFolder>/<slug>` by default — note: no `core/` in the URL).
|
|
10
|
+
*
|
|
11
|
+
* The `core/` segment appears in the GRAPH path only; the URL path that
|
|
12
|
+
* lands in `Function.binding.remoteUrl` is `${url}/<viewsFolder>/<slug>`.
|
|
13
|
+
*
|
|
14
|
+
* The author can override the URL via `binding` — host and/or path
|
|
15
|
+
* placeholders are supported (the kernel's `route` mechanism does the
|
|
16
|
+
* substitution + Hono matching, same as for methods). When `render` is
|
|
17
|
+
* omitted, no worker route is mounted — useful for Views whose iframe
|
|
18
|
+
* lives at an external host.
|
|
19
|
+
*/
|
|
20
|
+
import type { AuthPolicy, FunctionBinding } from '@astrale-os/kernel-api/routed';
|
|
21
|
+
import type { AuthContext } from '@astrale-os/kernel-core';
|
|
22
|
+
import type { EdgeEndpoint } from '@astrale-os/kernel-dsl';
|
|
23
|
+
import type { Context } from 'hono';
|
|
24
|
+
export type ViewRenderContext<TDeps = unknown> = {
|
|
25
|
+
/** Hono request context — read params, headers, query, etc. */
|
|
26
|
+
c: Context;
|
|
27
|
+
/**
|
|
28
|
+
* Placeholders extracted from the request URL (host + path placeholders
|
|
29
|
+
* declared in `binding.remoteUrl` / `binding.route.path`). Empty when
|
|
30
|
+
* the binding has no placeholders.
|
|
31
|
+
*/
|
|
32
|
+
params: Record<string, string>;
|
|
33
|
+
/** Resolved auth context. `null` when `auth: 'public'` or absent. */
|
|
34
|
+
auth: AuthContext | null;
|
|
35
|
+
/** Typed dependency container injected at server startup. */
|
|
36
|
+
deps: TDeps;
|
|
37
|
+
};
|
|
38
|
+
export type ViewDef<TDeps = unknown> = {
|
|
39
|
+
/**
|
|
40
|
+
* Override the binding (URL + route shape). When absent, SDK defaults to
|
|
41
|
+
* `{ remoteUrl: ${url}/<viewsFolder>/<slug> }`. The HTTP verb (GET for
|
|
42
|
+
* views) is applied by the worker route mounter at mount time — it is NOT
|
|
43
|
+
* stored on the binding.
|
|
44
|
+
*
|
|
45
|
+
* Use this to bind to a custom host (e.g. `https://{tenant}.example.com`)
|
|
46
|
+
* or REST-style path. Host + path placeholders both supported.
|
|
47
|
+
*/
|
|
48
|
+
binding?: FunctionBinding;
|
|
49
|
+
/**
|
|
50
|
+
* Worker-relative path the View's iframe is served from (e.g. `'/ui/note'`),
|
|
51
|
+
* for Views backed by the client SPA instead of a `render`. The spec producer
|
|
52
|
+
* resolves it against the serving url (`binding.remoteUrl = ${url}${mount}`)
|
|
53
|
+
* at materialize time — so the dev never hardcodes a URL. Mutually exclusive
|
|
54
|
+
* with `render`; takes precedence over `binding`.
|
|
55
|
+
*/
|
|
56
|
+
mount?: string;
|
|
57
|
+
/** Authentication policy. Defaults to `'required'`. */
|
|
58
|
+
auth?: AuthPolicy;
|
|
59
|
+
/**
|
|
60
|
+
* Optional pre-render authorization. Runs after auth resolution; throw to
|
|
61
|
+
* deny. SDK wraps as 403.
|
|
62
|
+
*/
|
|
63
|
+
authorize?: (ctx: ViewRenderContext<TDeps>) => void | Promise<void>;
|
|
64
|
+
/**
|
|
65
|
+
* Render the iframe response. May return a redirect, a proxy, or inline
|
|
66
|
+
* HTML. When omitted, no worker route is mounted — the binding URL
|
|
67
|
+
* points elsewhere (CDN, external service).
|
|
68
|
+
*/
|
|
69
|
+
render?: (ctx: ViewRenderContext<TDeps>) => Response | Promise<Response>;
|
|
70
|
+
/**
|
|
71
|
+
* Optional target(s) the View attaches to via `view_for` edge(s). Typically
|
|
72
|
+
* `selfOf(SomeClass)` to bind to a class meta-node, or a `CorePath`
|
|
73
|
+
* pointing at a specific instance. Pass an array to attach the same View
|
|
74
|
+
* to multiple targets (one `view_for` edge is materialized per entry).
|
|
75
|
+
*/
|
|
76
|
+
viewFor?: EdgeEndpoint | EdgeEndpoint[];
|
|
77
|
+
/** Optional human-readable description. */
|
|
78
|
+
description?: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* Identity helper for authoring a View. Returns its argument unchanged —
|
|
82
|
+
* `defineRemoteDomain` consumes the typed shape and the author retains
|
|
83
|
+
* full type inference on `render` / `authorize`.
|
|
84
|
+
*/
|
|
85
|
+
export declare function defineView<TDeps = unknown>(def: ViewDef<TDeps>): ViewDef<TDeps>;
|
|
86
|
+
//# sourceMappingURL=view.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/define/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AAChF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC1D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAEnC,MAAM,MAAM,iBAAiB,CAAC,KAAK,GAAG,OAAO,IAAI;IAC/C,+DAA+D;IAC/D,CAAC,EAAE,OAAO,CAAA;IACV;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,qEAAqE;IACrE,IAAI,EAAE,WAAW,GAAG,IAAI,CAAA;IACxB,6DAA6D;IAC7D,IAAI,EAAE,KAAK,CAAA;CACZ,CAAA;AAED,MAAM,MAAM,OAAO,CAAC,KAAK,GAAG,OAAO,IAAI;IACrC;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,uDAAuD;IACvD,IAAI,CAAC,EAAE,UAAU,CAAA;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACnE;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,iBAAiB,CAAC,KAAK,CAAC,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxE;;;;;OAKG;IACH,OAAO,CAAC,EAAE,YAAY,GAAG,YAAY,EAAE,CAAA;IACvC,2CAA2C;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,KAAK,GAAG,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC,CAE/E"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authoring a `View` — iframe-mountable callable served by the domain worker.
|
|
3
|
+
*
|
|
4
|
+
* Each entry in `defineRemoteDomain({ views: { ... } })` becomes both:
|
|
5
|
+
* - a graph node at `/${origin}/core/<viewsFolder>/<slug>` (auto-materialized
|
|
6
|
+
* by the SDK; the `core/` segment is the universal anchor injected by
|
|
7
|
+
* `buildCorePath`. `<slug>` is the map key, so it lives in exactly one place)
|
|
8
|
+
* - a Hono route on the worker at the path implied by `binding`
|
|
9
|
+
* (`/<viewsFolder>/<slug>` by default — note: no `core/` in the URL).
|
|
10
|
+
*
|
|
11
|
+
* The `core/` segment appears in the GRAPH path only; the URL path that
|
|
12
|
+
* lands in `Function.binding.remoteUrl` is `${url}/<viewsFolder>/<slug>`.
|
|
13
|
+
*
|
|
14
|
+
* The author can override the URL via `binding` — host and/or path
|
|
15
|
+
* placeholders are supported (the kernel's `route` mechanism does the
|
|
16
|
+
* substitution + Hono matching, same as for methods). When `render` is
|
|
17
|
+
* omitted, no worker route is mounted — useful for Views whose iframe
|
|
18
|
+
* lives at an external host.
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Identity helper for authoring a View. Returns its argument unchanged —
|
|
22
|
+
* `defineRemoteDomain` consumes the typed shape and the author retains
|
|
23
|
+
* full type inference on `render` / `authorize`.
|
|
24
|
+
*/
|
|
25
|
+
export function defineView(def) {
|
|
26
|
+
return def;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=view.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.js","sourceRoot":"","sources":["../../src/define/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAiEH;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAkB,GAAmB;IAC7D,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Meta } from './meta';
|
|
2
|
+
export type DeployCheckOptions = {
|
|
3
|
+
/** Deployed worker URL (e.g. `https://dist.astrale.ai`). */
|
|
4
|
+
url: string;
|
|
5
|
+
/**
|
|
6
|
+
* Expected `meta.schemaHash` — the hash of the locally-built `spec.json`
|
|
7
|
+
* (via `hashSpecFile`). REQUIRED to verify schema drift: when the worker
|
|
8
|
+
* advertises a `schemaHash` but this is absent, the check fails loudly rather
|
|
9
|
+
* than silently "passing" an unverified deploy. Per-domain deploy scripts
|
|
10
|
+
* compute it (`hashSpecFile('./spec.json')`) and pass it.
|
|
11
|
+
*/
|
|
12
|
+
expectedSchemaHash?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Path to the SDK repo used to read `sdkCommit`. If omitted and
|
|
15
|
+
* `workspaceRoot` is provided, defaults to `<workspaceRoot>/sdk`.
|
|
16
|
+
*/
|
|
17
|
+
sdkRepoPath?: string;
|
|
18
|
+
/** Astrale workspace root — enables auto-resolution of `sdkRepoPath` (`<root>/sdk`). */
|
|
19
|
+
workspaceRoot?: string;
|
|
20
|
+
/** Sink for progress output. Defaults to `console.log`. */
|
|
21
|
+
log?: (line: string) => void;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* Validate a deployed worker against local state by fetching `/meta` and
|
|
25
|
+
* verifying sdkCommit / schemaHash / JWKS reachability.
|
|
26
|
+
*
|
|
27
|
+
* Throws on any mismatch. Returns `Meta` on success.
|
|
28
|
+
*/
|
|
29
|
+
export declare function deployCheck(opts: DeployCheckOptions): Promise<Meta>;
|
|
30
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/deploy/check.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAIlC,MAAM,MAAM,kBAAkB,GAAG;IAC/B,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,wFAAwF;IACxF,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,2DAA2D;IAC3D,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B,CAAA;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBzE"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { MetaSchema } from './meta';
|
|
4
|
+
/**
|
|
5
|
+
* Validate a deployed worker against local state by fetching `/meta` and
|
|
6
|
+
* verifying sdkCommit / schemaHash / JWKS reachability.
|
|
7
|
+
*
|
|
8
|
+
* Throws on any mismatch. Returns `Meta` on success.
|
|
9
|
+
*/
|
|
10
|
+
export async function deployCheck(opts) {
|
|
11
|
+
// oxlint-disable-next-line no-console
|
|
12
|
+
const log = opts.log ?? ((line) => console.log(line));
|
|
13
|
+
const base = opts.url.replace(/\/+$/, '');
|
|
14
|
+
log(`# deploy:check ${base}`);
|
|
15
|
+
const meta = await fetchMeta(base);
|
|
16
|
+
log(` meta: ${JSON.stringify(meta)}`);
|
|
17
|
+
// `meta.iss` is required + non-empty by `MetaSchema`, enforced in `fetchMeta`.
|
|
18
|
+
await Promise.all([
|
|
19
|
+
checkSdkCommit(meta, opts, log),
|
|
20
|
+
checkSchemaHash(meta, opts, log),
|
|
21
|
+
checkJwks(meta.iss, log),
|
|
22
|
+
]);
|
|
23
|
+
return meta;
|
|
24
|
+
}
|
|
25
|
+
async function fetchMeta(base) {
|
|
26
|
+
const res = await fetch(`${base}/meta`);
|
|
27
|
+
if (!res.ok)
|
|
28
|
+
throw new Error(`GET ${base}/meta → ${res.status}`);
|
|
29
|
+
return MetaSchema.parse(await res.json());
|
|
30
|
+
}
|
|
31
|
+
async function checkSdkCommit(meta, opts, log) {
|
|
32
|
+
if (!meta.sdkCommit) {
|
|
33
|
+
log(' ! meta.sdkCommit absent — skipping sdkCommit check');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const sdkRepo = opts.sdkRepoPath ?? (opts.workspaceRoot ? join(opts.workspaceRoot, 'sdk') : undefined);
|
|
37
|
+
if (!sdkRepo) {
|
|
38
|
+
log(` ! no sdkRepoPath / workspaceRoot — skipping sdkCommit check`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const localSha = gitHead(sdkRepo);
|
|
42
|
+
if (!localSha) {
|
|
43
|
+
log(` ! could not read git HEAD from ${sdkRepo} — skipping sdkCommit check`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (!localSha.startsWith(meta.sdkCommit) && !meta.sdkCommit.startsWith(localSha)) {
|
|
47
|
+
throw new Error(`sdkCommit mismatch: deployed=${meta.sdkCommit} local=${localSha} (${sdkRepo})`);
|
|
48
|
+
}
|
|
49
|
+
log(` ✓ sdkCommit ${meta.sdkCommit} matches local HEAD`);
|
|
50
|
+
}
|
|
51
|
+
async function checkSchemaHash(meta, opts, log) {
|
|
52
|
+
if (!meta.schemaHash)
|
|
53
|
+
return;
|
|
54
|
+
// Fail loud: the worker advertises a schemaHash, so a missing expected value
|
|
55
|
+
// means we CANNOT verify drift — never silently "pass" an unverified deploy.
|
|
56
|
+
if (!opts.expectedSchemaHash) {
|
|
57
|
+
throw new Error(`worker advertises schemaHash=${meta.schemaHash} but no expectedSchemaHash was provided — ` +
|
|
58
|
+
`cannot verify schema drift (pass expectedSchemaHash, e.g. hashSpecFile('./spec.json'))`);
|
|
59
|
+
}
|
|
60
|
+
if (meta.schemaHash !== opts.expectedSchemaHash) {
|
|
61
|
+
throw new Error(`schemaHash mismatch: deployed=${meta.schemaHash} local=${opts.expectedSchemaHash}`);
|
|
62
|
+
}
|
|
63
|
+
log(` ✓ schemaHash ${meta.schemaHash} matches local`);
|
|
64
|
+
}
|
|
65
|
+
async function checkJwks(iss, log) {
|
|
66
|
+
const jwksUrl = `${iss.replace(/\/+$/, '')}/.well-known/jwks.json`;
|
|
67
|
+
const res = await fetch(jwksUrl);
|
|
68
|
+
if (!res.ok)
|
|
69
|
+
throw new Error(`GET ${jwksUrl} → ${res.status}`);
|
|
70
|
+
const body = (await res.json());
|
|
71
|
+
const keys = body.keys ?? [];
|
|
72
|
+
if (keys.length === 0)
|
|
73
|
+
throw new Error(`${jwksUrl} returned no keys`);
|
|
74
|
+
log(` ✓ JWKS resolves (${keys.length} key${keys.length === 1 ? '' : 's'})`);
|
|
75
|
+
}
|
|
76
|
+
function gitHead(repoPath) {
|
|
77
|
+
const r = spawnSync('git', ['-C', repoPath, 'rev-parse', 'HEAD'], { encoding: 'utf-8' });
|
|
78
|
+
if (r.status !== 0)
|
|
79
|
+
return null;
|
|
80
|
+
return r.stdout.trim();
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/deploy/check.ts"],"names":[],"mappings":"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"}
|