@astrale-os/sdk 0.4.0 → 0.4.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/compose.d.ts +2 -2
- package/dist/auth/compose.d.ts.map +1 -1
- package/dist/auth/compose.js +2 -2
- package/dist/auth/compose.js.map +1 -1
- package/dist/auth/function-context.d.ts +28 -0
- package/dist/auth/function-context.d.ts.map +1 -0
- package/dist/auth/function-context.js +47 -0
- package/dist/auth/function-context.js.map +1 -0
- package/dist/auth/index.d.ts +5 -3
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +3 -2
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/issuer-mint.d.ts +9 -9
- package/dist/auth/issuer-mint.d.ts.map +1 -1
- package/dist/auth/issuer-mint.js +3 -3
- package/dist/auth/issuer-mint.js.map +1 -1
- package/dist/auth/kernel-client.d.ts +5 -17
- package/dist/auth/kernel-client.d.ts.map +1 -1
- package/dist/auth/kernel-client.js +12 -34
- package/dist/auth/kernel-client.js.map +1 -1
- package/dist/cli/publish.js +1 -1
- package/dist/cli/publish.js.map +1 -1
- package/dist/config/define-domain.d.ts +1 -1
- package/dist/define/index.d.ts +1 -1
- package/dist/define/index.d.ts.map +1 -1
- package/dist/define/remote-function.d.ts +22 -30
- package/dist/define/remote-function.d.ts.map +1 -1
- package/dist/define/remote-function.js.map +1 -1
- package/dist/define/view.d.ts +6 -10
- package/dist/define/view.d.ts.map +1 -1
- package/dist/define/view.js.map +1 -1
- package/dist/dispatch/dispatcher.d.ts +1 -1
- package/dist/dispatch/dispatcher.d.ts.map +1 -1
- package/dist/dispatch/dispatcher.js +31 -7
- package/dist/dispatch/dispatcher.js.map +1 -1
- package/dist/dispatch/execute.d.ts +10 -6
- package/dist/dispatch/execute.d.ts.map +1 -1
- package/dist/dispatch/execute.js +5 -3
- package/dist/dispatch/execute.js.map +1 -1
- package/dist/dispatch/index.d.ts +0 -1
- package/dist/dispatch/index.d.ts.map +1 -1
- package/dist/dispatch/index.js +0 -1
- package/dist/dispatch/index.js.map +1 -1
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/method/context.d.ts +34 -28
- package/dist/method/context.d.ts.map +1 -1
- package/dist/method/context.js +2 -1
- package/dist/method/context.js.map +1 -1
- package/dist/method/index.d.ts +1 -1
- package/dist/method/index.d.ts.map +1 -1
- package/dist/method/index.js.map +1 -1
- package/dist/method/single.d.ts +2 -2
- package/dist/method/single.d.ts.map +1 -1
- package/dist/server/auxiliary-routes.d.ts.map +1 -1
- package/dist/server/auxiliary-routes.js +40 -21
- package/dist/server/auxiliary-routes.js.map +1 -1
- package/dist/server/create.js +1 -1
- package/dist/server/create.js.map +1 -1
- package/dist/step/index.d.ts +5 -0
- package/dist/step/index.d.ts.map +1 -0
- package/dist/step/index.js +3 -0
- package/dist/step/index.js.map +1 -0
- package/dist/step/inline.d.ts +8 -0
- package/dist/step/inline.d.ts.map +1 -0
- package/dist/step/inline.js +22 -0
- package/dist/step/inline.js.map +1 -0
- package/dist/step/step.d.ts +28 -0
- package/dist/step/step.d.ts.map +1 -0
- package/dist/step/step.js +53 -0
- package/dist/step/step.js.map +1 -0
- package/package.json +5 -1
- package/src/auth/compose.ts +2 -2
- package/src/auth/function-context.ts +108 -0
- package/src/auth/index.ts +9 -3
- package/src/auth/issuer-mint.ts +10 -9
- package/src/auth/kernel-client.ts +19 -44
- package/src/cli/publish.ts +1 -1
- package/src/config/define-domain.ts +1 -1
- package/src/define/index.ts +1 -0
- package/src/define/remote-function.ts +34 -30
- package/src/define/view.ts +6 -10
- package/src/dispatch/dispatcher.ts +34 -8
- package/src/dispatch/execute.ts +15 -9
- package/src/dispatch/index.ts +0 -1
- package/src/index.ts +20 -5
- package/src/method/context.ts +50 -28
- package/src/method/index.ts +8 -1
- package/src/method/single.ts +2 -2
- package/src/server/auxiliary-routes.ts +41 -23
- package/src/server/create.ts +1 -1
- package/src/step/index.ts +4 -0
- package/src/step/inline.ts +38 -0
- package/src/step/step.ts +95 -0
- package/dist/dispatch/call-remote.d.ts +0 -39
- package/dist/dispatch/call-remote.d.ts.map +0 -1
- package/dist/dispatch/call-remote.js +0 -37
- package/dist/dispatch/call-remote.js.map +0 -1
- package/src/dispatch/call-remote.ts +0 -53
|
@@ -36,16 +36,15 @@ import { buildCorsHeaders, type CorsConfig } from '@astrale-os/kernel-server'
|
|
|
36
36
|
import type { RemoteIdentityConfig } from '../auth/identity'
|
|
37
37
|
import type { AnyRemoteFunctionDef } from '../define/remote-function'
|
|
38
38
|
import type { ViewDef } from '../define/view'
|
|
39
|
-
import type { CallRemoteFn } from '../dispatch/call-remote'
|
|
40
39
|
import type { AuxIdentityMap } from '../dispatch/identity'
|
|
41
40
|
|
|
42
|
-
import {
|
|
43
|
-
import {
|
|
41
|
+
import { makeFunctionContext } from '../auth/function-context'
|
|
42
|
+
import { makeDomainAuthority } from '../auth/issuer-mint'
|
|
44
43
|
import { resolveInboundAuth } from '../auth/resolve'
|
|
45
44
|
import { runAuthorize } from '../dispatch/authorize'
|
|
46
|
-
import { makeCallRemote } from '../dispatch/call-remote'
|
|
47
45
|
import { SdkResultValidationError, SdkValidationError } from '../dispatch/errors'
|
|
48
46
|
import { validateParams, validateResult } from '../dispatch/validate'
|
|
47
|
+
import { createInlineStep } from '../step'
|
|
49
48
|
|
|
50
49
|
export type AuxiliaryRoutesConfig<TDeps> = {
|
|
51
50
|
app: Hono
|
|
@@ -100,16 +99,23 @@ export function mountAuxiliaryRoutes<TDeps>(config: AuxiliaryRoutesConfig<TDeps>
|
|
|
100
99
|
auth: def.auth,
|
|
101
100
|
identity,
|
|
102
101
|
corsHeaders,
|
|
103
|
-
// Views are transport-only (iframe HTML/redirect)
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
// Views are transport-only (iframe HTML/redirect). SERVER-rendered
|
|
103
|
+
// views that read the graph use `ctx.fn.kernel()`: the view's own
|
|
104
|
+
// identity, with narrow grants.
|
|
105
|
+
run: async ({ c, params, auth, kernel }) => {
|
|
106
|
+
const inboundIss = auth?.credential?.verified?.iss as string | undefined
|
|
107
|
+
const kernelUrl = kernel?.default ?? inboundIss
|
|
108
|
+
const ctx = {
|
|
109
|
+
c,
|
|
110
|
+
params,
|
|
111
|
+
auth,
|
|
112
|
+
deps,
|
|
113
|
+
env: { url },
|
|
114
|
+
fn: makeFunctionContext(identity, deps, {
|
|
115
|
+
ref: `view.${slug}`,
|
|
116
|
+
...(kernelUrl !== undefined ? { defaultKernelUrl: kernelUrl } : {}),
|
|
117
|
+
}),
|
|
118
|
+
}
|
|
113
119
|
if (def.authorize) await runAuthorize(def.authorize, ctx)
|
|
114
120
|
return def.render!(ctx)
|
|
115
121
|
},
|
|
@@ -130,26 +136,40 @@ export function mountAuxiliaryRoutes<TDeps>(config: AuxiliaryRoutesConfig<TDeps>
|
|
|
130
136
|
auth: def.auth,
|
|
131
137
|
identity,
|
|
132
138
|
corsHeaders,
|
|
133
|
-
run: async ({ c, auth, kernel
|
|
134
|
-
const selfKernel = makeSelfKernel(identity, deps)
|
|
139
|
+
run: async ({ c, auth, kernel }) => {
|
|
135
140
|
const rawBody: unknown = await c.req.json().catch(() => ({}))
|
|
136
141
|
const validation = validateParams(def.inputSchema, rawBody)
|
|
137
142
|
if (!validation.ok) {
|
|
138
143
|
throw new SdkValidationError(validation.issues as SdkValidationError['issues'])
|
|
139
144
|
}
|
|
140
|
-
const
|
|
145
|
+
const inboundIss = auth?.credential?.verified?.iss as string | undefined
|
|
146
|
+
const kernelUrl = kernel?.default ?? inboundIss
|
|
147
|
+
const caller =
|
|
148
|
+
auth && inboundIss
|
|
149
|
+
? {
|
|
150
|
+
iss: inboundIss,
|
|
151
|
+
url: kernelUrl ?? inboundIss,
|
|
152
|
+
}
|
|
153
|
+
: undefined
|
|
141
154
|
const ctx = {
|
|
142
155
|
params: validation.data,
|
|
143
156
|
c,
|
|
144
157
|
auth,
|
|
145
158
|
deps,
|
|
159
|
+
env: { url },
|
|
146
160
|
kernel,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
161
|
+
...(caller !== undefined ? { caller } : {}),
|
|
162
|
+
domain: makeDomainAuthority(identity),
|
|
163
|
+
fn: makeFunctionContext(identity, deps, {
|
|
164
|
+
ref: `function.${slug}`,
|
|
165
|
+
...(kernelUrl !== undefined ? { defaultKernelUrl: kernelUrl } : {}),
|
|
166
|
+
}),
|
|
150
167
|
}
|
|
151
168
|
if (def.authorize) await runAuthorize(def.authorize, ctx)
|
|
152
|
-
const result = await def.execute(
|
|
169
|
+
const result = await def.execute({
|
|
170
|
+
...ctx,
|
|
171
|
+
step: createInlineStep({ scope: { kind: 'function', ref: `function.${slug}`, slug } }),
|
|
172
|
+
})
|
|
153
173
|
const outValidation = validateResult(def.outputSchema, result)
|
|
154
174
|
if (!outValidation.ok) {
|
|
155
175
|
throw new SdkResultValidationError(
|
|
@@ -188,7 +208,6 @@ type RunArgs = {
|
|
|
188
208
|
params: Record<string, string>
|
|
189
209
|
auth: AuthContext | null
|
|
190
210
|
kernel: BoundClientSessionView<FnMap> | null
|
|
191
|
-
callRemote: CallRemoteFn
|
|
192
211
|
}
|
|
193
212
|
|
|
194
213
|
type MountEntryArgs = {
|
|
@@ -264,7 +283,6 @@ function mountEntry(args: MountEntryArgs): void {
|
|
|
264
283
|
params: { ...hostParams, ...pathParams },
|
|
265
284
|
auth: resolvedAuth,
|
|
266
285
|
kernel,
|
|
267
|
-
callRemote: makeCallRemote(kernel),
|
|
268
286
|
})
|
|
269
287
|
return applyCorsToResponse(response, corsHeaders)
|
|
270
288
|
} catch (err) {
|
package/src/server/create.ts
CHANGED
|
@@ -47,7 +47,7 @@ export function createRemoteServer<TDeps>(config: RemoteServerConfig<TDeps>): Re
|
|
|
47
47
|
deps: config.deps,
|
|
48
48
|
privateKey: config.privateKey,
|
|
49
49
|
issuer: iss,
|
|
50
|
-
// The canonicalized serving URL, NOT the raw config.url: `ctx.url` is
|
|
50
|
+
// The canonicalized serving URL, NOT the raw config.url: `ctx.env.url` is
|
|
51
51
|
// documented as the worker's `iss` identity, so the two must be one value.
|
|
52
52
|
url: iss,
|
|
53
53
|
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Step, StepRun, StepScope } from './step'
|
|
2
|
+
|
|
3
|
+
import { buildStepRun, roundTripStepResult } from './step'
|
|
4
|
+
|
|
5
|
+
export type StepExecutor = <T>(run: StepRun, handler: () => T | Promise<T>) => Promise<T>
|
|
6
|
+
|
|
7
|
+
export type InlineStepOptions = {
|
|
8
|
+
scope?: StepScope
|
|
9
|
+
execute?: StepExecutor
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function createInlineStep(options: InlineStepOptions = {}): Step {
|
|
13
|
+
const occurrences = new Map<string, number>()
|
|
14
|
+
const execute = options.execute ?? inlineExecute
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
async run(id, handler) {
|
|
18
|
+
const run = buildStepRun(id, options.scope, nextOccurrence(id, options.scope, occurrences))
|
|
19
|
+
return execute(run, handler)
|
|
20
|
+
},
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
async function inlineExecute<T>(run: StepRun, handler: () => T | Promise<T>): Promise<T> {
|
|
25
|
+
const result = await handler()
|
|
26
|
+
return roundTripStepResult(run.key, result)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function nextOccurrence(
|
|
30
|
+
id: string,
|
|
31
|
+
scope: StepScope | undefined,
|
|
32
|
+
occurrences: Map<string, number>,
|
|
33
|
+
): number {
|
|
34
|
+
const run = buildStepRun(id, scope, 0)
|
|
35
|
+
const occurrence = occurrences.get(run.key) ?? 0
|
|
36
|
+
occurrences.set(run.key, occurrence + 1)
|
|
37
|
+
return occurrence
|
|
38
|
+
}
|
package/src/step/step.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export type Step = {
|
|
2
|
+
run<T>(id: string, handler: () => T | Promise<T>): Promise<T>
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export type MethodStepScope = {
|
|
6
|
+
kind: 'method'
|
|
7
|
+
ref: string
|
|
8
|
+
owner: string
|
|
9
|
+
method: string
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type FunctionStepScope = {
|
|
13
|
+
kind: 'function'
|
|
14
|
+
ref: string
|
|
15
|
+
slug: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type StepScope = MethodStepScope | FunctionStepScope
|
|
19
|
+
|
|
20
|
+
export type StepRun = {
|
|
21
|
+
/** The author-provided id, normalized to the local id inside this scope. */
|
|
22
|
+
id: string
|
|
23
|
+
/** Backend-facing durable key, qualified by the method/function scope. */
|
|
24
|
+
key: string
|
|
25
|
+
/** Zero-based occurrence for repeated ids in one execution. */
|
|
26
|
+
occurrence: number
|
|
27
|
+
scope?: StepScope
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function requireStepId(id: string): string {
|
|
31
|
+
if (typeof id !== 'string' || id.trim() === '') {
|
|
32
|
+
throw new TypeError('step.run: id must be a non-empty string')
|
|
33
|
+
}
|
|
34
|
+
return id
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function buildStepRun(
|
|
38
|
+
id: string,
|
|
39
|
+
scope: StepScope | undefined,
|
|
40
|
+
occurrence: number,
|
|
41
|
+
): StepRun {
|
|
42
|
+
const stepId = requireStepId(localStepId(id, scope))
|
|
43
|
+
const key = scope ? `${canonicalScope(scope)}.${stepId}` : stepId
|
|
44
|
+
return {
|
|
45
|
+
id: stepId,
|
|
46
|
+
key,
|
|
47
|
+
occurrence,
|
|
48
|
+
...(scope ? { scope } : {}),
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function roundTripStepResult<T>(id: string, value: T): T {
|
|
53
|
+
if (value === undefined) return value
|
|
54
|
+
|
|
55
|
+
let serialized: string | undefined
|
|
56
|
+
try {
|
|
57
|
+
serialized = JSON.stringify(value)
|
|
58
|
+
} catch (err) {
|
|
59
|
+
throw new TypeError(
|
|
60
|
+
`step.run("${id}"): result must be JSON-serializable: ${
|
|
61
|
+
err instanceof Error ? err.message : String(err)
|
|
62
|
+
}`,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (serialized === undefined) {
|
|
67
|
+
throw new TypeError(`step.run("${id}"): result must be JSON-serializable`)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return JSON.parse(serialized) as T
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function localStepId(id: string, scope: StepScope | undefined): string {
|
|
74
|
+
if (!scope) return id
|
|
75
|
+
|
|
76
|
+
for (const prefix of scopePrefixes(scope)) {
|
|
77
|
+
const scoped = `${prefix}.`
|
|
78
|
+
if (id.startsWith(scoped) && id.length > scoped.length) return id.slice(scoped.length)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return id
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function scopePrefixes(scope: StepScope): string[] {
|
|
85
|
+
switch (scope.kind) {
|
|
86
|
+
case 'method':
|
|
87
|
+
return [scope.ref, `${scope.owner}.${scope.method}`]
|
|
88
|
+
case 'function':
|
|
89
|
+
return [scope.ref, `function.${scope.slug}`]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function canonicalScope(scope: StepScope): string {
|
|
94
|
+
return scope.ref
|
|
95
|
+
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `ctx.callRemote` — call ANOTHER worker's remote method from a handler.
|
|
3
|
-
*
|
|
4
|
-
* A worker's `kernel.call('/dom/class.X/method', …)` signs `aud = <kernel>`,
|
|
5
|
-
* which is correct for a **kernel syscall** (it runs in the kernel) but is
|
|
6
|
-
* rejected by a **remote method** (a Function with `binding.remoteUrl`, i.e.
|
|
7
|
-
* another worker) — the target worker verifies `aud` against its own identity
|
|
8
|
-
* and throws `Credential audience mismatch` at authentication.
|
|
9
|
-
*
|
|
10
|
-
* `callRemote` is now a thin wrapper over the bound kernel session: the kernel
|
|
11
|
-
* resolves a remote-bound path to a redirect carrying the worker's URL and its
|
|
12
|
-
* `iss`, and the session (configured in `bindKernel`) follows it reactively —
|
|
13
|
-
* minting a kernel-signed delegation envelope scoped to that `iss` via the
|
|
14
|
-
* caller's own `@<subject>::mintDelegationCredential`, then dialing the worker.
|
|
15
|
-
* Instance-method `self` is injected by the kernel resolver into the redirect,
|
|
16
|
-
* so a bare `kernel.call(path, params)` is all that's needed here.
|
|
17
|
-
*
|
|
18
|
-
* Prerequisite (authorization, unchanged): the calling Function's identity must
|
|
19
|
-
* hold `USE` on `Identity.mintDelegationCredential` AND the target method's own
|
|
20
|
-
* grants — the session only fixes the audience (authentication), not grants.
|
|
21
|
-
*/
|
|
22
|
-
import type { ClientSessionCallOptions } from '@astrale-os/kernel-client/session';
|
|
23
|
-
/**
|
|
24
|
-
* The minimal kernel-call surface: dynamic method dispatch by path string. The
|
|
25
|
-
* bound kernel session view (`BoundClientSessionView`) satisfies it structurally,
|
|
26
|
-
* as does any test double. Exported as the public narrow caller contract so
|
|
27
|
-
* handlers can depend on it instead of the wide, generic session view.
|
|
28
|
-
*/
|
|
29
|
-
export type KernelCaller = {
|
|
30
|
-
call: (method: string, params: unknown, opts?: ClientSessionCallOptions) => Promise<unknown>;
|
|
31
|
-
};
|
|
32
|
-
export type CallRemoteFn = (path: string, params?: Record<string, unknown>) => Promise<unknown>;
|
|
33
|
-
/**
|
|
34
|
-
* Build the `callRemote` helper for one handler invocation. `kernel` is the
|
|
35
|
-
* handler's bound kernel view (or `null` for a public/unauthenticated request,
|
|
36
|
-
* where `callRemote` cannot mint and throws on use).
|
|
37
|
-
*/
|
|
38
|
-
export declare function makeCallRemote(kernel: KernelCaller | null): CallRemoteFn;
|
|
39
|
-
//# sourceMappingURL=call-remote.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"call-remote.d.ts","sourceRoot":"","sources":["../../src/dispatch/call-remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAA;AAEjF;;;;;GAKG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,wBAAwB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAC7F,CAAA;AAED,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE/F;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,GAAG,YAAY,CAWxE"}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `ctx.callRemote` — call ANOTHER worker's remote method from a handler.
|
|
3
|
-
*
|
|
4
|
-
* A worker's `kernel.call('/dom/class.X/method', …)` signs `aud = <kernel>`,
|
|
5
|
-
* which is correct for a **kernel syscall** (it runs in the kernel) but is
|
|
6
|
-
* rejected by a **remote method** (a Function with `binding.remoteUrl`, i.e.
|
|
7
|
-
* another worker) — the target worker verifies `aud` against its own identity
|
|
8
|
-
* and throws `Credential audience mismatch` at authentication.
|
|
9
|
-
*
|
|
10
|
-
* `callRemote` is now a thin wrapper over the bound kernel session: the kernel
|
|
11
|
-
* resolves a remote-bound path to a redirect carrying the worker's URL and its
|
|
12
|
-
* `iss`, and the session (configured in `bindKernel`) follows it reactively —
|
|
13
|
-
* minting a kernel-signed delegation envelope scoped to that `iss` via the
|
|
14
|
-
* caller's own `@<subject>::mintDelegationCredential`, then dialing the worker.
|
|
15
|
-
* Instance-method `self` is injected by the kernel resolver into the redirect,
|
|
16
|
-
* so a bare `kernel.call(path, params)` is all that's needed here.
|
|
17
|
-
*
|
|
18
|
-
* Prerequisite (authorization, unchanged): the calling Function's identity must
|
|
19
|
-
* hold `USE` on `Identity.mintDelegationCredential` AND the target method's own
|
|
20
|
-
* grants — the session only fixes the audience (authentication), not grants.
|
|
21
|
-
*/
|
|
22
|
-
/**
|
|
23
|
-
* Build the `callRemote` helper for one handler invocation. `kernel` is the
|
|
24
|
-
* handler's bound kernel view (or `null` for a public/unauthenticated request,
|
|
25
|
-
* where `callRemote` cannot mint and throws on use).
|
|
26
|
-
*/
|
|
27
|
-
export function makeCallRemote(kernel) {
|
|
28
|
-
return async (path, params = {}) => {
|
|
29
|
-
if (!kernel) {
|
|
30
|
-
throw new Error('callRemote requires an authenticated request — no kernel credential (public method?)');
|
|
31
|
-
}
|
|
32
|
-
// The bound session auto-follows the kernel's redirect and mints for the
|
|
33
|
-
// worker's `iss`; a remote-bound path therefore just works as a kernel.call.
|
|
34
|
-
return kernel.call(path, params);
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
//# sourceMappingURL=call-remote.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"call-remote.js","sourceRoot":"","sources":["../../src/dispatch/call-remote.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAgBH;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,MAA2B;IACxD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,GAAG,EAAE,EAAE,EAAE;QACjC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,sFAAsF,CACvF,CAAA;QACH,CAAC;QACD,yEAAyE;QACzE,6EAA6E;QAC7E,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAClC,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `ctx.callRemote` — call ANOTHER worker's remote method from a handler.
|
|
3
|
-
*
|
|
4
|
-
* A worker's `kernel.call('/dom/class.X/method', …)` signs `aud = <kernel>`,
|
|
5
|
-
* which is correct for a **kernel syscall** (it runs in the kernel) but is
|
|
6
|
-
* rejected by a **remote method** (a Function with `binding.remoteUrl`, i.e.
|
|
7
|
-
* another worker) — the target worker verifies `aud` against its own identity
|
|
8
|
-
* and throws `Credential audience mismatch` at authentication.
|
|
9
|
-
*
|
|
10
|
-
* `callRemote` is now a thin wrapper over the bound kernel session: the kernel
|
|
11
|
-
* resolves a remote-bound path to a redirect carrying the worker's URL and its
|
|
12
|
-
* `iss`, and the session (configured in `bindKernel`) follows it reactively —
|
|
13
|
-
* minting a kernel-signed delegation envelope scoped to that `iss` via the
|
|
14
|
-
* caller's own `@<subject>::mintDelegationCredential`, then dialing the worker.
|
|
15
|
-
* Instance-method `self` is injected by the kernel resolver into the redirect,
|
|
16
|
-
* so a bare `kernel.call(path, params)` is all that's needed here.
|
|
17
|
-
*
|
|
18
|
-
* Prerequisite (authorization, unchanged): the calling Function's identity must
|
|
19
|
-
* hold `USE` on `Identity.mintDelegationCredential` AND the target method's own
|
|
20
|
-
* grants — the session only fixes the audience (authentication), not grants.
|
|
21
|
-
*/
|
|
22
|
-
|
|
23
|
-
import type { ClientSessionCallOptions } from '@astrale-os/kernel-client/session'
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* The minimal kernel-call surface: dynamic method dispatch by path string. The
|
|
27
|
-
* bound kernel session view (`BoundClientSessionView`) satisfies it structurally,
|
|
28
|
-
* as does any test double. Exported as the public narrow caller contract so
|
|
29
|
-
* handlers can depend on it instead of the wide, generic session view.
|
|
30
|
-
*/
|
|
31
|
-
export type KernelCaller = {
|
|
32
|
-
call: (method: string, params: unknown, opts?: ClientSessionCallOptions) => Promise<unknown>
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export type CallRemoteFn = (path: string, params?: Record<string, unknown>) => Promise<unknown>
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Build the `callRemote` helper for one handler invocation. `kernel` is the
|
|
39
|
-
* handler's bound kernel view (or `null` for a public/unauthenticated request,
|
|
40
|
-
* where `callRemote` cannot mint and throws on use).
|
|
41
|
-
*/
|
|
42
|
-
export function makeCallRemote(kernel: KernelCaller | null): CallRemoteFn {
|
|
43
|
-
return async (path, params = {}) => {
|
|
44
|
-
if (!kernel) {
|
|
45
|
-
throw new Error(
|
|
46
|
-
'callRemote requires an authenticated request — no kernel credential (public method?)',
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
// The bound session auto-follows the kernel's redirect and mints for the
|
|
50
|
-
// worker's `iss`; a remote-bound path therefore just works as a kernel.call.
|
|
51
|
-
return kernel.call(path, params)
|
|
52
|
-
}
|
|
53
|
-
}
|