@astrale-domains/shell 0.1.6 → 0.1.8
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/README.md +73 -173
- package/dist/domain.d.ts +499 -31
- package/dist/domain.js +99 -78
- package/dist/functions/application/index.js +2 -1
- package/dist/functions/application/legacy/index.js +1 -0
- package/dist/functions/application/legacy/list-entrypoints.js +8 -0
- package/dist/functions/authority/capabilities.js +1 -0
- package/dist/functions/authority/composition.js +47 -0
- package/dist/functions/authority/index.js +2 -0
- package/dist/functions/authority/roles.js +113 -0
- package/dist/functions/directory/disconnect-directory.js +35 -0
- package/dist/functions/directory/index.js +1 -0
- package/dist/functions/group/assign-member.js +7 -0
- package/dist/functions/group/change-group-membership.js +101 -20
- package/dist/functions/group/create-group.js +23 -0
- package/dist/functions/group/delete-group.js +33 -0
- package/dist/functions/group/deprovision-group.js +27 -0
- package/dist/functions/group/group-errors.js +43 -0
- package/dist/functions/group/group-membership-errors.js +3 -1
- package/dist/functions/group/group.js +51 -0
- package/dist/functions/group/index.js +8 -2
- package/dist/functions/group/legacy/index.js +1 -0
- package/dist/functions/group/legacy/membership.js +64 -0
- package/dist/functions/group/membership-laws.js +37 -0
- package/dist/functions/group/provision-group.js +33 -0
- package/dist/functions/group/unassign-member.js +7 -0
- package/dist/functions/group/update-group.js +55 -0
- package/dist/functions/invitation/index.js +2 -0
- package/dist/functions/invitation/invitation-errors.js +13 -0
- package/dist/functions/invitation/invitation-methods.js +41 -0
- package/dist/functions/invitation/send-invitation.js +131 -0
- package/dist/functions/user/account.js +35 -0
- package/dist/functions/user/create-user.js +45 -0
- package/dist/functions/user/deactivate-user.js +19 -0
- package/dist/functions/user/delete-user.js +34 -0
- package/dist/functions/user/deprovision-user.js +21 -0
- package/dist/functions/user/index.js +15 -1
- package/dist/functions/user/invite-errors.js +18 -0
- package/dist/functions/user/invite-user.js +42 -34
- package/dist/functions/user/legacy/claimed-account.js +11 -0
- package/dist/functions/user/legacy/index.js +4 -0
- package/dist/functions/user/legacy/invite.js +20 -0
- package/dist/functions/user/legacy/migrate-accounts.js +98 -0
- package/dist/functions/user/legacy/record-profile.js +19 -0
- package/dist/functions/user/protect-administrators.js +16 -0
- package/dist/functions/user/provision-user.js +70 -0
- package/dist/functions/user/reactivate-user.js +19 -0
- package/dist/functions/user/read-account.js +12 -0
- package/dist/functions/user/request-invitation.js +17 -0
- package/dist/functions/user/update-profile.js +22 -0
- package/dist/functions/user/update-user.js +68 -0
- package/dist/functions/user/user-errors.js +69 -0
- package/dist/functions/user/write-account.js +57 -0
- package/dist/functions/view-access/index.js +2 -1
- package/dist/functions/view-access/{assign-views.js → legacy/assign-views.js} +11 -7
- package/dist/functions/view-access/legacy/index.js +1 -0
- package/dist/functions/view-access/{view-access-errors.js → legacy/view-access-errors.js} +5 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/integrations/user-invitation/invite-user-request.d.ts +6 -0
- package/dist/legacy/index.js +1 -0
- package/dist/legacy/release.js +33 -0
- package/dist/mutations/composition/grant-role.js +13 -0
- package/dist/mutations/composition/index.js +1 -0
- package/dist/mutations/group/index.js +1 -1
- package/dist/mutations/group/legacy/index.js +1 -0
- package/dist/mutations/group/legacy/membership-class.js +7 -0
- package/dist/mutations/group/set-group-membership.js +60 -19
- package/dist/mutations/identity/create-profile.js +37 -0
- package/dist/mutations/identity/delete-identity.js +28 -0
- package/dist/mutations/identity/index.js +4 -0
- package/dist/mutations/identity/write-account.js +109 -0
- package/dist/mutations/identity/write-group.js +72 -0
- package/dist/mutations/invitation/index.js +1 -0
- package/dist/mutations/invitation/write-invitation.js +79 -0
- package/dist/mutations/user/legacy/index.js +1 -0
- package/dist/mutations/user/{record-user-profile.js → legacy/record-user-profile.js} +5 -2
- package/dist/providers/admin-enrollment/create-admin-enrollment-provider.js +6 -3
- package/dist/providers/admin-enrollment/legacy/index.js +1 -0
- package/dist/providers/admin-enrollment/legacy/send-without-profile.js +16 -0
- package/dist/queries/application/legacy/index.js +1 -0
- package/dist/queries/application/legacy/read-installed-entrypoints.js +47 -0
- package/dist/queries/composition/index.js +2 -0
- package/dist/queries/composition/read-extensions.js +34 -0
- package/dist/queries/composition/read-role-nodes.js +76 -0
- package/dist/queries/group/index.js +2 -1
- package/dist/queries/group/legacy/index.js +3 -0
- package/dist/queries/group/legacy/read-core-groups.js +46 -0
- package/dist/queries/group/legacy/read-member-of-group.js +24 -0
- package/dist/queries/group/legacy/read-members-of-group.js +27 -0
- package/dist/queries/group/read-group-members.js +73 -0
- package/dist/queries/group/read-group-membership-endpoints.js +11 -0
- package/dist/queries/group/read-group-membership.js +6 -21
- package/dist/queries/identity/index.js +1 -0
- package/dist/queries/identity/read-identities.js +29 -0
- package/dist/queries/invitation/index.js +1 -0
- package/dist/queries/invitation/read-invitation.js +50 -0
- package/dist/queries/profile/index.js +1 -0
- package/dist/queries/profile/read-profile.js +15 -0
- package/dist/queries/role/index.js +1 -0
- package/dist/queries/role/read-role-node.js +21 -0
- package/dist/queries/user/legacy/index.js +1 -0
- package/dist/queries/user/legacy/read-user-profile.js +27 -0
- package/dist/runtime.d.ts +20147 -466
- package/dist/runtime.js +34 -7
- package/dist/schema/index.d.ts +7 -4
- package/dist/schema/index.js +8 -4
- package/dist/schema/legacy/index.js +1 -0
- package/dist/schema/legacy/schema.js +32 -0
- package/dist/schema/modules/application/legacy/entrypoint-entry.js +11 -0
- package/dist/schema/modules/application/legacy/functions/index.js +1 -0
- package/dist/schema/modules/application/legacy/functions/list-entrypoints.js +22 -0
- package/dist/schema/modules/application/legacy/index.js +2 -0
- package/dist/schema/modules/directory/functions/disconnect-directory.d.ts +13 -0
- package/dist/schema/modules/directory/functions/disconnect-directory.js +15 -0
- package/dist/schema/modules/directory/functions/index.d.ts +1 -0
- package/dist/schema/modules/directory/functions/index.js +1 -0
- package/dist/schema/modules/directory/index.d.ts +1 -0
- package/dist/schema/modules/directory/index.js +1 -0
- package/dist/schema/modules/group/classes/group-profile-link.d.ts +34 -0
- package/dist/schema/modules/group/classes/group-profile-link.js +21 -0
- package/dist/schema/modules/group/classes/group-profile.d.ts +15 -0
- package/dist/schema/modules/group/classes/group-profile.js +20 -0
- package/dist/schema/modules/group/classes/group.d.ts +87 -1
- package/dist/schema/modules/group/classes/group.js +38 -7
- package/dist/schema/modules/group/classes/index.d.ts +2 -1
- package/dist/schema/modules/group/classes/index.js +3 -1
- package/dist/schema/modules/group/functions/assign-member.js +17 -0
- package/dist/schema/modules/group/functions/assign-members.js +17 -0
- package/dist/schema/modules/group/functions/create-group.js +20 -0
- package/dist/schema/modules/group/functions/delete-group.js +12 -0
- package/dist/schema/modules/group/functions/deprovision-group.js +14 -0
- package/dist/schema/modules/group/functions/index.js +9 -2
- package/dist/schema/modules/group/functions/provision-group.js +14 -0
- package/dist/schema/modules/group/functions/unassign-member.js +17 -0
- package/dist/schema/modules/group/functions/unassign-members.js +17 -0
- package/dist/schema/modules/group/functions/update-group.js +20 -0
- package/dist/schema/modules/group/index.d.ts +3 -3
- package/dist/schema/modules/group/index.js +4 -3
- package/dist/schema/modules/group/legacy/admission.d.ts +9 -0
- package/dist/schema/modules/group/legacy/admission.js +9 -0
- package/dist/schema/modules/group/legacy/classes/index.d.ts +1 -0
- package/dist/schema/modules/group/legacy/classes/index.js +1 -0
- package/dist/schema/modules/group/{classes → legacy/classes}/member-of-group.d.ts +10 -1
- package/dist/schema/modules/group/legacy/classes/member-of-group.js +32 -0
- package/dist/schema/modules/group/legacy/core-groups.d.ts +22 -0
- package/dist/schema/modules/group/legacy/core-groups.js +28 -0
- package/dist/schema/modules/group/legacy/index.d.ts +5 -0
- package/dist/schema/modules/group/legacy/index.js +6 -0
- package/dist/schema/modules/group/legacy/policies/belongs-to-group.d.ts +5 -0
- package/dist/schema/modules/group/legacy/policies/belongs-to-group.js +9 -0
- package/dist/schema/modules/group/legacy/policies/index.d.ts +2 -0
- package/dist/schema/modules/group/legacy/policies/index.js +2 -0
- package/dist/schema/modules/group/legacy/policies/owns-membership-group.d.ts +6 -0
- package/dist/schema/modules/group/legacy/policies/owns-membership-group.js +12 -0
- package/dist/schema/modules/group/legacy/relaxations.d.ts +21 -0
- package/dist/schema/modules/group/legacy/relaxations.js +27 -0
- package/dist/schema/modules/group/policies/describes-group-of-subject.d.ts +2 -0
- package/dist/schema/modules/group/policies/describes-group-of-subject.js +7 -0
- package/dist/schema/modules/group/policies/index.d.ts +2 -1
- package/dist/schema/modules/group/policies/index.js +2 -1
- package/dist/schema/modules/group/policies/is-group-profile-source.d.ts +2 -0
- package/dist/schema/modules/group/policies/is-group-profile-source.js +6 -0
- package/dist/schema/modules/group/types/group-membership-input.js +8 -0
- package/dist/schema/modules/group/types/group.js +10 -0
- package/dist/schema/modules/group/types/index.js +2 -1
- package/dist/schema/modules/invitation/classes/index.js +2 -0
- package/dist/schema/modules/invitation/classes/invitation-user.js +17 -0
- package/dist/schema/modules/invitation/classes/invitation.js +32 -0
- package/dist/schema/modules/invitation/functions/accept.js +16 -0
- package/dist/schema/modules/invitation/functions/cancel.js +12 -0
- package/dist/schema/modules/invitation/functions/index.js +4 -0
- package/dist/schema/modules/invitation/functions/resend.js +12 -0
- package/dist/schema/modules/invitation/functions/send.js +20 -0
- package/dist/schema/modules/invitation/index.js +2 -0
- package/dist/schema/modules/invitation/types/index.js +1 -0
- package/dist/schema/modules/invitation/types/invitation-status.js +5 -0
- package/dist/schema/modules/namespace/classes/alias.d.ts +2 -1
- package/dist/schema/modules/namespace/classes/alias.js +11 -2
- package/dist/schema/modules/namespace/functions/link.js +3 -2
- package/dist/schema/modules/namespace/functions/rename.js +3 -2
- package/dist/schema/modules/namespace/functions/unlink.js +3 -2
- package/dist/schema/modules/role/classes/index.d.ts +1 -0
- package/dist/schema/modules/role/classes/index.js +1 -0
- package/dist/schema/modules/role/classes/role.d.ts +16 -0
- package/dist/schema/modules/role/classes/role.js +19 -0
- package/dist/schema/modules/role/core/index.d.ts +1 -0
- package/dist/schema/modules/role/core/index.js +1 -0
- package/dist/schema/modules/role/core/roles.d.ts +39 -0
- package/dist/schema/modules/role/core/roles.js +31 -0
- package/dist/schema/modules/role/index.d.ts +2 -0
- package/dist/schema/modules/role/index.js +2 -0
- package/dist/schema/modules/user/classes/index.d.ts +2 -0
- package/dist/schema/modules/user/classes/index.js +3 -0
- package/dist/schema/modules/user/classes/user-profile-link.d.ts +35 -0
- package/dist/schema/modules/user/classes/user-profile-link.js +22 -0
- package/dist/schema/modules/user/classes/user-profile.d.ts +41 -0
- package/dist/schema/modules/user/classes/user-profile.js +30 -0
- package/dist/schema/modules/user/classes/user.d.ts +133 -8
- package/dist/schema/modules/user/classes/user.js +46 -15
- package/dist/schema/modules/user/functions/create-user.js +21 -0
- package/dist/schema/modules/user/functions/deactivate-user.js +12 -0
- package/dist/schema/modules/user/functions/delete-user.js +12 -0
- package/dist/schema/modules/user/functions/deprovision-user.js +14 -0
- package/dist/schema/modules/user/functions/index.js +8 -1
- package/dist/schema/modules/user/functions/invite-user.js +23 -4
- package/dist/schema/modules/user/functions/provision-user.js +25 -0
- package/dist/schema/modules/user/functions/reactivate-user.js +12 -0
- package/dist/schema/modules/user/functions/update-profile.js +16 -0
- package/dist/schema/modules/user/functions/update-user.js +22 -0
- package/dist/schema/modules/user/index.d.ts +2 -1
- package/dist/schema/modules/user/index.js +2 -1
- package/dist/schema/modules/user/legacy/account-properties.js +24 -0
- package/dist/schema/modules/user/legacy/functions/index.js +2 -0
- package/dist/schema/modules/user/legacy/functions/migrate-accounts.js +23 -0
- package/dist/schema/modules/user/legacy/functions/record-profile.js +18 -0
- package/dist/schema/modules/user/legacy/index.js +5 -0
- package/dist/schema/modules/user/legacy/invite.js +15 -0
- package/dist/schema/modules/user/legacy/relaxations.js +37 -0
- package/dist/schema/modules/user/policies/describes-subject.d.ts +2 -0
- package/dist/schema/modules/user/policies/describes-subject.js +7 -0
- package/dist/schema/modules/user/policies/index.d.ts +2 -0
- package/dist/schema/modules/user/policies/index.js +2 -0
- package/dist/schema/modules/user/policies/is-profile-source.d.ts +2 -0
- package/dist/schema/modules/user/policies/is-profile-source.js +6 -0
- package/dist/schema/modules/user/types/account.d.ts +12 -0
- package/dist/schema/modules/user/types/account.js +12 -0
- package/dist/schema/modules/user/types/index.d.ts +1 -1
- package/dist/schema/modules/user/types/index.js +1 -1
- package/dist/schema/modules/view-access/classes/view-access.d.ts +7 -11
- package/dist/schema/modules/view-access/classes/view-access.js +17 -12
- package/dist/schema/modules/view-access/index.d.ts +1 -2
- package/dist/schema/modules/view-access/index.js +1 -2
- package/dist/schema/modules/view-access/legacy/functions/assign-views.js +22 -0
- package/dist/schema/modules/view-access/legacy/functions/index.js +1 -0
- package/dist/schema/modules/view-access/legacy/index.js +2 -0
- package/dist/schema/modules/view-access/legacy/view-assignment.js +24 -0
- package/dist/schema/modules/view-access/policies/holds-view-access.d.ts +2 -0
- package/dist/schema/modules/view-access/policies/holds-view-access.js +5 -0
- package/dist/schema/modules/view-access/policies/index.d.ts +1 -0
- package/dist/schema/modules/view-access/policies/index.js +1 -0
- package/dist/schema/policies/has-role.d.ts +6 -0
- package/dist/schema/policies/has-role.js +9 -0
- package/dist/schema/policies/index.d.ts +1 -0
- package/dist/schema/policies/index.js +1 -4
- package/dist/schema/policies/legacy/administers-shell-class.js +21 -0
- package/dist/schema/policies/legacy/index.js +4 -0
- package/dist/schema/policies/legacy/is-self.js +9 -0
- package/dist/schema/policies/legacy/owns-class.js +12 -0
- package/dist/schema/policies/legacy/uses-function.js +9 -0
- package/dist/schema/schema.d.ts +1937 -119
- package/dist/schema/schema.js +35 -15
- package/dist/schema/types/attributes.js +15 -0
- package/dist/schema/types/index.js +1 -0
- package/dist/utils/attributes/attributes.js +12 -0
- package/dist/utils/attributes/index.js +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/same-json/index.js +1 -0
- package/dist/utils/same-json/same-json.js +9 -0
- package/package.json +3 -3
- package/dist/functions/application/list-entrypoints.js +0 -6
- package/dist/functions/group/assign-member-to-group.js +0 -4
- package/dist/functions/group/unassign-member-from-group.js +0 -4
- package/dist/functions/user/record-profile.js +0 -18
- package/dist/mutations/user/index.js +0 -1
- package/dist/queries/application/index.js +0 -1
- package/dist/queries/application/read-installed-entrypoints.js +0 -28
- package/dist/queries/user/index.js +0 -1
- package/dist/queries/user/read-user-profile.js +0 -9
- package/dist/schema/modules/application/functions/index.d.ts +0 -1
- package/dist/schema/modules/application/functions/index.js +0 -1
- package/dist/schema/modules/application/functions/list-entrypoints.d.ts +0 -15
- package/dist/schema/modules/application/functions/list-entrypoints.js +0 -16
- package/dist/schema/modules/application/index.d.ts +0 -2
- package/dist/schema/modules/application/index.js +0 -2
- package/dist/schema/modules/application/types/entrypoint-entry.d.ts +0 -8
- package/dist/schema/modules/application/types/entrypoint-entry.js +0 -7
- package/dist/schema/modules/application/types/index.d.ts +0 -1
- package/dist/schema/modules/application/types/index.js +0 -1
- package/dist/schema/modules/group/classes/member-of-group.js +0 -12
- package/dist/schema/modules/group/core/administrators-group.d.ts +0 -1
- package/dist/schema/modules/group/core/administrators-group.js +0 -6
- package/dist/schema/modules/group/core/applications-group.d.ts +0 -1
- package/dist/schema/modules/group/core/applications-group.js +0 -6
- package/dist/schema/modules/group/core/index.d.ts +0 -3
- package/dist/schema/modules/group/core/index.js +0 -3
- package/dist/schema/modules/group/core/members-group.d.ts +0 -1
- package/dist/schema/modules/group/core/members-group.js +0 -6
- package/dist/schema/modules/group/functions/assign-member-to-group.js +0 -11
- package/dist/schema/modules/group/functions/unassign-member-from-group.js +0 -11
- package/dist/schema/modules/group/policies/belongs-to-group.d.ts +0 -1
- package/dist/schema/modules/group/policies/belongs-to-group.js +0 -5
- package/dist/schema/modules/user/functions/record-profile.js +0 -14
- package/dist/schema/modules/user/types/user-profile.d.ts +0 -7
- package/dist/schema/modules/user/types/user-profile.js +0 -7
- package/dist/schema/modules/view-access/core/index.d.ts +0 -1
- package/dist/schema/modules/view-access/core/index.js +0 -1
- package/dist/schema/modules/view-access/core/view-only-group.d.ts +0 -5
- package/dist/schema/modules/view-access/core/view-only-group.js +0 -10
- package/dist/schema/modules/view-access/functions/assign-views.d.ts +0 -16
- package/dist/schema/modules/view-access/functions/assign-views.js +0 -17
- package/dist/schema/modules/view-access/functions/index.d.ts +0 -1
- package/dist/schema/modules/view-access/functions/index.js +0 -1
- package/dist/schema/modules/view-access/types/index.js +0 -1
- package/dist/schema/modules/view-access/types/view-assignment.js +0 -16
- package/dist/schema/policies/administers-shell-class.js +0 -11
- package/dist/schema/policies/is-self.js +0 -5
- package/dist/schema/policies/owns-class.js +0 -7
- package/dist/schema/policies/uses-function.js +0 -5
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { PROFILE_PROPERTIES, newProfileValues, updateAccount, } from '../../mutations/identity/index.js';
|
|
2
|
+
import { readProfile } from '../../queries/profile/index.js';
|
|
3
|
+
import { sameJson } from '../../utils/index.js';
|
|
4
|
+
/** The values of an account a write is decided on. */
|
|
5
|
+
const DECIDED = [
|
|
6
|
+
'name',
|
|
7
|
+
'email',
|
|
8
|
+
'givenName',
|
|
9
|
+
'familyName',
|
|
10
|
+
'icon',
|
|
11
|
+
'directory',
|
|
12
|
+
'externalId',
|
|
13
|
+
'frozen',
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* Write what differs between an account and a change (`null` erases). `frozen` is written as is: it
|
|
17
|
+
* alone states whether the account may sign in. The write holds only on the values it was decided on. It answers whether
|
|
18
|
+
* anything changed, or the refusal: a key another account holds, or a concurrent change.
|
|
19
|
+
*/
|
|
20
|
+
export async function writeAccount({ mutate, query }, account, change) {
|
|
21
|
+
const set = {};
|
|
22
|
+
const unset = [];
|
|
23
|
+
for (const [key, value] of Object.entries(change)) {
|
|
24
|
+
const current = account[key];
|
|
25
|
+
if (value === null || value === undefined) {
|
|
26
|
+
if (value === null && current !== undefined)
|
|
27
|
+
unset.push(key);
|
|
28
|
+
}
|
|
29
|
+
else if (!sameJson(value, current))
|
|
30
|
+
set[key] = value;
|
|
31
|
+
}
|
|
32
|
+
if (Object.keys(set).length === 0 && unset.length === 0)
|
|
33
|
+
return 'unchanged';
|
|
34
|
+
const expected = Object.fromEntries(DECIDED.map((key) => [key, account[key]]));
|
|
35
|
+
// The profile carries the shared values; an account stored before profiles gets one now.
|
|
36
|
+
const shares = PROFILE_PROPERTIES.some((key) => key in set || unset.includes(key));
|
|
37
|
+
const profileNode = shares
|
|
38
|
+
? await query(readProfile, { kind: 'User', node: account.id })
|
|
39
|
+
: undefined;
|
|
40
|
+
const merged = Object.fromEntries(Object.entries({ ...account, ...set }).filter(([key]) => !unset.includes(key)));
|
|
41
|
+
const created = profileNode === undefined ? newProfileValues(merged) : undefined;
|
|
42
|
+
const profile = !shares
|
|
43
|
+
? undefined
|
|
44
|
+
: profileNode !== undefined
|
|
45
|
+
? { id: profileNode }
|
|
46
|
+
: created === undefined
|
|
47
|
+
? undefined
|
|
48
|
+
: { create: created };
|
|
49
|
+
const result = await mutate(updateAccount, {
|
|
50
|
+
user: account.id,
|
|
51
|
+
set: set,
|
|
52
|
+
unset,
|
|
53
|
+
expected,
|
|
54
|
+
...(profile === undefined ? {} : { profile }),
|
|
55
|
+
});
|
|
56
|
+
return result.ok ? 'written' : result.refusal;
|
|
57
|
+
}
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
// Seam L-SHELL-12: the legacy handler the Runtime registers.
|
|
2
|
+
export { legacyAssignViews } from './legacy/index.js';
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
import { defineAction } from '@astrale-os/sdk/action';
|
|
2
2
|
import { Path } from '@astrale-os/sdk/graph/path';
|
|
3
|
-
import { setViewAccess } from '
|
|
4
|
-
import { readViewAccess } from '
|
|
5
|
-
import { canonicalNodeId } from '
|
|
6
|
-
import {
|
|
3
|
+
import { setViewAccess } from '../../../mutations/view-access/index.js';
|
|
4
|
+
import { readViewAccess } from '../../../queries/view-access/index.js';
|
|
5
|
+
import { canonicalNodeId } from '../../../utils/canonical-node-path/index.js';
|
|
6
|
+
import { legacyViewAccessErrors } from './view-access-errors.js';
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* @deprecated Give and withdraw Views for each identity in one write (L-SHELL-12). Replaced by a
|
|
9
|
+
* Mutation on `view_access`, which `workspace.admin` holders write. Removal: Shell major (delivery
|
|
10
|
+
* step 5) after 1Pact step 4.
|
|
11
|
+
*
|
|
12
|
+
* One read and at most one Mutation, both with Shell's own authority: `workspace.admin` admits the
|
|
13
|
+
* caller. The write changes only what differs
|
|
10
14
|
* from the Edges read, under their guard, so a View already given or already withdrawn costs
|
|
11
15
|
* nothing and a concurrent change refuses the whole write. An identity listed twice gets both
|
|
12
16
|
* lists; one listed with no View is not read.
|
|
13
17
|
*/
|
|
14
|
-
export const
|
|
18
|
+
export const legacyAssignViews = defineAction()('assignViews', { errors: legacyViewAccessErrors }, async ({ error, input, query, mutate }) => {
|
|
15
19
|
const nodeId = (reference) => {
|
|
16
20
|
const invalid = () => error('INVALID_VIEW_ASSIGNMENT_REFERENCE', {});
|
|
17
21
|
try {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { legacyAssignViews } from './assign-views.js';
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated The refusals of `assignViews` (L-SHELL-12). Replaced by the Kernel's refusals of a
|
|
4
|
+
* Mutation on `view_access`. Removal: Shell major (delivery step 5) after 1Pact step 4.
|
|
5
|
+
*/
|
|
6
|
+
export const legacyViewAccessErrors = {
|
|
3
7
|
INVALID_VIEW_ASSIGNMENT_REFERENCE: {
|
|
4
8
|
family: 'VALIDATION_ERROR',
|
|
5
9
|
message: 'Identities and Views must be exact canonical @NodeId paths.',
|
package/dist/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ShellSchema, S, type Shell, type ShellClasses, type ShellSchemaInput, type InvitationSummary, User, Group,
|
|
1
|
+
export { ShellSchema, S, type Shell, type ShellClasses, type ShellSchemaInput, type InvitationSummary, type ProfileName, User, Group, Role, hasRole, profileRoles, atomicRoles, shellRoles, PROFILE_NAMES, view_access, Namespace, alias, viewsNamespace, member_of_group, adminGroup, memberGroup, } from './schema/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
export { ShellSchema, S, User, Group,
|
|
1
|
+
export { ShellSchema, S, User, Group, Role, hasRole, profileRoles, atomicRoles, shellRoles, PROFILE_NAMES, view_access, Namespace, alias, viewsNamespace,
|
|
2
|
+
// L-SHELL-16: the former names of the legacy Edge Class and Core groups.
|
|
3
|
+
member_of_group, adminGroup, memberGroup, } from './schema/index.js';
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
+
import type { ProfileName } from '../../schema/modules/role/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* What Shell asks Admin to send: the account, its email, the profile it was granted, and who asked.
|
|
4
|
+
* `profile` is optional on the wire, so an Admin that ignores it still sends the invitation.
|
|
5
|
+
*/
|
|
1
6
|
export interface InviteRequest {
|
|
2
7
|
readonly requestId: string;
|
|
3
8
|
readonly user: string;
|
|
4
9
|
readonly email: string;
|
|
10
|
+
readonly profile?: ProfileName;
|
|
5
11
|
readonly requestedBy: string;
|
|
6
12
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { legacyRelease } from './release.js';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { requirements, } from '@astrale-os/sdk/domain';
|
|
2
|
+
import { K } from '@astrale-os/sdk/schema';
|
|
3
|
+
import { S } from '../schema/index.js';
|
|
4
|
+
const key = ({ ref }) => `${ref.origin}:${ref.name}`;
|
|
5
|
+
/** The members each legacy binding adds to a target binding, by Role. */
|
|
6
|
+
const members = new Map([
|
|
7
|
+
// The legacy Core groups each become a member of the profile they stood for, so every stored
|
|
8
|
+
// member holds that profile with no data migration (AM3).
|
|
9
|
+
[key(S.core.nodes['workspace.admin']), [S.core.nodes.admin]],
|
|
10
|
+
[key(S.core.nodes['workspace.member']), [S.core.nodes.member]],
|
|
11
|
+
// View only and Applications open only what they are given: Kernel reader, with no profile (AM10).
|
|
12
|
+
[key(K.core.nodes.reader), [S.core.nodes['view-only'], S.core.nodes.applications]],
|
|
13
|
+
// listEntrypoints reads every entrypoint View as Shell.
|
|
14
|
+
[key(K.core.nodes['view.reader']), [requirements.domain]],
|
|
15
|
+
]);
|
|
16
|
+
/**
|
|
17
|
+
* @deprecated The release bindings legacy Core groups and callers need (L-SHELL-7): each legacy
|
|
18
|
+
* group is a member of its profile (AM3); Shell reads installed entrypoints for `listEntrypoints`
|
|
19
|
+
* (row L-SHELL-11), and writes `extends_with` when it acts for the owner of a foreign Group
|
|
20
|
+
* subclass, bounded by its own scope (row L-SHELL-9, AM5). Replaced by the target bindings alone.
|
|
21
|
+
* Removal: Shell major (delivery step 5) after 1Pact step 4.
|
|
22
|
+
*/
|
|
23
|
+
export function legacyRelease(target) {
|
|
24
|
+
return {
|
|
25
|
+
roles: target.roles.map((binding) => {
|
|
26
|
+
const added = members.get(key(binding.role));
|
|
27
|
+
return added === undefined
|
|
28
|
+
? binding
|
|
29
|
+
: { ...binding, members: [...(binding.members ?? []), ...added] };
|
|
30
|
+
}),
|
|
31
|
+
scopes: [{ on: K.classes.extends_with, operations: ['create', 'delete'] }],
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
/** Grant one Role: `extends_with` from the holder to it (R1). Shell owns its Roles' Class. */
|
|
3
|
+
export const grantRole = defineMutation()((domain) => ({
|
|
4
|
+
id: 'shell.role.grant',
|
|
5
|
+
build({ holder, role }, mutation) {
|
|
6
|
+
mutation.createEdge({
|
|
7
|
+
class: domain.dependencies.kernel.classes.extends_with,
|
|
8
|
+
source: { id: holder },
|
|
9
|
+
target: role,
|
|
10
|
+
});
|
|
11
|
+
},
|
|
12
|
+
project: () => ({}),
|
|
13
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { grantRole } from './grant-role.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { setGroupMembership } from './set-group-membership.js';
|
|
1
|
+
export { setGroupMembership, setGroupMemberships, } from './set-group-membership.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { legacyMembershipClass } from './membership-class.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated The legacy `member_of_group` Edge Class a membership write converges (L-SHELL-8).
|
|
3
|
+
* Replaced by `extends_with` alone. Removal: Shell major (delivery step 5) after 1Pact step 4.
|
|
4
|
+
*/
|
|
5
|
+
export function legacyMembershipClass(domain) {
|
|
6
|
+
return domain.classes.member_of_group;
|
|
7
|
+
}
|
|
@@ -1,29 +1,70 @@
|
|
|
1
1
|
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
// Seam L-SHELL-8: the legacy membership Edge a change may converge beside `extends_with`.
|
|
3
|
+
import { legacyMembershipClass } from './legacy/index.js';
|
|
4
|
+
const rejectChange = (failure) => {
|
|
5
|
+
if (failure.outcomeKnown &&
|
|
6
|
+
failure.code !== 'MUTATION_PRECONDITION_FAILED' &&
|
|
7
|
+
failure.code !== 'MUTATION_CONFLICT' &&
|
|
8
|
+
failure.code !== 'MUTATION_POST_STATE_INVALID')
|
|
9
|
+
throw failure;
|
|
10
|
+
return {
|
|
11
|
+
ok: false,
|
|
12
|
+
code: failure.code,
|
|
13
|
+
...(failure.rule !== undefined ? { rule: failure.rule } : {}),
|
|
14
|
+
outcomeKnown: failure.outcomeKnown,
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Create or delete membership Edges of several members of one group in one commit, under the few
|
|
19
|
+
* guards that cover all of them: every change is written, or none.
|
|
20
|
+
*/
|
|
21
|
+
export const setGroupMemberships = defineMutation()((domain) => ({
|
|
22
|
+
id: 'shell.group.memberships.set',
|
|
23
|
+
build(input, mutation) {
|
|
24
|
+
for (const guard of input.guards)
|
|
25
|
+
mutation.expect.query(guard);
|
|
26
|
+
for (const change of input.changes) {
|
|
27
|
+
const endpoints = { source: { id: change.member }, target: { id: input.group } };
|
|
28
|
+
const selected = change.edge === 'authority'
|
|
29
|
+
? domain.dependencies.kernel.classes.extends_with
|
|
30
|
+
: legacyMembershipClass(domain);
|
|
31
|
+
if (change.present)
|
|
32
|
+
mutation.createEdge({ class: selected, ...endpoints });
|
|
33
|
+
else
|
|
34
|
+
mutation.deleteEdge({ class: selected, ...endpoints });
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
project: () => ({ ok: true }),
|
|
38
|
+
reject: (failure) => rejectChange({
|
|
39
|
+
outcomeKnown: failure.outcomeKnown,
|
|
40
|
+
code: failure.code,
|
|
41
|
+
...('rule' in failure && failure.rule !== undefined ? { rule: failure.rule } : {}),
|
|
42
|
+
}),
|
|
43
|
+
}));
|
|
44
|
+
/** Converge the membership Edges of one pair, guarded by what was observed of them. */
|
|
2
45
|
export const setGroupMembership = defineMutation()((domain) => ({
|
|
3
46
|
id: 'shell.group.membership.set',
|
|
4
47
|
build(input, mutation) {
|
|
5
|
-
mutation.expect.query(input.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
];
|
|
12
|
-
for (const edge of changes) {
|
|
13
|
-
if (edge.current === input.present)
|
|
48
|
+
mutation.expect.query(input.endpoints);
|
|
49
|
+
for (const edge of input.edges)
|
|
50
|
+
mutation.expect.query(edge.guard);
|
|
51
|
+
const endpoints = { source: { id: input.member }, target: { id: input.group } };
|
|
52
|
+
for (const edge of input.edges) {
|
|
53
|
+
if (edge.current === edge.present)
|
|
14
54
|
continue;
|
|
15
|
-
|
|
16
|
-
|
|
55
|
+
const selected = edge.edge === 'authority'
|
|
56
|
+
? domain.dependencies.kernel.classes.extends_with
|
|
57
|
+
: legacyMembershipClass(domain);
|
|
58
|
+
if (edge.present)
|
|
59
|
+
mutation.createEdge({ class: selected, ...endpoints });
|
|
17
60
|
else
|
|
18
|
-
mutation.deleteEdge({ class:
|
|
61
|
+
mutation.deleteEdge({ class: selected, ...endpoints });
|
|
19
62
|
}
|
|
20
63
|
},
|
|
21
64
|
project: () => ({ ok: true }),
|
|
22
|
-
reject: (failure) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
return { ok: false, code: failure.code, outcomeKnown: failure.outcomeKnown };
|
|
28
|
-
},
|
|
65
|
+
reject: (failure) => rejectChange({
|
|
66
|
+
outcomeKnown: failure.outcomeKnown,
|
|
67
|
+
code: failure.code,
|
|
68
|
+
...('rule' in failure && failure.rule !== undefined ? { rule: failure.rule } : {}),
|
|
69
|
+
}),
|
|
29
70
|
}));
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
/** Give an account or a group stored before profiles its profile. */
|
|
3
|
+
export const createProfile = defineMutation()((domain) => ({
|
|
4
|
+
id: 'shell.profile.create',
|
|
5
|
+
build(input, mutation) {
|
|
6
|
+
if (input.kind === 'User') {
|
|
7
|
+
const profile = mutation.createNode({
|
|
8
|
+
as: 'profile',
|
|
9
|
+
class: domain.classes.UserProfile,
|
|
10
|
+
props: input.values,
|
|
11
|
+
});
|
|
12
|
+
mutation.createEdge({
|
|
13
|
+
class: domain.classes.user_profile,
|
|
14
|
+
source: { id: input.owner },
|
|
15
|
+
target: profile,
|
|
16
|
+
});
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
const profile = mutation.createNode({
|
|
20
|
+
as: 'profile',
|
|
21
|
+
class: domain.classes.GroupProfile,
|
|
22
|
+
props: input.values,
|
|
23
|
+
});
|
|
24
|
+
mutation.createEdge({
|
|
25
|
+
class: domain.classes.group_profile,
|
|
26
|
+
source: { id: input.owner },
|
|
27
|
+
target: profile,
|
|
28
|
+
});
|
|
29
|
+
},
|
|
30
|
+
project: () => ({ ok: true }),
|
|
31
|
+
reject: (failure) => {
|
|
32
|
+
// Another write gave it its profile meanwhile, or another profile holds the email.
|
|
33
|
+
if (failure.outcomeKnown)
|
|
34
|
+
return { ok: false, refusal: failure.code };
|
|
35
|
+
throw failure;
|
|
36
|
+
},
|
|
37
|
+
}));
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
/** Delete one account or group, and every membership into it, in one write. */
|
|
3
|
+
export const deleteIdentity = defineMutation()((domain) => ({
|
|
4
|
+
id: 'shell.identity.delete',
|
|
5
|
+
build({ kind, node, members, profile }, mutation) {
|
|
6
|
+
for (const { source, target } of members) {
|
|
7
|
+
mutation.deleteEdge({
|
|
8
|
+
class: domain.dependencies.kernel.classes.extends_with,
|
|
9
|
+
source: { id: source },
|
|
10
|
+
target: { id: target },
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
mutation.deleteNode({ node: { id: node }, class: domain.classes[kind] });
|
|
14
|
+
if (profile !== undefined) {
|
|
15
|
+
mutation.deleteNode({
|
|
16
|
+
node: { id: profile },
|
|
17
|
+
class: kind === 'User' ? domain.classes.UserProfile : domain.classes.GroupProfile,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
project: () => ({ ok: true }),
|
|
22
|
+
reject: (failure) => {
|
|
23
|
+
// A member joined, or the Node changed, since it was read.
|
|
24
|
+
if (failure.outcomeKnown)
|
|
25
|
+
return { ok: false, refusal: failure.code };
|
|
26
|
+
throw failure;
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { PROFILE_PROPERTIES, createAccount, newProfileValues, profileValues, updateAccount, } from './write-account.js';
|
|
2
|
+
export { GROUP_PROFILE_PROPERTIES, createGroup, groupProfileValues, updateGroup, } from './write-group.js';
|
|
3
|
+
export { deleteIdentity } from './delete-identity.js';
|
|
4
|
+
export { createProfile } from './create-profile.js';
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
/** What an account shares on its profile: the rest stays private on the account. */
|
|
3
|
+
export const PROFILE_PROPERTIES = ['name', 'givenName', 'familyName', 'email'];
|
|
4
|
+
/**
|
|
5
|
+
* The values of a new profile: its name is the account's name, else "given family", else the
|
|
6
|
+
* email; undefined for an account that has none of them (it gets its profile once it has one).
|
|
7
|
+
*/
|
|
8
|
+
export function newProfileValues(values) {
|
|
9
|
+
const shared = profileValues(values);
|
|
10
|
+
const full = [values.givenName, values.familyName].filter(Boolean).join(' ');
|
|
11
|
+
const name = values.name ?? (full === '' ? undefined : full) ?? values.email;
|
|
12
|
+
return name === undefined ? undefined : { ...shared, name: name.slice(0, 100) };
|
|
13
|
+
}
|
|
14
|
+
/** A profile keeps an email of 100 characters at most; a longer one stays on the account alone. */
|
|
15
|
+
export const PROFILE_EMAIL_MAX = 100;
|
|
16
|
+
/** The profile values among account values. */
|
|
17
|
+
export function profileValues(values) {
|
|
18
|
+
return Object.fromEntries(PROFILE_PROPERTIES.flatMap((key) => {
|
|
19
|
+
const value = values[key];
|
|
20
|
+
if (value === undefined)
|
|
21
|
+
return [];
|
|
22
|
+
if (key === 'email' && value.length > PROFILE_EMAIL_MAX)
|
|
23
|
+
return [];
|
|
24
|
+
return [[key, value]];
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
const refuse = (failure) => {
|
|
28
|
+
if (failure.outcomeKnown && failure.code === 'MUTATION_POST_STATE_INVALID') {
|
|
29
|
+
if (failure.rule === 'duplicate-key')
|
|
30
|
+
return { ok: false, refusal: 'DUPLICATE_KEY' };
|
|
31
|
+
}
|
|
32
|
+
if (failure.outcomeKnown && failure.code === 'MUTATION_PRECONDITION_FAILED') {
|
|
33
|
+
return { ok: false, refusal: 'CHANGED' };
|
|
34
|
+
}
|
|
35
|
+
throw failure;
|
|
36
|
+
};
|
|
37
|
+
/** Create one account, optionally granting it Roles in the same write. */
|
|
38
|
+
export const createAccount = defineMutation()((domain) => ({
|
|
39
|
+
id: 'shell.account.create',
|
|
40
|
+
build({ values }, mutation) {
|
|
41
|
+
const account = mutation.createNode({
|
|
42
|
+
as: 'account',
|
|
43
|
+
class: domain.classes.User,
|
|
44
|
+
props: values,
|
|
45
|
+
});
|
|
46
|
+
const shared = newProfileValues(values);
|
|
47
|
+
if (shared === undefined)
|
|
48
|
+
return;
|
|
49
|
+
const profile = mutation.createNode({
|
|
50
|
+
as: 'profile',
|
|
51
|
+
class: domain.classes.UserProfile,
|
|
52
|
+
props: shared,
|
|
53
|
+
});
|
|
54
|
+
mutation.createEdge({ class: domain.classes.user_profile, source: account, target: profile });
|
|
55
|
+
},
|
|
56
|
+
project: (result) => {
|
|
57
|
+
const user = result.createdNodes['account'];
|
|
58
|
+
if (user === undefined)
|
|
59
|
+
throw new TypeError('The Kernel created no account.');
|
|
60
|
+
return { ok: true, user };
|
|
61
|
+
},
|
|
62
|
+
reject: refuse,
|
|
63
|
+
}));
|
|
64
|
+
/** Set and erase Properties of one account, on the values it was decided on. */
|
|
65
|
+
export const updateAccount = defineMutation()((domain) => ({
|
|
66
|
+
id: 'shell.account.update',
|
|
67
|
+
build({ user, set, unset, expected, profile }, mutation) {
|
|
68
|
+
if (expected !== undefined) {
|
|
69
|
+
const absent = Object.keys(expected).filter((key) => expected[key] === undefined);
|
|
70
|
+
const equals = Object.fromEntries(Object.entries(expected).filter(([, value]) => value !== undefined));
|
|
71
|
+
mutation.expect.node({
|
|
72
|
+
node: { id: user },
|
|
73
|
+
class: domain.classes.User,
|
|
74
|
+
props: { equals, ...(absent.length === 0 ? {} : { absent }) },
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
mutation.updateNode({
|
|
78
|
+
node: { id: user },
|
|
79
|
+
class: domain.classes.User,
|
|
80
|
+
props: { set, ...(unset === undefined || unset.length === 0 ? {} : { unset }) },
|
|
81
|
+
});
|
|
82
|
+
if (profile === undefined)
|
|
83
|
+
return;
|
|
84
|
+
if ('create' in profile) {
|
|
85
|
+
const created = mutation.createNode({
|
|
86
|
+
as: 'profile',
|
|
87
|
+
class: domain.classes.UserProfile,
|
|
88
|
+
props: profile.create,
|
|
89
|
+
});
|
|
90
|
+
mutation.createEdge({
|
|
91
|
+
class: domain.classes.user_profile,
|
|
92
|
+
source: { id: user },
|
|
93
|
+
target: created,
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const shared = profileValues(set);
|
|
98
|
+
const erased = (unset ?? []).filter((key) => PROFILE_PROPERTIES.includes(key));
|
|
99
|
+
if (Object.keys(shared).length === 0 && erased.length === 0)
|
|
100
|
+
return;
|
|
101
|
+
mutation.updateNode({
|
|
102
|
+
node: { id: profile.id },
|
|
103
|
+
class: domain.classes.UserProfile,
|
|
104
|
+
props: { set: shared, ...(erased.length === 0 ? {} : { unset: erased }) },
|
|
105
|
+
});
|
|
106
|
+
},
|
|
107
|
+
project: () => ({ ok: true }),
|
|
108
|
+
reject: refuse,
|
|
109
|
+
}));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
/** What a group shares on its profile: the rest stays private on the group. */
|
|
3
|
+
export const GROUP_PROFILE_PROPERTIES = ['name', 'description'];
|
|
4
|
+
/** The profile values among group values. */
|
|
5
|
+
export function groupProfileValues(values) {
|
|
6
|
+
return Object.fromEntries(GROUP_PROFILE_PROPERTIES.flatMap((key) => values[key] === undefined ? [] : [[key, values[key]]]));
|
|
7
|
+
}
|
|
8
|
+
const refuse = (failure) => {
|
|
9
|
+
if (failure.outcomeKnown &&
|
|
10
|
+
failure.code === 'MUTATION_POST_STATE_INVALID' &&
|
|
11
|
+
failure.rule === 'duplicate-key') {
|
|
12
|
+
return { ok: false, refusal: 'DUPLICATE_KEY' };
|
|
13
|
+
}
|
|
14
|
+
throw failure;
|
|
15
|
+
};
|
|
16
|
+
/** Create one group. */
|
|
17
|
+
export const createGroup = defineMutation()((domain) => ({
|
|
18
|
+
id: 'shell.group.create',
|
|
19
|
+
build({ values }, mutation) {
|
|
20
|
+
const group = mutation.createNode({ as: 'group', class: domain.classes.Group, props: values });
|
|
21
|
+
const profile = mutation.createNode({
|
|
22
|
+
as: 'profile',
|
|
23
|
+
class: domain.classes.GroupProfile,
|
|
24
|
+
props: groupProfileValues(values),
|
|
25
|
+
});
|
|
26
|
+
mutation.createEdge({ class: domain.classes.group_profile, source: group, target: profile });
|
|
27
|
+
},
|
|
28
|
+
project: (result) => {
|
|
29
|
+
const group = result.createdNodes['group'];
|
|
30
|
+
if (group === undefined)
|
|
31
|
+
throw new TypeError('The Kernel created no group.');
|
|
32
|
+
return { ok: true, group };
|
|
33
|
+
},
|
|
34
|
+
reject: refuse,
|
|
35
|
+
}));
|
|
36
|
+
/** Set and erase Properties of one group. */
|
|
37
|
+
export const updateGroup = defineMutation()((domain) => ({
|
|
38
|
+
id: 'shell.group.update',
|
|
39
|
+
build({ group, set, unset, profile, }, mutation) {
|
|
40
|
+
mutation.updateNode({
|
|
41
|
+
node: { id: group },
|
|
42
|
+
class: domain.classes.Group,
|
|
43
|
+
props: { set, ...(unset === undefined || unset.length === 0 ? {} : { unset }) },
|
|
44
|
+
});
|
|
45
|
+
if (profile === undefined)
|
|
46
|
+
return;
|
|
47
|
+
if ('create' in profile) {
|
|
48
|
+
const created = mutation.createNode({
|
|
49
|
+
as: 'profile',
|
|
50
|
+
class: domain.classes.GroupProfile,
|
|
51
|
+
props: profile.create,
|
|
52
|
+
});
|
|
53
|
+
mutation.createEdge({
|
|
54
|
+
class: domain.classes.group_profile,
|
|
55
|
+
source: { id: group },
|
|
56
|
+
target: created,
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const shared = groupProfileValues(set);
|
|
61
|
+
const erased = (unset ?? []).filter((key) => GROUP_PROFILE_PROPERTIES.includes(key));
|
|
62
|
+
if (Object.keys(shared).length === 0 && erased.length === 0)
|
|
63
|
+
return;
|
|
64
|
+
mutation.updateNode({
|
|
65
|
+
node: { id: profile.id },
|
|
66
|
+
class: domain.classes.GroupProfile,
|
|
67
|
+
props: { set: shared, ...(erased.length === 0 ? {} : { unset: erased }) },
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
project: () => ({ ok: true }),
|
|
71
|
+
reject: refuse,
|
|
72
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { bindAccount, createInvitation, updateInvitation, } from './write-invitation.js';
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
+
/**
|
|
3
|
+
* Record a pending invitation of one account, kept by one durable run, and cancel in the same
|
|
4
|
+
* commit the pending invitations it replaces: an account has at most one.
|
|
5
|
+
*/
|
|
6
|
+
export const createInvitation = defineMutation()((domain) => ({
|
|
7
|
+
id: 'shell.invitation.create',
|
|
8
|
+
build(input, mutation) {
|
|
9
|
+
for (const previous of input.replaces ?? []) {
|
|
10
|
+
mutation.expect.node({
|
|
11
|
+
node: { id: previous },
|
|
12
|
+
class: domain.classes.Invitation,
|
|
13
|
+
props: { equals: { status: 'pending' } },
|
|
14
|
+
});
|
|
15
|
+
mutation.updateNode({
|
|
16
|
+
node: { id: previous },
|
|
17
|
+
class: domain.classes.Invitation,
|
|
18
|
+
props: { set: { status: 'cancelled' } },
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
const invitation = mutation.createNode({
|
|
22
|
+
as: 'invitation',
|
|
23
|
+
class: domain.classes.Invitation,
|
|
24
|
+
props: {
|
|
25
|
+
status: 'pending',
|
|
26
|
+
expiresAt: input.expiresAt,
|
|
27
|
+
execution: input.execution,
|
|
28
|
+
round: 0,
|
|
29
|
+
email: input.email,
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
mutation.createEdge({
|
|
33
|
+
class: domain.classes.invitation_user,
|
|
34
|
+
source: invitation,
|
|
35
|
+
target: { id: input.user },
|
|
36
|
+
});
|
|
37
|
+
},
|
|
38
|
+
project: (result) => {
|
|
39
|
+
const invitation = result.createdNodes['invitation'];
|
|
40
|
+
if (invitation === undefined)
|
|
41
|
+
throw new TypeError('The Kernel created no invitation.');
|
|
42
|
+
return { invitation };
|
|
43
|
+
},
|
|
44
|
+
}));
|
|
45
|
+
/** Change an invitation's status, or its round and expiry, while it is still pending. */
|
|
46
|
+
export const updateInvitation = defineMutation()((domain) => ({
|
|
47
|
+
id: 'shell.invitation.update',
|
|
48
|
+
build(input, mutation) {
|
|
49
|
+
mutation.expect.node({
|
|
50
|
+
node: { id: input.invitation },
|
|
51
|
+
class: domain.classes.Invitation,
|
|
52
|
+
props: { equals: { status: 'pending' } },
|
|
53
|
+
});
|
|
54
|
+
mutation.updateNode({
|
|
55
|
+
node: { id: input.invitation },
|
|
56
|
+
class: domain.classes.Invitation,
|
|
57
|
+
props: {
|
|
58
|
+
set: {
|
|
59
|
+
...(input.status === undefined ? {} : { status: input.status }),
|
|
60
|
+
...(input.round === undefined ? {} : { round: input.round }),
|
|
61
|
+
...(input.expiresAt === undefined ? {} : { expiresAt: input.expiresAt }),
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
},
|
|
66
|
+
project: () => ({ ok: true }),
|
|
67
|
+
}));
|
|
68
|
+
/** Bind an account to the sign-in that accepted its invitation (U8). */
|
|
69
|
+
export const bindAccount = defineMutation()((domain) => ({
|
|
70
|
+
id: 'shell.account.bind',
|
|
71
|
+
build(input, mutation) {
|
|
72
|
+
mutation.updateNode({
|
|
73
|
+
node: { id: input.user },
|
|
74
|
+
class: domain.classes.User,
|
|
75
|
+
props: { set: { iss: input.iss, sub: input.sub } },
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
project: () => ({ ok: true }),
|
|
79
|
+
}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { legacyRecordUserProfile } from './record-user-profile.js';
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { defineMutation } from '@astrale-os/sdk/mutation';
|
|
2
|
-
/**
|
|
3
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Set the email and display name an account recorded about itself (L-SHELL-5). Replaced
|
|
4
|
+
* by `User.updateProfile`. Removal: Shell major (delivery step 5) after 1Pact step 4.
|
|
5
|
+
*/
|
|
6
|
+
export const legacyRecordUserProfile = defineMutation()((domain) => ({
|
|
4
7
|
id: 'shell.user.profile.record',
|
|
5
8
|
build({ user, set }, mutation) {
|
|
6
9
|
const props = {
|