@astrale-os/sdk 0.1.9 → 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 +21 -10
- package/dist/cli/run.js.map +1 -1
- package/dist/config/adapter.d.ts +19 -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 +14 -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-core.d.ts.map +1 -1
- package/dist/domain/extend-core.js +9 -1
- package/dist/domain/extend-core.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 +21 -12
- package/src/config/adapter.ts +16 -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 +14 -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 -287
|
@@ -1,287 +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
|
-
|
|
17
|
-
import type { FunctionBinding } from '@astrale-os/kernel-api/routed'
|
|
18
|
-
import type {
|
|
19
|
-
AnyEdgeDef,
|
|
20
|
-
AnyNodeDef,
|
|
21
|
-
Core,
|
|
22
|
-
CoreEdgeEntry,
|
|
23
|
-
CoreNodeEntry,
|
|
24
|
-
Schema,
|
|
25
|
-
} from '@astrale-os/kernel-dsl'
|
|
26
|
-
|
|
27
|
-
import { Folder, K, KernelSchema } from '@astrale-os/kernel-core'
|
|
28
|
-
import { buildCorePath } from '@astrale-os/kernel-dsl'
|
|
29
|
-
|
|
30
|
-
/** Canonical node class for standalone callables (the former `RemoteFunction`). */
|
|
31
|
-
const FUNCTION_CLASS = KernelSchema.classes.Function as unknown as AnyNodeDef
|
|
32
|
-
/** Canonical node class for GUI views. */
|
|
33
|
-
const VIEW_CLASS = KernelSchema.classes.View as unknown as AnyNodeDef
|
|
34
|
-
/** Canonical edge class linking a View to its target. */
|
|
35
|
-
const VIEW_FOR_EDGE_CLASS = KernelSchema.classes.view_for as unknown as AnyEdgeDef
|
|
36
|
-
|
|
37
|
-
import type { AnyRemoteFunctionDef } from '../define/remote-function'
|
|
38
|
-
import type { ViewDef } from '../define/view'
|
|
39
|
-
|
|
40
|
-
export const DEFAULT_VIEWS_FOLDER = 'views'
|
|
41
|
-
export const DEFAULT_FUNCTIONS_FOLDER = 'functions'
|
|
42
|
-
const SLUG_RE = /^[a-z][a-z0-9-]*$/
|
|
43
|
-
|
|
44
|
-
export type ExtendCoreConfig = {
|
|
45
|
-
schema: Schema
|
|
46
|
-
origin: string
|
|
47
|
-
userCore?: Core
|
|
48
|
-
/**
|
|
49
|
-
* The worker's serving URL — the base every auto-materialized binding
|
|
50
|
-
* resolves against. OMITTED at define time (the URL is known only to the
|
|
51
|
-
* spec producers): the aux nodes then materialize structure-only (paths,
|
|
52
|
-
* names, refs — what identity/subs resolution needs) with no `binding`
|
|
53
|
-
* stamped and empty binding maps. Every install graph comes from a
|
|
54
|
-
* `materializeRemoteDomain(domain, url)` call where it is present.
|
|
55
|
-
*/
|
|
56
|
-
url?: string
|
|
57
|
-
|
|
58
|
-
viewClass?: AnyNodeDef
|
|
59
|
-
viewForEdgeClass?: AnyEdgeDef
|
|
60
|
-
viewsFolder?: string
|
|
61
|
-
// oxlint-disable-next-line no-explicit-any
|
|
62
|
-
views?: Record<string, ViewDef<any>>
|
|
63
|
-
|
|
64
|
-
functionsFolder?: string
|
|
65
|
-
remoteFunctions?: Record<string, AnyRemoteFunctionDef>
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export type ExtendCoreResult = {
|
|
69
|
-
core: Core
|
|
70
|
-
viewBindings: Record<string, FunctionBinding>
|
|
71
|
-
remoteFunctionBindings: Record<string, FunctionBinding>
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export function extendCore(config: ExtendCoreConfig): ExtendCoreResult {
|
|
75
|
-
const {
|
|
76
|
-
schema,
|
|
77
|
-
origin,
|
|
78
|
-
userCore,
|
|
79
|
-
url,
|
|
80
|
-
viewClass = VIEW_CLASS,
|
|
81
|
-
viewForEdgeClass = VIEW_FOR_EDGE_CLASS,
|
|
82
|
-
viewsFolder = DEFAULT_VIEWS_FOLDER,
|
|
83
|
-
views,
|
|
84
|
-
functionsFolder = DEFAULT_FUNCTIONS_FOLDER,
|
|
85
|
-
remoteFunctions,
|
|
86
|
-
} = config
|
|
87
|
-
|
|
88
|
-
validateInputs(config)
|
|
89
|
-
|
|
90
|
-
const nodes: CoreNodeEntry[] = userCore ? [...userCore.__nodes] : []
|
|
91
|
-
const edges: CoreEdgeEntry[] = userCore ? [...userCore.__edges] : []
|
|
92
|
-
const viewBindings: Record<string, FunctionBinding> = {}
|
|
93
|
-
const remoteFunctionBindings: Record<string, FunctionBinding> = {}
|
|
94
|
-
|
|
95
|
-
if (views && viewClass) {
|
|
96
|
-
// Enforce ViewDef's documented exclusivity: `mount` (SPA route) cannot be
|
|
97
|
-
// combined with `render` (inline HTML handler) or an explicit `binding` —
|
|
98
|
-
// silently ignoring one of them would deploy a view that behaves
|
|
99
|
-
// differently than its definition reads.
|
|
100
|
-
for (const [slug, def] of Object.entries(views)) {
|
|
101
|
-
if (def.mount && (def.render || def.binding)) {
|
|
102
|
-
throw new Error(
|
|
103
|
-
`defineRemoteDomain: view "${slug}" sets \`mount\` together with ` +
|
|
104
|
-
`${def.render ? '`render`' : '`binding`'} — they are mutually exclusive.`,
|
|
105
|
-
)
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
assertNoConflict(nodes, origin, viewsFolder)
|
|
109
|
-
addFolderAndEntries({
|
|
110
|
-
origin,
|
|
111
|
-
folderSlug: viewsFolder,
|
|
112
|
-
nodes,
|
|
113
|
-
entries: Object.entries(views).map(([slug, def]) => {
|
|
114
|
-
const binding = url
|
|
115
|
-
? def.mount
|
|
116
|
-
? { remoteUrl: joinWorkerPath(url, def.mount) }
|
|
117
|
-
: resolveBinding(def.binding, url, viewsFolder, slug)
|
|
118
|
-
: undefined
|
|
119
|
-
if (binding) viewBindings[slug] = binding
|
|
120
|
-
return {
|
|
121
|
-
slug,
|
|
122
|
-
nodeClass: viewClass,
|
|
123
|
-
data: buildFunctionData(slug, binding),
|
|
124
|
-
edges: buildViewForEdges(slug, def, viewForEdgeClass, viewsFolder, origin),
|
|
125
|
-
}
|
|
126
|
-
}),
|
|
127
|
-
edges,
|
|
128
|
-
})
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (remoteFunctions) {
|
|
132
|
-
assertNoConflict(nodes, origin, functionsFolder)
|
|
133
|
-
addFolderAndEntries({
|
|
134
|
-
origin,
|
|
135
|
-
folderSlug: functionsFolder,
|
|
136
|
-
nodes,
|
|
137
|
-
entries: Object.entries(remoteFunctions).map(([slug, def]) => {
|
|
138
|
-
const binding = url ? resolveBinding(def.binding, url, functionsFolder, slug) : undefined
|
|
139
|
-
if (binding) remoteFunctionBindings[slug] = binding
|
|
140
|
-
return {
|
|
141
|
-
slug,
|
|
142
|
-
// Standalone callables materialize as the canonical kernel Function class.
|
|
143
|
-
nodeClass: FUNCTION_CLASS,
|
|
144
|
-
data: {
|
|
145
|
-
...buildFunctionData(slug, binding),
|
|
146
|
-
[K.$.i('Function').ref.key]: def.ref ?? `function.${slug}`,
|
|
147
|
-
},
|
|
148
|
-
edges: [],
|
|
149
|
-
}
|
|
150
|
-
}),
|
|
151
|
-
edges,
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return {
|
|
156
|
-
core: { schema, domain: origin, __nodes: nodes, __edges: edges },
|
|
157
|
-
viewBindings,
|
|
158
|
-
remoteFunctionBindings,
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/** Join a worker-relative mount path onto the serving url (single slash). */
|
|
163
|
-
function joinWorkerPath(url: string, mount: string): string {
|
|
164
|
-
const base = url.replace(/\/+$/, '')
|
|
165
|
-
return `${base}/${mount.replace(/^\/+/, '')}`
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export function resolveBinding(
|
|
169
|
-
override: FunctionBinding | undefined,
|
|
170
|
-
url: string,
|
|
171
|
-
folderSlug: string,
|
|
172
|
-
slug: string,
|
|
173
|
-
): FunctionBinding {
|
|
174
|
-
// Same trailing-slash discipline as `joinWorkerPath` — a `url` ending in `/`
|
|
175
|
-
// must not produce `//` in the binding (the kernel pins iss by exact string).
|
|
176
|
-
const base = url.replace(/\/+$/, '')
|
|
177
|
-
if (override) {
|
|
178
|
-
return {
|
|
179
|
-
...override,
|
|
180
|
-
remoteUrl: override.remoteUrl ?? `${base}/${folderSlug}/${slug}`,
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
return { remoteUrl: `${base}/${folderSlug}/${slug}` }
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ── Internal ───────────────────────────────────────────────────────────────
|
|
187
|
-
|
|
188
|
-
function validateInputs(config: ExtendCoreConfig): void {
|
|
189
|
-
if (config.views) {
|
|
190
|
-
for (const slug of Object.keys(config.views)) {
|
|
191
|
-
if (!SLUG_RE.test(slug)) {
|
|
192
|
-
throw new Error(`defineRemoteDomain: invalid view slug "${slug}" — must match ${SLUG_RE}.`)
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
if (config.remoteFunctions) {
|
|
197
|
-
for (const slug of Object.keys(config.remoteFunctions)) {
|
|
198
|
-
if (!SLUG_RE.test(slug)) {
|
|
199
|
-
throw new Error(
|
|
200
|
-
`defineRemoteDomain: invalid remote-function slug "${slug}" — must match ${SLUG_RE}.`,
|
|
201
|
-
)
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
function assertNoConflict(
|
|
208
|
-
nodes: readonly CoreNodeEntry[],
|
|
209
|
-
origin: string,
|
|
210
|
-
folderSlug: string,
|
|
211
|
-
): void {
|
|
212
|
-
const folderPath = buildCorePath(origin, [folderSlug])
|
|
213
|
-
if (nodes.some((n) => n.path === folderPath)) {
|
|
214
|
-
throw new Error(
|
|
215
|
-
`defineRemoteDomain: top-level core slug "${folderSlug}" is reserved by ` +
|
|
216
|
-
'SDK auto-materialization. Move the conflicting node or rename the ' +
|
|
217
|
-
'`viewsFolder` / `functionsFolder` config.',
|
|
218
|
-
)
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
type EntryDescriptor = {
|
|
223
|
-
slug: string
|
|
224
|
-
nodeClass: AnyNodeDef
|
|
225
|
-
data: Record<string, unknown>
|
|
226
|
-
edges: CoreEdgeEntry[]
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function addFolderAndEntries(args: {
|
|
230
|
-
origin: string
|
|
231
|
-
folderSlug: string
|
|
232
|
-
entries: EntryDescriptor[]
|
|
233
|
-
nodes: CoreNodeEntry[]
|
|
234
|
-
edges: CoreEdgeEntry[]
|
|
235
|
-
}): void {
|
|
236
|
-
const { origin, folderSlug, entries, nodes, edges } = args
|
|
237
|
-
|
|
238
|
-
const folderPath = buildCorePath(origin, [folderSlug])
|
|
239
|
-
nodes.push({
|
|
240
|
-
path: folderPath,
|
|
241
|
-
def: Folder as unknown as AnyNodeDef,
|
|
242
|
-
data: { [K.Named.name.key]: folderSlug },
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
for (const entry of entries) {
|
|
246
|
-
nodes.push({
|
|
247
|
-
path: buildCorePath(origin, [folderSlug, entry.slug]),
|
|
248
|
-
def: entry.nodeClass,
|
|
249
|
-
data: entry.data,
|
|
250
|
-
parent: folderPath,
|
|
251
|
-
})
|
|
252
|
-
for (const e of entry.edges) edges.push(e)
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
function buildFunctionData(
|
|
257
|
-
slug: string,
|
|
258
|
-
binding: FunctionBinding | undefined,
|
|
259
|
-
): Record<string, unknown> {
|
|
260
|
-
// Match the kernel-core schema serializer which JSON-stringifies the
|
|
261
|
-
// `Function.binding` value on Function nodes (see
|
|
262
|
-
// kernel/core/domain/serialize/schema.ts). The kernel install validator
|
|
263
|
-
// checks `typeof binding === 'string'` then parses; storing a raw object
|
|
264
|
-
// trips the validator with "missing remote binding" even when the object IS
|
|
265
|
-
// the binding. No binding at all (define-time, no url) → no prop stamped.
|
|
266
|
-
return {
|
|
267
|
-
[K.Named.name.key]: slug,
|
|
268
|
-
...(binding ? { [K.$.i('Function').binding.key]: JSON.stringify(binding) } : {}),
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
function buildViewForEdges(
|
|
273
|
-
slug: string,
|
|
274
|
-
def: ViewDef,
|
|
275
|
-
edgeClass: AnyEdgeDef | undefined,
|
|
276
|
-
viewsFolder: string,
|
|
277
|
-
origin: string,
|
|
278
|
-
): CoreEdgeEntry[] {
|
|
279
|
-
if (!def.viewFor || !edgeClass) return []
|
|
280
|
-
const targets = Array.isArray(def.viewFor) ? def.viewFor : [def.viewFor]
|
|
281
|
-
const from = buildCorePath(origin, [viewsFolder, slug])
|
|
282
|
-
return targets.map((target) => ({
|
|
283
|
-
from,
|
|
284
|
-
edge: edgeClass,
|
|
285
|
-
to: target as CoreEdgeEntry['to'],
|
|
286
|
-
}))
|
|
287
|
-
}
|