@aphexcms/cms-core 2.0.10 → 2.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/api-keys.d.ts +4 -0
- package/dist/api/api-keys.d.ts.map +1 -1
- package/dist/api/assets.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +1 -0
- package/dist/api/roles.d.ts +22 -0
- package/dist/api/roles.d.ts.map +1 -0
- package/dist/api/roles.js +26 -0
- package/dist/api/schemas/api-keys.d.ts +50 -4
- package/dist/api/schemas/api-keys.d.ts.map +1 -1
- package/dist/api/schemas/api-keys.js +22 -3
- package/dist/api/schemas/organizations.d.ts +4 -22
- package/dist/api/schemas/organizations.d.ts.map +1 -1
- package/dist/api/schemas/organizations.js +13 -2
- package/dist/api/schemas/roles.d.ts +77 -0
- package/dist/api/schemas/roles.d.ts.map +1 -0
- package/dist/api/schemas/roles.js +42 -0
- package/dist/app-augment.d.ts +32 -0
- package/dist/app-augment.d.ts.map +1 -0
- package/dist/app-augment.js +18 -0
- package/dist/auth/auth-hooks.d.ts +2 -1
- package/dist/auth/auth-hooks.d.ts.map +1 -1
- package/dist/auth/auth-hooks.js +22 -2
- package/dist/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +4 -0
- package/dist/components/AdminApp.svelte +300 -140
- package/dist/components/AdminApp.svelte.d.ts +8 -0
- package/dist/components/AdminApp.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentEditor.svelte +633 -350
- package/dist/components/admin/DocumentEditor.svelte.d.ts +2 -0
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/DocumentVersionPanel.svelte +46 -20
- package/dist/components/admin/DocumentVersionPanel.svelte.d.ts.map +1 -1
- package/dist/components/admin/MediaBrowser.svelte +70 -30
- package/dist/components/admin/MediaBrowser.svelte.d.ts.map +1 -1
- package/dist/components/admin/ObjectModal.svelte +70 -95
- package/dist/components/admin/ObjectModal.svelte.d.ts +1 -2
- package/dist/components/admin/ObjectModal.svelte.d.ts.map +1 -1
- package/dist/components/admin/PermissionsDebug.svelte +119 -0
- package/dist/components/admin/PermissionsDebug.svelte.d.ts +4 -0
- package/dist/components/admin/PermissionsDebug.svelte.d.ts.map +1 -0
- package/dist/components/admin/SchemaField.svelte +3 -1
- package/dist/components/admin/SchemaField.svelte.d.ts.map +1 -1
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte +8 -10
- package/dist/components/admin/confirm-dialog/ConfirmDialogHost.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ArrayField.svelte +104 -108
- package/dist/components/admin/fields/ArrayField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/FileField.svelte +22 -17
- package/dist/components/admin/fields/FileField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ImageField.svelte +21 -15
- package/dist/components/admin/fields/ImageField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/ReferenceField.svelte +142 -112
- package/dist/components/admin/fields/ReferenceField.svelte.d.ts.map +1 -1
- package/dist/components/admin/fields/TextareaField.svelte +4 -3
- package/dist/components/admin/fields/TextareaField.svelte.d.ts +2 -2
- package/dist/components/admin/fields/TextareaField.svelte.d.ts.map +1 -1
- package/dist/components/layout/Sidebar.svelte +21 -11
- package/dist/components/layout/Sidebar.svelte.d.ts.map +1 -1
- package/dist/components/layout/sidebar/NavMain.svelte +1 -0
- package/dist/db/interfaces/document.d.ts.map +1 -1
- package/dist/db/interfaces/index.d.ts +3 -1
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/organization.d.ts +1 -1
- package/dist/db/interfaces/organization.d.ts.map +1 -1
- package/dist/db/interfaces/role.d.ts +25 -0
- package/dist/db/interfaces/role.d.ts.map +1 -0
- package/dist/db/interfaces/role.js +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +5 -0
- package/dist/field-access.d.ts +30 -0
- package/dist/field-access.d.ts.map +1 -0
- package/dist/field-access.js +79 -0
- package/dist/hooks.d.ts +2 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +19 -13
- package/dist/lib/api/api-keys.d.ts +4 -0
- package/dist/lib/api/api-keys.d.ts.map +1 -1
- package/dist/lib/api/api-keys.js.map +1 -1
- package/dist/lib/api/assets.d.ts.map +1 -1
- package/dist/lib/api/assets.js.map +1 -1
- package/dist/lib/api/index.d.ts +1 -0
- package/dist/lib/api/index.d.ts.map +1 -1
- package/dist/lib/api/index.js +1 -0
- package/dist/lib/api/index.js.map +1 -1
- package/dist/lib/api/roles.d.ts +22 -0
- package/dist/lib/api/roles.d.ts.map +1 -0
- package/dist/lib/api/roles.js +27 -0
- package/dist/lib/api/roles.js.map +1 -0
- package/dist/lib/api/schemas/api-keys.d.ts +50 -4
- package/dist/lib/api/schemas/api-keys.d.ts.map +1 -1
- package/dist/lib/api/schemas/api-keys.js +22 -3
- package/dist/lib/api/schemas/api-keys.js.map +1 -1
- package/dist/lib/api/schemas/organizations.d.ts +4 -22
- package/dist/lib/api/schemas/organizations.d.ts.map +1 -1
- package/dist/lib/api/schemas/organizations.js +13 -2
- package/dist/lib/api/schemas/organizations.js.map +1 -1
- package/dist/lib/api/schemas/roles.d.ts +77 -0
- package/dist/lib/api/schemas/roles.d.ts.map +1 -0
- package/dist/lib/api/schemas/roles.js +43 -0
- package/dist/lib/api/schemas/roles.js.map +1 -0
- package/dist/lib/app-augment.d.ts +32 -0
- package/dist/lib/app-augment.d.ts.map +1 -0
- package/dist/lib/app-augment.js +19 -0
- package/dist/lib/app-augment.js.map +1 -0
- package/dist/lib/auth/auth-hooks.d.ts +2 -1
- package/dist/lib/auth/auth-hooks.d.ts.map +1 -1
- package/dist/lib/auth/auth-hooks.js +22 -2
- package/dist/lib/auth/auth-hooks.js.map +1 -1
- package/dist/lib/client/index.d.ts +2 -0
- package/dist/lib/client/index.d.ts.map +1 -1
- package/dist/lib/client/index.js +4 -0
- package/dist/lib/client/index.js.map +1 -1
- package/dist/lib/db/interfaces/document.d.ts.map +1 -1
- package/dist/lib/db/interfaces/index.d.ts +3 -1
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/organization.d.ts +1 -1
- package/dist/lib/db/interfaces/organization.d.ts.map +1 -1
- package/dist/lib/db/interfaces/role.d.ts +25 -0
- package/dist/lib/db/interfaces/role.d.ts.map +1 -0
- package/dist/lib/db/interfaces/role.js +2 -0
- package/dist/lib/db/interfaces/role.js.map +1 -0
- package/dist/lib/engine.d.ts.map +1 -1
- package/dist/lib/engine.js +5 -0
- package/dist/lib/engine.js.map +1 -1
- package/dist/lib/field-access.d.ts +30 -0
- package/dist/lib/field-access.d.ts.map +1 -0
- package/dist/lib/field-access.js +80 -0
- package/dist/lib/field-access.js.map +1 -0
- package/dist/lib/hooks.d.ts +2 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +19 -13
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/local-api/collection-api.d.ts +2 -0
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +98 -30
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/local-api/index.d.ts.map +1 -1
- package/dist/lib/local-api/index.js.map +1 -1
- package/dist/lib/local-api/permissions.d.ts +26 -26
- package/dist/lib/local-api/permissions.d.ts.map +1 -1
- package/dist/lib/local-api/permissions.js +122 -80
- package/dist/lib/local-api/permissions.js.map +1 -1
- package/dist/lib/permissions-context.svelte.d.ts +44 -0
- package/dist/lib/permissions-context.svelte.d.ts.map +1 -0
- package/dist/lib/permissions-context.svelte.js +80 -0
- package/dist/lib/permissions-context.svelte.js.map +1 -0
- package/dist/lib/routes/assets.d.ts.map +1 -1
- package/dist/lib/routes/assets.js.map +1 -1
- package/dist/lib/routes/document-versions.d.ts.map +1 -1
- package/dist/lib/routes/document-versions.js.map +1 -1
- package/dist/lib/routes/organizations-by-id.d.ts.map +1 -1
- package/dist/lib/routes/organizations-by-id.js +6 -3
- package/dist/lib/routes/organizations-by-id.js.map +1 -1
- package/dist/lib/routes/organizations-invitations.d.ts.map +1 -1
- package/dist/lib/routes/organizations-invitations.js +17 -7
- package/dist/lib/routes/organizations-invitations.js.map +1 -1
- package/dist/lib/routes/organizations-members.d.ts.map +1 -1
- package/dist/lib/routes/organizations-members.js +15 -7
- package/dist/lib/routes/organizations-members.js.map +1 -1
- package/dist/lib/routes/organizations.d.ts.map +1 -1
- package/dist/lib/routes/organizations.js +3 -0
- package/dist/lib/routes/organizations.js.map +1 -1
- package/dist/lib/routes/roles-by-name.d.ts +4 -0
- package/dist/lib/routes/roles-by-name.d.ts.map +1 -0
- package/dist/lib/routes/roles-by-name.js +112 -0
- package/dist/lib/routes/roles-by-name.js.map +1 -0
- package/dist/lib/routes/roles.d.ts +4 -0
- package/dist/lib/routes/roles.d.ts.map +1 -0
- package/dist/lib/routes/roles.js +91 -0
- package/dist/lib/routes/roles.js.map +1 -0
- package/dist/lib/routes-exports.d.ts +2 -0
- package/dist/lib/routes-exports.d.ts.map +1 -1
- package/dist/lib/routes-exports.js +3 -0
- package/dist/lib/routes-exports.js.map +1 -1
- package/dist/lib/save-state-context.svelte.d.ts +8 -0
- package/dist/lib/save-state-context.svelte.d.ts.map +1 -0
- package/dist/lib/save-state-context.svelte.js +9 -0
- package/dist/lib/save-state-context.svelte.js.map +1 -0
- package/dist/lib/schema-utils/validator.d.ts.map +1 -1
- package/dist/lib/schema-utils/validator.js +14 -0
- package/dist/lib/schema-utils/validator.js.map +1 -1
- package/dist/lib/server/index.d.ts +1 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +1 -0
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/services/index.d.ts +1 -0
- package/dist/lib/services/index.d.ts.map +1 -1
- package/dist/lib/services/index.js +1 -0
- package/dist/lib/services/index.js.map +1 -1
- package/dist/lib/services/roles-service.d.ts +35 -0
- package/dist/lib/services/roles-service.d.ts.map +1 -0
- package/dist/lib/services/roles-service.js +91 -0
- package/dist/lib/services/roles-service.js.map +1 -0
- package/dist/lib/services/version-service.d.ts.map +1 -1
- package/dist/lib/services/version-service.js.map +1 -1
- package/dist/lib/types/auth.d.ts +43 -9
- package/dist/lib/types/auth.d.ts.map +1 -1
- package/dist/lib/types/auth.js +31 -26
- package/dist/lib/types/auth.js.map +1 -1
- package/dist/lib/types/capabilities.d.ts +104 -0
- package/dist/lib/types/capabilities.d.ts.map +1 -0
- package/dist/lib/types/capabilities.js +217 -0
- package/dist/lib/types/capabilities.js.map +1 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/types/organization.d.ts +13 -4
- package/dist/lib/types/organization.d.ts.map +1 -1
- package/dist/lib/types/schemas.d.ts +71 -0
- package/dist/lib/types/schemas.d.ts.map +1 -1
- package/dist/lib/types/sidebar.d.ts +1 -1
- package/dist/lib/types/sidebar.d.ts.map +1 -1
- package/dist/lib/utils/mime-detect.d.ts.map +1 -1
- package/dist/lib/utils/mime-detect.js +28 -6
- package/dist/lib/utils/mime-detect.js.map +1 -1
- package/dist/local-api/collection-api.d.ts +2 -0
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +98 -30
- package/dist/local-api/index.d.ts.map +1 -1
- package/dist/local-api/permissions.d.ts +26 -26
- package/dist/local-api/permissions.d.ts.map +1 -1
- package/dist/local-api/permissions.js +122 -80
- package/dist/permissions-context.svelte.d.ts +44 -0
- package/dist/permissions-context.svelte.d.ts.map +1 -0
- package/dist/permissions-context.svelte.js +79 -0
- package/dist/plugins/README.md +20 -20
- package/dist/routes/assets.d.ts.map +1 -1
- package/dist/routes/document-versions.d.ts.map +1 -1
- package/dist/routes/organizations-by-id.d.ts.map +1 -1
- package/dist/routes/organizations-by-id.js +6 -3
- package/dist/routes/organizations-invitations.d.ts.map +1 -1
- package/dist/routes/organizations-invitations.js +17 -7
- package/dist/routes/organizations-members.d.ts.map +1 -1
- package/dist/routes/organizations-members.js +15 -7
- package/dist/routes/organizations.d.ts.map +1 -1
- package/dist/routes/organizations.js +3 -0
- package/dist/routes/roles-by-name.d.ts +4 -0
- package/dist/routes/roles-by-name.d.ts.map +1 -0
- package/dist/routes/roles-by-name.js +111 -0
- package/dist/routes/roles.d.ts +4 -0
- package/dist/routes/roles.d.ts.map +1 -0
- package/dist/routes/roles.js +90 -0
- package/dist/routes-exports.d.ts +2 -0
- package/dist/routes-exports.d.ts.map +1 -1
- package/dist/routes-exports.js +3 -0
- package/dist/save-state-context.svelte.d.ts +8 -0
- package/dist/save-state-context.svelte.d.ts.map +1 -0
- package/dist/save-state-context.svelte.js +8 -0
- package/dist/schema-utils/validator.d.ts.map +1 -1
- package/dist/schema-utils/validator.js +14 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -0
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +1 -0
- package/dist/services/roles-service.d.ts +35 -0
- package/dist/services/roles-service.d.ts.map +1 -0
- package/dist/services/roles-service.js +90 -0
- package/dist/services/version-service.d.ts.map +1 -1
- package/dist/types/auth.d.ts +43 -9
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js +31 -26
- package/dist/types/capabilities.d.ts +104 -0
- package/dist/types/capabilities.d.ts.map +1 -0
- package/dist/types/capabilities.js +216 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/organization.d.ts +13 -4
- package/dist/types/organization.d.ts.map +1 -1
- package/dist/types/schemas.d.ts +71 -0
- package/dist/types/schemas.d.ts.map +1 -1
- package/dist/types/sidebar.d.ts +1 -1
- package/dist/types/sidebar.d.ts.map +1 -1
- package/dist/utils/mime-detect.d.ts.map +1 -1
- package/dist/utils/mime-detect.js +28 -6
- 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
|
+
}
|
package/dist/plugins/README.md
CHANGED
|
@@ -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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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,
|
|
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,
|
|
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;
|
|
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
|
-
//
|
|
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 || (
|
|
80
|
+
if (!membership || !hasCapability(auth, 'org.settings')) {
|
|
78
81
|
return json({
|
|
79
82
|
success: false,
|
|
80
83
|
error: 'Forbidden',
|
|
81
|
-
message: '
|
|
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;
|
|
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
|
-
|
|
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: '
|
|
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
|
|
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
|
-
|
|
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: '
|
|
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;
|
|
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
|
-
|
|
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: '
|
|
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
|
-
|
|
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: '
|
|
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
|
|
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,
|
|
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 @@
|
|
|
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 @@
|
|
|
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
|
+
};
|
package/dist/routes-exports.d.ts
CHANGED
|
@@ -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"}
|
package/dist/routes-exports.js
CHANGED
|
@@ -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,
|
|
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) || []);
|
package/dist/server/index.d.ts
CHANGED
|
@@ -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"}
|