@astrale-os/sdk 0.3.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/deploy/hash-spec.d.ts +0 -9
- package/dist/deploy/hash-spec.d.ts.map +0 -1
- package/dist/deploy/hash-spec.js +0 -29
- package/dist/deploy/hash-spec.js.map +0 -1
- 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/dist/domain/extend-core.d.ts +0 -49
- package/dist/domain/extend-core.d.ts.map +0 -1
- package/dist/domain/extend-core.js +0 -190
- package/dist/domain/extend-core.js.map +0 -1
- package/dist/server/worker-meta.d.ts +0 -6
- package/dist/server/worker-meta.d.ts.map +0 -1
- package/dist/server/worker-meta.js +0 -10
- package/dist/server/worker-meta.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,9 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/deploy/hash-spec.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -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,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build an augmented `Core<S>` that includes auto-materialized View and
|
|
3
|
-
* standalone-function nodes (one per entry in `defineRemoteDomain`'s `views` /
|
|
4
|
-
* `remoteFunctions` config), plus their parent Folder + optional `view_for`
|
|
5
|
-
* edges. Returns the resolved effective bindings alongside so callers don't
|
|
6
|
-
* recompute them.
|
|
7
|
-
*
|
|
8
|
-
* Standalone callables (the former `RemoteFunction` class) are materialized as
|
|
9
|
-
* the canonical kernel `Function` node class — "remote" is just a `binding`,
|
|
10
|
-
* not a distinct kind, so there is no per-domain class to configure.
|
|
11
|
-
*
|
|
12
|
-
* Conflicts: if the user core already declares a top-level node at
|
|
13
|
-
* `<viewsFolder>` or `<functionsFolder>`, throws — the auto-materialization
|
|
14
|
-
* reserves those slugs.
|
|
15
|
-
*/
|
|
16
|
-
import type { FunctionBinding } from '@astrale-os/kernel-api/routed';
|
|
17
|
-
import type { AnyEdgeDef, AnyNodeDef, Core, Schema } from '@astrale-os/kernel-dsl';
|
|
18
|
-
import type { AnyRemoteFunctionDef } from '../define/remote-function';
|
|
19
|
-
import type { ViewDef } from '../define/view';
|
|
20
|
-
export declare const DEFAULT_VIEWS_FOLDER = "views";
|
|
21
|
-
export declare const DEFAULT_FUNCTIONS_FOLDER = "functions";
|
|
22
|
-
export type ExtendCoreConfig = {
|
|
23
|
-
schema: Schema;
|
|
24
|
-
origin: string;
|
|
25
|
-
userCore?: Core;
|
|
26
|
-
/**
|
|
27
|
-
* The worker's serving URL — the base every auto-materialized binding
|
|
28
|
-
* resolves against. OMITTED at define time (the URL is known only to the
|
|
29
|
-
* spec producers): the aux nodes then materialize structure-only (paths,
|
|
30
|
-
* names, refs — what identity/subs resolution needs) with no `binding`
|
|
31
|
-
* stamped and empty binding maps. Every install graph comes from a
|
|
32
|
-
* `materializeRemoteDomain(domain, url)` call where it is present.
|
|
33
|
-
*/
|
|
34
|
-
url?: string;
|
|
35
|
-
viewClass?: AnyNodeDef;
|
|
36
|
-
viewForEdgeClass?: AnyEdgeDef;
|
|
37
|
-
viewsFolder?: string;
|
|
38
|
-
views?: Record<string, ViewDef<any>>;
|
|
39
|
-
functionsFolder?: string;
|
|
40
|
-
remoteFunctions?: Record<string, AnyRemoteFunctionDef>;
|
|
41
|
-
};
|
|
42
|
-
export type ExtendCoreResult = {
|
|
43
|
-
core: Core;
|
|
44
|
-
viewBindings: Record<string, FunctionBinding>;
|
|
45
|
-
remoteFunctionBindings: Record<string, FunctionBinding>;
|
|
46
|
-
};
|
|
47
|
-
export declare function extendCore(config: ExtendCoreConfig): ExtendCoreResult;
|
|
48
|
-
export declare function resolveBinding(override: FunctionBinding | undefined, url: string, folderSlug: string, slug: string): FunctionBinding;
|
|
49
|
-
//# sourceMappingURL=extend-core.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extend-core.d.ts","sourceRoot":"","sources":["../../src/domain/extend-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,IAAI,EAGJ,MAAM,EACP,MAAM,wBAAwB,CAAA;AAY/B,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AACrE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAE7C,eAAO,MAAM,oBAAoB,UAAU,CAAA;AAC3C,eAAO,MAAM,wBAAwB,cAAc,CAAA;AAGnD,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IAEZ,SAAS,CAAC,EAAE,UAAU,CAAA;IACtB,gBAAgB,CAAC,EAAE,UAAU,CAAA;IAC7B,WAAW,CAAC,EAAE,MAAM,CAAA;IAEpB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAA;IAEpC,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;CACvD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,IAAI,CAAA;IACV,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IAC7C,sBAAsB,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;CACxD,CAAA;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,gBAAgB,CAuFrE;AAQD,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,eAAe,GAAG,SAAS,EACrC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,GACX,eAAe,CAWjB"}
|
|
@@ -1,190 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build an augmented `Core<S>` that includes auto-materialized View and
|
|
3
|
-
* standalone-function nodes (one per entry in `defineRemoteDomain`'s `views` /
|
|
4
|
-
* `remoteFunctions` config), plus their parent Folder + optional `view_for`
|
|
5
|
-
* edges. Returns the resolved effective bindings alongside so callers don't
|
|
6
|
-
* recompute them.
|
|
7
|
-
*
|
|
8
|
-
* Standalone callables (the former `RemoteFunction` class) are materialized as
|
|
9
|
-
* the canonical kernel `Function` node class — "remote" is just a `binding`,
|
|
10
|
-
* not a distinct kind, so there is no per-domain class to configure.
|
|
11
|
-
*
|
|
12
|
-
* Conflicts: if the user core already declares a top-level node at
|
|
13
|
-
* `<viewsFolder>` or `<functionsFolder>`, throws — the auto-materialization
|
|
14
|
-
* reserves those slugs.
|
|
15
|
-
*/
|
|
16
|
-
import { Folder, K, KernelSchema } from '@astrale-os/kernel-core';
|
|
17
|
-
import { buildCorePath } from '@astrale-os/kernel-dsl';
|
|
18
|
-
/** Canonical node class for standalone callables (the former `RemoteFunction`). */
|
|
19
|
-
const FUNCTION_CLASS = KernelSchema.classes.Function;
|
|
20
|
-
/** Canonical node class for GUI views. */
|
|
21
|
-
const VIEW_CLASS = KernelSchema.classes.View;
|
|
22
|
-
/** Canonical edge class linking a View to its target. */
|
|
23
|
-
const VIEW_FOR_EDGE_CLASS = KernelSchema.classes.view_for;
|
|
24
|
-
export const DEFAULT_VIEWS_FOLDER = 'views';
|
|
25
|
-
export const DEFAULT_FUNCTIONS_FOLDER = 'functions';
|
|
26
|
-
const SLUG_RE = /^[a-z][a-z0-9-]*$/;
|
|
27
|
-
export function extendCore(config) {
|
|
28
|
-
const { schema, origin, userCore, url, viewClass = VIEW_CLASS, viewForEdgeClass = VIEW_FOR_EDGE_CLASS, viewsFolder = DEFAULT_VIEWS_FOLDER, views, functionsFolder = DEFAULT_FUNCTIONS_FOLDER, remoteFunctions, } = config;
|
|
29
|
-
validateInputs(config);
|
|
30
|
-
const nodes = userCore ? [...userCore.__nodes] : [];
|
|
31
|
-
const edges = userCore ? [...userCore.__edges] : [];
|
|
32
|
-
const viewBindings = {};
|
|
33
|
-
const remoteFunctionBindings = {};
|
|
34
|
-
const enableUiHandshake = viewClass === VIEW_CLASS;
|
|
35
|
-
if (views && viewClass) {
|
|
36
|
-
// Enforce ViewDef's documented exclusivity: `mount` (SPA route) cannot be
|
|
37
|
-
// combined with `render` (inline HTML handler) or an explicit `binding` —
|
|
38
|
-
// silently ignoring one of them would deploy a view that behaves
|
|
39
|
-
// differently than its definition reads.
|
|
40
|
-
for (const [slug, def] of Object.entries(views)) {
|
|
41
|
-
if (def.mount && (def.render || def.binding)) {
|
|
42
|
-
throw new Error(`defineRemoteDomain: view "${slug}" sets \`mount\` together with ` +
|
|
43
|
-
`${def.render ? '`render`' : '`binding`'} — they are mutually exclusive.`);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
assertNoConflict(nodes, origin, viewsFolder);
|
|
47
|
-
addFolderAndEntries({
|
|
48
|
-
origin,
|
|
49
|
-
folderSlug: viewsFolder,
|
|
50
|
-
nodes,
|
|
51
|
-
entries: Object.entries(views).map(([slug, def]) => {
|
|
52
|
-
const binding = url
|
|
53
|
-
? def.mount
|
|
54
|
-
? { remoteUrl: joinWorkerPath(url, def.mount) }
|
|
55
|
-
: resolveBinding(def.binding, url, viewsFolder, slug)
|
|
56
|
-
: undefined;
|
|
57
|
-
if (binding)
|
|
58
|
-
viewBindings[slug] = binding;
|
|
59
|
-
return {
|
|
60
|
-
slug,
|
|
61
|
-
nodeClass: viewClass,
|
|
62
|
-
data: buildViewData(slug, binding, def, enableUiHandshake),
|
|
63
|
-
edges: buildViewForEdges(slug, def, viewForEdgeClass, viewsFolder, origin),
|
|
64
|
-
};
|
|
65
|
-
}),
|
|
66
|
-
edges,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
if (remoteFunctions) {
|
|
70
|
-
assertNoConflict(nodes, origin, functionsFolder);
|
|
71
|
-
addFolderAndEntries({
|
|
72
|
-
origin,
|
|
73
|
-
folderSlug: functionsFolder,
|
|
74
|
-
nodes,
|
|
75
|
-
entries: Object.entries(remoteFunctions).map(([slug, def]) => {
|
|
76
|
-
const binding = url ? resolveBinding(def.binding, url, functionsFolder, slug) : undefined;
|
|
77
|
-
if (binding)
|
|
78
|
-
remoteFunctionBindings[slug] = binding;
|
|
79
|
-
return {
|
|
80
|
-
slug,
|
|
81
|
-
// Standalone callables materialize as the canonical kernel Function class.
|
|
82
|
-
nodeClass: FUNCTION_CLASS,
|
|
83
|
-
data: {
|
|
84
|
-
...buildFunctionData(slug, binding),
|
|
85
|
-
[K.$.i('Function').ref.key]: def.ref ?? `function.${slug}`,
|
|
86
|
-
},
|
|
87
|
-
edges: [],
|
|
88
|
-
};
|
|
89
|
-
}),
|
|
90
|
-
edges,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
return {
|
|
94
|
-
core: { schema, domain: origin, __nodes: nodes, __edges: edges },
|
|
95
|
-
viewBindings,
|
|
96
|
-
remoteFunctionBindings,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
/** Join a worker-relative mount path onto the serving url (single slash). */
|
|
100
|
-
function joinWorkerPath(url, mount) {
|
|
101
|
-
const base = url.replace(/\/+$/, '');
|
|
102
|
-
return `${base}/${mount.replace(/^\/+/, '')}`;
|
|
103
|
-
}
|
|
104
|
-
export function resolveBinding(override, url, folderSlug, slug) {
|
|
105
|
-
// Same trailing-slash discipline as `joinWorkerPath` — a `url` ending in `/`
|
|
106
|
-
// must not produce `//` in the binding (the kernel pins iss by exact string).
|
|
107
|
-
const base = url.replace(/\/+$/, '');
|
|
108
|
-
if (override) {
|
|
109
|
-
return {
|
|
110
|
-
...override,
|
|
111
|
-
remoteUrl: override.remoteUrl ?? `${base}/${folderSlug}/${slug}`,
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
return { remoteUrl: `${base}/${folderSlug}/${slug}` };
|
|
115
|
-
}
|
|
116
|
-
// ── Internal ───────────────────────────────────────────────────────────────
|
|
117
|
-
function validateInputs(config) {
|
|
118
|
-
if (config.views) {
|
|
119
|
-
for (const slug of Object.keys(config.views)) {
|
|
120
|
-
if (!SLUG_RE.test(slug)) {
|
|
121
|
-
throw new Error(`defineRemoteDomain: invalid view slug "${slug}" — must match ${SLUG_RE}.`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
if (config.remoteFunctions) {
|
|
126
|
-
for (const slug of Object.keys(config.remoteFunctions)) {
|
|
127
|
-
if (!SLUG_RE.test(slug)) {
|
|
128
|
-
throw new Error(`defineRemoteDomain: invalid remote-function slug "${slug}" — must match ${SLUG_RE}.`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
function assertNoConflict(nodes, origin, folderSlug) {
|
|
134
|
-
const folderPath = buildCorePath(origin, [folderSlug]);
|
|
135
|
-
if (nodes.some((n) => n.path === folderPath)) {
|
|
136
|
-
throw new Error(`defineRemoteDomain: top-level core slug "${folderSlug}" is reserved by ` +
|
|
137
|
-
'SDK auto-materialization. Move the conflicting node or rename the ' +
|
|
138
|
-
'`viewsFolder` / `functionsFolder` config.');
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
function addFolderAndEntries(args) {
|
|
142
|
-
const { origin, folderSlug, entries, nodes, edges } = args;
|
|
143
|
-
const folderPath = buildCorePath(origin, [folderSlug]);
|
|
144
|
-
nodes.push({
|
|
145
|
-
path: folderPath,
|
|
146
|
-
def: Folder,
|
|
147
|
-
data: { [K.Named.name.key]: folderSlug },
|
|
148
|
-
});
|
|
149
|
-
for (const entry of entries) {
|
|
150
|
-
nodes.push({
|
|
151
|
-
path: buildCorePath(origin, [folderSlug, entry.slug]),
|
|
152
|
-
def: entry.nodeClass,
|
|
153
|
-
data: entry.data,
|
|
154
|
-
parent: folderPath,
|
|
155
|
-
});
|
|
156
|
-
for (const e of entry.edges)
|
|
157
|
-
edges.push(e);
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
function buildFunctionData(slug, binding) {
|
|
161
|
-
// Match the kernel-core schema serializer which JSON-stringifies the
|
|
162
|
-
// `Function.binding` value on Function nodes (see
|
|
163
|
-
// kernel/core/domain/serialize/schema.ts). The kernel install validator
|
|
164
|
-
// checks `typeof binding === 'string'` then parses; storing a raw object
|
|
165
|
-
// trips the validator with "missing remote binding" even when the object IS
|
|
166
|
-
// the binding. No binding at all (define-time, no url) → no prop stamped.
|
|
167
|
-
return {
|
|
168
|
-
[K.Named.name.key]: slug,
|
|
169
|
-
...(binding ? { [K.$.i('Function').binding.key]: JSON.stringify(binding) } : {}),
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
function buildViewData(slug, binding, def, enableUiHandshake) {
|
|
173
|
-
const handshake = def.handshake ?? (def.render ? 'none' : undefined);
|
|
174
|
-
return {
|
|
175
|
-
...buildFunctionData(slug, binding),
|
|
176
|
-
...(enableUiHandshake && handshake ? { [K.UI.handshake.key]: handshake } : {}),
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
function buildViewForEdges(slug, def, edgeClass, viewsFolder, origin) {
|
|
180
|
-
if (!def.viewFor || !edgeClass)
|
|
181
|
-
return [];
|
|
182
|
-
const targets = Array.isArray(def.viewFor) ? def.viewFor : [def.viewFor];
|
|
183
|
-
const from = buildCorePath(origin, [viewsFolder, slug]);
|
|
184
|
-
return targets.map((target) => ({
|
|
185
|
-
from,
|
|
186
|
-
edge: edgeClass,
|
|
187
|
-
to: target,
|
|
188
|
-
}));
|
|
189
|
-
}
|
|
190
|
-
//# sourceMappingURL=extend-core.js.map
|