@astrale-os/sdk 0.1.10 → 0.2.0
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/index.d.ts +1 -1
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/cli/run.d.ts +0 -1
- package/dist/cli/run.d.ts.map +1 -1
- package/dist/cli/run.js +17 -10
- package/dist/cli/run.js.map +1 -1
- package/dist/config/adapter.d.ts +12 -11
- package/dist/config/adapter.d.ts.map +1 -1
- package/dist/config/adapter.js.map +1 -1
- package/dist/config/define-domain.d.ts +13 -29
- package/dist/config/define-domain.d.ts.map +1 -1
- package/dist/config/define-domain.js +22 -33
- package/dist/config/define-domain.js.map +1 -1
- package/dist/config/deploy.d.ts +1 -1
- package/dist/config/deploy.js +1 -1
- package/dist/config/index.d.ts +1 -1
- package/dist/config/index.d.ts.map +1 -1
- package/dist/define/remote-function.d.ts +9 -14
- package/dist/define/remote-function.d.ts.map +1 -1
- package/dist/define/remote-function.js +9 -8
- package/dist/define/remote-function.js.map +1 -1
- package/dist/define/view.d.ts +8 -6
- package/dist/define/view.d.ts.map +1 -1
- package/dist/define/view.js +8 -6
- package/dist/define/view.js.map +1 -1
- package/dist/dispatch/identity.d.ts +10 -9
- package/dist/dispatch/identity.d.ts.map +1 -1
- package/dist/dispatch/identity.js +9 -15
- package/dist/dispatch/identity.js.map +1 -1
- package/dist/domain/binding.d.ts +18 -0
- package/dist/domain/binding.d.ts.map +1 -0
- package/dist/domain/binding.js +29 -0
- package/dist/domain/binding.js.map +1 -0
- package/dist/domain/build-spec.d.ts.map +1 -1
- package/dist/domain/build-spec.js +10 -7
- package/dist/domain/build-spec.js.map +1 -1
- package/dist/domain/define.d.ts +27 -27
- package/dist/domain/define.d.ts.map +1 -1
- package/dist/domain/define.js +31 -49
- package/dist/domain/define.js.map +1 -1
- package/dist/domain/extend-functions.d.ts +44 -0
- package/dist/domain/extend-functions.d.ts.map +1 -0
- package/dist/domain/extend-functions.js +69 -0
- package/dist/domain/extend-functions.js.map +1 -0
- package/dist/domain/extend-views.d.ts +45 -0
- package/dist/domain/extend-views.d.ts.map +1 -0
- package/dist/domain/extend-views.js +116 -0
- package/dist/domain/extend-views.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server/auxiliary-routes.js +1 -1
- package/dist/server/auxiliary-routes.js.map +1 -1
- package/dist/server/worker-entry.d.ts +3 -3
- package/dist/server/worker-entry.js +3 -3
- package/package.json +2 -5
- package/src/auth/index.ts +1 -1
- package/src/cli/run.ts +17 -12
- package/src/config/adapter.ts +9 -11
- package/src/config/define-domain.ts +34 -56
- package/src/config/deploy.ts +1 -1
- package/src/config/index.ts +1 -1
- package/src/define/remote-function.ts +9 -14
- package/src/define/view.ts +8 -6
- package/src/dispatch/identity.ts +15 -21
- package/src/domain/binding.ts +37 -0
- package/src/domain/build-spec.ts +18 -7
- package/src/domain/define.ts +67 -62
- package/src/domain/extend-functions.ts +86 -0
- package/src/domain/extend-views.ts +151 -0
- package/src/index.ts +7 -2
- package/src/server/auxiliary-routes.ts +1 -1
- package/src/server/worker-entry.ts +3 -3
- package/src/domain/extend-core.ts +0 -301
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `defineDomain` — the WORKER-SAFE definition of a domain: what the domain *is*
|
|
3
|
-
* (its `schema`, `methods`, `deps`, `views`, standalone `functions
|
|
4
|
-
*
|
|
3
|
+
* (its `schema`, `methods`, `deps`, `views`, standalone `functions`) plus its
|
|
4
|
+
* addressing identity (`origin`, `requires`, `postInstall`). It
|
|
5
5
|
* deliberately carries NO deployment adapter — the adapter (`cloudflare(...)`,
|
|
6
6
|
* `astrale(...)`) is node-only code (filesystem, wrangler) that must never enter
|
|
7
7
|
* the worker bundle. The author wires this in a `domain.ts` the generated worker
|
|
@@ -11,14 +11,14 @@
|
|
|
11
11
|
* The modules are wired EXPLICITLY here — imported and passed in — not
|
|
12
12
|
* discovered from magic folder names. A renamed or mistyped module is a compile
|
|
13
13
|
* error at this call site, never a silently-missing worker route. The adapter
|
|
14
|
-
* reads this one definition for
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* reads this one definition for domain-side codegen; frontend source folders
|
|
15
|
+
* live in adapter env config. `defineDomain` itself builds no server and boots
|
|
16
|
+
* no kernel — it validates and packages the declaration.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
20
20
|
|
|
21
|
-
import { DomainOrigin
|
|
21
|
+
import { DomainOrigin } from '@astrale-os/kernel-core/domain'
|
|
22
22
|
|
|
23
23
|
import type { RemoteFunctionDef, ViewDef } from '../define'
|
|
24
24
|
import type { SchemaMethodsImpl } from '../method'
|
|
@@ -33,15 +33,6 @@ type AnyViewDef = ViewDef<any>
|
|
|
33
33
|
type AnyFunctionDef = RemoteFunctionDef<any, any, any>
|
|
34
34
|
// oxlint-enable no-explicit-any
|
|
35
35
|
|
|
36
|
-
/**
|
|
37
|
-
* The domain's client SPA binding. Its presence is the whole signal — there is
|
|
38
|
-
* no `existsSync('client/')` probe. `dir` is the project-relative source folder
|
|
39
|
-
* (e.g. `'client'`); the worker serves its built SPA under `/ui` via its Assets
|
|
40
|
-
* binding. Always written out explicitly (`client: { dir: 'client' }`) — there
|
|
41
|
-
* is no boolean shorthand, so the source folder is never implicit.
|
|
42
|
-
*/
|
|
43
|
-
export type ClientBinding = { dir: string }
|
|
44
|
-
|
|
45
36
|
export interface DefineDomainConfig<S extends Schema, TDeps, TEnv = unknown> {
|
|
46
37
|
/** The domain schema (from `schema/`). Its `.domain` seeds the default origin. */
|
|
47
38
|
schema: S
|
|
@@ -76,12 +67,6 @@ export interface DefineDomainConfig<S extends Schema, TDeps, TEnv = unknown> {
|
|
|
76
67
|
* by slug. Omit when the domain has none.
|
|
77
68
|
*/
|
|
78
69
|
functions?: Record<string, AnyFunctionDef>
|
|
79
|
-
/**
|
|
80
|
-
* The domain's client SPA, e.g. `{ dir: 'client' }`. Its presence enables it
|
|
81
|
-
* (no folder probing); `dir` is the project-relative source folder, built and
|
|
82
|
-
* served under `/ui`. Omit for a domain with no SPA.
|
|
83
|
-
*/
|
|
84
|
-
client?: ClientBinding
|
|
85
70
|
/**
|
|
86
71
|
* The domain's **addressing name** (the graph slug it mounts under, e.g.
|
|
87
72
|
* `'crm.acme.dev'`). Defaults to `schema.domain`. Must be a name, never a
|
|
@@ -94,11 +79,15 @@ export interface DefineDomainConfig<S extends Schema, TDeps, TEnv = unknown> {
|
|
|
94
79
|
/** Cross-domain deps, by origin. Verified present on the instance at install. */
|
|
95
80
|
requires?: readonly string[]
|
|
96
81
|
/**
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
*
|
|
82
|
+
* The function the kernel runs once after install, as __SYSTEM__ — where the
|
|
83
|
+
* domain seeds itself / posts its own grants. Reference it from the `functions`
|
|
84
|
+
* map: `postInstall: functions.seed`. The SDK derives its path by identity, so a
|
|
85
|
+
* typo or a renamed key is a compile error here, never a stale string. It is
|
|
86
|
+
* always a standalone function (a domain bootstrap belongs to the domain, not to
|
|
87
|
+
* a class) under THIS domain — you never write the origin, and the kernel
|
|
88
|
+
* resolves it relative to wherever the domain is installed.
|
|
100
89
|
*/
|
|
101
|
-
postInstall?:
|
|
90
|
+
postInstall?: AnyFunctionDef
|
|
102
91
|
}
|
|
103
92
|
|
|
104
93
|
export interface DomainDefinition {
|
|
@@ -114,8 +103,6 @@ export interface DomainDefinition {
|
|
|
114
103
|
deps?: (env: any, url: string) => any
|
|
115
104
|
views?: Record<string, ViewDef>
|
|
116
105
|
functions?: Record<string, AnyFunctionDef>
|
|
117
|
-
/** Normalized client binding (resolved `dir`), or absent when the domain has no SPA. */
|
|
118
|
-
client?: { dir: string }
|
|
119
106
|
origin: string
|
|
120
107
|
requires: readonly string[]
|
|
121
108
|
postInstall?: string
|
|
@@ -170,46 +157,37 @@ export function defineDomain<S extends Schema, TDeps, TEnv = unknown>(
|
|
|
170
157
|
...(config.deps ? { deps: config.deps as DomainDefinition['deps'] } : {}),
|
|
171
158
|
...(config.views ? { views: config.views as Record<string, ViewDef> } : {}),
|
|
172
159
|
...(config.functions ? { functions: config.functions } : {}),
|
|
173
|
-
...(config.client ? { client: config.client } : {}),
|
|
174
160
|
origin,
|
|
175
161
|
requires,
|
|
176
|
-
...(config.postInstall
|
|
177
|
-
? { postInstall: normalizePostInstall(config.postInstall, origin) }
|
|
162
|
+
...(config.postInstall !== undefined
|
|
163
|
+
? { postInstall: normalizePostInstall(config.postInstall, origin, config.functions) }
|
|
178
164
|
: {}),
|
|
179
165
|
}
|
|
180
166
|
}
|
|
181
167
|
|
|
182
168
|
/**
|
|
183
|
-
*
|
|
184
|
-
* the
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* casing, but the kernel stores graph nodes (and runs its guard) under the
|
|
190
|
-
* lowercased origin — so the origin segment is re-stamped canonical. Rejects a
|
|
191
|
-
* tree path or one pointing at a different domain (the kernel calls the hook
|
|
192
|
-
* as __SYSTEM__ and refuses a foreign target).
|
|
169
|
+
* Resolve a `postInstall` function reference to the colon-path the bundle carries.
|
|
170
|
+
* The slug is the `functions` map key the reference is registered under (found by
|
|
171
|
+
* identity), so a renamed key is a compile error at the reference site AND the
|
|
172
|
+
* derived path follows the rename. The origin is never the author's to supply
|
|
173
|
+
* (postInstall is always a standalone function of THIS domain) and the path is
|
|
174
|
+
* mount-agnostic — the kernel resolves it wherever the domain is installed.
|
|
193
175
|
*/
|
|
194
|
-
function normalizePostInstall(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (slug.toLowerCase() !== origin) {
|
|
176
|
+
function normalizePostInstall(
|
|
177
|
+
postInstall: AnyFunctionDef,
|
|
178
|
+
origin: string,
|
|
179
|
+
functions: Record<string, AnyFunctionDef> | undefined,
|
|
180
|
+
): string {
|
|
181
|
+
const slug = functions
|
|
182
|
+
? Object.entries(functions).find(([, def]) => def === postInstall)?.[0]
|
|
183
|
+
: undefined
|
|
184
|
+
if (slug === undefined) {
|
|
204
185
|
throw new Error(
|
|
205
|
-
|
|
206
|
-
`
|
|
186
|
+
"defineDomain: `postInstall` must reference a function from this domain's `functions` map " +
|
|
187
|
+
'(e.g. `postInstall: functions.seed`).',
|
|
207
188
|
)
|
|
208
189
|
}
|
|
209
|
-
|
|
210
|
-
return postInstall.startsWith('/:')
|
|
211
|
-
? `/:${origin}${postInstall.slice(2 + slug.length)}`
|
|
212
|
-
: `/${origin}${postInstall.slice(1 + slug.length)}`
|
|
190
|
+
return `/:${origin}:function.${slug}`
|
|
213
191
|
}
|
|
214
192
|
|
|
215
193
|
function schemaDomain(schema: Schema): string | undefined {
|
package/src/config/deploy.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* is authored in `astrale.config.ts` — a Node-only module the CLI loads but the
|
|
10
10
|
* worker never imports — so the adapter stays out of the bundle.
|
|
11
11
|
*
|
|
12
|
-
* export const domain = defineDomain({ schema, methods, deps, views
|
|
12
|
+
* export const domain = defineDomain({ schema, methods, deps, views })
|
|
13
13
|
*
|
|
14
14
|
* import { domain } from './domain'
|
|
15
15
|
* export default deploy(domain, cloudflare({ dev, prod }))
|
package/src/config/index.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
export { defineDomain } from './define-domain'
|
|
17
|
-
export type {
|
|
17
|
+
export type { DefineDomainConfig, DomainDefinition } from './define-domain'
|
|
18
18
|
|
|
19
19
|
export { deploy } from './deploy'
|
|
20
20
|
export type { DeployConfig } from './deploy'
|
|
@@ -4,16 +4,17 @@
|
|
|
4
4
|
* the canonical kernel `Function` class, the former distribution `RemoteFunction`.)
|
|
5
5
|
*
|
|
6
6
|
* Each entry in `defineRemoteDomain({ remoteFunctions: { ... } })` becomes:
|
|
7
|
-
* - a graph node at `/${origin}/
|
|
8
|
-
* as the kernel `Function` class
|
|
9
|
-
* `
|
|
7
|
+
* - a graph node at `/${origin}/functions/<slug>` — a first-class domain MEMBER,
|
|
8
|
+
* materialized as the kernel `Function` class and attached to the Domain via an
|
|
9
|
+
* `of_domain` edge (slug `function.<slug>`), so it is addressable by the
|
|
10
|
+
* semantic path `/:${origin}:function.<slug>` (the form a `postInstall` uses).
|
|
10
11
|
* - a Hono route on the worker at the path implied by `binding`
|
|
11
|
-
* (`/<functionsFolder>/<slug>` POST by default —
|
|
12
|
+
* (`/<functionsFolder>/<slug>` POST by default — the route URL is decoupled
|
|
13
|
+
* from the graph layout).
|
|
12
14
|
*
|
|
13
|
-
* The slug = the map key (single source of truth, no duplication).
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
16
|
-
* `Function.ref` on the graph node and as the dispatch key.
|
|
15
|
+
* The slug = the map key (single source of truth, no duplication). The member
|
|
16
|
+
* ref (`function.<slug>`), the layout (`/<origin>/functions/<slug>`), and the
|
|
17
|
+
* `of_domain` edge slug are all DERIVED from it — there is nothing else to name.
|
|
17
18
|
*/
|
|
18
19
|
|
|
19
20
|
import type { AuthPolicy, FunctionBinding } from '@astrale-os/kernel-api/routed'
|
|
@@ -77,12 +78,6 @@ export type RemoteFunctionDef<
|
|
|
77
78
|
TDeps = unknown,
|
|
78
79
|
TAuth extends AuthPolicy = 'required',
|
|
79
80
|
> = {
|
|
80
|
-
/**
|
|
81
|
-
* Canonical callable identity. Auto-derived as `function.<slug>` (where
|
|
82
|
-
* `<slug>` is the map key) when omitted. Stored as `Function.ref` on the
|
|
83
|
-
* graph node and used by the kernel dispatcher to route the call.
|
|
84
|
-
*/
|
|
85
|
-
ref?: string
|
|
86
81
|
/** Zod schema for the call's parameters. */
|
|
87
82
|
inputSchema: z.ZodType<TParams>
|
|
88
83
|
/** Zod schema for the call's result. */
|
package/src/define/view.ts
CHANGED
|
@@ -2,14 +2,16 @@
|
|
|
2
2
|
* Authoring a `View` — iframe-mountable callable served by the domain worker.
|
|
3
3
|
*
|
|
4
4
|
* Each entry in `defineRemoteDomain({ views: { ... } })` becomes both:
|
|
5
|
-
* - a
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* - a first-class domain MEMBER: a `View` node at `/${origin}/views/<slug>`
|
|
6
|
+
* attached to the Domain via an `of_domain` edge (slug `view.<slug>`),
|
|
7
|
+
* addressable as `/:${origin}:view.<slug>`. `<slug>` is the map key, so it
|
|
8
|
+
* lives in exactly one place.
|
|
8
9
|
* - a Hono route on the worker at the path implied by `binding`
|
|
9
|
-
* (`/<viewsFolder>/<slug>` by default
|
|
10
|
+
* (`/<viewsFolder>/<slug>` by default).
|
|
10
11
|
*
|
|
11
|
-
* The
|
|
12
|
-
* lands in `Function.binding.remoteUrl` is
|
|
12
|
+
* The graph layout (`/<origin>/views/<slug>`) is a fixed kernel convention; the
|
|
13
|
+
* URL path that lands in `Function.binding.remoteUrl` is
|
|
14
|
+
* `${url}/<viewsFolder>/<slug>` — DECOUPLED from the graph layout.
|
|
13
15
|
*
|
|
14
16
|
* The author can override the URL via `binding` — host and/or path
|
|
15
17
|
* placeholders are supported (the kernel's `route` mechanism does the
|
package/src/dispatch/identity.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Per-callable identity — dispatcher runtime + install-time wiring.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* binding: Methods on classes/interfaces (sub = MethodPath)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Three flavors of callable get an identity per the install-time identity
|
|
5
|
+
* binding: Methods on classes/interfaces (sub = MethodPath), standalone-function
|
|
6
|
+
* MEMBERS (sub = AbsolutePath at `/<origin>/functions/<slug>`), and view MEMBERS
|
|
7
|
+
* (sub = AbsolutePath at `/<origin>/views/<slug>`).
|
|
8
8
|
*
|
|
9
9
|
* At server startup the method dispatcher and the View / RemoteFunction
|
|
10
10
|
* route mounter pre-compute, for every materialized callable, the
|
|
@@ -54,11 +54,12 @@ export type AuxBuckets<T> = {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* slug → `AbsolutePath.raw` for each
|
|
58
|
-
* (
|
|
59
|
-
* `/<origin>/
|
|
60
|
-
*
|
|
61
|
-
*
|
|
57
|
+
* slug → `AbsolutePath.raw` for each aux callable MEMBER node:
|
|
58
|
+
* - standalone-function members (`kind: 'function'`) at `/<origin>/functions/<slug>`;
|
|
59
|
+
* - view members (`kind: 'view'`) at `/<origin>/views/<slug>` (plus any
|
|
60
|
+
* hand-authored/legacy core `View` nodes, `kind: 'core'` className `View`).
|
|
61
|
+
* Neither has a class+method decomposition that would justify a MethodPath —
|
|
62
|
+
* their identity is their graph position.
|
|
62
63
|
*/
|
|
63
64
|
export type AuxIdentityPaths = AuxBuckets<string>
|
|
64
65
|
|
|
@@ -66,20 +67,13 @@ export function collectAuxIdentityPaths(compiled: CompiledDomain): AuxIdentityPa
|
|
|
66
67
|
const views: Record<string, string> = {}
|
|
67
68
|
const remoteFunctions: Record<string, string> = {}
|
|
68
69
|
for (const c of resolveCallables(compiled)) {
|
|
69
|
-
if (
|
|
70
|
-
if (c.
|
|
71
|
-
views[c.slug] = c.sub
|
|
72
|
-
} else if (c.className === 'Function') {
|
|
73
|
-
// Standalone callables (the former `RemoteFunction`) materialize as the
|
|
74
|
-
// canonical kernel `Function` class.
|
|
70
|
+
if (!c.slug) continue
|
|
71
|
+
if (c.kind === 'function') {
|
|
75
72
|
remoteFunctions[c.slug] = c.sub
|
|
76
|
-
} else {
|
|
77
|
-
|
|
78
|
-
`collectAuxIdentityPaths: unrecognised aux callable className "${c.className}" ` +
|
|
79
|
-
`at ${c.ref}. If you've added a new auto-materialized Function class to extendCore, ` +
|
|
80
|
-
`extend this collector + the kernel walker (resolveCallables) to handle it.`,
|
|
81
|
-
)
|
|
73
|
+
} else if (c.kind === 'view' || (c.kind === 'core' && c.className === 'View')) {
|
|
74
|
+
views[c.slug] = c.sub
|
|
82
75
|
}
|
|
76
|
+
// Methods (`kind: 'method'`) get their identity via `collectMethodPaths`.
|
|
83
77
|
}
|
|
84
78
|
return { views, remoteFunctions }
|
|
85
79
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared binding helpers for auto-materialized members (functions + views).
|
|
3
|
+
*
|
|
4
|
+
* The worker ROUTE URL a member is served at — `<url>/<folderSlug>/<slug>` — is
|
|
5
|
+
* decoupled from the member's GRAPH layout (`/<origin>/{functions,views}/<slug>`,
|
|
6
|
+
* a fixed kernel convention). `folderSlug` names only the URL segment.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { FunctionBinding } from '@astrale-os/kernel-api/routed'
|
|
10
|
+
|
|
11
|
+
/** Join a worker-relative mount path onto the serving url (single slash). */
|
|
12
|
+
export function joinWorkerPath(url: string, mount: string): string {
|
|
13
|
+
const base = url.replace(/\/+$/, '')
|
|
14
|
+
return `${base}/${mount.replace(/^\/+/, '')}`
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolve a member's effective binding against the serving `url`. An explicit
|
|
19
|
+
* `override.remoteUrl` wins; otherwise defaults to `<url>/<folderSlug>/<slug>`.
|
|
20
|
+
* Same trailing-slash discipline as {@link joinWorkerPath} — a `url` ending in
|
|
21
|
+
* `/` must not produce `//` (the kernel pins `iss` by exact string).
|
|
22
|
+
*/
|
|
23
|
+
export function resolveBinding(
|
|
24
|
+
override: FunctionBinding | undefined,
|
|
25
|
+
url: string,
|
|
26
|
+
folderSlug: string,
|
|
27
|
+
slug: string,
|
|
28
|
+
): FunctionBinding {
|
|
29
|
+
const base = url.replace(/\/+$/, '')
|
|
30
|
+
if (override) {
|
|
31
|
+
return {
|
|
32
|
+
...override,
|
|
33
|
+
remoteUrl: override.remoteUrl ?? `${base}/${folderSlug}/${slug}`,
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { remoteUrl: `${base}/${folderSlug}/${slug}` }
|
|
37
|
+
}
|
package/src/domain/build-spec.ts
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type { Graph, WireGraph } from '@astrale-os/kernel-core'
|
|
21
|
-
import type { BoundMethod, FunctionSchema } from '@astrale-os/kernel-core/domain'
|
|
21
|
+
import type { BoundMethod, FunctionSchema, ViewSchema } from '@astrale-os/kernel-core/domain'
|
|
22
22
|
import type { Schema } from '@astrale-os/kernel-dsl'
|
|
23
23
|
|
|
24
24
|
import { hashInstallGraph, serialize, zodToJsonSchema } from '@astrale-os/kernel-core/domain'
|
|
@@ -41,8 +41,14 @@ export function buildInstallGraph<S extends Schema>(
|
|
|
41
41
|
domain: RemoteDomain<S>,
|
|
42
42
|
url: string,
|
|
43
43
|
): WireGraph {
|
|
44
|
-
const { compiled } = materializeRemoteDomain(domain, url)
|
|
45
|
-
return buildSpecInternal(
|
|
44
|
+
const { compiled, auxiliary } = materializeRemoteDomain(domain, url)
|
|
45
|
+
return buildSpecInternal(
|
|
46
|
+
compiled,
|
|
47
|
+
domain.methods,
|
|
48
|
+
url,
|
|
49
|
+
auxiliary?.functionSchemas ?? [],
|
|
50
|
+
auxiliary?.viewSchemas ?? [],
|
|
51
|
+
).toWire() as WireGraph
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/**
|
|
@@ -63,12 +69,17 @@ function buildSpecInternal(
|
|
|
63
69
|
compiled: RemoteDomain['compiled'],
|
|
64
70
|
methods: BoundMethod<AnyRemoteHandler>[],
|
|
65
71
|
url: string,
|
|
72
|
+
functionSchemas: FunctionSchema[],
|
|
73
|
+
viewSchemas: ViewSchema[],
|
|
66
74
|
): Graph {
|
|
67
75
|
const serialized = serializeMethodsWithStubs(compiled, methods, url)
|
|
68
|
-
|
|
69
|
-
//
|
|
70
|
-
//
|
|
71
|
-
//
|
|
76
|
+
// Method impls + standalone-function-member impls travel in the same callable
|
|
77
|
+
// array (distinct refs: `class.X.method.y` vs `function.<slug>`); view-member
|
|
78
|
+
// impls travel in `options.views` (a view differs structurally — handshake,
|
|
79
|
+
// view_for, View class). The serializer emits method nodes from the IR,
|
|
80
|
+
// function/view members from `compiled.$.refs.{functions,views}`, pulling each
|
|
81
|
+
// impl by ref.
|
|
82
|
+
const tree = serialize(compiled, [...serialized, ...functionSchemas], { views: viewSchemas })
|
|
72
83
|
return tree.toGraph()
|
|
73
84
|
}
|
|
74
85
|
|
package/src/domain/define.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `defineRemoteDomain` — turn a typed schema + methods map into a mountable domain.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* configure). The same entries'
|
|
4
|
+
* `views` and `functions` entries become first-class DOMAIN MEMBERS: a `View` /
|
|
5
|
+
* `Function` node attached to the Domain via an `of_domain` edge (slug
|
|
6
|
+
* `view.<slug>` / `function.<slug>`), laid out at `/<origin>/{views,functions}/<slug>`.
|
|
7
|
+
* Their contract half (the member ref) threads through `compileDomain`; their
|
|
8
|
+
* impl/binding half threads through `serialize`. The same entries'
|
|
10
9
|
* `render` / `execute` handlers are mounted as Hono routes by
|
|
11
|
-
* `createRemoteServer
|
|
10
|
+
* `createRemoteServer` at `<url>/<viewsFolder|functionsFolder>/<slug>` (the route
|
|
11
|
+
* URL is decoupled from the graph layout). Slug = map key.
|
|
12
12
|
*
|
|
13
13
|
* The domain definition is deployment-agnostic: it carries NO serving url. The
|
|
14
14
|
* url is supplied late by the spec producer (`createRemoteServer({ url })` at
|
|
@@ -18,8 +18,13 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import type { FunctionBinding } from '@astrale-os/kernel-api/routed'
|
|
21
|
-
import type {
|
|
22
|
-
|
|
21
|
+
import type {
|
|
22
|
+
BoundMethod,
|
|
23
|
+
CompiledDomain,
|
|
24
|
+
FunctionSchema,
|
|
25
|
+
ViewSchema,
|
|
26
|
+
} from '@astrale-os/kernel-core/domain'
|
|
27
|
+
import type { Core, Schema } from '@astrale-os/kernel-dsl'
|
|
23
28
|
|
|
24
29
|
import { bindMethods, compileDomain } from '@astrale-os/kernel-core/domain'
|
|
25
30
|
|
|
@@ -27,7 +32,12 @@ import type { AnyRemoteFunctionDef, ViewDef } from '../define'
|
|
|
27
32
|
import type { SchemaMethodsImpl } from '../method/class'
|
|
28
33
|
import type { AnyRemoteHandler } from '../method/single'
|
|
29
34
|
|
|
30
|
-
import {
|
|
35
|
+
import {
|
|
36
|
+
buildFunctionDeclarations,
|
|
37
|
+
buildFunctionSchemas,
|
|
38
|
+
DEFAULT_FUNCTIONS_FOLDER,
|
|
39
|
+
} from './extend-functions'
|
|
40
|
+
import { buildViewDeclarations, buildViewSchemas, DEFAULT_VIEWS_FOLDER } from './extend-views'
|
|
31
41
|
|
|
32
42
|
export type RemoteDomainConfig<S extends Schema, TDeps> = {
|
|
33
43
|
schema: S
|
|
@@ -35,27 +45,29 @@ export type RemoteDomainConfig<S extends Schema, TDeps> = {
|
|
|
35
45
|
core?: Core<S>
|
|
36
46
|
|
|
37
47
|
views?: Record<string, ViewDef<TDeps>>
|
|
38
|
-
viewClass?: AnyNodeDef
|
|
39
|
-
viewForEdgeClass?: AnyEdgeDef
|
|
40
48
|
viewsFolder?: string
|
|
41
49
|
|
|
42
50
|
remoteFunctions?: Record<string, AnyRemoteFunctionDef>
|
|
43
51
|
functionsFolder?: string
|
|
44
52
|
}
|
|
45
53
|
|
|
46
|
-
/** Effective bindings + folder layout for auxiliary routes, resolved against `url`. */
|
|
54
|
+
/** Effective bindings + folder layout + member schemas for auxiliary routes, resolved against `url`. */
|
|
47
55
|
export type AuxiliaryMetadata = {
|
|
48
56
|
url: string
|
|
49
57
|
viewsFolder: string
|
|
50
58
|
functionsFolder: string
|
|
51
59
|
viewBindings: Record<string, FunctionBinding>
|
|
52
60
|
remoteFunctionBindings: Record<string, FunctionBinding>
|
|
61
|
+
/** Function members' impl/binding half (`function.<slug>`) for `serialize`. */
|
|
62
|
+
functionSchemas: FunctionSchema[]
|
|
63
|
+
/** View members' impl/binding half (`view.<slug>`) for `serialize`. */
|
|
64
|
+
viewSchemas: ViewSchema[]
|
|
53
65
|
}
|
|
54
66
|
|
|
55
67
|
export type RemoteDomain<S extends Schema = Schema> = {
|
|
56
68
|
/**
|
|
57
|
-
* Define-time compile: full domain STRUCTURE (classes, methods, and the
|
|
58
|
-
*
|
|
69
|
+
* Define-time compile: full domain STRUCTURE (classes, methods, and the
|
|
70
|
+
* view/function members' paths/names/refs — what identity, subs, and contract
|
|
59
71
|
* resolution need). It carries NO `binding` values: bindings derive from the
|
|
60
72
|
* serving url, which only the spec producers know — they call
|
|
61
73
|
* `materializeRemoteDomain(domain, url)` for the install-ready compile.
|
|
@@ -65,42 +77,32 @@ export type RemoteDomain<S extends Schema = Schema> = {
|
|
|
65
77
|
// oxlint-disable-next-line no-explicit-any
|
|
66
78
|
views?: Record<string, ViewDef<any>>
|
|
67
79
|
remoteFunctions?: Record<string, AnyRemoteFunctionDef>
|
|
68
|
-
/** The original config, so `materializeRemoteDomain` re-
|
|
69
|
-
config:
|
|
80
|
+
/** The original config, so `materializeRemoteDomain` re-materializes from source. */
|
|
81
|
+
config: MaterializeInputs
|
|
70
82
|
}
|
|
71
83
|
|
|
72
|
-
/** The defineRemoteDomain inputs `materializeRemoteDomain` needs to re-
|
|
73
|
-
type
|
|
84
|
+
/** The defineRemoteDomain inputs `materializeRemoteDomain` needs to re-materialize. */
|
|
85
|
+
type MaterializeInputs = {
|
|
74
86
|
userCore?: Core
|
|
75
|
-
viewClass?: AnyNodeDef
|
|
76
|
-
viewForEdgeClass?: AnyEdgeDef
|
|
77
87
|
viewsFolder: string
|
|
78
88
|
functionsFolder: string
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
export function defineRemoteDomain<TDeps>() {
|
|
82
92
|
return function <S extends Schema>(config: RemoteDomainConfig<S, TDeps>): RemoteDomain<S> {
|
|
83
|
-
const hasAux = Boolean(config.views || config.remoteFunctions)
|
|
84
93
|
const viewsFolder = config.viewsFolder ?? DEFAULT_VIEWS_FOLDER
|
|
85
94
|
const functionsFolder = config.functionsFolder ?? DEFAULT_FUNCTIONS_FOLDER
|
|
86
95
|
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
views: config.views,
|
|
98
|
-
functionsFolder,
|
|
99
|
-
remoteFunctions: config.remoteFunctions,
|
|
100
|
-
}).core
|
|
101
|
-
: config.core
|
|
102
|
-
|
|
103
|
-
const compiled = compileDomain(config.schema, effectiveCore as Core<S> | undefined)
|
|
96
|
+
// Views + functions are domain MEMBERS — their contract enters compile via
|
|
97
|
+
// the `functions` / `views` args (no Core involvement). `config.core` is the
|
|
98
|
+
// author's own genuine genesis instance data, untouched.
|
|
99
|
+
const compiled = compileDomain(
|
|
100
|
+
config.schema,
|
|
101
|
+
config.core,
|
|
102
|
+
undefined,
|
|
103
|
+
config.remoteFunctions ? buildFunctionDeclarations(config.remoteFunctions) : undefined,
|
|
104
|
+
config.views ? buildViewDeclarations(config.views) : undefined,
|
|
105
|
+
)
|
|
104
106
|
const methods = bindMethods<AnyRemoteHandler>(
|
|
105
107
|
compiled.$.schema,
|
|
106
108
|
compiled.$.methods,
|
|
@@ -115,8 +117,6 @@ export function defineRemoteDomain<TDeps>() {
|
|
|
115
117
|
...(config.remoteFunctions ? { remoteFunctions: config.remoteFunctions } : {}),
|
|
116
118
|
config: {
|
|
117
119
|
userCore: config.core,
|
|
118
|
-
viewClass: config.viewClass,
|
|
119
|
-
viewForEdgeClass: config.viewForEdgeClass,
|
|
120
120
|
viewsFolder,
|
|
121
121
|
functionsFolder,
|
|
122
122
|
},
|
|
@@ -125,13 +125,13 @@ export function defineRemoteDomain<TDeps>() {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/**
|
|
128
|
-
* Materialize a `RemoteDomain` at its real serving `url`: re-
|
|
129
|
-
*
|
|
130
|
-
*
|
|
131
|
-
* only two spec producers — `createRemoteServer`
|
|
132
|
-
* `astrale-domain` CLI. Returns the define-time `compiled`
|
|
133
|
-
* stamp.
|
|
134
|
-
*
|
|
128
|
+
* Materialize a `RemoteDomain` at its real serving `url`: re-compiles the domain
|
|
129
|
+
* and builds every member's url-stamped impl schema + binding, returning the
|
|
130
|
+
* binding maps the auxiliary routes mount from and the member schemas `serialize`
|
|
131
|
+
* emits from. Called by the only two spec producers — `createRemoteServer`
|
|
132
|
+
* (`config.url`) and the `astrale-domain` CLI. Returns the define-time `compiled`
|
|
133
|
+
* untouched when there is no aux to stamp. Pure, so safe to call repeatedly (and
|
|
134
|
+
* memoized per cold isolate by the callers).
|
|
135
135
|
*/
|
|
136
136
|
export function materializeRemoteDomain<S extends Schema>(
|
|
137
137
|
domain: RemoteDomain<S>,
|
|
@@ -142,27 +142,32 @@ export function materializeRemoteDomain<S extends Schema>(
|
|
|
142
142
|
|
|
143
143
|
const { config } = domain
|
|
144
144
|
const schema = domain.compiled.$.schema as S
|
|
145
|
-
|
|
145
|
+
|
|
146
|
+
const compiled = compileDomain(
|
|
146
147
|
schema,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
148
|
+
config.userCore as Core<S> | undefined,
|
|
149
|
+
undefined,
|
|
150
|
+
domain.remoteFunctions ? buildFunctionDeclarations(domain.remoteFunctions) : undefined,
|
|
151
|
+
domain.views ? buildViewDeclarations(domain.views) : undefined,
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
const fns = domain.remoteFunctions
|
|
155
|
+
? buildFunctionSchemas(domain.remoteFunctions, url, config.functionsFolder)
|
|
156
|
+
: { schemas: [], bindings: {} }
|
|
157
|
+
const vws = domain.views
|
|
158
|
+
? buildViewSchemas(domain.views, url, config.viewsFolder, schema)
|
|
159
|
+
: { schemas: [], bindings: {} }
|
|
160
|
+
|
|
158
161
|
return {
|
|
159
162
|
compiled,
|
|
160
163
|
auxiliary: {
|
|
161
164
|
url,
|
|
162
165
|
viewsFolder: config.viewsFolder,
|
|
163
166
|
functionsFolder: config.functionsFolder,
|
|
164
|
-
viewBindings:
|
|
165
|
-
remoteFunctionBindings:
|
|
167
|
+
viewBindings: vws.bindings,
|
|
168
|
+
remoteFunctionBindings: fns.bindings,
|
|
169
|
+
functionSchemas: fns.schemas,
|
|
170
|
+
viewSchemas: vws.schemas,
|
|
166
171
|
},
|
|
167
172
|
}
|
|
168
173
|
}
|