@astrale-domains/shell 0.1.0-beta.8 → 0.1.1

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.
Files changed (244) hide show
  1. package/README.md +264 -64
  2. package/dist/domain.d.ts +225 -0
  3. package/dist/domain.js +96 -0
  4. package/dist/functions/application/index.js +1 -0
  5. package/dist/functions/application/list-entrypoints.js +6 -0
  6. package/dist/functions/group/assign-member-to-group.js +4 -0
  7. package/dist/functions/group/change-group-membership.js +34 -0
  8. package/dist/functions/group/group-membership-errors.js +23 -0
  9. package/dist/functions/group/index.js +2 -0
  10. package/dist/functions/group/unassign-member-from-group.js +4 -0
  11. package/dist/functions/namespace/index.js +3 -0
  12. package/dist/functions/namespace/link.js +30 -0
  13. package/dist/functions/namespace/namespace-errors.js +28 -0
  14. package/dist/functions/namespace/namespace-name.js +13 -0
  15. package/dist/functions/namespace/rename.js +31 -0
  16. package/dist/functions/namespace/unlink.js +21 -0
  17. package/dist/functions/user/index.js +2 -0
  18. package/dist/functions/user/invite-user.js +39 -0
  19. package/dist/functions/user/record-profile.js +18 -0
  20. package/dist/functions/view-access/assign-views.js +86 -0
  21. package/dist/functions/view-access/index.js +1 -0
  22. package/dist/functions/view-access/view-access-errors.js +28 -0
  23. package/dist/index.d.ts +1 -3
  24. package/dist/index.js +1 -3
  25. package/dist/integrations/index.d.ts +1 -0
  26. package/dist/integrations/index.js +1 -0
  27. package/dist/integrations/integrations.d.ts +9 -0
  28. package/dist/integrations/integrations.js +2 -0
  29. package/dist/integrations/user-invitation/index.d.ts +4 -0
  30. package/dist/integrations/user-invitation/index.js +3 -0
  31. package/dist/integrations/user-invitation/invitation-request-failure.d.ts +5 -0
  32. package/dist/integrations/user-invitation/invitation-request-failure.js +9 -0
  33. package/dist/integrations/user-invitation/invite-user-request.d.ts +6 -0
  34. package/dist/integrations/user-invitation/invite-user-request.js +1 -0
  35. package/dist/integrations/user-invitation/request-user-invitation.d.ts +8 -0
  36. package/dist/integrations/user-invitation/request-user-invitation.js +9 -0
  37. package/dist/mutations/group/index.js +1 -1
  38. package/dist/mutations/group/set-group-membership.js +29 -0
  39. package/dist/mutations/namespace/alias-write.js +22 -0
  40. package/dist/mutations/namespace/index.js +3 -0
  41. package/dist/mutations/namespace/link-alias.js +15 -0
  42. package/dist/mutations/namespace/rename-alias.js +13 -0
  43. package/dist/mutations/namespace/unlink-alias.js +13 -0
  44. package/dist/mutations/user/index.js +1 -1
  45. package/dist/mutations/user/record-user-profile.js +13 -0
  46. package/dist/mutations/view-access/index.js +1 -0
  47. package/dist/mutations/view-access/set-view-access.js +29 -0
  48. package/dist/providers/admin-enrollment/create-admin-enrollment-provider.js +78 -0
  49. package/dist/providers/admin-enrollment/decode-admin-invitation-response.js +20 -0
  50. package/dist/providers/admin-enrollment/index.js +1 -0
  51. package/dist/providers/admin-enrollment/read-enrollment-response.js +34 -0
  52. package/dist/queries/application/index.js +1 -0
  53. package/dist/queries/application/read-installed-entrypoints.js +28 -0
  54. package/dist/queries/group/index.js +2 -0
  55. package/dist/queries/group/read-group-membership-endpoints.js +18 -0
  56. package/dist/queries/group/read-group-membership.js +35 -0
  57. package/dist/queries/namespace/index.js +2 -0
  58. package/dist/queries/namespace/read-designated-node.js +12 -0
  59. package/dist/queries/namespace/read-view-aliases.js +46 -0
  60. package/dist/queries/user/index.js +1 -5
  61. package/dist/queries/user/read-user-profile.js +9 -0
  62. package/dist/queries/view-access/index.js +1 -0
  63. package/dist/queries/view-access/read-view-access.js +35 -0
  64. package/dist/runtime.d.ts +2175 -3
  65. package/dist/runtime.js +24 -14
  66. package/dist/schema/index.d.ts +7 -6
  67. package/dist/schema/index.js +6 -6
  68. package/dist/schema/modules/application/functions/index.d.ts +1 -0
  69. package/dist/schema/modules/application/functions/index.js +1 -0
  70. package/dist/schema/modules/application/functions/list-entrypoints.d.ts +15 -0
  71. package/dist/schema/modules/application/functions/list-entrypoints.js +16 -0
  72. package/dist/schema/modules/application/index.d.ts +2 -0
  73. package/dist/schema/modules/application/index.js +2 -0
  74. package/dist/schema/modules/application/types/entrypoint-entry.d.ts +8 -0
  75. package/dist/schema/modules/application/types/entrypoint-entry.js +7 -0
  76. package/dist/schema/modules/application/types/index.d.ts +1 -0
  77. package/dist/schema/modules/application/types/index.js +1 -0
  78. package/dist/schema/modules/group/classes/group.d.ts +24 -0
  79. package/dist/schema/modules/group/classes/group.js +11 -0
  80. package/dist/schema/modules/group/classes/index.d.ts +2 -0
  81. package/dist/schema/modules/group/classes/index.js +2 -0
  82. package/dist/schema/modules/group/classes/member-of-group.d.ts +30 -0
  83. package/dist/schema/modules/group/classes/member-of-group.js +12 -0
  84. package/dist/schema/modules/group/core/administrators-group.d.ts +1 -0
  85. package/dist/schema/modules/group/core/administrators-group.js +6 -0
  86. package/dist/schema/modules/group/core/applications-group.d.ts +1 -0
  87. package/dist/schema/modules/group/core/applications-group.js +6 -0
  88. package/dist/schema/modules/group/core/index.d.ts +3 -0
  89. package/dist/schema/modules/group/core/index.js +3 -0
  90. package/dist/schema/modules/group/core/members-group.d.ts +1 -0
  91. package/dist/schema/modules/group/core/members-group.js +6 -0
  92. package/dist/schema/modules/group/functions/assign-member-to-group.js +11 -0
  93. package/dist/schema/modules/group/functions/index.js +2 -0
  94. package/dist/schema/modules/group/functions/unassign-member-from-group.js +11 -0
  95. package/dist/schema/modules/group/index.d.ts +3 -0
  96. package/dist/schema/modules/group/index.js +3 -0
  97. package/dist/schema/modules/group/policies/belongs-to-group.d.ts +1 -0
  98. package/dist/schema/modules/group/policies/belongs-to-group.js +5 -0
  99. package/dist/schema/modules/group/policies/index.d.ts +1 -0
  100. package/dist/schema/modules/group/policies/index.js +1 -0
  101. package/dist/schema/modules/group/types/group-membership-input.js +8 -0
  102. package/dist/schema/modules/group/types/index.js +1 -0
  103. package/dist/schema/modules/namespace/classes/alias.d.ts +31 -0
  104. package/dist/schema/modules/namespace/classes/alias.js +13 -0
  105. package/dist/schema/modules/namespace/classes/index.d.ts +2 -0
  106. package/dist/schema/modules/namespace/classes/index.js +2 -0
  107. package/dist/schema/modules/namespace/classes/namespace.d.ts +31 -0
  108. package/dist/schema/modules/namespace/classes/namespace.js +10 -0
  109. package/dist/schema/modules/namespace/core/index.d.ts +1 -0
  110. package/dist/schema/modules/namespace/core/index.js +1 -0
  111. package/dist/schema/modules/namespace/core/views-namespace.d.ts +2 -0
  112. package/dist/schema/modules/namespace/core/views-namespace.js +7 -0
  113. package/dist/schema/modules/namespace/functions/index.js +3 -0
  114. package/dist/schema/modules/namespace/functions/link.js +11 -0
  115. package/dist/schema/modules/namespace/functions/rename.js +11 -0
  116. package/dist/schema/modules/namespace/functions/unlink.js +11 -0
  117. package/dist/schema/modules/namespace/index.d.ts +2 -0
  118. package/dist/schema/modules/namespace/index.js +2 -0
  119. package/dist/schema/modules/namespace/types/index.js +1 -0
  120. package/dist/schema/modules/namespace/types/namespace-name.js +7 -0
  121. package/dist/schema/modules/user/classes/index.d.ts +1 -0
  122. package/dist/schema/modules/user/classes/index.js +1 -0
  123. package/dist/schema/modules/user/classes/user.d.ts +34 -0
  124. package/dist/schema/modules/user/classes/user.js +21 -0
  125. package/dist/schema/modules/user/functions/index.js +2 -0
  126. package/dist/schema/modules/user/functions/invite-user.js +12 -0
  127. package/dist/schema/modules/user/functions/record-profile.js +14 -0
  128. package/dist/schema/modules/user/index.d.ts +2 -0
  129. package/dist/schema/modules/user/index.js +2 -0
  130. package/dist/schema/modules/user/types/index.d.ts +2 -0
  131. package/dist/schema/modules/user/types/index.js +2 -0
  132. package/dist/schema/modules/user/types/invitation-summary.d.ts +16 -0
  133. package/dist/schema/modules/user/types/invitation-summary.js +15 -0
  134. package/dist/schema/modules/user/types/user-profile.d.ts +7 -0
  135. package/dist/schema/modules/user/types/user-profile.js +7 -0
  136. package/dist/schema/modules/view-access/classes/index.d.ts +1 -0
  137. package/dist/schema/modules/view-access/classes/index.js +1 -0
  138. package/dist/schema/modules/view-access/classes/view-access.d.ts +32 -0
  139. package/dist/schema/modules/view-access/classes/view-access.js +18 -0
  140. package/dist/schema/modules/view-access/core/index.d.ts +1 -0
  141. package/dist/schema/modules/view-access/core/index.js +1 -0
  142. package/dist/schema/modules/view-access/core/view-only-group.d.ts +5 -0
  143. package/dist/schema/modules/view-access/core/view-only-group.js +10 -0
  144. package/dist/schema/modules/view-access/functions/assign-views.d.ts +16 -0
  145. package/dist/schema/modules/view-access/functions/assign-views.js +17 -0
  146. package/dist/schema/modules/view-access/functions/index.d.ts +1 -0
  147. package/dist/schema/modules/view-access/functions/index.js +1 -0
  148. package/dist/schema/modules/view-access/index.d.ts +3 -0
  149. package/dist/schema/modules/view-access/index.js +3 -0
  150. package/dist/schema/modules/view-access/types/index.js +1 -0
  151. package/dist/schema/modules/view-access/types/view-assignment.js +16 -0
  152. package/dist/schema/policies/administers-shell-class.js +11 -0
  153. package/dist/schema/policies/index.js +4 -0
  154. package/dist/schema/policies/is-self.js +5 -0
  155. package/dist/schema/policies/owns-class.js +7 -0
  156. package/dist/schema/policies/uses-function.js +5 -0
  157. package/dist/schema/schema.d.ts +833 -0
  158. package/dist/schema/schema.js +35 -0
  159. package/dist/schema/views/application-view.js +4 -0
  160. package/dist/schema/views/index.js +1 -0
  161. package/dist/utils/canonical-node-path/index.js +1 -0
  162. package/dist/utils/canonical-node-path/parse-canonical-node-path.js +8 -0
  163. package/package.json +50 -10
  164. package/dist/actions/index.js +0 -1
  165. package/dist/actions/user/index.js +0 -1
  166. package/dist/actions/user/resolve-home.js +0 -19
  167. package/dist/application.d.ts +0 -5
  168. package/dist/application.js +0 -29
  169. package/dist/mutations/group/membership.js +0 -21
  170. package/dist/mutations/space/access.js +0 -25
  171. package/dist/mutations/space/default.js +0 -25
  172. package/dist/mutations/space/index.js +0 -2
  173. package/dist/mutations/user/repair.js +0 -85
  174. package/dist/queries/space/access.js +0 -14
  175. package/dist/queries/space/admin.js +0 -27
  176. package/dist/queries/space/index.js +0 -3
  177. package/dist/queries/space/member.js +0 -24
  178. package/dist/queries/user/groups.js +0 -24
  179. package/dist/queries/user/home.js +0 -28
  180. package/dist/queries/user/owned-spaces.js +0 -24
  181. package/dist/queries/user/profile.js +0 -17
  182. package/dist/queries/user/setup.js +0 -18
  183. package/dist/schema/domain/index.d.ts +0 -26911
  184. package/dist/schema/domain/index.js +0 -40
  185. package/dist/schema/group/class.d.ts +0 -3288
  186. package/dist/schema/group/class.js +0 -7
  187. package/dist/schema/group/core.d.ts +0 -14
  188. package/dist/schema/group/core.js +0 -14
  189. package/dist/schema/group/index.d.ts +0 -6
  190. package/dist/schema/group/index.js +0 -6
  191. package/dist/schema/group/methods.d.ts +0 -2059
  192. package/dist/schema/group/methods.js +0 -21
  193. package/dist/schema/group/policies.d.ts +0 -1
  194. package/dist/schema/group/policies.js +0 -6
  195. package/dist/schema/group/relationships.d.ts +0 -4313
  196. package/dist/schema/group/relationships.js +0 -8
  197. package/dist/schema/group/view.d.ts +0 -3291
  198. package/dist/schema/group/view.js +0 -6
  199. package/dist/schema/home/index.d.ts +0 -1
  200. package/dist/schema/home/index.js +0 -1
  201. package/dist/schema/home/view.d.ts +0 -3
  202. package/dist/schema/home/view.js +0 -4
  203. package/dist/schema/setup/functions.d.ts +0 -47
  204. package/dist/schema/setup/functions.js +0 -27
  205. package/dist/schema/setup/index.d.ts +0 -1
  206. package/dist/schema/setup/index.js +0 -1
  207. package/dist/schema/space/class.d.ts +0 -2313
  208. package/dist/schema/space/class.js +0 -11
  209. package/dist/schema/space/core.d.ts +0 -22520
  210. package/dist/schema/space/core.js +0 -15
  211. package/dist/schema/space/index.d.ts +0 -6
  212. package/dist/schema/space/index.js +0 -6
  213. package/dist/schema/space/methods.d.ts +0 -2089
  214. package/dist/schema/space/methods.js +0 -30
  215. package/dist/schema/space/policies.d.ts +0 -4
  216. package/dist/schema/space/policies.js +0 -21
  217. package/dist/schema/space/relationships.d.ts +0 -23213
  218. package/dist/schema/space/relationships.js +0 -24
  219. package/dist/schema/space/view.d.ts +0 -2316
  220. package/dist/schema/space/view.js +0 -6
  221. package/dist/schema/user/class.d.ts +0 -1015
  222. package/dist/schema/user/class.js +0 -11
  223. package/dist/schema/user/index.d.ts +0 -3
  224. package/dist/schema/user/index.js +0 -3
  225. package/dist/schema/user/methods.d.ts +0 -14
  226. package/dist/schema/user/methods.js +0 -11
  227. package/dist/schema/user/view.d.ts +0 -1017
  228. package/dist/schema/user/view.js +0 -6
  229. package/dist/workflows/group/assign.js +0 -3
  230. package/dist/workflows/group/change.js +0 -31
  231. package/dist/workflows/group/index.js +0 -3
  232. package/dist/workflows/group/unassign.js +0 -3
  233. package/dist/workflows/index.js +0 -3
  234. package/dist/workflows/setup/admin.js +0 -3
  235. package/dist/workflows/setup/index.js +0 -5
  236. package/dist/workflows/setup/member.js +0 -3
  237. package/dist/workflows/setup/plan.js +0 -88
  238. package/dist/workflows/setup/provision.js +0 -57
  239. package/dist/workflows/setup/run.js +0 -74
  240. package/dist/workflows/space/access.js +0 -41
  241. package/dist/workflows/space/add.js +0 -3
  242. package/dist/workflows/space/default.js +0 -37
  243. package/dist/workflows/space/index.js +0 -4
  244. package/dist/workflows/space/remove.js +0 -3
@@ -1,6 +0,0 @@
1
- import { view } from '@astrale-os/sdk/schema';
2
- import { User } from './class.js';
3
- export const userView = view({
4
- description: 'Shell User profile and relationships.',
5
- target: User,
6
- });
@@ -1,3 +0,0 @@
1
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
2
- import { changeMembership } from './change.js';
3
- export const assignGroupUserWorkflow = defineWorkflow()('Group.assignUser', (context) => changeMembership(context, true));
@@ -1,31 +0,0 @@
1
- import { InvocationError } from '@astrale-os/sdk/execution';
2
- import { changeGroupMembership } from '#mutations/group';
3
- import { observeUserGroups } from '#queries/user';
4
- export async function changeMembership(context, present) {
5
- const observed = await context.step.run('observe-membership', () => context.query(observeUserGroups(context.domain), context.input.user));
6
- const wasPresent = includes(observed.groups, context.self);
7
- if (wasPresent === present)
8
- return Object.freeze({});
9
- const result = await context.step.run('change-membership', () => context.mutate(changeGroupMembership(context.domain), {
10
- user: context.input.user,
11
- group: context.self,
12
- present,
13
- guard: observed.guard,
14
- }));
15
- if (result.ok)
16
- return Object.freeze({});
17
- if (result.outcomeKnown)
18
- return membershipConflict(result.code);
19
- const recovered = await context.step.run('recover-membership', () => context.query(observeUserGroups(context.domain), context.input.user));
20
- if (includes(recovered.groups, context.self) === present)
21
- return Object.freeze({});
22
- throw new InvocationError('BACKEND_UNAVAILABLE', 'Group membership outcome remains unknown after exact observation.', { reason: { code: result.code, details: {} } });
23
- }
24
- function includes(groups, group) {
25
- return groups.some(({ id }) => id === group);
26
- }
27
- function membershipConflict(code) {
28
- throw new InvocationError('CONFLICT', 'Group membership conflicted with concurrent graph state.', {
29
- reason: { code, details: {} },
30
- });
31
- }
@@ -1,3 +0,0 @@
1
- export { assignGroupUserWorkflow } from './assign.js';
2
- export { changeMembership } from './change.js';
3
- export { unassignGroupUserWorkflow } from './unassign.js';
@@ -1,3 +0,0 @@
1
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
2
- import { changeMembership } from './change.js';
3
- export const unassignGroupUserWorkflow = defineWorkflow()('Group.unassignUser', (context) => changeMembership(context, false));
@@ -1,3 +0,0 @@
1
- export * from '#workflows/group';
2
- export * from '#workflows/setup';
3
- export * from '#workflows/space';
@@ -1,3 +0,0 @@
1
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
2
- import { runSetup } from './run.js';
3
- export const setupAdminWorkflow = defineWorkflow()('setupAdmin', (context) => runSetup(context, 'admin'));
@@ -1,5 +0,0 @@
1
- export { setupAdminWorkflow } from './admin.js';
2
- export { setupMemberWorkflow } from './member.js';
3
- export { planUserSetup } from './plan.js';
4
- export { provisioningRequest, provisioningResult } from './provision.js';
5
- export { runSetup } from './run.js';
@@ -1,3 +0,0 @@
1
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
2
- import { runSetup } from './run.js';
3
- export const setupMemberWorkflow = defineWorkflow()('setupMember', (context) => runSetup(context, 'member'));
@@ -1,88 +0,0 @@
1
- export function planUserSetup(domain, input, role, observation) {
2
- const profile = observation.profile;
3
- if (profile.class !== domain.classes.User.key) {
4
- return conflict('IDENTITY_CLASS_CONFLICT', 'The asserted identity already belongs to a non-Shell User Class.');
5
- }
6
- const identityIssuer = profile.props[domain.classes.User.properties.iss.key];
7
- const identitySubject = profile.props[domain.classes.User.properties.sub.key];
8
- if (identityIssuer !== input.issuer || identitySubject !== input.subject) {
9
- return conflict('IDENTITY_FACT_CONFLICT', 'The resolved Shell User does not retain the asserted issuer and subject.');
10
- }
11
- if (observation.home.spaces.length > 1) {
12
- return conflict('MULTIPLE_DEFAULT_SPACES', 'The Shell User has more than one default personal Space.');
13
- }
14
- const currentHome = observation.home.spaces[0];
15
- if (currentHome !== undefined && currentHome.class !== domain.classes.Space.key) {
16
- return conflict('DEFAULT_SPACE_CLASS_CONFLICT', 'The Shell User default target is not a Shell Space.');
17
- }
18
- const candidates = currentHome === undefined
19
- ? observation.ownedSpaces.spaces.filter((space) => space.class === domain.classes.Space.key &&
20
- space.props[domain.classes.Space.properties.name.key] === input.personalSpaceName)
21
- : [];
22
- if (candidates.length > 1) {
23
- return conflict('AMBIGUOUS_PERSONAL_SPACE', 'More than one owned Space matches the requested personal Space name.');
24
- }
25
- const home = currentHome ?? candidates[0];
26
- const currentDisplayName = profile.props[domain.classes.User.properties.displayName.key];
27
- if (currentDisplayName !== undefined && typeof currentDisplayName !== 'string') {
28
- throw new TypeError('Shell User displayName is not a string.');
29
- }
30
- const member = hasGroup(domain, observation.groups.groups, 'core.member');
31
- const admin = hasGroup(domain, observation.groups.groups, 'core.admin');
32
- const ownsHome = home !== undefined && observation.ownedSpaces.spaces.some((space) => space.id === home.id);
33
- let homeName;
34
- if (home !== undefined) {
35
- const value = home.props[domain.classes.Space.properties.name.key];
36
- if (typeof value !== 'string') {
37
- throw new TypeError('Shell personal Space name is not a string.');
38
- }
39
- homeName = value;
40
- }
41
- const displayName = currentDisplayName === input.displayName ? undefined : input.displayName;
42
- const desiredHomeName = homeName === input.personalSpaceName ? undefined : input.personalSpaceName;
43
- const addDefault = currentHome === undefined;
44
- const addOwnership = home === undefined || !ownsHome;
45
- const addMember = !member;
46
- const addAdmin = role === 'admin' && !admin;
47
- if (displayName === undefined &&
48
- desiredHomeName === undefined &&
49
- !addDefault &&
50
- !addOwnership &&
51
- !addMember &&
52
- !addAdmin) {
53
- return Object.freeze({ kind: 'unchanged', personalSpaceId: home.id });
54
- }
55
- return Object.freeze({
56
- kind: 'repair',
57
- repair: Object.freeze({
58
- userId: profile.id,
59
- ...(currentDisplayName === undefined ? {} : { currentDisplayName }),
60
- ...(displayName === undefined ? {} : { displayName }),
61
- home: home === undefined
62
- ? Object.freeze({ kind: 'create', name: input.personalSpaceName })
63
- : Object.freeze({
64
- kind: 'existing',
65
- id: home.id,
66
- currentName: homeName,
67
- ...(desiredHomeName === undefined ? {} : { name: desiredHomeName }),
68
- }),
69
- addDefault,
70
- addOwnership,
71
- addMember,
72
- addAdmin,
73
- guards: Object.freeze({
74
- home: observation.home.guard,
75
- ownedSpaces: observation.ownedSpaces.guard,
76
- groups: observation.groups.guard,
77
- }),
78
- }),
79
- });
80
- }
81
- function hasGroup(domain, groups, subject) {
82
- return groups.some((group) => group.class === domain.classes.Group.key &&
83
- group.props[domain.classes.Group.properties.iss.key] === domain.origin &&
84
- group.props[domain.classes.Group.properties.sub.key] === subject);
85
- }
86
- function conflict(reason, message) {
87
- return Object.freeze({ kind: 'conflict', reason, message });
88
- }
@@ -1,57 +0,0 @@
1
- import { issuer } from '@astrale-os/sdk/auth';
2
- import { LocalBinding } from '@astrale-os/sdk/graph';
3
- import { Path } from '@astrale-os/sdk/graph/path';
4
- import { MutationAST } from '@astrale-os/sdk/mutation';
5
- const user = LocalBinding('user');
6
- const personalSpace = LocalBinding('personalSpace');
7
- export function provisioningRequest(domain, input, role) {
8
- const mutation = MutationAST.build((change) => {
9
- const createdUser = change.createNode({
10
- as: user,
11
- class: domain.classes.User.key,
12
- props: domain.classes.User.properties.from({ displayName: input.displayName }),
13
- });
14
- const createdSpace = change.createNode({
15
- as: personalSpace,
16
- class: domain.classes.Space.key,
17
- props: domain.classes.Space.properties.from({ name: input.personalSpaceName }),
18
- });
19
- change.createEdge({
20
- class: domain.classes.owns_space.key,
21
- source: createdUser,
22
- target: createdSpace,
23
- });
24
- change.createEdge({
25
- class: domain.classes.default_space.key,
26
- source: createdUser,
27
- target: createdSpace,
28
- });
29
- change.createEdge({
30
- class: domain.classes.member_of_group.key,
31
- source: createdUser,
32
- target: Path.project(domain.core.nodes.member.ref),
33
- });
34
- if (role === 'admin') {
35
- change.createEdge({
36
- class: domain.classes.member_of_group.key,
37
- source: createdUser,
38
- target: Path.project(domain.core.nodes.admin.ref),
39
- });
40
- }
41
- });
42
- return Object.freeze({
43
- idempotencyKey: input.operationId,
44
- mutation,
45
- identities: Object.freeze({
46
- [user]: Object.freeze({ issuer: issuer.accept(input.issuer), subject: input.subject }),
47
- }),
48
- });
49
- }
50
- export function provisioningResult(result) {
51
- const userId = result.createdNodes[user];
52
- const personalSpaceId = result.createdNodes[personalSpace];
53
- if (userId === undefined || personalSpaceId === undefined) {
54
- throw new TypeError('Shell provisioning omitted its User or personal Space identity.');
55
- }
56
- return Object.freeze({ userId, personalSpaceId, changed: true });
57
- }
@@ -1,74 +0,0 @@
1
- import { issuer } from '@astrale-os/sdk/auth';
2
- import { ResponseError, TransportError } from '@astrale-os/sdk/client';
3
- import { InvocationError } from '@astrale-os/sdk/execution';
4
- import { Path } from '@astrale-os/sdk/graph/path';
5
- import { repairUser } from '#mutations/user';
6
- import { observeUserSetup } from '#queries/user';
7
- import { planUserSetup } from './plan.js';
8
- import { provisioningRequest, provisioningResult } from './provision.js';
9
- export async function runSetup(context, role) {
10
- const { client, input, step } = context;
11
- const identity = Object.freeze({
12
- issuer: issuer.accept(input.issuer),
13
- subject: input.subject,
14
- });
15
- const existing = await step.run('resolve-identity', () => client.auth.whois(identity));
16
- if (existing === null) {
17
- try {
18
- const provisioned = await step.run('provision-identity', () => client.auth.provision(provisioningRequest(context.domain, input, role)));
19
- return provisioningResult(provisioned);
20
- }
21
- catch (cause) {
22
- if (!recoverableProvisionFailure(cause))
23
- throw cause;
24
- const recovered = await step.run('recover-provisioned-identity', () => client.auth.whois(identity));
25
- if (recovered === null)
26
- throw cause;
27
- return convergeExisting(context, role, recovered.id, true);
28
- }
29
- }
30
- return convergeExisting(context, role, existing.id, false);
31
- }
32
- async function convergeExisting(context, role, userId, changedBeforeObservation) {
33
- const observed = await context.step.run('observe-user-setup', () => context.query(observeUserSetup(context.domain), Path.id(userId).raw));
34
- const plan = planUserSetup(context.domain, context.input, role, observed);
35
- if (plan.kind === 'conflict')
36
- return setupConflict(plan);
37
- if (plan.kind === 'unchanged') {
38
- return Object.freeze({
39
- userId,
40
- personalSpaceId: plan.personalSpaceId,
41
- changed: changedBeforeObservation,
42
- });
43
- }
44
- const repaired = await context.step.run('repair-user-setup', () => context.mutate(repairUser(context.domain), plan.repair));
45
- if (repaired.ok) {
46
- return Object.freeze({ userId, personalSpaceId: repaired.personalSpaceId, changed: true });
47
- }
48
- if (repaired.outcomeKnown) {
49
- throw new InvocationError('CONFLICT', 'Shell User setup conflicted with concurrent graph state.', {
50
- reason: { code: repaired.code, details: {} },
51
- });
52
- }
53
- const recovered = await context.step.run('recover-user-repair', () => context.query(observeUserSetup(context.domain), Path.id(userId).raw));
54
- const recoveredPlan = planUserSetup(context.domain, context.input, role, recovered);
55
- if (recoveredPlan.kind === 'conflict')
56
- return setupConflict(recoveredPlan);
57
- if (recoveredPlan.kind === 'unchanged') {
58
- return Object.freeze({ userId, personalSpaceId: recoveredPlan.personalSpaceId, changed: true });
59
- }
60
- throw new InvocationError('BACKEND_UNAVAILABLE', 'Shell User setup outcome remains unknown after exact state observation.', { reason: { code: repaired.code, details: {} } });
61
- }
62
- function setupConflict(plan) {
63
- throw new InvocationError('CONFLICT', plan.message, {
64
- reason: { code: plan.reason, details: {} },
65
- });
66
- }
67
- function recoverableProvisionFailure(cause) {
68
- if (cause instanceof TransportError) {
69
- return cause.context.kind === 'invocation' && cause.context.delivery === 'unknown';
70
- }
71
- return (cause instanceof ResponseError &&
72
- (cause.reason?.code === 'PROVISION_CONFLICT' ||
73
- cause.reason?.code === 'PROVISION_PRECONDITION_FAILED'));
74
- }
@@ -1,41 +0,0 @@
1
- import { InvocationError } from '@astrale-os/sdk/execution';
2
- import { changeSpaceAccess } from '#mutations/space';
3
- import { observeDirectSpaceAccess } from '#queries/space';
4
- export async function setUserAccess(context, desired) {
5
- const observed = await context.step.run('observe-space-access', () => context.query(observeDirectSpaceAccess(context.domain), context.input.user));
6
- const current = state(observed, context.self);
7
- if (current === desired)
8
- return Object.freeze({});
9
- const result = await context.step.run('change-space-access', () => context.mutate(changeSpaceAccess(context.domain), {
10
- user: context.input.user,
11
- space: context.self,
12
- addMember: desired === 'member' && current !== 'member',
13
- removeMember: current === 'member' && desired !== 'member',
14
- addAdmin: desired === 'admin' && current !== 'admin',
15
- removeAdmin: current === 'admin' && desired !== 'admin',
16
- guards: { member: observed.member.guard, admin: observed.admin.guard },
17
- }));
18
- if (result.ok)
19
- return Object.freeze({});
20
- if (result.outcomeKnown)
21
- return accessConflict(result.code);
22
- const recovered = await context.step.run('recover-space-access', () => context.query(observeDirectSpaceAccess(context.domain), context.input.user));
23
- if (state(recovered, context.self) === desired)
24
- return Object.freeze({});
25
- throw new InvocationError('BACKEND_UNAVAILABLE', 'Space access outcome remains unknown after exact observation.', { reason: { code: result.code, details: {} } });
26
- }
27
- function state(observation, space) {
28
- const member = observation.member.spaces.some(({ id }) => id === space);
29
- const admin = observation.admin.spaces.some(({ id }) => id === space);
30
- if (member && admin) {
31
- throw new InvocationError('CONFLICT', 'The User has conflicting direct Space access edges.', {
32
- reason: { code: 'SPACE_ACCESS_AMBIGUOUS', details: {} },
33
- });
34
- }
35
- return admin ? 'admin' : member ? 'member' : null;
36
- }
37
- function accessConflict(code) {
38
- throw new InvocationError('CONFLICT', 'Space access conflicted with concurrent graph state.', {
39
- reason: { code, details: {} },
40
- });
41
- }
@@ -1,3 +0,0 @@
1
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
2
- import { setUserAccess } from './access.js';
3
- export const addSpaceUserWorkflow = defineWorkflow()('Space.addUser', (context) => setUserAccess(context, context.input.access));
@@ -1,37 +0,0 @@
1
- import { InvocationError } from '@astrale-os/sdk/execution';
2
- import { Path } from '@astrale-os/sdk/graph/path';
3
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
4
- import { changeDefaultSpace } from '#mutations/space';
5
- import { observeHome } from '#queries/user';
6
- async function setDefault(context) {
7
- const user = context.caller.principal;
8
- const observed = await context.step.run('observe-default-space', () => context.query(observeHome(context.domain), Path.id(user).raw));
9
- if (observed.spaces.length > 1) {
10
- throw new InvocationError('CONFLICT', 'The Shell User has more than one default Space.', {
11
- reason: { code: 'MULTIPLE_DEFAULT_SPACES', details: {} },
12
- });
13
- }
14
- if (observed.spaces[0]?.id === context.self)
15
- return Object.freeze({});
16
- const result = await context.step.run('change-default-space', () => context.mutate(changeDefaultSpace(context.domain), {
17
- user,
18
- ...(observed.spaces[0] === undefined ? {} : { previous: observed.spaces[0].id }),
19
- next: context.self,
20
- guard: observed.guard,
21
- }));
22
- if (result.ok)
23
- return Object.freeze({});
24
- if (result.outcomeKnown)
25
- return defaultConflict(result.code);
26
- const recovered = await context.step.run('recover-default-space', () => context.query(observeHome(context.domain), Path.id(user).raw));
27
- if (recovered.spaces.length === 1 && recovered.spaces[0]?.id === context.self) {
28
- return Object.freeze({});
29
- }
30
- throw new InvocationError('BACKEND_UNAVAILABLE', 'Default Space outcome remains unknown after exact observation.', { reason: { code: result.code, details: {} } });
31
- }
32
- function defaultConflict(code) {
33
- throw new InvocationError('CONFLICT', 'Default Space conflicted with concurrent graph state.', {
34
- reason: { code, details: {} },
35
- });
36
- }
37
- export const setDefaultSpaceWorkflow = defineWorkflow()('Space.setDefault', setDefault);
@@ -1,4 +0,0 @@
1
- export { setUserAccess } from './access.js';
2
- export { addSpaceUserWorkflow } from './add.js';
3
- export { setDefaultSpaceWorkflow } from './default.js';
4
- export { removeSpaceUserWorkflow } from './remove.js';
@@ -1,3 +0,0 @@
1
- import { defineWorkflow } from '@astrale-os/sdk/workflow';
2
- import { setUserAccess } from './access.js';
3
- export const removeSpaceUserWorkflow = defineWorkflow()('Space.removeUser', (context) => setUserAccess(context, null));