@astrale-os/shell 0.3.1 → 0.3.3
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/application/apps.d.ts +2 -2
- package/dist/application/apps.d.ts.map +1 -1
- package/dist/application/apps.js +4 -8
- package/dist/application/spaces.d.ts +2 -2
- package/dist/application/spaces.d.ts.map +1 -1
- package/dist/application/spaces.js +3 -6
- package/dist/application/user.d.ts +2 -2
- package/dist/application/user.d.ts.map +1 -1
- package/dist/application/user.js +5 -5
- package/dist/application/view.d.ts +7 -3
- package/dist/application/view.d.ts.map +1 -1
- package/dist/application/view.js +3 -3
- package/package.json +5 -5
- package/src/application/apps.ts +6 -10
- package/src/application/spaces.ts +5 -10
- package/src/application/user.ts +7 -7
- package/src/application/view.ts +10 -6
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BoundNode, DefOf, NodeRefInput } from '@astrale-os/kernel-client';
|
|
2
2
|
import type { KernelClient } from '../kernel/client.js';
|
|
3
3
|
import type { AppSession } from './session/session.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ShellView, ShellSchema } from './view.js';
|
|
5
5
|
/** An installed `Application` node. */
|
|
6
6
|
export type ApplicationNode = BoundNode<DefOf<ShellSchema, 'Application'>, ShellSchema>;
|
|
7
7
|
export interface AppsNamespace {
|
|
@@ -12,7 +12,7 @@ export interface AppsNamespace {
|
|
|
12
12
|
/** Resolve the app node and open its {@link AppSession}. */
|
|
13
13
|
open(app: NodeRefInput): Promise<AppSession>;
|
|
14
14
|
}
|
|
15
|
-
export declare function createAppsNamespace(kernel: KernelClient, v:
|
|
15
|
+
export declare function createAppsNamespace(kernel: KernelClient, v: ShellView, deps?: {
|
|
16
16
|
readonly now?: () => number;
|
|
17
17
|
}): AppsNamespace;
|
|
18
18
|
//# sourceMappingURL=apps.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/application/apps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAK/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../src/application/apps.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAK/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAIvD,uCAAuC;AACvC,MAAM,MAAM,eAAe,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,aAAa,CAAC,EAAE,WAAW,CAAC,CAAA;AAEvF,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,CAAC,CAAA;IACtE,+DAA+D;IAC/D,EAAE,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAAA;IACnD,4DAA4D;IAC5D,IAAI,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,UAAU,CAAC,CAAA;CAC7C;AAKD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,CAAC,EAAE,SAAS,EACZ,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CAAE,GACrC,aAAa,CAyBf"}
|
package/dist/application/apps.js
CHANGED
|
@@ -6,13 +6,9 @@ const INSTALLED_IN_EDGE = D.installed_in.path.class.raw;
|
|
|
6
6
|
export function createAppsNamespace(kernel, v, deps) {
|
|
7
7
|
return {
|
|
8
8
|
async install(target, space) {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
target,
|
|
13
|
-
space: normalizeRef(space),
|
|
14
|
-
}));
|
|
15
|
-
const app = await v.view().node('Application', `@${created.id}`);
|
|
9
|
+
const Application = v.get().classes.Application;
|
|
10
|
+
const created = await Application.install({ target, space: normalizeRef(space) });
|
|
11
|
+
const app = await Application.get(`@${created.id}`);
|
|
16
12
|
if (!app)
|
|
17
13
|
throw new Error(`Application.install: app @${created.id} is not readable`);
|
|
18
14
|
return app;
|
|
@@ -26,7 +22,7 @@ export function createAppsNamespace(kernel, v, deps) {
|
|
|
26
22
|
});
|
|
27
23
|
},
|
|
28
24
|
async open(app) {
|
|
29
|
-
const node = await v.
|
|
25
|
+
const node = await v.get().classes.Application.get(app);
|
|
30
26
|
if (!node)
|
|
31
27
|
throw new Error(`apps.open: application ${normalizeRef(app)} is not readable`);
|
|
32
28
|
return openAppSession({ kernel, ...(deps?.now ? { now: deps.now } : {}) }, node.id);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BoundNode, DefOf, NodeRefInput } from '@astrale-os/kernel-client';
|
|
2
2
|
import type { KernelClient } from '../kernel/client.js';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ShellView, ShellSchema } from './view.js';
|
|
4
4
|
/** A workspace `Space` node. */
|
|
5
5
|
export type SpaceNode = BoundNode<DefOf<ShellSchema, 'Space'>, ShellSchema>;
|
|
6
6
|
export interface SpacesNamespace {
|
|
@@ -13,5 +13,5 @@ export interface SpacesNamespace {
|
|
|
13
13
|
name?: string;
|
|
14
14
|
}): Promise<SpaceNode>;
|
|
15
15
|
}
|
|
16
|
-
export declare function createSpacesNamespace(kernel: KernelClient, v:
|
|
16
|
+
export declare function createSpacesNamespace(kernel: KernelClient, v: ShellView): SpacesNamespace;
|
|
17
17
|
//# sourceMappingURL=spaces.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"spaces.d.ts","sourceRoot":"","sources":["../../src/application/spaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAI/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"spaces.d.ts","sourceRoot":"","sources":["../../src/application/spaces.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAI/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAEvD,gCAAgC;AAChC,MAAM,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,WAAW,CAAC,CAAA;AAE3E,MAAM,WAAW,eAAe;IAC9B,6EAA6E;IAC7E,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;IAC5B,uEAAuE;IACvE,GAAG,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAA;IACjD,2DAA2D;IAC3D,MAAM,CAAC,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,SAAS,CAAC,CAAA;CACrD;AAKD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,GAAG,eAAe,CAwBzF"}
|
|
@@ -16,12 +16,9 @@ export function createSpacesNamespace(kernel, v) {
|
|
|
16
16
|
return node ? v.bindAs('Space', node) : null;
|
|
17
17
|
},
|
|
18
18
|
async create(opts) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const create = v.view()('Space').create;
|
|
23
|
-
const created = await create(opts?.name !== undefined ? { name: opts.name } : undefined);
|
|
24
|
-
const space = await v.view().node('Space', `@${created.id}`);
|
|
19
|
+
const Space = v.get().classes.Space;
|
|
20
|
+
const created = await Space.create(opts?.name !== undefined ? { name: opts.name } : undefined);
|
|
21
|
+
const space = await Space.get(`@${created.id}`);
|
|
25
22
|
if (!space)
|
|
26
23
|
throw new Error(`Space.create: created space @${created.id} is not readable`);
|
|
27
24
|
return space;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { BoundNode, DefOf, NodeRefInput } from '@astrale-os/kernel-client';
|
|
2
2
|
import type { KernelClient } from '../kernel/client.js';
|
|
3
3
|
import type { SpaceNode } from './spaces.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { ShellView, ShellSchema } from './view.js';
|
|
5
5
|
/** Self as the shell-domain `User` — typed `firstName`/`lastName`/`email`. */
|
|
6
6
|
export type UserNode = BoundNode<DefOf<ShellSchema, 'User'>, ShellSchema>;
|
|
7
7
|
/** A `Role` a user holds. */
|
|
@@ -16,5 +16,5 @@ export interface UserNamespace {
|
|
|
16
16
|
/** The `has_role` out-edges of self. */
|
|
17
17
|
roles(): Promise<RoleNode[]>;
|
|
18
18
|
}
|
|
19
|
-
export declare function createUserNamespace(kernel: KernelClient, v:
|
|
19
|
+
export declare function createUserNamespace(kernel: KernelClient, v: ShellView): UserNamespace;
|
|
20
20
|
//# sourceMappingURL=user.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/application/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAI/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../src/application/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAA;AAI/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AACvD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAIvD,8EAA8E;AAC9E,MAAM,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAA;AACzE,6BAA6B;AAC7B,MAAM,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,WAAW,CAAC,CAAA;AAEzE,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,EAAE,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAA;IACvB,yEAAyE;IACzE,YAAY,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAA;IACzC,sFAAsF;IACtF,WAAW,CAAC,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,wCAAwC;IACxC,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAA;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,GAAG,aAAa,CA2BrF"}
|
package/dist/application/user.js
CHANGED
|
@@ -2,23 +2,23 @@ import { normalizeRef } from '@astrale-os/kernel-client';
|
|
|
2
2
|
import { asArray } from './view.js';
|
|
3
3
|
export function createUserNamespace(kernel, v) {
|
|
4
4
|
async function me() {
|
|
5
|
-
return v.
|
|
5
|
+
return v.get().bind('User', await kernel.auth.whoami());
|
|
6
6
|
}
|
|
7
7
|
return {
|
|
8
8
|
me,
|
|
9
9
|
async currentSpace() {
|
|
10
10
|
const self = await me();
|
|
11
|
-
const first = asArray(await self.out('selected_space'))[0];
|
|
11
|
+
const first = asArray(await self.links.out('selected_space'))[0];
|
|
12
12
|
return first ? v.bindAs('Space', first.raw) : null;
|
|
13
13
|
},
|
|
14
14
|
async switchSpace(ref) {
|
|
15
15
|
const self = await me();
|
|
16
|
-
await self.
|
|
16
|
+
await self.switchSpace({ space: normalizeRef(ref) });
|
|
17
17
|
},
|
|
18
18
|
async roles() {
|
|
19
19
|
const self = await me();
|
|
20
|
-
return asArray(await self.out('has_role')).flatMap((
|
|
21
|
-
const role = v.bindAs('Role',
|
|
20
|
+
return asArray(await self.links.out('has_role')).flatMap((node) => {
|
|
21
|
+
const role = v.bindAs('Role', node.raw);
|
|
22
22
|
return role ? [role] : [];
|
|
23
23
|
});
|
|
24
24
|
},
|
|
@@ -3,18 +3,22 @@
|
|
|
3
3
|
* shell domain (`@astrale-domains/shell-schema`). The bound view is built LAZILY
|
|
4
4
|
* (first call) so the sandboxed shell's "init() first" kernel guard applies
|
|
5
5
|
* uniformly — constructing namespaces touches no kernel.
|
|
6
|
+
*
|
|
7
|
+
* Typed access uses `.classes`: `get().classes.Space(ref)` dispatches without
|
|
8
|
+
* a read and `get().classes.Space.get(ref)` returns a bound node.
|
|
6
9
|
*/
|
|
7
10
|
import type { BoundNode, DefOf, SchemaBoundView } from '@astrale-os/kernel-client';
|
|
8
11
|
import type { Node } from '@astrale-os/kernel-core';
|
|
9
12
|
import { schema } from '@astrale-domains/shell-schema';
|
|
10
13
|
import type { KernelClient } from '../kernel/client.js';
|
|
11
14
|
export type ShellSchema = typeof schema;
|
|
12
|
-
|
|
13
|
-
|
|
15
|
+
/** Lazily-created schema-bound Shell client. */
|
|
16
|
+
export interface ShellView {
|
|
17
|
+
get(): SchemaBoundView<ShellSchema>;
|
|
14
18
|
/** Bind `node` as `type` when its concrete class satisfies it, else `null`. */
|
|
15
19
|
bindAs<T extends 'User' | 'Space' | 'Application' | 'Role'>(type: T, node: Node): BoundNode<DefOf<ShellSchema, T>, ShellSchema> | null;
|
|
16
20
|
}
|
|
17
|
-
export declare function createShellDomainView(kernel: KernelClient):
|
|
21
|
+
export declare function createShellDomainView(kernel: KernelClient): ShellView;
|
|
18
22
|
/** Normalize a typed traversal result (single | array | null) to an array. */
|
|
19
23
|
export declare function asArray<T>(result: T | readonly T[] | null): T[];
|
|
20
24
|
//# sourceMappingURL=view.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/application/view.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/application/view.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAClF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAA;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAA;AAEtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAEvD,MAAM,MAAM,WAAW,GAAG,OAAO,MAAM,CAAA;AAEvC,gDAAgD;AAChD,MAAM,WAAW,SAAS;IACxB,GAAG,IAAI,eAAe,CAAC,WAAW,CAAC,CAAA;IACnC,+EAA+E;IAC/E,MAAM,CAAC,CAAC,SAAS,MAAM,GAAG,OAAO,GAAG,aAAa,GAAG,MAAM,EACxD,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,IAAI,GACT,SAAS,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,GAAG,IAAI,CAAA;CACxD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,YAAY,GAAG,SAAS,CAWrE;AAED,8EAA8E;AAC9E,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,GAAG,IAAI,GAAG,CAAC,EAAE,CAG/D"}
|
package/dist/application/view.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { schema } from '@astrale-domains/shell-schema';
|
|
2
2
|
export function createShellDomainView(kernel) {
|
|
3
3
|
let bound = null;
|
|
4
|
-
const
|
|
4
|
+
const get = () => (bound ??= kernel.withSchema(schema));
|
|
5
5
|
return {
|
|
6
|
-
|
|
6
|
+
get,
|
|
7
7
|
bindAs(type, node) {
|
|
8
|
-
const v =
|
|
8
|
+
const v = get();
|
|
9
9
|
return v.bindAny(node).is(type) ? v.bind(type, node) : null;
|
|
10
10
|
},
|
|
11
11
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrale-os/shell",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"description": "Astrale Shell SDK — parent/child/kernel communication",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@astrale-domains/shell-schema": ">=0.3.
|
|
29
|
-
"@astrale-os/kernel-client": ">=0.4.
|
|
30
|
-
"@astrale-os/kernel-core": ">=0.7.
|
|
31
|
-
"@astrale-os/kernel-dsl": ">=0.1.
|
|
28
|
+
"@astrale-domains/shell-schema": ">=0.3.2 <1.0.0",
|
|
29
|
+
"@astrale-os/kernel-client": ">=0.4.6 <1.0.0",
|
|
30
|
+
"@astrale-os/kernel-core": ">=0.7.5 <1.0.0",
|
|
31
|
+
"@astrale-os/kernel-dsl": ">=0.1.4 <1.0.0",
|
|
32
32
|
"jose": "^6.2.3",
|
|
33
33
|
"zod": "^4.3.6"
|
|
34
34
|
},
|
package/src/application/apps.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { normalizeRef } from '@astrale-os/kernel-client'
|
|
|
5
5
|
|
|
6
6
|
import type { KernelClient } from '../kernel/client.js'
|
|
7
7
|
import type { AppSession } from './session/session.js'
|
|
8
|
-
import type {
|
|
8
|
+
import type { ShellView, ShellSchema } from './view.js'
|
|
9
9
|
|
|
10
10
|
import { openAppSession } from './session/open.js'
|
|
11
11
|
|
|
@@ -26,18 +26,14 @@ const INSTALLED_IN_EDGE = D.installed_in.path.class.raw
|
|
|
26
26
|
|
|
27
27
|
export function createAppsNamespace(
|
|
28
28
|
kernel: KernelClient,
|
|
29
|
-
v:
|
|
29
|
+
v: ShellView,
|
|
30
30
|
deps?: { readonly now?: () => number },
|
|
31
31
|
): AppsNamespace {
|
|
32
32
|
return {
|
|
33
33
|
async install(target, space) {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
target,
|
|
38
|
-
space: normalizeRef(space),
|
|
39
|
-
})) as { id: string }
|
|
40
|
-
const app = await v.view().node('Application', `@${created.id}`)
|
|
34
|
+
const Application = v.get().classes.Application
|
|
35
|
+
const created = await Application.install({ target, space: normalizeRef(space) })
|
|
36
|
+
const app = await Application.get(`@${created.id}`)
|
|
41
37
|
if (!app) throw new Error(`Application.install: app @${created.id} is not readable`)
|
|
42
38
|
return app
|
|
43
39
|
},
|
|
@@ -52,7 +48,7 @@ export function createAppsNamespace(
|
|
|
52
48
|
},
|
|
53
49
|
|
|
54
50
|
async open(app) {
|
|
55
|
-
const node = await v.
|
|
51
|
+
const node = await v.get().classes.Application.get(app)
|
|
56
52
|
if (!node) throw new Error(`apps.open: application ${normalizeRef(app)} is not readable`)
|
|
57
53
|
return openAppSession({ kernel, ...(deps?.now ? { now: deps.now } : {}) }, node.id)
|
|
58
54
|
},
|
|
@@ -3,7 +3,7 @@ import type { BoundNode, DefOf, NodeRefInput } from '@astrale-os/kernel-client'
|
|
|
3
3
|
import { normalizeRef } from '@astrale-os/kernel-client'
|
|
4
4
|
|
|
5
5
|
import type { KernelClient } from '../kernel/client.js'
|
|
6
|
-
import type {
|
|
6
|
+
import type { ShellView, ShellSchema } from './view.js'
|
|
7
7
|
|
|
8
8
|
/** A workspace `Space` node. */
|
|
9
9
|
export type SpaceNode = BoundNode<DefOf<ShellSchema, 'Space'>, ShellSchema>
|
|
@@ -20,7 +20,7 @@ export interface SpacesNamespace {
|
|
|
20
20
|
/** The spaces directory (mirrors the shell domain's `SPACES_DIR`). */
|
|
21
21
|
const SPACES_DIR = '/spaces'
|
|
22
22
|
|
|
23
|
-
export function createSpacesNamespace(kernel: KernelClient, v:
|
|
23
|
+
export function createSpacesNamespace(kernel: KernelClient, v: ShellView): SpacesNamespace {
|
|
24
24
|
return {
|
|
25
25
|
async list() {
|
|
26
26
|
const page = await kernel.children(SPACES_DIR)
|
|
@@ -37,14 +37,9 @@ export function createSpacesNamespace(kernel: KernelClient, v: ShellDomainView):
|
|
|
37
37
|
},
|
|
38
38
|
|
|
39
39
|
async create(opts) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const create = v.view()('Space').create as (params?: {
|
|
44
|
-
name?: string
|
|
45
|
-
}) => Promise<{ id: string }>
|
|
46
|
-
const created = await create(opts?.name !== undefined ? { name: opts.name } : undefined)
|
|
47
|
-
const space = await v.view().node('Space', `@${created.id}`)
|
|
40
|
+
const Space = v.get().classes.Space
|
|
41
|
+
const created = await Space.create(opts?.name !== undefined ? { name: opts.name } : undefined)
|
|
42
|
+
const space = await Space.get(`@${created.id}`)
|
|
48
43
|
if (!space) throw new Error(`Space.create: created space @${created.id} is not readable`)
|
|
49
44
|
return space
|
|
50
45
|
},
|
package/src/application/user.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { normalizeRef } from '@astrale-os/kernel-client'
|
|
|
4
4
|
|
|
5
5
|
import type { KernelClient } from '../kernel/client.js'
|
|
6
6
|
import type { SpaceNode } from './spaces.js'
|
|
7
|
-
import type {
|
|
7
|
+
import type { ShellView, ShellSchema } from './view.js'
|
|
8
8
|
|
|
9
9
|
import { asArray } from './view.js'
|
|
10
10
|
|
|
@@ -24,9 +24,9 @@ export interface UserNamespace {
|
|
|
24
24
|
roles(): Promise<RoleNode[]>
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
export function createUserNamespace(kernel: KernelClient, v:
|
|
27
|
+
export function createUserNamespace(kernel: KernelClient, v: ShellView): UserNamespace {
|
|
28
28
|
async function me(): Promise<UserNode> {
|
|
29
|
-
return v.
|
|
29
|
+
return v.get().bind('User', await kernel.auth.whoami())
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
return {
|
|
@@ -34,19 +34,19 @@ export function createUserNamespace(kernel: KernelClient, v: ShellDomainView): U
|
|
|
34
34
|
|
|
35
35
|
async currentSpace() {
|
|
36
36
|
const self = await me()
|
|
37
|
-
const first = asArray(await self.out('selected_space'))[0]
|
|
37
|
+
const first = asArray(await self.links.out('selected_space'))[0]
|
|
38
38
|
return first ? v.bindAs('Space', first.raw) : null
|
|
39
39
|
},
|
|
40
40
|
|
|
41
41
|
async switchSpace(ref) {
|
|
42
42
|
const self = await me()
|
|
43
|
-
await self.
|
|
43
|
+
await self.switchSpace({ space: normalizeRef(ref) })
|
|
44
44
|
},
|
|
45
45
|
|
|
46
46
|
async roles() {
|
|
47
47
|
const self = await me()
|
|
48
|
-
return asArray(await self.out('has_role')).flatMap((
|
|
49
|
-
const role = v.bindAs('Role',
|
|
48
|
+
return asArray(await self.links.out('has_role')).flatMap((node) => {
|
|
49
|
+
const role = v.bindAs('Role', node.raw)
|
|
50
50
|
return role ? [role] : []
|
|
51
51
|
})
|
|
52
52
|
},
|
package/src/application/view.ts
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
* shell domain (`@astrale-domains/shell-schema`). The bound view is built LAZILY
|
|
4
4
|
* (first call) so the sandboxed shell's "init() first" kernel guard applies
|
|
5
5
|
* uniformly — constructing namespaces touches no kernel.
|
|
6
|
+
*
|
|
7
|
+
* Typed access uses `.classes`: `get().classes.Space(ref)` dispatches without
|
|
8
|
+
* a read and `get().classes.Space.get(ref)` returns a bound node.
|
|
6
9
|
*/
|
|
7
10
|
import type { BoundNode, DefOf, SchemaBoundView } from '@astrale-os/kernel-client'
|
|
8
11
|
import type { Node } from '@astrale-os/kernel-core'
|
|
@@ -13,8 +16,9 @@ import type { KernelClient } from '../kernel/client.js'
|
|
|
13
16
|
|
|
14
17
|
export type ShellSchema = typeof schema
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
/** Lazily-created schema-bound Shell client. */
|
|
20
|
+
export interface ShellView {
|
|
21
|
+
get(): SchemaBoundView<ShellSchema>
|
|
18
22
|
/** Bind `node` as `type` when its concrete class satisfies it, else `null`. */
|
|
19
23
|
bindAs<T extends 'User' | 'Space' | 'Application' | 'Role'>(
|
|
20
24
|
type: T,
|
|
@@ -22,14 +26,14 @@ export interface ShellDomainView {
|
|
|
22
26
|
): BoundNode<DefOf<ShellSchema, T>, ShellSchema> | null
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
export function createShellDomainView(kernel: KernelClient):
|
|
29
|
+
export function createShellDomainView(kernel: KernelClient): ShellView {
|
|
26
30
|
let bound: SchemaBoundView<ShellSchema> | null = null
|
|
27
|
-
const
|
|
31
|
+
const get = (): SchemaBoundView<ShellSchema> => (bound ??= kernel.withSchema(schema))
|
|
28
32
|
|
|
29
33
|
return {
|
|
30
|
-
|
|
34
|
+
get,
|
|
31
35
|
bindAs(type, node) {
|
|
32
|
-
const v =
|
|
36
|
+
const v = get()
|
|
33
37
|
return v.bindAny(node).is(type) ? v.bind(type, node) : null
|
|
34
38
|
},
|
|
35
39
|
}
|