@astrale-domains/shell 0.1.0-beta.23 → 0.1.0-beta.25
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/CHANGELOG.md +28 -0
- package/README.md +83 -79
- package/dist/application.d.ts +6 -5
- package/dist/application.js +20 -51
- package/dist/functions/group/assign-user-to-group.d.ts +27 -0
- package/dist/functions/group/assign-user-to-group.js +4 -0
- package/dist/functions/group/change-user-group-membership.d.ts +7 -0
- package/dist/functions/group/change-user-group-membership.js +34 -0
- package/dist/functions/group/group-membership-errors.d.ts +28 -0
- package/dist/functions/group/group-membership-errors.js +23 -0
- package/dist/functions/group/index.d.ts +2 -3
- package/dist/functions/group/index.js +2 -3
- package/dist/functions/group/unassign-user-from-group.d.ts +27 -0
- package/dist/functions/group/unassign-user-from-group.js +4 -0
- package/dist/functions/user/index.d.ts +1 -3
- package/dist/functions/user/index.js +1 -3
- package/dist/functions/user/invite-user.d.ts +30 -0
- package/dist/functions/user/invite-user.js +39 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/integrations/index.d.ts +1 -0
- package/dist/integrations/index.js +1 -0
- package/dist/integrations/integrations.d.ts +9 -0
- package/dist/integrations/integrations.js +2 -0
- package/dist/integrations/user-invitation/index.d.ts +4 -0
- package/dist/integrations/user-invitation/index.js +3 -0
- package/dist/integrations/user-invitation/invitation-request-failure.d.ts +5 -0
- package/dist/integrations/user-invitation/invitation-request-failure.js +9 -0
- package/dist/integrations/user-invitation/invite-user-request.d.ts +6 -0
- package/dist/integrations/user-invitation/invite-user-request.js +1 -0
- package/dist/integrations/user-invitation/request-user-invitation.d.ts +8 -0
- package/dist/integrations/user-invitation/request-user-invitation.js +9 -0
- package/dist/mutations/group/index.d.ts +1 -1
- package/dist/mutations/group/index.js +1 -1
- package/dist/mutations/group/set-user-group-membership.d.ts +26 -0
- package/dist/mutations/group/set-user-group-membership.js +29 -0
- package/dist/providers/admin-enrollment/create-admin-enrollment-provider.d.ts +7 -0
- package/dist/providers/admin-enrollment/create-admin-enrollment-provider.js +78 -0
- package/dist/providers/admin-enrollment/decode-admin-invitation-response.d.ts +7 -0
- package/dist/providers/admin-enrollment/decode-admin-invitation-response.js +20 -0
- package/dist/providers/admin-enrollment/index.d.ts +1 -0
- package/dist/providers/admin-enrollment/index.js +1 -0
- package/dist/providers/admin-enrollment/read-enrollment-response.d.ts +1 -0
- package/dist/providers/admin-enrollment/read-enrollment-response.js +34 -0
- package/dist/queries/group/index.d.ts +2 -0
- package/dist/queries/group/index.js +2 -0
- package/dist/queries/group/read-group-membership-endpoints.d.ts +13 -0
- package/dist/queries/group/read-group-membership-endpoints.js +18 -0
- package/dist/queries/group/read-user-group-membership.d.ts +15 -0
- package/dist/queries/group/read-user-group-membership.js +35 -0
- package/dist/runtime.d.ts +94 -9
- package/dist/runtime.js +9 -5
- package/dist/schema/index.d.ts +4 -4
- package/dist/schema/index.js +3 -4
- package/dist/schema/modules/group/classes/group.d.ts +4 -6
- package/dist/schema/modules/group/classes/group.js +4 -6
- package/dist/schema/modules/group/classes/index.d.ts +2 -0
- package/dist/schema/modules/group/classes/index.js +2 -0
- package/dist/schema/modules/group/classes/member-of-group.js +2 -3
- package/dist/schema/modules/group/core/administrators-group.js +6 -0
- package/dist/schema/modules/group/core/index.d.ts +2 -0
- package/dist/schema/modules/group/core/index.js +2 -0
- package/dist/schema/modules/group/core/members-group.js +6 -0
- package/dist/schema/modules/group/functions/assign-user-to-group.d.ts +7 -0
- package/dist/schema/modules/group/functions/assign-user-to-group.js +11 -0
- package/dist/schema/modules/group/functions/index.d.ts +2 -0
- package/dist/schema/modules/group/functions/index.js +2 -0
- package/dist/schema/modules/group/functions/unassign-user-from-group.d.ts +7 -0
- package/dist/schema/modules/group/functions/unassign-user-from-group.js +11 -0
- package/dist/schema/modules/group/index.d.ts +3 -9
- package/dist/schema/modules/group/index.js +3 -9
- package/dist/schema/modules/group/policies/belongs-to-group.d.ts +1 -0
- package/dist/schema/modules/group/policies/belongs-to-group.js +5 -0
- package/dist/schema/modules/group/policies/index.d.ts +1 -0
- package/dist/schema/modules/group/policies/index.js +1 -0
- package/dist/schema/modules/group/types/group-user-reference.d.ts +6 -0
- package/dist/schema/modules/group/types/group-user-reference.js +8 -0
- package/dist/schema/modules/group/types/index.d.ts +1 -0
- package/dist/schema/modules/group/types/index.js +1 -0
- package/dist/schema/modules/user/classes/index.d.ts +1 -0
- package/dist/schema/modules/user/classes/index.js +1 -0
- package/dist/schema/modules/user/classes/user.d.ts +5 -8
- package/dist/schema/modules/user/classes/user.js +7 -7
- package/dist/schema/modules/user/functions/index.d.ts +1 -0
- package/dist/schema/modules/user/functions/index.js +1 -0
- package/dist/schema/modules/user/functions/invite-user.d.ts +11 -0
- package/dist/schema/modules/user/functions/invite-user.js +12 -0
- package/dist/schema/modules/user/index.d.ts +2 -6
- package/dist/schema/modules/user/index.js +2 -6
- package/dist/schema/modules/user/types/index.d.ts +1 -0
- package/dist/schema/modules/user/types/index.js +1 -0
- package/dist/schema/modules/user/types/invitation-summary.d.ts +16 -0
- package/dist/schema/modules/user/types/invitation-summary.js +15 -0
- package/dist/schema/policies/administers-shell-class.d.ts +2 -0
- package/dist/schema/policies/administers-shell-class.js +11 -0
- package/dist/schema/policies/index.d.ts +2 -0
- package/dist/schema/policies/index.js +2 -0
- package/dist/schema/policies/owns-class.d.ts +1 -0
- package/dist/schema/policies/owns-class.js +7 -0
- package/dist/schema/schema.d.ts +14 -69
- package/dist/schema/schema.js +10 -27
- package/dist/schema/views/application-view.d.ts +1 -0
- package/dist/schema/views/application-view.js +4 -0
- package/dist/schema/views/index.d.ts +1 -0
- package/dist/schema/views/index.js +1 -0
- package/dist/utils/canonical-node-path/index.d.ts +1 -0
- package/dist/utils/canonical-node-path/index.js +1 -0
- package/dist/utils/canonical-node-path/parse-canonical-node-path.d.ts +2 -0
- package/dist/utils/canonical-node-path/parse-canonical-node-path.js +8 -0
- package/package.json +16 -7
- package/dist/functions/group/assign.d.ts +0 -3
- package/dist/functions/group/assign.js +0 -3
- package/dist/functions/group/change.d.ts +0 -6
- package/dist/functions/group/change.js +0 -41
- package/dist/functions/group/unassign.d.ts +0 -3
- package/dist/functions/group/unassign.js +0 -3
- package/dist/functions/registry/index.d.ts +0 -12
- package/dist/functions/registry/index.js +0 -12
- package/dist/functions/setup/admin.d.ts +0 -3
- package/dist/functions/setup/admin.js +0 -3
- package/dist/functions/setup/index.d.ts +0 -4
- package/dist/functions/setup/index.js +0 -4
- package/dist/functions/setup/member.d.ts +0 -3
- package/dist/functions/setup/member.js +0 -3
- package/dist/functions/setup/provision.d.ts +0 -5
- package/dist/functions/setup/provision.js +0 -70
- package/dist/functions/setup/run.d.ts +0 -7
- package/dist/functions/setup/run.js +0 -82
- package/dist/functions/space/access.d.ts +0 -7
- package/dist/functions/space/access.js +0 -41
- package/dist/functions/space/add.d.ts +0 -3
- package/dist/functions/space/add.js +0 -3
- package/dist/functions/space/default.d.ts +0 -3
- package/dist/functions/space/default.js +0 -37
- package/dist/functions/space/index.d.ts +0 -4
- package/dist/functions/space/index.js +0 -4
- package/dist/functions/space/remove.d.ts +0 -3
- package/dist/functions/space/remove.js +0 -3
- package/dist/functions/user/resolve-home.d.ts +0 -3
- package/dist/functions/user/resolve-home.js +0 -19
- package/dist/mutations/group/membership.d.ts +0 -23
- package/dist/mutations/group/membership.js +0 -32
- package/dist/mutations/space/access.d.ts +0 -25
- package/dist/mutations/space/access.js +0 -23
- package/dist/mutations/space/default.d.ts +0 -19
- package/dist/mutations/space/default.js +0 -23
- package/dist/mutations/space/index.d.ts +0 -2
- package/dist/mutations/space/index.js +0 -2
- package/dist/mutations/user/index.d.ts +0 -1
- package/dist/mutations/user/index.js +0 -1
- package/dist/mutations/user/repair.d.ts +0 -22
- package/dist/mutations/user/repair.js +0 -104
- package/dist/queries/space/access.d.ts +0 -9
- package/dist/queries/space/access.js +0 -12
- package/dist/queries/space/admin.d.ts +0 -9
- package/dist/queries/space/admin.js +0 -20
- package/dist/queries/space/index.d.ts +0 -3
- package/dist/queries/space/index.js +0 -3
- package/dist/queries/space/member.d.ts +0 -9
- package/dist/queries/space/member.js +0 -17
- package/dist/queries/user/groups.d.ts +0 -10
- package/dist/queries/user/groups.js +0 -41
- package/dist/queries/user/home.d.ts +0 -9
- package/dist/queries/user/home.js +0 -21
- package/dist/queries/user/index.d.ts +0 -5
- package/dist/queries/user/index.js +0 -5
- package/dist/queries/user/owned-spaces.d.ts +0 -9
- package/dist/queries/user/owned-spaces.js +0 -17
- package/dist/queries/user/profile.d.ts +0 -4
- package/dist/queries/user/profile.js +0 -16
- package/dist/queries/user/setup.d.ts +0 -13
- package/dist/queries/user/setup.js +0 -16
- package/dist/rules/user/index.d.ts +0 -1
- package/dist/rules/user/index.js +0 -1
- package/dist/rules/user/setup.d.ts +0 -38
- package/dist/rules/user/setup.js +0 -95
- package/dist/schema/modules/group/core/admin-group.js +0 -2
- package/dist/schema/modules/group/core/core.d.ts +0 -8
- package/dist/schema/modules/group/core/core.js +0 -6
- package/dist/schema/modules/group/core/identity.d.ts +0 -1
- package/dist/schema/modules/group/core/identity.js +0 -10
- package/dist/schema/modules/group/core/member-group.js +0 -2
- package/dist/schema/modules/group/functions/assign-user.d.ts +0 -7
- package/dist/schema/modules/group/functions/assign-user.js +0 -12
- package/dist/schema/modules/group/functions/unassign-user.d.ts +0 -7
- package/dist/schema/modules/group/functions/unassign-user.js +0 -12
- package/dist/schema/modules/group/policies/may-setup-users.d.ts +0 -1
- package/dist/schema/modules/group/policies/may-setup-users.js +0 -6
- package/dist/schema/modules/group/types/membership.d.ts +0 -276
- package/dist/schema/modules/group/types/membership.js +0 -5
- package/dist/schema/modules/group/views/group.d.ts +0 -1
- package/dist/schema/modules/group/views/group.js +0 -6
- package/dist/schema/modules/space/classes/administers-space.d.ts +0 -16
- package/dist/schema/modules/space/classes/administers-space.js +0 -9
- package/dist/schema/modules/space/classes/default-space.d.ts +0 -16
- package/dist/schema/modules/space/classes/default-space.js +0 -8
- package/dist/schema/modules/space/classes/member-of-space.d.ts +0 -16
- package/dist/schema/modules/space/classes/member-of-space.js +0 -9
- package/dist/schema/modules/space/classes/owns-space.d.ts +0 -16
- package/dist/schema/modules/space/classes/owns-space.js +0 -9
- package/dist/schema/modules/space/classes/space.d.ts +0 -15
- package/dist/schema/modules/space/classes/space.js +0 -15
- package/dist/schema/modules/space/core/core.d.ts +0 -7
- package/dist/schema/modules/space/core/core.js +0 -12
- package/dist/schema/modules/space/core/default-space.d.ts +0 -1
- package/dist/schema/modules/space/core/default-space.js +0 -6
- package/dist/schema/modules/space/functions/add-user.d.ts +0 -8
- package/dist/schema/modules/space/functions/add-user.js +0 -12
- package/dist/schema/modules/space/functions/remove-user.d.ts +0 -7
- package/dist/schema/modules/space/functions/remove-user.js +0 -11
- package/dist/schema/modules/space/functions/set-default.d.ts +0 -5
- package/dist/schema/modules/space/functions/set-default.js +0 -11
- package/dist/schema/modules/space/index.d.ts +0 -14
- package/dist/schema/modules/space/index.js +0 -14
- package/dist/schema/modules/space/policies/belongs-to-space.d.ts +0 -1
- package/dist/schema/modules/space/policies/belongs-to-space.js +0 -9
- package/dist/schema/modules/space/policies/may-administer-space.d.ts +0 -1
- package/dist/schema/modules/space/policies/may-administer-space.js +0 -8
- package/dist/schema/modules/space/policies/owns-space.d.ts +0 -1
- package/dist/schema/modules/space/policies/owns-space.js +0 -7
- package/dist/schema/modules/space/types/access.d.ts +0 -280
- package/dist/schema/modules/space/types/access.js +0 -12
- package/dist/schema/modules/space/views/space.d.ts +0 -1
- package/dist/schema/modules/space/views/space.js +0 -6
- package/dist/schema/modules/user/functions/resolve-home.d.ts +0 -7
- package/dist/schema/modules/user/functions/resolve-home.js +0 -11
- package/dist/schema/modules/user/functions/setup-admin.d.ts +0 -15
- package/dist/schema/modules/user/functions/setup-admin.js +0 -11
- package/dist/schema/modules/user/functions/setup-member.d.ts +0 -15
- package/dist/schema/modules/user/functions/setup-member.js +0 -11
- package/dist/schema/modules/user/types/setup-user.d.ts +0 -13
- package/dist/schema/modules/user/types/setup-user.js +0 -14
- package/dist/schema/modules/user/views/home.d.ts +0 -1
- package/dist/schema/modules/user/views/home.js +0 -4
- package/dist/schema/modules/user/views/user.d.ts +0 -1
- package/dist/schema/modules/user/views/user.js +0 -6
- /package/dist/schema/modules/group/core/{admin-group.d.ts → administrators-group.d.ts} +0 -0
- /package/dist/schema/modules/group/core/{member-group.d.ts → members-group.d.ts} +0 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const integrations: {
|
|
2
|
+
enrollment: import("@astrale-os/sdk/integration").IntegrationDefinition<"shell.enrollment", {
|
|
3
|
+
invite: import("@astrale-os/sdk/integration").IntegrationOperation<import("./user-invitation/index.js").InviteRequest, {
|
|
4
|
+
invitationId: string;
|
|
5
|
+
user: string;
|
|
6
|
+
state: "accepted" | "cancelled" | "completed" | "expired" | "failed" | "pending" | "registered" | "registering";
|
|
7
|
+
}>;
|
|
8
|
+
}>;
|
|
9
|
+
};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { enrollment } from './request-user-invitation.js';
|
|
2
|
+
export { InvitationRequestFailure } from './invitation-request-failure.js';
|
|
3
|
+
export { type InviteRequest } from './invite-user-request.js';
|
|
4
|
+
export type { InvitationSummary } from '../../schema/modules/user/index.js';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Expected business refusal from the invitation service, without its response body. */
|
|
2
|
+
export declare class InvitationRequestFailure extends Error {
|
|
3
|
+
readonly code: 'INVITATION_CONFLICT' | 'INVITATION_REJECTED';
|
|
4
|
+
constructor(code: 'INVITATION_CONFLICT' | 'INVITATION_REJECTED');
|
|
5
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { InviteRequest } from './invite-user-request.js';
|
|
2
|
+
export declare const enrollment: import("@astrale-os/sdk/integration").IntegrationDefinition<"shell.enrollment", {
|
|
3
|
+
invite: import("@astrale-os/sdk/integration").IntegrationOperation<InviteRequest, {
|
|
4
|
+
invitationId: string;
|
|
5
|
+
user: string;
|
|
6
|
+
state: "accepted" | "cancelled" | "completed" | "expired" | "failed" | "pending" | "registered" | "registering";
|
|
7
|
+
}>;
|
|
8
|
+
}>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { defineIntegration } from '@astrale-os/sdk/integration';
|
|
2
|
+
export const enrollment = defineIntegration({
|
|
3
|
+
id: 'shell.enrollment',
|
|
4
|
+
operations: {
|
|
5
|
+
invite: defineIntegration.operation({
|
|
6
|
+
replay: ({ requestId }) => ({ kind: 'keyed', source: 'input', key: requestId }),
|
|
7
|
+
}),
|
|
8
|
+
},
|
|
9
|
+
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { setGroupMembership } from './set-user-group-membership.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { setGroupMembership } from './set-user-group-membership.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { NodeId } from '@astrale-os/sdk/graph/node';
|
|
2
|
+
import type { QueryEdgeAST, QueryNodeAST } from '@astrale-os/sdk/query';
|
|
3
|
+
import { type QueryPrecondition } from '@astrale-os/sdk/mutation';
|
|
4
|
+
interface GroupMembership {
|
|
5
|
+
readonly user: NodeId;
|
|
6
|
+
readonly group: NodeId;
|
|
7
|
+
}
|
|
8
|
+
interface GroupMembershipObservation {
|
|
9
|
+
readonly membership: boolean;
|
|
10
|
+
readonly authority: boolean;
|
|
11
|
+
readonly guard: QueryPrecondition<QueryEdgeAST>;
|
|
12
|
+
readonly endpoints: QueryPrecondition<QueryNodeAST>;
|
|
13
|
+
}
|
|
14
|
+
interface Change extends GroupMembership {
|
|
15
|
+
readonly current: GroupMembershipObservation;
|
|
16
|
+
readonly present: boolean;
|
|
17
|
+
}
|
|
18
|
+
type ChangeResult = {
|
|
19
|
+
readonly ok: true;
|
|
20
|
+
} | {
|
|
21
|
+
readonly ok: false;
|
|
22
|
+
readonly code: string;
|
|
23
|
+
readonly outcomeKnown: boolean;
|
|
24
|
+
};
|
|
25
|
+
export declare const setGroupMembership: import("@astrale-os/sdk/mutation").Mutation<import("@astrale-os/sdk/schema").ResolvedDomainOfInput<"shell.astrale.ai", import("../../schema/index.js").ShellSchemaInput>, Change, ChangeResult>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
export const setGroupMembership = defineMutation()((domain) => ({
|
|
3
|
+
id: 'shell.group.membership.set',
|
|
4
|
+
build(input, mutation) {
|
|
5
|
+
mutation.expect.query(input.current.endpoints);
|
|
6
|
+
mutation.expect.query(input.current.guard);
|
|
7
|
+
const endpoints = { source: input.user, target: input.group };
|
|
8
|
+
const changes = [
|
|
9
|
+
{ class: domain.classes.member_of_group, current: input.current.membership },
|
|
10
|
+
{ class: domain.dependencies.kernel.classes.extends_with, current: input.current.authority },
|
|
11
|
+
];
|
|
12
|
+
for (const edge of changes) {
|
|
13
|
+
if (edge.current === input.present)
|
|
14
|
+
continue;
|
|
15
|
+
if (input.present)
|
|
16
|
+
mutation.createEdge({ class: edge.class, ...endpoints });
|
|
17
|
+
else
|
|
18
|
+
mutation.deleteEdge({ class: edge.class, ...endpoints });
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
project: () => ({ ok: true }),
|
|
22
|
+
reject: (failure) => {
|
|
23
|
+
if (failure.outcomeKnown &&
|
|
24
|
+
failure.code !== 'MUTATION_PRECONDITION_FAILED' &&
|
|
25
|
+
failure.code !== 'MUTATION_CONFLICT')
|
|
26
|
+
throw failure;
|
|
27
|
+
return { ok: false, code: failure.code, outcomeKnown: failure.outcomeKnown };
|
|
28
|
+
},
|
|
29
|
+
}));
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function enrollmentProvider(environment: unknown): import("@astrale-os/sdk/integration").Provider<import("@astrale-os/sdk/integration").IntegrationDefinition<"shell.enrollment", {
|
|
2
|
+
invite: import("@astrale-os/sdk/integration").IntegrationOperation<import("../../integrations/user-invitation/index.js").InviteRequest, {
|
|
3
|
+
invitationId: string;
|
|
4
|
+
user: string;
|
|
5
|
+
state: "accepted" | "cancelled" | "completed" | "expired" | "failed" | "pending" | "registered" | "registering";
|
|
6
|
+
}>;
|
|
7
|
+
}>>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { TransportError } from '@astrale-os/sdk/client';
|
|
2
|
+
import { defineProvider } from '@astrale-os/sdk/integration';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { enrollment, InvitationRequestFailure } from '../../integrations/user-invitation/index.js';
|
|
5
|
+
import { decodeAdminInvitationResponse } from './decode-admin-invitation-response.js';
|
|
6
|
+
import { readReply } from './read-enrollment-response.js';
|
|
7
|
+
// Environment is a representation boundary, unlike already-admitted handler input.
|
|
8
|
+
const configuration = z.object({ ENROLLMENT_INGRESS_URL: z.string().url() });
|
|
9
|
+
export function enrollmentProvider(environment) {
|
|
10
|
+
const input = configuration.parse(environment);
|
|
11
|
+
const endpoint = new URL(input.ENROLLMENT_INGRESS_URL);
|
|
12
|
+
if (endpoint.protocol !== 'https:' ||
|
|
13
|
+
endpoint.username ||
|
|
14
|
+
endpoint.password ||
|
|
15
|
+
endpoint.hash ||
|
|
16
|
+
endpoint.search) {
|
|
17
|
+
throw new TypeError('Enrollment ingress must be an HTTPS URL without credentials, query or hash.');
|
|
18
|
+
}
|
|
19
|
+
const audience = endpoint.href;
|
|
20
|
+
return defineProvider(enrollment, {
|
|
21
|
+
async invite(input, execution) {
|
|
22
|
+
if (execution.auth === undefined)
|
|
23
|
+
throw new Error('Authenticated Shell invocation required.');
|
|
24
|
+
// Mint per attempt, using only the current invocation's Domain-self identity.
|
|
25
|
+
const credential = await execution.auth.mint({ audience, ttlSeconds: 60 });
|
|
26
|
+
execution.signal.throwIfAborted();
|
|
27
|
+
const remaining = execution.deadline - Date.now();
|
|
28
|
+
if (remaining <= 0) {
|
|
29
|
+
throw TransportError.invocation('Enrollment deadline exceeded.', {
|
|
30
|
+
phase: 'timeout',
|
|
31
|
+
delivery: 'not-sent',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
// No automatic HTTP retry. A timeout after send has an unknown effect.
|
|
35
|
+
const signal = AbortSignal.any([execution.signal, AbortSignal.timeout(remaining)]);
|
|
36
|
+
const response = await fetch(audience, {
|
|
37
|
+
method: 'POST',
|
|
38
|
+
// Workers reject redirect:error before sending. Manual preserves the refusal:
|
|
39
|
+
// every 3xx is rejected below, without forwarding the proof to its Location.
|
|
40
|
+
redirect: 'manual',
|
|
41
|
+
headers: {
|
|
42
|
+
Authorization: `Bearer ${credential}`,
|
|
43
|
+
'Content-Type': 'application/json',
|
|
44
|
+
Accept: 'application/json',
|
|
45
|
+
'Idempotency-Key': input.requestId,
|
|
46
|
+
},
|
|
47
|
+
body: JSON.stringify(input),
|
|
48
|
+
signal,
|
|
49
|
+
}).catch((cause) => {
|
|
50
|
+
if (!(cause instanceof TypeError) && !(cause instanceof DOMException))
|
|
51
|
+
throw cause;
|
|
52
|
+
throw TransportError.invocation('Admin enrollment transport failed.', {
|
|
53
|
+
phase: signal.aborted ? 'timeout' : 'unknown',
|
|
54
|
+
delivery: 'unknown',
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
if (!response.ok) {
|
|
58
|
+
await response.body?.cancel();
|
|
59
|
+
if (response.status === 409)
|
|
60
|
+
throw new InvitationRequestFailure('INVITATION_CONFLICT');
|
|
61
|
+
if (response.status === 400 || response.status === 422) {
|
|
62
|
+
throw new InvitationRequestFailure('INVITATION_REJECTED');
|
|
63
|
+
}
|
|
64
|
+
// Shell admission already happened. A refused service credential is not a new
|
|
65
|
+
// authorization decision about the caller, and no upstream body is exposed.
|
|
66
|
+
throw TransportError.invocation('Admin enrollment request was not completed.', {
|
|
67
|
+
phase: 'receive',
|
|
68
|
+
delivery: 'unknown',
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const result = decodeAdminInvitationResponse(await readReply(response));
|
|
72
|
+
if (result.requestId !== input.requestId || result.user !== input.user) {
|
|
73
|
+
throw new TypeError('Admin enrollment response does not match the request.');
|
|
74
|
+
}
|
|
75
|
+
return { invitationId: result.invitationId, user: result.user, state: result.state };
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// Codec du JSON HTTP entrant ; la valeur admise satisfait le contrat de l'Integration.
|
|
3
|
+
const httpReply = z.object({
|
|
4
|
+
requestId: z.string().min(1),
|
|
5
|
+
invitationId: z.string().min(1),
|
|
6
|
+
user: z.string().min(1),
|
|
7
|
+
state: z.enum([
|
|
8
|
+
'pending',
|
|
9
|
+
'accepted',
|
|
10
|
+
'registering',
|
|
11
|
+
'registered',
|
|
12
|
+
'completed',
|
|
13
|
+
'cancelled',
|
|
14
|
+
'expired',
|
|
15
|
+
'failed',
|
|
16
|
+
]),
|
|
17
|
+
});
|
|
18
|
+
export function decodeAdminInvitationResponse(value) {
|
|
19
|
+
return httpReply.parse(value);
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { enrollmentProvider } from './create-admin-enrollment-provider.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { enrollmentProvider } from './create-admin-enrollment-provider.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function readReply(response: Response): Promise<unknown>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export async function readReply(response) {
|
|
2
|
+
if (!response.headers.get('content-type')?.toLowerCase().startsWith('application/json')) {
|
|
3
|
+
await response.body?.cancel();
|
|
4
|
+
throw new TypeError('Expected a JSON enrollment response.');
|
|
5
|
+
}
|
|
6
|
+
const reader = response.body?.getReader();
|
|
7
|
+
if (!reader)
|
|
8
|
+
throw new TypeError('Missing enrollment response body.');
|
|
9
|
+
const chunks = [];
|
|
10
|
+
let size = 0;
|
|
11
|
+
try {
|
|
12
|
+
for (;;) {
|
|
13
|
+
const { done, value } = await reader.read();
|
|
14
|
+
if (done)
|
|
15
|
+
break;
|
|
16
|
+
size += value.byteLength;
|
|
17
|
+
if (size > 16384) {
|
|
18
|
+
await reader.cancel();
|
|
19
|
+
throw new TypeError('Enrollment response exceeds 16 KiB.');
|
|
20
|
+
}
|
|
21
|
+
chunks.push(value);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
reader.releaseLock();
|
|
26
|
+
}
|
|
27
|
+
const bytes = new Uint8Array(size);
|
|
28
|
+
let offset = 0;
|
|
29
|
+
for (const chunk of chunks) {
|
|
30
|
+
bytes.set(chunk, offset);
|
|
31
|
+
offset += chunk.byteLength;
|
|
32
|
+
}
|
|
33
|
+
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(bytes));
|
|
34
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { NodeId } from '@astrale-os/sdk/graph/node';
|
|
2
|
+
import type { QueryPrecondition } from '@astrale-os/sdk/mutation';
|
|
3
|
+
import { type QueryNodeAST } from '@astrale-os/sdk/query';
|
|
4
|
+
interface Endpoints {
|
|
5
|
+
readonly user: NodeId;
|
|
6
|
+
readonly group: NodeId;
|
|
7
|
+
}
|
|
8
|
+
export interface GroupMembershipEndpoints {
|
|
9
|
+
readonly visible: boolean;
|
|
10
|
+
readonly guard: QueryPrecondition<QueryNodeAST>;
|
|
11
|
+
}
|
|
12
|
+
export declare const readGroupMembershipEndpoints: import("@astrale-os/sdk/query").SingleQueryDefinition<import("@astrale-os/sdk/schema").ResolvedDomainOfInput<"shell.astrale.ai", import("../../schema/index.js").ShellSchemaInput>, Endpoints, GroupMembershipEndpoints>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Path } from '@astrale-os/sdk/graph/path';
|
|
2
|
+
import { defineQuery, Query, queryResult, } from '@astrale-os/sdk/query';
|
|
3
|
+
export const readGroupMembershipEndpoints = defineQuery()(() => ({
|
|
4
|
+
id: 'shell.group.membership.endpoints',
|
|
5
|
+
page: { size: 2 },
|
|
6
|
+
pagination: { maximumPages: 2 },
|
|
7
|
+
build: ({ user, group }) => Query.from({ nodes: [Path.id(user), Path.id(group)] }).select({
|
|
8
|
+
kind: 'nodes',
|
|
9
|
+
projection: { kind: 'reference' },
|
|
10
|
+
}),
|
|
11
|
+
project(pages, input, { ast, complete }) {
|
|
12
|
+
const ids = queryResult.completeNodeIds(pages, 'Shell membership endpoints');
|
|
13
|
+
return {
|
|
14
|
+
visible: ids.includes(input.user) && ids.includes(input.group),
|
|
15
|
+
guard: { query: ast, equals: complete },
|
|
16
|
+
};
|
|
17
|
+
},
|
|
18
|
+
}));
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { NodeId } from '@astrale-os/sdk/graph/node';
|
|
2
|
+
import type { QueryPrecondition } from '@astrale-os/sdk/mutation';
|
|
3
|
+
import { type QueryEdgeAST } from '@astrale-os/sdk/query';
|
|
4
|
+
export interface GroupMembership {
|
|
5
|
+
readonly user: NodeId;
|
|
6
|
+
readonly group: NodeId;
|
|
7
|
+
}
|
|
8
|
+
export interface GroupMembershipState {
|
|
9
|
+
readonly membership: boolean;
|
|
10
|
+
readonly authority: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface GroupMembershipObservation extends GroupMembershipState {
|
|
13
|
+
readonly guard: QueryPrecondition<QueryEdgeAST>;
|
|
14
|
+
}
|
|
15
|
+
export declare const readGroupMembership: import("@astrale-os/sdk/query").SingleQueryDefinition<import("@astrale-os/sdk/schema").ResolvedDomainOfInput<"shell.astrale.ai", import("../../schema/index.js").ShellSchemaInput>, GroupMembership, GroupMembershipObservation>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Query, defineQuery, queryResult, } from '@astrale-os/sdk/query';
|
|
2
|
+
export const readGroupMembership = defineQuery()((domain) => ({
|
|
3
|
+
id: 'shell.group.membership.read',
|
|
4
|
+
build({ user, group }) {
|
|
5
|
+
const edges = Query.from({
|
|
6
|
+
edges: [domain.classes.member_of_group, domain.dependencies.kernel.classes.extends_with],
|
|
7
|
+
});
|
|
8
|
+
return edges
|
|
9
|
+
.filter({ binding: edges.source, predicate: { kind: 'identity.equal', identity: user } })
|
|
10
|
+
.filter({ binding: edges.target, predicate: { kind: 'identity.equal', identity: group } })
|
|
11
|
+
.select({
|
|
12
|
+
kind: 'edges',
|
|
13
|
+
projection: { edge: 'value', source: 'reference', target: 'reference' },
|
|
14
|
+
});
|
|
15
|
+
},
|
|
16
|
+
pagination: { maximumPages: 4 },
|
|
17
|
+
project(pages, _input, { ast, complete }) {
|
|
18
|
+
let membership = false;
|
|
19
|
+
let authority = false;
|
|
20
|
+
for (const page of pages) {
|
|
21
|
+
for (const item of queryResult.edgeItems(page, 'Shell group membership')) {
|
|
22
|
+
if (item.edge.kind !== 'value')
|
|
23
|
+
throw new TypeError('Expected an Edge value.');
|
|
24
|
+
if (item.edge.value.class === domain.classes.member_of_group.key)
|
|
25
|
+
membership = true;
|
|
26
|
+
else if (item.edge.value.class === domain.dependencies.kernel.classes.extends_with.key) {
|
|
27
|
+
authority = true;
|
|
28
|
+
}
|
|
29
|
+
else
|
|
30
|
+
throw new TypeError('Unexpected Edge Class.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return { membership, authority, guard: { query: ast, equals: complete } };
|
|
34
|
+
},
|
|
35
|
+
}));
|
package/dist/runtime.d.ts
CHANGED
|
@@ -1,13 +1,98 @@
|
|
|
1
1
|
import { type Runtime } from '@astrale-os/sdk/runtime';
|
|
2
|
-
import { workflows } from './functions/registry/index.js';
|
|
3
|
-
import { actions } from './functions/user/index.js';
|
|
4
2
|
import type { ShellSchema } from './schema/index.js';
|
|
5
|
-
|
|
6
|
-
declare const initialize: () => {
|
|
7
|
-
providers: {
|
|
3
|
+
import { integrations } from './integrations/index.js';
|
|
4
|
+
declare const initialize: (environment: unknown) => {
|
|
5
|
+
providers: {
|
|
6
|
+
enrollment: import("@astrale-os/sdk/integration").Provider<import("@astrale-os/sdk/integration").IntegrationDefinition<"shell.enrollment", {
|
|
7
|
+
invite: import("@astrale-os/sdk/integration").IntegrationOperation<import("./integrations/user-invitation/index.js").InviteRequest, {
|
|
8
|
+
invitationId: string;
|
|
9
|
+
user: string;
|
|
10
|
+
state: "accepted" | "cancelled" | "completed" | "expired" | "failed" | "pending" | "registered" | "registering";
|
|
11
|
+
}>;
|
|
12
|
+
}>>;
|
|
13
|
+
};
|
|
8
14
|
};
|
|
9
|
-
declare const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
15
|
+
declare const functions: readonly [import("@astrale-os/sdk/workflow").WorkflowDefinition<import("@astrale-os/sdk/schema").DefinedSchema<"shell.astrale.ai", import("@astrale-os/sdk/schema").ResolvedDomainOfInput<"shell.astrale.ai", import("./schema/index.js").ShellSchemaInput>>, "User.invite", {
|
|
16
|
+
enrollment: import("@astrale-os/sdk/integration").IntegrationDefinition<"shell.enrollment", {
|
|
17
|
+
invite: import("@astrale-os/sdk/integration").IntegrationOperation<import("./integrations/user-invitation/index.js").InviteRequest, {
|
|
18
|
+
invitationId: string;
|
|
19
|
+
user: string;
|
|
20
|
+
state: "accepted" | "cancelled" | "completed" | "expired" | "failed" | "pending" | "registered" | "registering";
|
|
21
|
+
}>;
|
|
22
|
+
}>;
|
|
23
|
+
}, {
|
|
24
|
+
readonly INVALID_INVITATION_REFERENCE: {
|
|
25
|
+
readonly family: "VALIDATION_ERROR";
|
|
26
|
+
readonly message: "User must be an exact canonical @NodeId path.";
|
|
27
|
+
readonly details: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
|
|
28
|
+
};
|
|
29
|
+
readonly INVITATION_CONFLICT: {
|
|
30
|
+
readonly family: "CONFLICT";
|
|
31
|
+
readonly message: "The invitation conflicts with an existing request.";
|
|
32
|
+
readonly details: import("zod").ZodObject<{
|
|
33
|
+
requestId: import("zod").ZodString;
|
|
34
|
+
}, import("zod/v4/core").$strict>;
|
|
35
|
+
};
|
|
36
|
+
readonly INVITATION_REJECTED: {
|
|
37
|
+
readonly family: "VALIDATION_ERROR";
|
|
38
|
+
readonly message: "Admin rejected the invitation request.";
|
|
39
|
+
readonly details: import("zod").ZodObject<{
|
|
40
|
+
requestId: import("zod").ZodString;
|
|
41
|
+
}, import("zod/v4/core").$strict>;
|
|
42
|
+
};
|
|
43
|
+
}>, import("@astrale-os/sdk/workflow").WorkflowDefinition<import("@astrale-os/sdk/schema").DefinedSchema<"shell.astrale.ai", import("@astrale-os/sdk/schema").ResolvedDomainOfInput<"shell.astrale.ai", import("./schema/index.js").ShellSchemaInput>>, "Group.assignUser", Readonly<Record<never, never>>, {
|
|
44
|
+
readonly GROUP_MEMBERSHIP_ENDPOINTS_UNAVAILABLE: {
|
|
45
|
+
readonly family: 'CONFLICT';
|
|
46
|
+
readonly message: 'Shell must be able to traverse both membership endpoints before confirming membership.';
|
|
47
|
+
readonly details: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
|
|
48
|
+
};
|
|
49
|
+
readonly INVALID_GROUP_MEMBERSHIP_REFERENCE: {
|
|
50
|
+
readonly family: 'VALIDATION_ERROR';
|
|
51
|
+
readonly message: 'User and group must be exact canonical @NodeId paths.';
|
|
52
|
+
readonly details: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
|
|
53
|
+
};
|
|
54
|
+
readonly GROUP_MEMBERSHIP_CONFLICT: {
|
|
55
|
+
readonly family: 'CONFLICT';
|
|
56
|
+
readonly message: 'Membership changed concurrently; retry the operation.';
|
|
57
|
+
readonly details: import("zod").ZodObject<{
|
|
58
|
+
cause: import("zod").ZodString;
|
|
59
|
+
}, import("zod/v4/core").$strict>;
|
|
60
|
+
};
|
|
61
|
+
readonly GROUP_MEMBERSHIP_UNCONFIRMED: {
|
|
62
|
+
readonly family: 'CONFLICT';
|
|
63
|
+
readonly message: 'The requested membership could not be confirmed; retry the operation.';
|
|
64
|
+
readonly details: import("zod").ZodObject<{
|
|
65
|
+
cause: import("zod").ZodString;
|
|
66
|
+
outcomeKnown: import("zod").ZodLiteral<false>;
|
|
67
|
+
}, import("zod/v4/core").$strict>;
|
|
68
|
+
};
|
|
69
|
+
}>, import("@astrale-os/sdk/workflow").WorkflowDefinition<import("@astrale-os/sdk/schema").DefinedSchema<"shell.astrale.ai", import("@astrale-os/sdk/schema").ResolvedDomainOfInput<"shell.astrale.ai", import("./schema/index.js").ShellSchemaInput>>, "Group.unassignUser", Readonly<Record<never, never>>, {
|
|
70
|
+
readonly GROUP_MEMBERSHIP_ENDPOINTS_UNAVAILABLE: {
|
|
71
|
+
readonly family: 'CONFLICT';
|
|
72
|
+
readonly message: 'Shell must be able to traverse both membership endpoints before confirming membership.';
|
|
73
|
+
readonly details: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
|
|
74
|
+
};
|
|
75
|
+
readonly INVALID_GROUP_MEMBERSHIP_REFERENCE: {
|
|
76
|
+
readonly family: 'VALIDATION_ERROR';
|
|
77
|
+
readonly message: 'User and group must be exact canonical @NodeId paths.';
|
|
78
|
+
readonly details: import("zod").ZodObject<{}, import("zod/v4/core").$strict>;
|
|
79
|
+
};
|
|
80
|
+
readonly GROUP_MEMBERSHIP_CONFLICT: {
|
|
81
|
+
readonly family: 'CONFLICT';
|
|
82
|
+
readonly message: 'Membership changed concurrently; retry the operation.';
|
|
83
|
+
readonly details: import("zod").ZodObject<{
|
|
84
|
+
cause: import("zod").ZodString;
|
|
85
|
+
}, import("zod/v4/core").$strict>;
|
|
86
|
+
};
|
|
87
|
+
readonly GROUP_MEMBERSHIP_UNCONFIRMED: {
|
|
88
|
+
readonly family: 'CONFLICT';
|
|
89
|
+
readonly message: 'The requested membership could not be confirmed; retry the operation.';
|
|
90
|
+
readonly details: import("zod").ZodObject<{
|
|
91
|
+
cause: import("zod").ZodString;
|
|
92
|
+
outcomeKnown: import("zod").ZodLiteral<false>;
|
|
93
|
+
}, import("zod/v4/core").$strict>;
|
|
94
|
+
};
|
|
95
|
+
}>];
|
|
96
|
+
export type ShellRuntime = Runtime<ShellSchema, typeof integrations, typeof initialize, typeof functions>;
|
|
97
|
+
declare const runtime: ShellRuntime;
|
|
13
98
|
export default runtime;
|
package/dist/runtime.js
CHANGED
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import { defineRuntime } from '@astrale-os/sdk/runtime';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import { assignUser, unassignUser } from './functions/group/index.js';
|
|
3
|
+
import { invite } from './functions/user/index.js';
|
|
4
|
+
import { integrations } from './integrations/index.js';
|
|
5
|
+
import { enrollmentProvider } from './providers/admin-enrollment/index.js';
|
|
6
|
+
const initialize = (environment) => ({
|
|
7
|
+
providers: { enrollment: enrollmentProvider(environment) },
|
|
8
|
+
});
|
|
9
|
+
const functions = [invite, assignUser, unassignUser];
|
|
6
10
|
const runtime = defineRuntime()({
|
|
7
11
|
integrations,
|
|
8
12
|
initialize,
|
|
9
|
-
functions
|
|
13
|
+
functions,
|
|
10
14
|
});
|
|
11
15
|
export default runtime;
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
1
|
+
export { ShellSchema, S, type Shell, type ShellClasses, type ShellSchemaInput } from './schema.js';
|
|
2
|
+
export { User } from './modules/user/index.js';
|
|
3
|
+
export type { InvitationSummary } from './modules/user/index.js';
|
|
4
|
+
export { Group, member_of_group, adminGroup, memberGroup } from './modules/group/index.js';
|
package/dist/schema/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export { User, homeView, resolveHome, setupAdmin, setupMember, userView, } from '#schema/modules/user';
|
|
1
|
+
export { ShellSchema, S } from './schema.js';
|
|
2
|
+
export { User } from './modules/user/index.js';
|
|
3
|
+
export { Group, member_of_group, adminGroup, memberGroup } from './modules/group/index.js';
|
|
@@ -1,17 +1,15 @@
|
|
|
1
1
|
import { nodeClass, type ClassIcon, type Kernel } from '@astrale-os/sdk/schema';
|
|
2
|
-
import {
|
|
3
|
-
import { groupUnassignUser } from '../functions/unassign-user.js';
|
|
2
|
+
import { assignUser, unassignUser } from '../functions/index.js';
|
|
4
3
|
export interface GroupConfig {
|
|
5
|
-
readonly
|
|
4
|
+
readonly icon: ClassIcon;
|
|
6
5
|
readonly extends: readonly [
|
|
7
6
|
Kernel['classes']['Identity'],
|
|
8
7
|
Kernel['classes']['Named'],
|
|
9
8
|
Kernel['classes']['Descriptable']
|
|
10
9
|
];
|
|
11
|
-
readonly icon: ClassIcon;
|
|
12
10
|
readonly methods: {
|
|
13
|
-
readonly assignUser: typeof
|
|
14
|
-
readonly unassignUser: typeof
|
|
11
|
+
readonly assignUser: typeof assignUser;
|
|
12
|
+
readonly unassignUser: typeof unassignUser;
|
|
15
13
|
};
|
|
16
14
|
}
|
|
17
15
|
export declare const Group: ReturnType<typeof nodeClass<GroupConfig>>;
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { K, classIcon, nodeClass } from '@astrale-os/sdk/schema';
|
|
2
2
|
import { UsersRound } from '@astrale-os/sdk/schema/icons';
|
|
3
|
-
import {
|
|
4
|
-
import { groupUnassignUser } from '../functions/unassign-user.js';
|
|
3
|
+
import { assignUser, unassignUser } from '../functions/index.js';
|
|
5
4
|
export const Group = nodeClass({
|
|
6
|
-
description: 'A named compositional Shell Identity.',
|
|
7
|
-
extends: [K.classes.Identity, K.classes.Named, K.classes.Descriptable],
|
|
8
5
|
icon: classIcon.lucide(UsersRound),
|
|
9
|
-
|
|
6
|
+
extends: [K.classes.Identity, K.classes.Named, K.classes.Descriptable],
|
|
7
|
+
methods: { assignUser, unassignUser },
|
|
10
8
|
});
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { edgeClass } from '@astrale-os/sdk/schema';
|
|
2
|
-
import { User } from '
|
|
2
|
+
import { User } from '../../user/index.js';
|
|
3
3
|
import { Group } from './group.js';
|
|
4
4
|
export const member_of_group = edgeClass.directed({
|
|
5
|
-
source: { as: 'user', accepts: [User], outgoing: '0..*' },
|
|
5
|
+
source: { as: 'user', accepts: [() => User], outgoing: '0..*' },
|
|
6
6
|
target: { as: 'group', accepts: [() => Group], incoming: '0..*' },
|
|
7
|
-
description: 'Shell role membership paired atomically with Kernel authority composition.',
|
|
8
7
|
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { K, core } from '@astrale-os/sdk/schema';
|
|
2
|
+
import { Group } from '../classes/group.js';
|
|
3
|
+
export const adminGroup = core.node(() => Group, {
|
|
4
|
+
[K.classes.Named.properties.name.key]: 'Administrators',
|
|
5
|
+
[K.classes.Descriptable.properties.description.key]: 'Instance administrators.',
|
|
6
|
+
});
|