@astrale-os/sdk 0.1.1 → 0.1.2
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 +22 -0
- package/dist/auth/compose.d.ts.map +1 -0
- package/dist/auth/compose.js +23 -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 +28 -0
- package/dist/auth/kernel-client.d.ts.map +1 -0
- package/dist/auth/kernel-client.js +84 -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 +86 -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 +237 -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 +30 -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 +1 -1
|
@@ -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,86 @@
|
|
|
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
|
+
export type RemoteFunctionDef<TParams = unknown, TResult = unknown, TDeps = unknown> = {
|
|
50
|
+
/**
|
|
51
|
+
* Canonical callable identity. Auto-derived as `function.<slug>` (where
|
|
52
|
+
* `<slug>` is the map key) when omitted. Stored as `Function.ref` on the
|
|
53
|
+
* graph node and used by the kernel dispatcher to route the call.
|
|
54
|
+
*/
|
|
55
|
+
ref?: string;
|
|
56
|
+
/** Zod schema for the call's parameters. */
|
|
57
|
+
inputSchema: z.ZodType<TParams>;
|
|
58
|
+
/** Zod schema for the call's result. */
|
|
59
|
+
outputSchema: z.ZodType<TResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Override the binding (URL + route shape). When absent, SDK defaults to
|
|
62
|
+
* `{ remoteUrl: ${url}/<functionsFolder>/<slug> }`. The HTTP verb (POST
|
|
63
|
+
* for functions) is applied by the worker route mounter at mount time — it is
|
|
64
|
+
* NOT stored on the binding, so the materialized `Function.binding` carries
|
|
65
|
+
* `remoteUrl` only.
|
|
66
|
+
*
|
|
67
|
+
* Use this to bind to a custom host or REST-style path. Host + path
|
|
68
|
+
* placeholders both supported.
|
|
69
|
+
*/
|
|
70
|
+
binding?: FunctionBinding;
|
|
71
|
+
/** Authentication policy. Defaults to `'required'`. */
|
|
72
|
+
auth?: AuthPolicy;
|
|
73
|
+
/** Optional pre-execute authorization. Throw to deny. */
|
|
74
|
+
authorize?: (ctx: RemoteFunctionContext<TParams, TDeps>) => void | Promise<void>;
|
|
75
|
+
/** The function body. May be async. */
|
|
76
|
+
execute: (ctx: RemoteFunctionContext<TParams, TDeps>) => TResult | Promise<TResult>;
|
|
77
|
+
/** Optional human-readable description. */
|
|
78
|
+
description?: string;
|
|
79
|
+
};
|
|
80
|
+
export type AnyRemoteFunctionDef = RemoteFunctionDef<any, any, any>;
|
|
81
|
+
/**
|
|
82
|
+
* Identity helper for authoring a RemoteFunction. Returns its argument
|
|
83
|
+
* unchanged — `defineRemoteDomain` consumes the typed shape.
|
|
84
|
+
*/
|
|
85
|
+
export declare function defineRemoteFunction<TParams, TResult, TDeps = unknown>(def: RemoteFunctionDef<TParams, TResult, TDeps>): RemoteFunctionDef<TParams, TResult, TDeps>;
|
|
86
|
+
//# 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;CACzB,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;AAuEH;;;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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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash a `spec.json` file deterministically. Only the schema payload
|
|
3
|
+
* (`nodes` + `edges`) is hashed — the `meta` block carries `builtAt`
|
|
4
|
+
* timestamps that would poison drift detection.
|
|
5
|
+
*
|
|
6
|
+
* Returns `sha256:<hex>`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function hashSpecFile(path: string): string;
|
|
9
|
+
//# sourceMappingURL=hash-spec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-spec.d.ts","sourceRoot":"","sources":["../../src/deploy/hash-spec.ts"],"names":[],"mappings":"AAKA;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
const HASH_ALGORITHM = 'sha256';
|
|
4
|
+
/**
|
|
5
|
+
* Hash a `spec.json` file deterministically. Only the schema payload
|
|
6
|
+
* (`nodes` + `edges`) is hashed — the `meta` block carries `builtAt`
|
|
7
|
+
* timestamps that would poison drift detection.
|
|
8
|
+
*
|
|
9
|
+
* Returns `sha256:<hex>`.
|
|
10
|
+
*/
|
|
11
|
+
export function hashSpecFile(path) {
|
|
12
|
+
const raw = readFileSync(path, 'utf-8');
|
|
13
|
+
const parsed = JSON.parse(raw);
|
|
14
|
+
const canonical = canonicalJson({ nodes: parsed.nodes ?? [], edges: parsed.edges ?? [] });
|
|
15
|
+
return `${HASH_ALGORITHM}:${createHash(HASH_ALGORITHM).update(canonical).digest('hex')}`;
|
|
16
|
+
}
|
|
17
|
+
function canonicalJson(value) {
|
|
18
|
+
if (value === null || typeof value !== 'object')
|
|
19
|
+
return JSON.stringify(value);
|
|
20
|
+
if (Array.isArray(value))
|
|
21
|
+
return '[' + value.map(canonicalJson).join(',') + ']';
|
|
22
|
+
const keys = Object.keys(value).sort();
|
|
23
|
+
return ('{' +
|
|
24
|
+
keys
|
|
25
|
+
.map((k) => JSON.stringify(k) + ':' + canonicalJson(value[k]))
|
|
26
|
+
.join(',') +
|
|
27
|
+
'}');
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=hash-spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hash-spec.js","sourceRoot":"","sources":["../../src/deploy/hash-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAEtC,MAAM,cAAc,GAAG,QAAQ,CAAA;AAE/B;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAA;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAyC,CAAA;IACtE,MAAM,SAAS,GAAG,aAAa,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC,CAAA;IACzF,OAAO,GAAG,cAAc,IAAI,UAAU,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAA;AAC1F,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7E,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,CAAA;IAC/E,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC,CAAC,IAAI,EAAE,CAAA;IACjE,OAAO,CACL,GAAG;QACH,IAAI;aACD,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,aAAa,CAAE,KAAiC,CAAC,CAAC,CAAC,CAAC,CAAC;aAC1F,IAAI,CAAC,GAAG,CAAC;QACZ,GAAG,CACJ,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/deploy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,QAAQ,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/deploy/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,QAAQ,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,WAAW,EAA2B,MAAM,SAAS,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/meta` payload — the contract between `createRemoteServer` (producer)
|
|
3
|
+
* and `deployCheck` (verifier). Both sides parse through `MetaSchema`, so
|
|
4
|
+
* a new field added here flows to both paths and drift is caught at the
|
|
5
|
+
* boundary rather than silently skipped.
|
|
6
|
+
*
|
|
7
|
+
* Scope: **domain workers only**. Kernels rely on OIDC discovery
|
|
8
|
+
* (`/.well-known/openid-configuration`) + JWKS — they have no `/meta`.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
export declare const MetaSchema: z.ZodObject<{
|
|
12
|
+
iss: z.ZodString;
|
|
13
|
+
sdkCommit: z.ZodOptional<z.ZodString>;
|
|
14
|
+
schemaHash: z.ZodOptional<z.ZodString>;
|
|
15
|
+
domainName: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, z.core.$strip>;
|
|
17
|
+
export type Meta = z.infer<typeof MetaSchema>;
|
|
18
|
+
//# sourceMappingURL=meta.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../../src/deploy/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,eAAO,MAAM,UAAU;;;;;iBAUrB,CAAA;AAEF,MAAM,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `/meta` payload — the contract between `createRemoteServer` (producer)
|
|
3
|
+
* and `deployCheck` (verifier). Both sides parse through `MetaSchema`, so
|
|
4
|
+
* a new field added here flows to both paths and drift is caught at the
|
|
5
|
+
* boundary rather than silently skipped.
|
|
6
|
+
*
|
|
7
|
+
* Scope: **domain workers only**. Kernels rely on OIDC discovery
|
|
8
|
+
* (`/.well-known/openid-configuration`) + JWKS — they have no `/meta`.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
export const MetaSchema = z.object({
|
|
12
|
+
/** Base URL where JWKS is published. Always stamped by `createRemoteServer`
|
|
13
|
+
* and required by `deployCheck` to verify JWKS reachability. */
|
|
14
|
+
iss: z.string().min(1),
|
|
15
|
+
/** Short git SHA of the SDK used to build the worker. */
|
|
16
|
+
sdkCommit: z.string().optional(),
|
|
17
|
+
/** Deterministic hash of the compiled spec (`sha256:<hex>`). */
|
|
18
|
+
schemaHash: z.string().optional(),
|
|
19
|
+
/** Local directory name under `kernel/domains/<...>/` — used to auto-resolve the local spec. */
|
|
20
|
+
domainName: z.string().optional(),
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=meta.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta.js","sourceRoot":"","sources":["../../src/deploy/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAEvB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC;qEACiE;IACjE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,yDAAyD;IACzD,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,gEAAgE;IAChE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,gGAAgG;IAChG,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAClC,CAAC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared `authorize`-hook runner.
|
|
3
|
+
*
|
|
4
|
+
* Both the method dispatcher (`dispatcher.ts`) and the worker-side aux routes
|
|
5
|
+
* (`server/auxiliary-routes.ts`) let an author deny a call by throwing from an
|
|
6
|
+
* `authorize` hook. They MUST agree on the wire semantics: an already-typed
|
|
7
|
+
* `AuthorizationDeniedError` passes through unchanged (so callers can attach
|
|
8
|
+
* hints), and any other thrown error is wrapped into `AuthorizationDeniedError`
|
|
9
|
+
* (→ `PERMISSION_DENIED` / HTTP 403). Centralised here so the two call sites
|
|
10
|
+
* cannot drift — previously the aux routes awaited `authorize` directly, so a
|
|
11
|
+
* plain `Error` thrown to deny leaked out as a 500 instead of a 403.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runAuthorize<C>(hook: (ctx: C) => void | Promise<void>, ctx: C): Promise<void>;
|
|
14
|
+
//# sourceMappingURL=authorize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/dispatch/authorize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAIH,wBAAsB,YAAY,CAAC,CAAC,EAClC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACtC,GAAG,EAAE,CAAC,GACL,OAAO,CAAC,IAAI,CAAC,CAUf"}
|