@aphexcms/cms-core 2.0.10 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/dist/api/api-keys.d.ts +4 -0
  2. package/dist/api/api-keys.d.ts.map +1 -1
  3. package/dist/api/assets.d.ts.map +1 -1
  4. package/dist/api/index.d.ts +1 -0
  5. package/dist/api/index.d.ts.map +1 -1
  6. package/dist/api/index.js +1 -0
  7. package/dist/api/roles.d.ts +22 -0
  8. package/dist/api/roles.d.ts.map +1 -0
  9. package/dist/api/roles.js +26 -0
  10. package/dist/api/schemas/api-keys.d.ts +50 -4
  11. package/dist/api/schemas/api-keys.d.ts.map +1 -1
  12. package/dist/api/schemas/api-keys.js +22 -3
  13. package/dist/api/schemas/organizations.d.ts +4 -22
  14. package/dist/api/schemas/organizations.d.ts.map +1 -1
  15. package/dist/api/schemas/organizations.js +13 -2
  16. package/dist/api/schemas/roles.d.ts +77 -0
  17. package/dist/api/schemas/roles.d.ts.map +1 -0
  18. package/dist/api/schemas/roles.js +42 -0
  19. package/dist/app-augment.d.ts +32 -0
  20. package/dist/app-augment.d.ts.map +1 -0
  21. package/dist/app-augment.js +18 -0
  22. package/dist/auth/auth-hooks.d.ts +2 -1
  23. package/dist/auth/auth-hooks.d.ts.map +1 -1
  24. package/dist/auth/auth-hooks.js +22 -2
  25. package/dist/client/index.d.ts +4 -2
  26. package/dist/client/index.d.ts.map +1 -1
  27. package/dist/client/index.js +6 -2
  28. package/dist/components/AdminApp.svelte +300 -140
  29. package/dist/components/AdminApp.svelte.d.ts +8 -0
  30. package/dist/components/AdminApp.svelte.d.ts.map +1 -1
  31. package/dist/components/admin/DocumentEditor.svelte +633 -350
  32. package/dist/components/admin/DocumentEditor.svelte.d.ts +2 -0
  33. package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
  34. package/dist/components/admin/DocumentVersionPanel.svelte +46 -20
  35. package/dist/components/admin/DocumentVersionPanel.svelte.d.ts.map +1 -1
  36. package/dist/components/admin/MediaBrowser.svelte +70 -30
  37. package/dist/components/admin/MediaBrowser.svelte.d.ts.map +1 -1
  38. package/dist/components/admin/ObjectModal.svelte +70 -95
  39. package/dist/components/admin/ObjectModal.svelte.d.ts +1 -2
  40. package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
  41. package/dist/components/admin/PermissionsDebug.svelte +119 -0
  42. package/dist/components/admin/PermissionsDebug.svelte.d.ts +4 -0
  43. package/dist/components/admin/PermissionsDebug.svelte.d.ts.map +1 -0
  44. package/dist/components/admin/SchemaField.svelte +3 -1
  45. package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -1
  46. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +8 -10
  47. package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -1
  48. package/dist/components/admin/fields/ArrayField.svelte +104 -108
  49. package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
  50. package/dist/components/admin/fields/FileField.svelte +22 -17
  51. package/dist/components/admin/fields/FileField.svelte.d.ts.map +1 -1
  52. package/dist/components/admin/fields/ImageField.svelte +21 -15
  53. package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
  54. package/dist/components/admin/fields/ReferenceField.svelte +142 -112
  55. package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
  56. package/dist/components/admin/fields/TextareaField.svelte +4 -3
  57. package/dist/components/admin/fields/TextareaField.svelte.d.ts +2 -2
  58. package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +1 -1
  59. package/dist/components/layout/Sidebar.svelte +21 -11
  60. package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
  61. package/dist/components/layout/sidebar/NavMain.svelte +1 -0
  62. package/dist/db/interfaces/document.d.ts.map +1 -1
  63. package/dist/db/interfaces/index.d.ts +3 -1
  64. package/dist/db/interfaces/index.d.ts.map +1 -1
  65. package/dist/db/interfaces/organization.d.ts +1 -1
  66. package/dist/db/interfaces/organization.d.ts.map +1 -1
  67. package/dist/db/interfaces/role.d.ts +25 -0
  68. package/dist/db/interfaces/role.d.ts.map +1 -0
  69. package/dist/db/interfaces/role.js +1 -0
  70. package/dist/engine.d.ts.map +1 -1
  71. package/dist/engine.js +5 -0
  72. package/dist/field-access.d.ts +30 -0
  73. package/dist/field-access.d.ts.map +1 -0
  74. package/dist/field-access.js +79 -0
  75. package/dist/hooks.d.ts +2 -0
  76. package/dist/hooks.d.ts.map +1 -1
  77. package/dist/hooks.js +19 -13
  78. package/dist/lib/api/api-keys.d.ts +4 -0
  79. package/dist/lib/api/api-keys.d.ts.map +1 -1
  80. package/dist/lib/api/api-keys.js.map +1 -1
  81. package/dist/lib/api/assets.d.ts.map +1 -1
  82. package/dist/lib/api/assets.js.map +1 -1
  83. package/dist/lib/api/index.d.ts +1 -0
  84. package/dist/lib/api/index.d.ts.map +1 -1
  85. package/dist/lib/api/index.js +1 -0
  86. package/dist/lib/api/index.js.map +1 -1
  87. package/dist/lib/api/roles.d.ts +22 -0
  88. package/dist/lib/api/roles.d.ts.map +1 -0
  89. package/dist/lib/api/roles.js +27 -0
  90. package/dist/lib/api/roles.js.map +1 -0
  91. package/dist/lib/api/schemas/api-keys.d.ts +50 -4
  92. package/dist/lib/api/schemas/api-keys.d.ts.map +1 -1
  93. package/dist/lib/api/schemas/api-keys.js +22 -3
  94. package/dist/lib/api/schemas/api-keys.js.map +1 -1
  95. package/dist/lib/api/schemas/organizations.d.ts +4 -22
  96. package/dist/lib/api/schemas/organizations.d.ts.map +1 -1
  97. package/dist/lib/api/schemas/organizations.js +13 -2
  98. package/dist/lib/api/schemas/organizations.js.map +1 -1
  99. package/dist/lib/api/schemas/roles.d.ts +77 -0
  100. package/dist/lib/api/schemas/roles.d.ts.map +1 -0
  101. package/dist/lib/api/schemas/roles.js +43 -0
  102. package/dist/lib/api/schemas/roles.js.map +1 -0
  103. package/dist/lib/app-augment.d.ts +32 -0
  104. package/dist/lib/app-augment.d.ts.map +1 -0
  105. package/dist/lib/app-augment.js +19 -0
  106. package/dist/lib/app-augment.js.map +1 -0
  107. package/dist/lib/auth/auth-hooks.d.ts +2 -1
  108. package/dist/lib/auth/auth-hooks.d.ts.map +1 -1
  109. package/dist/lib/auth/auth-hooks.js +22 -2
  110. package/dist/lib/auth/auth-hooks.js.map +1 -1
  111. package/dist/lib/client/index.d.ts +4 -2
  112. package/dist/lib/client/index.d.ts.map +1 -1
  113. package/dist/lib/client/index.js +6 -2
  114. package/dist/lib/client/index.js.map +1 -1
  115. package/dist/lib/db/interfaces/document.d.ts.map +1 -1
  116. package/dist/lib/db/interfaces/index.d.ts +3 -1
  117. package/dist/lib/db/interfaces/index.d.ts.map +1 -1
  118. package/dist/lib/db/interfaces/organization.d.ts +1 -1
  119. package/dist/lib/db/interfaces/organization.d.ts.map +1 -1
  120. package/dist/lib/db/interfaces/role.d.ts +25 -0
  121. package/dist/lib/db/interfaces/role.d.ts.map +1 -0
  122. package/dist/lib/db/interfaces/role.js +2 -0
  123. package/dist/lib/db/interfaces/role.js.map +1 -0
  124. package/dist/lib/engine.d.ts.map +1 -1
  125. package/dist/lib/engine.js +5 -0
  126. package/dist/lib/engine.js.map +1 -1
  127. package/dist/lib/field-access.d.ts +30 -0
  128. package/dist/lib/field-access.d.ts.map +1 -0
  129. package/dist/lib/field-access.js +80 -0
  130. package/dist/lib/field-access.js.map +1 -0
  131. package/dist/lib/hooks.d.ts +2 -0
  132. package/dist/lib/hooks.d.ts.map +1 -1
  133. package/dist/lib/hooks.js +19 -13
  134. package/dist/lib/hooks.js.map +1 -1
  135. package/dist/lib/local-api/collection-api.d.ts +2 -0
  136. package/dist/lib/local-api/collection-api.d.ts.map +1 -1
  137. package/dist/lib/local-api/collection-api.js +98 -30
  138. package/dist/lib/local-api/collection-api.js.map +1 -1
  139. package/dist/lib/local-api/index.d.ts.map +1 -1
  140. package/dist/lib/local-api/index.js.map +1 -1
  141. package/dist/lib/local-api/permissions.d.ts +26 -26
  142. package/dist/lib/local-api/permissions.d.ts.map +1 -1
  143. package/dist/lib/local-api/permissions.js +122 -80
  144. package/dist/lib/local-api/permissions.js.map +1 -1
  145. package/dist/lib/permissions-context.svelte.d.ts +44 -0
  146. package/dist/lib/permissions-context.svelte.d.ts.map +1 -0
  147. package/dist/lib/permissions-context.svelte.js +80 -0
  148. package/dist/lib/permissions-context.svelte.js.map +1 -0
  149. package/dist/lib/routes/assets.d.ts.map +1 -1
  150. package/dist/lib/routes/assets.js.map +1 -1
  151. package/dist/lib/routes/document-versions.d.ts.map +1 -1
  152. package/dist/lib/routes/document-versions.js.map +1 -1
  153. package/dist/lib/routes/organizations-by-id.d.ts.map +1 -1
  154. package/dist/lib/routes/organizations-by-id.js +6 -3
  155. package/dist/lib/routes/organizations-by-id.js.map +1 -1
  156. package/dist/lib/routes/organizations-invitations.d.ts.map +1 -1
  157. package/dist/lib/routes/organizations-invitations.js +17 -7
  158. package/dist/lib/routes/organizations-invitations.js.map +1 -1
  159. package/dist/lib/routes/organizations-members.d.ts.map +1 -1
  160. package/dist/lib/routes/organizations-members.js +15 -7
  161. package/dist/lib/routes/organizations-members.js.map +1 -1
  162. package/dist/lib/routes/organizations.d.ts.map +1 -1
  163. package/dist/lib/routes/organizations.js +3 -0
  164. package/dist/lib/routes/organizations.js.map +1 -1
  165. package/dist/lib/routes/roles-by-name.d.ts +4 -0
  166. package/dist/lib/routes/roles-by-name.d.ts.map +1 -0
  167. package/dist/lib/routes/roles-by-name.js +112 -0
  168. package/dist/lib/routes/roles-by-name.js.map +1 -0
  169. package/dist/lib/routes/roles.d.ts +4 -0
  170. package/dist/lib/routes/roles.d.ts.map +1 -0
  171. package/dist/lib/routes/roles.js +91 -0
  172. package/dist/lib/routes/roles.js.map +1 -0
  173. package/dist/lib/routes-exports.d.ts +2 -0
  174. package/dist/lib/routes-exports.d.ts.map +1 -1
  175. package/dist/lib/routes-exports.js +3 -0
  176. package/dist/lib/routes-exports.js.map +1 -1
  177. package/dist/lib/save-state-context.svelte.d.ts +8 -0
  178. package/dist/lib/save-state-context.svelte.d.ts.map +1 -0
  179. package/dist/lib/save-state-context.svelte.js +9 -0
  180. package/dist/lib/save-state-context.svelte.js.map +1 -0
  181. package/dist/lib/schema-utils/validator.d.ts.map +1 -1
  182. package/dist/lib/schema-utils/validator.js +14 -0
  183. package/dist/lib/schema-utils/validator.js.map +1 -1
  184. package/dist/lib/server/index.d.ts +1 -0
  185. package/dist/lib/server/index.d.ts.map +1 -1
  186. package/dist/lib/server/index.js +1 -0
  187. package/dist/lib/server/index.js.map +1 -1
  188. package/dist/lib/services/index.d.ts +1 -0
  189. package/dist/lib/services/index.d.ts.map +1 -1
  190. package/dist/lib/services/index.js +1 -0
  191. package/dist/lib/services/index.js.map +1 -1
  192. package/dist/lib/services/roles-service.d.ts +35 -0
  193. package/dist/lib/services/roles-service.d.ts.map +1 -0
  194. package/dist/lib/services/roles-service.js +91 -0
  195. package/dist/lib/services/roles-service.js.map +1 -0
  196. package/dist/lib/services/version-service.d.ts.map +1 -1
  197. package/dist/lib/services/version-service.js.map +1 -1
  198. package/dist/lib/types/auth.d.ts +43 -9
  199. package/dist/lib/types/auth.d.ts.map +1 -1
  200. package/dist/lib/types/auth.js +31 -26
  201. package/dist/lib/types/auth.js.map +1 -1
  202. package/dist/lib/types/capabilities.d.ts +104 -0
  203. package/dist/lib/types/capabilities.d.ts.map +1 -0
  204. package/dist/lib/types/capabilities.js +217 -0
  205. package/dist/lib/types/capabilities.js.map +1 -0
  206. package/dist/lib/types/index.d.ts +1 -0
  207. package/dist/lib/types/index.d.ts.map +1 -1
  208. package/dist/lib/types/index.js +1 -0
  209. package/dist/lib/types/index.js.map +1 -1
  210. package/dist/lib/types/organization.d.ts +13 -4
  211. package/dist/lib/types/organization.d.ts.map +1 -1
  212. package/dist/lib/types/schemas.d.ts +71 -0
  213. package/dist/lib/types/schemas.d.ts.map +1 -1
  214. package/dist/lib/types/sidebar.d.ts +1 -1
  215. package/dist/lib/types/sidebar.d.ts.map +1 -1
  216. package/dist/lib/utils/mime-detect.d.ts.map +1 -1
  217. package/dist/lib/utils/mime-detect.js +28 -6
  218. package/dist/lib/utils/mime-detect.js.map +1 -1
  219. package/dist/local-api/collection-api.d.ts +2 -0
  220. package/dist/local-api/collection-api.d.ts.map +1 -1
  221. package/dist/local-api/collection-api.js +98 -30
  222. package/dist/local-api/index.d.ts.map +1 -1
  223. package/dist/local-api/permissions.d.ts +26 -26
  224. package/dist/local-api/permissions.d.ts.map +1 -1
  225. package/dist/local-api/permissions.js +122 -80
  226. package/dist/permissions-context.svelte.d.ts +44 -0
  227. package/dist/permissions-context.svelte.d.ts.map +1 -0
  228. package/dist/permissions-context.svelte.js +79 -0
  229. package/dist/plugins/README.md +20 -20
  230. package/dist/routes/assets.d.ts.map +1 -1
  231. package/dist/routes/document-versions.d.ts.map +1 -1
  232. package/dist/routes/organizations-by-id.d.ts.map +1 -1
  233. package/dist/routes/organizations-by-id.js +6 -3
  234. package/dist/routes/organizations-invitations.d.ts.map +1 -1
  235. package/dist/routes/organizations-invitations.js +17 -7
  236. package/dist/routes/organizations-members.d.ts.map +1 -1
  237. package/dist/routes/organizations-members.js +15 -7
  238. package/dist/routes/organizations.d.ts.map +1 -1
  239. package/dist/routes/organizations.js +3 -0
  240. package/dist/routes/roles-by-name.d.ts +4 -0
  241. package/dist/routes/roles-by-name.d.ts.map +1 -0
  242. package/dist/routes/roles-by-name.js +111 -0
  243. package/dist/routes/roles.d.ts +4 -0
  244. package/dist/routes/roles.d.ts.map +1 -0
  245. package/dist/routes/roles.js +90 -0
  246. package/dist/routes-exports.d.ts +2 -0
  247. package/dist/routes-exports.d.ts.map +1 -1
  248. package/dist/routes-exports.js +3 -0
  249. package/dist/save-state-context.svelte.d.ts +8 -0
  250. package/dist/save-state-context.svelte.d.ts.map +1 -0
  251. package/dist/save-state-context.svelte.js +8 -0
  252. package/dist/schema-utils/validator.d.ts.map +1 -1
  253. package/dist/schema-utils/validator.js +14 -0
  254. package/dist/server/index.d.ts +1 -0
  255. package/dist/server/index.d.ts.map +1 -1
  256. package/dist/server/index.js +1 -0
  257. package/dist/services/index.d.ts +1 -0
  258. package/dist/services/index.d.ts.map +1 -1
  259. package/dist/services/index.js +1 -0
  260. package/dist/services/roles-service.d.ts +35 -0
  261. package/dist/services/roles-service.d.ts.map +1 -0
  262. package/dist/services/roles-service.js +90 -0
  263. package/dist/services/version-service.d.ts.map +1 -1
  264. package/dist/types/auth.d.ts +43 -9
  265. package/dist/types/auth.d.ts.map +1 -1
  266. package/dist/types/auth.js +31 -26
  267. package/dist/types/capabilities.d.ts +104 -0
  268. package/dist/types/capabilities.d.ts.map +1 -0
  269. package/dist/types/capabilities.js +216 -0
  270. package/dist/types/index.d.ts +1 -0
  271. package/dist/types/index.d.ts.map +1 -1
  272. package/dist/types/index.js +1 -0
  273. package/dist/types/organization.d.ts +13 -4
  274. package/dist/types/organization.d.ts.map +1 -1
  275. package/dist/types/schemas.d.ts +71 -0
  276. package/dist/types/schemas.d.ts.map +1 -1
  277. package/dist/types/sidebar.d.ts +1 -1
  278. package/dist/types/sidebar.d.ts.map +1 -1
  279. package/dist/utils/mime-detect.d.ts.map +1 -1
  280. package/dist/utils/mime-detect.js +28 -6
  281. package/package.json +6 -2
@@ -0,0 +1,79 @@
1
+ // Svelte context for capability-based UI gating.
2
+ //
3
+ // Set once at the root of the admin shell with a reactive capability source;
4
+ // descendants consume via `usePermissions()`. Mirrors the server-side
5
+ // `hasCapability()` API so the same mental model applies on both sides.
6
+ import { getContext, setContext } from 'svelte';
7
+ const KEY = Symbol.for('aphex.permissions');
8
+ /**
9
+ * Publish a capability context to descendants.
10
+ *
11
+ * `getCapabilities` is a getter rather than a static array so reactive
12
+ * sources (Svelte state, `$page.data.rbac.capabilities`) propagate: every
13
+ * `can()` call re-reads through the closure.
14
+ *
15
+ * @example
16
+ * ```svelte
17
+ * <script>
18
+ * import { page } from '$app/state';
19
+ * import { setPermissionsContext } from '@aphexcms/cms-core';
20
+ * setPermissionsContext(() => page.data.rbac?.capabilities ?? []);
21
+ * </script>
22
+ * ```
23
+ */
24
+ export function setPermissionsContext(getCapabilities, getRole = () => null) {
25
+ const ctx = {
26
+ get capabilities() {
27
+ return getCapabilities();
28
+ },
29
+ get role() {
30
+ return getRole();
31
+ },
32
+ can(cap) {
33
+ return getCapabilities().includes(cap);
34
+ },
35
+ canAny(...caps) {
36
+ const current = getCapabilities();
37
+ return caps.some((c) => current.includes(c));
38
+ },
39
+ canAll(...caps) {
40
+ const current = getCapabilities();
41
+ return caps.every((c) => current.includes(c));
42
+ }
43
+ };
44
+ setContext(KEY, ctx);
45
+ return ctx;
46
+ }
47
+ /**
48
+ * Read the capability context set by an ancestor.
49
+ *
50
+ * When no provider is present (e.g. a component rendered in isolation during
51
+ * tests or Storybook), returns a deny-all stub with a one-time dev warning
52
+ * rather than throwing — that way consumers degrade to "no affordances shown"
53
+ * instead of crashing the tree.
54
+ */
55
+ export function usePermissions() {
56
+ const ctx = getContext(KEY);
57
+ if (ctx)
58
+ return ctx;
59
+ warnOnce();
60
+ return DENY_ALL;
61
+ }
62
+ const DENY_ALL = Object.freeze({
63
+ capabilities: Object.freeze([]),
64
+ role: null,
65
+ can: () => false,
66
+ canAny: () => false,
67
+ canAll: () => false
68
+ });
69
+ let warned = false;
70
+ function warnOnce() {
71
+ if (warned)
72
+ return;
73
+ warned = true;
74
+ if (typeof window !== 'undefined') {
75
+ // eslint-disable-next-line no-console
76
+ console.warn('[aphex] usePermissions() called outside a PermissionsContext provider. ' +
77
+ 'All capability checks will return false. Call setPermissionsContext() in an ancestor.');
78
+ }
79
+ }
@@ -124,26 +124,26 @@ Under this system, a plugin becomes a clean, declarative manifest of its parts.
124
124
  import AnalyticsDashboard from './AnalyticsDashboard.svelte';
125
125
 
126
126
  export function createAnalyticsPlugin(config: AnalyticsConfig = {}): CMSPlugin {
127
- const endpoint = config.endpoint ?? '/api/analytics';
128
-
129
- return {
130
- name: 'my-analytics-plugin',
131
- parts: [
132
- // Part 1: The API endpoint
133
- {
134
- implements: 'aphex/server/route',
135
- path: endpoint,
136
- handler: (event) => handleAnalyticsRequest(event)
137
- },
138
- // Part 2: The UI tab in the admin interface
139
- {
140
- implements: 'aphex/admin/tool',
141
- id: 'analytics',
142
- title: 'Analytics',
143
- component: AnalyticsDashboard
144
- }
145
- ]
146
- };
127
+ const endpoint = config.endpoint ?? '/api/analytics';
128
+
129
+ return {
130
+ name: 'my-analytics-plugin',
131
+ parts: [
132
+ // Part 1: The API endpoint
133
+ {
134
+ implements: 'aphex/server/route',
135
+ path: endpoint,
136
+ handler: (event) => handleAnalyticsRequest(event)
137
+ },
138
+ // Part 2: The UI tab in the admin interface
139
+ {
140
+ implements: 'aphex/admin/tool',
141
+ id: 'analytics',
142
+ title: 'Analytics',
143
+ component: AnalyticsDashboard
144
+ }
145
+ ]
146
+ };
147
147
  }
148
148
  ```
149
149
 
@@ -1 +1 @@
1
- {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/lib/routes/assets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,IAAI,EAAE,cAuFlB,CAAC;AAEF,eAAO,MAAM,GAAG,EAAE,cAqEjB,CAAC"}
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/lib/routes/assets.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,IAAI,EAAE,cAuFlB,CAAC;AAEF,eAAO,MAAM,GAAG,EAAE,cAmEjB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"document-versions.d.ts","sourceRoot":"","sources":["../../src/lib/routes/document-versions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAMpD,eAAO,MAAM,GAAG,EAAE,cAyEjB,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,cAuCxB,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,cA4C5B,CAAC"}
1
+ {"version":3,"file":"document-versions.d.ts","sourceRoot":"","sources":["../../src/lib/routes/document-versions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAMpD,eAAO,MAAM,GAAG,EAAE,cAqEjB,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,cAkCxB,CAAC;AAGF,eAAO,MAAM,cAAc,EAAE,cA0C5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"organizations-by-id.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations-by-id.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,GAAG,EAAE,cAmEjB,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,cA4GnB,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,cAmFpB,CAAC"}
1
+ {"version":3,"file":"organizations-by-id.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations-by-id.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAMpD,eAAO,MAAM,GAAG,EAAE,cAmEjB,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,cA8GnB,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,cAmFpB,CAAC"}
@@ -2,6 +2,7 @@
2
2
  import { json } from '@sveltejs/kit';
3
3
  import { cmsLogger } from '../utils/logger.js';
4
4
  import { updateOrganizationRequest } from '../api/schemas/organizations.js';
5
+ import { hasCapability } from '../types/capabilities.js';
5
6
  // GET /api/organizations/[id] - Get organization by ID
6
7
  export const GET = async ({ params, locals }) => {
7
8
  try {
@@ -72,13 +73,15 @@ export const PATCH = async ({ params, request, locals }) => {
72
73
  message: 'Organization ID is required'
73
74
  }, { status: 400 });
74
75
  }
75
- // Check if user is owner or admin of this organization
76
+ // Require `org.settings` capability + membership in the target org.
77
+ // Membership check stands regardless — even a capability holder can only
78
+ // edit orgs they actually belong to.
76
79
  const membership = await databaseAdapter.findUserMembership(auth.user.id, id);
77
- if (!membership || (membership.role !== 'owner' && membership.role !== 'admin')) {
80
+ if (!membership || !hasCapability(auth, 'org.settings')) {
78
81
  return json({
79
82
  success: false,
80
83
  error: 'Forbidden',
81
- message: 'Only owners and admins can update organization settings'
84
+ message: 'You do not have permission to update organization settings'
82
85
  }, { status: 403 });
83
86
  }
84
87
  const rawBody = await request.json();
@@ -1 +1 @@
1
- {"version":3,"file":"organizations-invitations.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations-invitations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,IAAI,EAAE,cA+HlB,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,cAuEpB,CAAC"}
1
+ {"version":3,"file":"organizations-invitations.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations-invitations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAMpD,eAAO,MAAM,IAAI,EAAE,cA6IlB,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,cAsEpB,CAAC"}
@@ -2,6 +2,7 @@
2
2
  import { json } from '@sveltejs/kit';
3
3
  import { cmsLogger } from '../utils/logger.js';
4
4
  import { inviteMemberRequest, cancelInvitationRequest } from '../api/schemas/organizations.js';
5
+ import { hasCapability } from '../types/capabilities.js';
5
6
  // POST /api/organizations/invitations - Create/send an invitation
6
7
  export const POST = async ({ request, locals }) => {
7
8
  try {
@@ -14,12 +15,11 @@ export const POST = async ({ request, locals }) => {
14
15
  message: 'Session authentication required'
15
16
  }, { status: 401 });
16
17
  }
17
- // Only owners and admins can invite members
18
- if (auth.organizationRole !== 'owner' && auth.organizationRole !== 'admin') {
18
+ if (!hasCapability(auth, 'member.invite')) {
19
19
  return json({
20
20
  success: false,
21
21
  error: 'Forbidden',
22
- message: 'Only owners and admins can invite members'
22
+ message: 'You do not have permission to invite members'
23
23
  }, { status: 403 });
24
24
  }
25
25
  const rawBody = await request.json();
@@ -28,11 +28,22 @@ export const POST = async ({ request, locals }) => {
28
28
  return json({
29
29
  success: false,
30
30
  error: 'Invalid request body',
31
- message: 'email and role (admin|editor|viewer) are required',
31
+ message: 'email and role are required',
32
32
  issues: parsed.error.issues
33
33
  }, { status: 400 });
34
34
  }
35
35
  const body = parsed.data;
36
+ // Verify the role exists in this organization. Defends against
37
+ // clients sending a role name that was deleted between page load
38
+ // and submit, or against typos slipping past the format regex.
39
+ const roleRow = await databaseAdapter.findRoleByName(auth.organizationId, body.role);
40
+ if (!roleRow) {
41
+ return json({
42
+ success: false,
43
+ error: 'Unknown role',
44
+ message: `No role named "${body.role}" in this organization`
45
+ }, { status: 400 });
46
+ }
36
47
  // Reject self-invitation
37
48
  if (body.email.toLowerCase() === auth.user.email.toLowerCase()) {
38
49
  return json({
@@ -103,12 +114,11 @@ export const DELETE = async ({ request, locals }) => {
103
114
  message: 'Session authentication required'
104
115
  }, { status: 401 });
105
116
  }
106
- // Only owners and admins can cancel invitations
107
- if (auth.organizationRole !== 'owner' && auth.organizationRole !== 'admin') {
117
+ if (!hasCapability(auth, 'member.invite')) {
108
118
  return json({
109
119
  success: false,
110
120
  error: 'Forbidden',
111
- message: 'Only owners and admins can cancel invitations'
121
+ message: 'You do not have permission to cancel invitations'
112
122
  }, { status: 403 });
113
123
  }
114
124
  const rawBody = await request.json();
@@ -1 +1 @@
1
- {"version":3,"file":"organizations-members.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations-members.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,GAAG,EAAE,cAkCjB,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,cAqIpB,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,cAiHnB,CAAC"}
1
+ {"version":3,"file":"organizations-members.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations-members.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAMpD,eAAO,MAAM,GAAG,EAAE,cAkCjB,CAAC;AAGF,eAAO,MAAM,MAAM,EAAE,cAoIpB,CAAC;AAGF,eAAO,MAAM,KAAK,EAAE,cA6HnB,CAAC"}
@@ -2,6 +2,7 @@
2
2
  import { json } from '@sveltejs/kit';
3
3
  import { cmsLogger } from '../utils/logger.js';
4
4
  import { removeMemberRequest, updateMemberRoleRequest } from '../api/schemas/organizations.js';
5
+ import { hasCapability } from '../types/capabilities.js';
5
6
  // GET /api/organizations/members - List organization members
6
7
  export const GET = async ({ locals }) => {
7
8
  try {
@@ -42,12 +43,11 @@ export const DELETE = async ({ request, locals }) => {
42
43
  message: 'Session authentication required'
43
44
  }, { status: 401 });
44
45
  }
45
- // Only owners and admins can remove members
46
- if (auth.organizationRole !== 'owner' && auth.organizationRole !== 'admin') {
46
+ if (!hasCapability(auth, 'member.remove')) {
47
47
  return json({
48
48
  success: false,
49
49
  error: 'Forbidden',
50
- message: 'Only owners and admins can remove members'
50
+ message: 'You do not have permission to remove members'
51
51
  }, { status: 403 });
52
52
  }
53
53
  const rawBody = await request.json();
@@ -137,12 +137,11 @@ export const PATCH = async ({ request, locals }) => {
137
137
  message: 'Session authentication required'
138
138
  }, { status: 401 });
139
139
  }
140
- // Only owners and admins can update roles
141
- if (auth.organizationRole !== 'owner' && auth.organizationRole !== 'admin') {
140
+ if (!hasCapability(auth, 'member.changeRole')) {
142
141
  return json({
143
142
  success: false,
144
143
  error: 'Forbidden',
145
- message: 'Only owners and admins can update member roles'
144
+ message: 'You do not have permission to change member roles'
146
145
  }, { status: 403 });
147
146
  }
148
147
  const rawBody = await request.json();
@@ -151,11 +150,20 @@ export const PATCH = async ({ request, locals }) => {
151
150
  return json({
152
151
  success: false,
153
152
  error: 'Invalid request body',
154
- message: 'userId and role (owner|admin|editor|viewer) are required',
153
+ message: 'userId and role are required',
155
154
  issues: parsed.error.issues
156
155
  }, { status: 400 });
157
156
  }
158
157
  const body = parsed.data;
158
+ // Verify the target role exists in this organization.
159
+ const roleRow = await databaseAdapter.findRoleByName(auth.organizationId, body.role);
160
+ if (!roleRow) {
161
+ return json({
162
+ success: false,
163
+ error: 'Unknown role',
164
+ message: `No role named "${body.role}" in this organization`
165
+ }, { status: 400 });
166
+ }
159
167
  // Prevent changing your own role
160
168
  if (body.userId === auth.user.id) {
161
169
  return json({
@@ -1 +1 @@
1
- {"version":3,"file":"organizations.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,GAAG,EAAE,cA6CjB,CAAC;AAGF,eAAO,MAAM,IAAI,EAAE,cA8FlB,CAAC"}
1
+ {"version":3,"file":"organizations.d.ts","sourceRoot":"","sources":["../../src/lib/routes/organizations.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAKpD,eAAO,MAAM,GAAG,EAAE,cA6CjB,CAAC;AAGF,eAAO,MAAM,IAAI,EAAE,cAkGlB,CAAC"}
@@ -89,6 +89,9 @@ export const POST = async ({ request, locals }) => {
89
89
  parentOrganizationId: auth.organizationId, // Current active org becomes parent
90
90
  createdBy: auth.user.id
91
91
  });
92
+ // Seed the four built-in roles for this org before assigning membership.
93
+ // The member row references the role by name, so the rows must exist.
94
+ await databaseAdapter.seedBuiltinRoles(newOrganization.id);
92
95
  // Add the creator as owner
93
96
  await databaseAdapter.addMember({
94
97
  organizationId: newOrganization.id,
@@ -0,0 +1,4 @@
1
+ import type { RequestHandler } from '@sveltejs/kit';
2
+ export declare const PATCH: RequestHandler;
3
+ export declare const DELETE: RequestHandler;
4
+ //# sourceMappingURL=roles-by-name.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles-by-name.d.ts","sourceRoot":"","sources":["../../src/lib/routes/roles-by-name.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAgBpD,eAAO,MAAM,KAAK,EAAE,cA4DnB,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,cAoEpB,CAAC"}
@@ -0,0 +1,111 @@
1
+ // Aphex CMS Roles API Handlers (by-name)
2
+ //
3
+ // PATCH /api/roles/[name] — edit description / capabilities
4
+ // DELETE /api/roles/[name] — delete a custom role (built-ins cannot be deleted)
5
+ import { json } from '@sveltejs/kit';
6
+ import { cmsLogger } from '../utils/logger.js';
7
+ import { hasCapability, BUILTIN_ROLE_NAMES } from '../types/capabilities.js';
8
+ import { updateRoleRequest } from '../api/schemas/roles.js';
9
+ function unauthorized() {
10
+ return json({ success: false, error: 'Unauthorized', message: 'Session authentication required' }, { status: 401 });
11
+ }
12
+ function forbidden(message) {
13
+ return json({ success: false, error: 'Forbidden', message }, { status: 403 });
14
+ }
15
+ export const PATCH = async ({ params, request, locals }) => {
16
+ try {
17
+ const { databaseAdapter, rolesService } = locals.aphexCMS;
18
+ const auth = locals.auth;
19
+ if (!auth || auth.type !== 'session')
20
+ return unauthorized();
21
+ if (!hasCapability(auth, 'role.manage')) {
22
+ return forbidden('You do not have permission to manage roles');
23
+ }
24
+ const name = params.name;
25
+ if (!name) {
26
+ return json({ success: false, error: 'Invalid request', message: 'Role name is required' }, { status: 400 });
27
+ }
28
+ const rawBody = await request.json();
29
+ const parsed = updateRoleRequest.safeParse(rawBody);
30
+ if (!parsed.success) {
31
+ return json({
32
+ success: false,
33
+ error: 'Invalid request body',
34
+ issues: parsed.error.issues
35
+ }, { status: 400 });
36
+ }
37
+ const body = parsed.data;
38
+ const updated = await databaseAdapter.updateRole(auth.organizationId, name, body);
39
+ if (!updated) {
40
+ return json({
41
+ success: false,
42
+ error: 'Not found',
43
+ message: `No role named "${name}" in this organization`
44
+ }, { status: 404 });
45
+ }
46
+ // Bust the capability cache so open sessions pick up the change on
47
+ // their next request instead of waiting for TTL.
48
+ await rolesService.invalidate(auth.organizationId, name);
49
+ return json({ success: true, data: updated });
50
+ }
51
+ catch (error) {
52
+ cmsLogger.error('Failed to update role:', error);
53
+ return json({
54
+ success: false,
55
+ error: 'Failed to update role',
56
+ message: error instanceof Error ? error.message : 'Unknown error'
57
+ }, { status: 500 });
58
+ }
59
+ };
60
+ export const DELETE = async ({ params, locals }) => {
61
+ try {
62
+ const { databaseAdapter, rolesService } = locals.aphexCMS;
63
+ const auth = locals.auth;
64
+ if (!auth || auth.type !== 'session')
65
+ return unauthorized();
66
+ if (!hasCapability(auth, 'role.manage')) {
67
+ return forbidden('You do not have permission to manage roles');
68
+ }
69
+ const name = params.name;
70
+ if (!name) {
71
+ return json({ success: false, error: 'Invalid request', message: 'Role name is required' }, { status: 400 });
72
+ }
73
+ // Built-ins are part of the org's guaranteed floor — deleting one
74
+ // would let a seed run re-create it with stale capabilities. Force the
75
+ // user to edit instead.
76
+ if (BUILTIN_ROLE_NAMES.includes(name)) {
77
+ return forbidden(`"${name}" is a built-in role and cannot be deleted.`);
78
+ }
79
+ // Block deletion while the role is assigned to any member or invitation.
80
+ // Avoids silently orphaning memberships to an unknown role name.
81
+ const members = await databaseAdapter.findOrganizationMembers(auth.organizationId);
82
+ const inUseByMember = members.some((m) => m.role === name);
83
+ const invitations = await databaseAdapter.findOrganizationInvitations(auth.organizationId);
84
+ const inUseByInvitation = invitations.some((i) => i.role === name && !i.acceptedAt);
85
+ if (inUseByMember || inUseByInvitation) {
86
+ return json({
87
+ success: false,
88
+ error: 'Role in use',
89
+ message: `Cannot delete "${name}": reassign affected members or invitations first.`
90
+ }, { status: 409 });
91
+ }
92
+ const deleted = await databaseAdapter.deleteRole(auth.organizationId, name);
93
+ if (!deleted) {
94
+ return json({
95
+ success: false,
96
+ error: 'Not found',
97
+ message: `No role named "${name}" in this organization`
98
+ }, { status: 404 });
99
+ }
100
+ await rolesService.invalidate(auth.organizationId, name);
101
+ return json({ success: true, message: 'Role deleted' });
102
+ }
103
+ catch (error) {
104
+ cmsLogger.error('Failed to delete role:', error);
105
+ return json({
106
+ success: false,
107
+ error: 'Failed to delete role',
108
+ message: error instanceof Error ? error.message : 'Unknown error'
109
+ }, { status: 500 });
110
+ }
111
+ };
@@ -0,0 +1,4 @@
1
+ import type { RequestHandler } from '@sveltejs/kit';
2
+ export declare const GET: RequestHandler;
3
+ export declare const POST: RequestHandler;
4
+ //# sourceMappingURL=roles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roles.d.ts","sourceRoot":"","sources":["../../src/lib/routes/roles.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAgBpD,eAAO,MAAM,GAAG,EAAE,cAoBjB,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,cA0ElB,CAAC"}
@@ -0,0 +1,90 @@
1
+ // Aphex CMS Roles API Handlers
2
+ //
3
+ // GET /api/roles — list roles for the active org
4
+ // POST /api/roles — create a custom role (requires role.manage)
5
+ import { json } from '@sveltejs/kit';
6
+ import { cmsLogger } from '../utils/logger.js';
7
+ import { hasCapability, BUILTIN_ROLE_NAMES } from '../types/capabilities.js';
8
+ import { createRoleRequest } from '../api/schemas/roles.js';
9
+ function unauthorized() {
10
+ return json({ success: false, error: 'Unauthorized', message: 'Session authentication required' }, { status: 401 });
11
+ }
12
+ function forbidden(message) {
13
+ return json({ success: false, error: 'Forbidden', message }, { status: 403 });
14
+ }
15
+ export const GET = async ({ locals }) => {
16
+ try {
17
+ const { rolesService } = locals.aphexCMS;
18
+ const auth = locals.auth;
19
+ if (!auth || auth.type !== 'session')
20
+ return unauthorized();
21
+ const roles = await rolesService.listRoles(auth.organizationId);
22
+ return json({ success: true, data: roles });
23
+ }
24
+ catch (error) {
25
+ cmsLogger.error('Failed to list roles:', error);
26
+ return json({
27
+ success: false,
28
+ error: 'Failed to list roles',
29
+ message: error instanceof Error ? error.message : 'Unknown error'
30
+ }, { status: 500 });
31
+ }
32
+ };
33
+ export const POST = async ({ request, locals }) => {
34
+ try {
35
+ const { databaseAdapter, rolesService } = locals.aphexCMS;
36
+ const auth = locals.auth;
37
+ if (!auth || auth.type !== 'session')
38
+ return unauthorized();
39
+ if (!hasCapability(auth, 'role.manage')) {
40
+ return forbidden('You do not have permission to manage roles');
41
+ }
42
+ const rawBody = await request.json();
43
+ const parsed = createRoleRequest.safeParse(rawBody);
44
+ if (!parsed.success) {
45
+ return json({
46
+ success: false,
47
+ error: 'Invalid request body',
48
+ message: 'name and capabilities are required',
49
+ issues: parsed.error.issues
50
+ }, { status: 400 });
51
+ }
52
+ const body = parsed.data;
53
+ // Reject collisions with reserved built-in names — built-ins are seeded
54
+ // on every org; a matching custom row would never be reachable.
55
+ if (BUILTIN_ROLE_NAMES.includes(body.name)) {
56
+ return json({
57
+ success: false,
58
+ error: 'Reserved name',
59
+ message: `"${body.name}" is a built-in role name. Edit the existing role instead.`
60
+ }, { status: 409 });
61
+ }
62
+ const existing = await databaseAdapter.findRoleByName(auth.organizationId, body.name);
63
+ if (existing) {
64
+ return json({
65
+ success: false,
66
+ error: 'Conflict',
67
+ message: `A role named "${body.name}" already exists in this organization.`
68
+ }, { status: 409 });
69
+ }
70
+ const role = await databaseAdapter.createRole({
71
+ organizationId: auth.organizationId,
72
+ name: body.name,
73
+ description: body.description ?? null,
74
+ capabilities: body.capabilities,
75
+ isBuiltIn: false
76
+ });
77
+ // New role can't be in use yet, but invalidate the prefix just in case
78
+ // a prior lookup populated the cache with an empty fallback entry.
79
+ await rolesService.invalidate(auth.organizationId, body.name);
80
+ return json({ success: true, data: role }, { status: 201 });
81
+ }
82
+ catch (error) {
83
+ cmsLogger.error('Failed to create role:', error);
84
+ return json({
85
+ success: false,
86
+ error: 'Failed to create role',
87
+ message: error instanceof Error ? error.message : 'Unknown error'
88
+ }, { status: 500 });
89
+ }
90
+ };
@@ -15,4 +15,6 @@ export { GET as getOrganizationById, PATCH as updateOrganization, DELETE as dele
15
15
  export { POST as switchOrganization } from './routes/organizations-switch.js';
16
16
  export { GET as getOrganizationMembers, DELETE as removeMember, PATCH as updateMemberRole } from './routes/organizations-members.js';
17
17
  export { POST as inviteMember, DELETE as cancelInvitation } from './routes/organizations-invitations.js';
18
+ export { GET as getRoles, POST as createRole } from './routes/roles.js';
19
+ export { PATCH as updateRole, DELETE as deleteRole } from './routes/roles-by-name.js';
18
20
  //# sourceMappingURL=routes-exports.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"routes-exports.d.ts","sourceRoot":"","sources":["../src/lib/routes-exports.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,IAAI,YAAY,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACN,GAAG,IAAI,eAAe,EACtB,GAAG,IAAI,cAAc,EACrB,MAAM,IAAI,cAAc,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,EACN,GAAG,IAAI,mBAAmB,EAC1B,UAAU,IAAI,kBAAkB,EAChC,cAAc,IAAI,sBAAsB,EACxC,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,GAAG,IAAI,YAAY,EACnB,KAAK,IAAI,WAAW,EACpB,MAAM,IAAI,WAAW,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,GAAG,IAAI,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,IAAI,IAAI,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAGpF,OAAO,EAAE,GAAG,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,GAAG,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,GAAG,IAAI,gBAAgB,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC7F,OAAO,EACN,GAAG,IAAI,mBAAmB,EAC1B,KAAK,IAAI,kBAAkB,EAC3B,MAAM,IAAI,kBAAkB,EAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EACN,GAAG,IAAI,sBAAsB,EAC7B,MAAM,IAAI,YAAY,EACtB,KAAK,IAAI,gBAAgB,EACzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACN,IAAI,IAAI,YAAY,EACpB,MAAM,IAAI,gBAAgB,EAC1B,MAAM,oCAAoC,CAAC"}
1
+ {"version":3,"file":"routes-exports.d.ts","sourceRoot":"","sources":["../src/lib/routes-exports.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,GAAG,IAAI,YAAY,EAAE,IAAI,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACjF,OAAO,EACN,GAAG,IAAI,eAAe,EACtB,GAAG,IAAI,cAAc,EACrB,MAAM,IAAI,cAAc,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,IAAI,IAAI,eAAe,EAAE,MAAM,IAAI,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AAClG,OAAO,EACN,GAAG,IAAI,mBAAmB,EAC1B,UAAU,IAAI,kBAAkB,EAChC,cAAc,IAAI,sBAAsB,EACxC,MAAM,4BAA4B,CAAC;AAGpC,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,IAAI,IAAI,WAAW,EAAE,MAAM,iBAAiB,CAAC;AACxE,OAAO,EACN,GAAG,IAAI,YAAY,EACnB,KAAK,IAAI,WAAW,EACpB,MAAM,IAAI,WAAW,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,GAAG,IAAI,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,MAAM,IAAI,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,GAAG,IAAI,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,IAAI,IAAI,uBAAuB,EAAE,MAAM,mCAAmC,CAAC;AAGpF,OAAO,EAAE,GAAG,IAAI,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,GAAG,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAGlE,OAAO,EAAE,GAAG,IAAI,gBAAgB,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC7F,OAAO,EACN,GAAG,IAAI,mBAAmB,EAC1B,KAAK,IAAI,kBAAkB,EAC3B,MAAM,IAAI,kBAAkB,EAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,IAAI,IAAI,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EACN,GAAG,IAAI,sBAAsB,EAC7B,MAAM,IAAI,YAAY,EACtB,KAAK,IAAI,gBAAgB,EACzB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EACN,IAAI,IAAI,YAAY,EACpB,MAAM,IAAI,gBAAgB,EAC1B,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,GAAG,IAAI,QAAQ,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,KAAK,IAAI,UAAU,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,wBAAwB,CAAC"}
@@ -21,3 +21,6 @@ export { GET as getOrganizationById, PATCH as updateOrganization, DELETE as dele
21
21
  export { POST as switchOrganization } from './routes/organizations-switch.js';
22
22
  export { GET as getOrganizationMembers, DELETE as removeMember, PATCH as updateMemberRole } from './routes/organizations-members.js';
23
23
  export { POST as inviteMember, DELETE as cancelInvitation } from './routes/organizations-invitations.js';
24
+ // Role management routes
25
+ export { GET as getRoles, POST as createRole } from './routes/roles.js';
26
+ export { PATCH as updateRole, DELETE as deleteRole } from './routes/roles-by-name.js';
@@ -0,0 +1,8 @@
1
+ export interface SaveState {
2
+ readonly saving: boolean;
3
+ readonly hasUnsavedChanges: boolean;
4
+ readonly savedAgoText: string | null;
5
+ }
6
+ export declare function setSaveStateContext(state: SaveState): void;
7
+ export declare function getSaveStateContext(): SaveState | null;
8
+ //# sourceMappingURL=save-state-context.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"save-state-context.svelte.d.ts","sourceRoot":"","sources":["../src/lib/save-state-context.svelte.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,iBAAiB,EAAE,OAAO,CAAC;IACpC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,SAAS,QAEnD;AAED,wBAAgB,mBAAmB,IAAI,SAAS,GAAG,IAAI,CAEtD"}
@@ -0,0 +1,8 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const SAVE_STATE_KEY = Symbol('aphex-save-state');
3
+ export function setSaveStateContext(state) {
4
+ setContext(SAVE_STATE_KEY, state);
5
+ }
6
+ export function getSaveStateContext() {
7
+ return getContext(SAVE_STATE_KEY) ?? null;
8
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/lib/schema-utils/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAS,MAAM,kBAAkB,CAAC;AAmB1D;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAqMpE"}
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/lib/schema-utils/validator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAS,MAAM,kBAAkB,CAAC;AAmB1D;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,UAAU,EAAE,GAAG,IAAI,CAqNpE"}
@@ -103,6 +103,20 @@ export function validateSchemaReferences(schemas) {
103
103
  validateField(field, schema.name);
104
104
  }
105
105
  }
106
+ // Validate field.group references against schema.groups
107
+ if (schema.fields) {
108
+ const groupNames = new Set((schema.groups ?? []).map((g) => g.name));
109
+ for (const field of schema.fields) {
110
+ if (!field.group)
111
+ continue;
112
+ const refs = Array.isArray(field.group) ? field.group : [field.group];
113
+ for (const ref of refs) {
114
+ if (!groupNames.has(ref)) {
115
+ errors.push(`Schema "${schema.name}" field "${field.name}" references unknown group "${ref}". Declare it in schema.groups.`);
116
+ }
117
+ }
118
+ }
119
+ }
106
120
  // Validate preview config references
107
121
  if (schema.preview?.select) {
108
122
  const fieldNames = new Set(schema.fields?.map((f) => f.name) || []);
@@ -12,6 +12,7 @@ export * from '../storage/interfaces/index.js';
12
12
  export * from '../storage/providers/storage.js';
13
13
  export * from '../services/index.js';
14
14
  export { AssetService } from '../services/asset-service.js';
15
+ export { RolesService } from '../services/roles-service.js';
15
16
  export * from '../routes-exports.js';
16
17
  export * from '../schema-utils/index.js';
17
18
  export { createHashForPublishing } from '../utils/content-hash.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/server/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAE/B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,gBAAgB,CAAC;AAE/B,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAG5D,cAAc,wBAAwB,CAAC;AAGvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAG7C,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAIzD,cAAc,mBAAmB,CAAC;AAGlC,cAAc,uBAAuB,CAAC;AAGtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EACN,oBAAoB,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACN,QAAQ,EACR,cAAc,EACd,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/server/index.ts"],"names":[],"mappings":"AAIA,cAAc,gBAAgB,CAAC;AAE/B,cAAc,kBAAkB,CAAC;AAEjC,cAAc,gBAAgB,CAAC;AAE/B,cAAc,gBAAgB,CAAC;AAG/B,OAAO,EAAE,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpE,OAAO,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAG5C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAGtC,OAAO,EAAE,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AAG5D,cAAc,wBAAwB,CAAC;AAGvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC;AAG7C,cAAc,mBAAmB,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAIzD,cAAc,mBAAmB,CAAC;AAGlC,cAAc,uBAAuB,CAAC;AAGtC,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,OAAO,EACN,oBAAoB,EACpB,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,oBAAoB,EACzB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACN,QAAQ,EACR,cAAc,EACd,WAAW,EACX,aAAa,EACb,iBAAiB,EACjB,eAAe,EACf,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,aAAa,EAClB,MAAM,oBAAoB,CAAC"}