create-aphex 0.1.1 → 0.2.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 (104) hide show
  1. package/dist/index.js +9 -88
  2. package/package.json +4 -4
  3. package/templates/base/.dockerignore +0 -44
  4. package/templates/base/.env.example +0 -38
  5. package/templates/base/CHANGELOG.md +0 -119
  6. package/templates/base/Dockerfile +0 -69
  7. package/templates/base/README.md +0 -147
  8. package/templates/base/aphex.config.ts +0 -45
  9. package/templates/base/docker-compose.yml +0 -31
  10. package/templates/base/drizzle/0000_tiny_redwing.sql +0 -226
  11. package/templates/base/drizzle/meta/0000_snapshot.json +0 -1379
  12. package/templates/base/drizzle/meta/_journal.json +0 -13
  13. package/templates/base/drizzle.config.ts +0 -17
  14. package/templates/base/package.json +0 -81
  15. package/templates/base/prod.docker-compose.yml +0 -61
  16. package/templates/base/src/app.css +0 -32
  17. package/templates/base/src/app.d.ts +0 -26
  18. package/templates/base/src/app.html +0 -11
  19. package/templates/base/src/hooks.server.ts +0 -52
  20. package/templates/base/src/lib/assets/favicon.svg +0 -5
  21. package/templates/base/src/lib/auth-client.ts +0 -19
  22. package/templates/base/src/lib/index.ts +0 -1
  23. package/templates/base/src/lib/schemaTypes/index.ts +0 -11
  24. package/templates/base/src/lib/schemaTypes/post.ts +0 -47
  25. package/templates/base/src/lib/server/auth/better-auth/instance.ts +0 -165
  26. package/templates/base/src/lib/server/auth/index.ts +0 -25
  27. package/templates/base/src/lib/server/auth/instance.ts +0 -7
  28. package/templates/base/src/lib/server/auth/service.ts +0 -486
  29. package/templates/base/src/lib/server/cache/index.ts +0 -10
  30. package/templates/base/src/lib/server/db/auth-schema.ts +0 -86
  31. package/templates/base/src/lib/server/db/cms-schema.ts +0 -23
  32. package/templates/base/src/lib/server/db/index.ts +0 -55
  33. package/templates/base/src/lib/server/db/schema.ts +0 -3
  34. package/templates/base/src/lib/server/email/components/EmailLayout.svelte +0 -24
  35. package/templates/base/src/lib/server/email/components/EmailVerification.svelte +0 -26
  36. package/templates/base/src/lib/server/email/components/Invitation.svelte +0 -30
  37. package/templates/base/src/lib/server/email/components/PasswordReset.svelte +0 -28
  38. package/templates/base/src/lib/server/email/index.ts +0 -28
  39. package/templates/base/src/lib/server/email/invitation-hook.ts +0 -56
  40. package/templates/base/src/lib/server/email/renderer.ts +0 -13
  41. package/templates/base/src/lib/server/email/templates/email-verification.ts +0 -8
  42. package/templates/base/src/lib/server/email/templates/invitation.ts +0 -8
  43. package/templates/base/src/lib/server/email/templates/password-reset.ts +0 -7
  44. package/templates/base/src/lib/server/services/organization.ts +0 -68
  45. package/templates/base/src/lib/server/storage/index.ts +0 -28
  46. package/templates/base/src/lib/stores/activeTab.svelte.ts +0 -14
  47. package/templates/base/src/lib/utils/imageBuilder.ts +0 -3
  48. package/templates/base/src/lib/utils/slug.ts +0 -33
  49. package/templates/base/src/routes/(protected)/admin/+layout.server.ts +0 -86
  50. package/templates/base/src/routes/(protected)/admin/+layout.svelte +0 -78
  51. package/templates/base/src/routes/(protected)/admin/+page.server.ts +0 -60
  52. package/templates/base/src/routes/(protected)/admin/+page.svelte +0 -34
  53. package/templates/base/src/routes/(protected)/admin/organizations/+page.server.ts +0 -39
  54. package/templates/base/src/routes/(protected)/admin/organizations/+page.svelte +0 -31
  55. package/templates/base/src/routes/(protected)/admin/organizations/_components/CreateOrganization.svelte +0 -141
  56. package/templates/base/src/routes/(protected)/admin/organizations/_components/OrganizationsList.svelte +0 -102
  57. package/templates/base/src/routes/(protected)/admin/settings/+layout.server.ts +0 -42
  58. package/templates/base/src/routes/(protected)/admin/settings/+layout.svelte +0 -116
  59. package/templates/base/src/routes/(protected)/admin/settings/+page.server.ts +0 -16
  60. package/templates/base/src/routes/(protected)/admin/settings/+page.svelte +0 -32
  61. package/templates/base/src/routes/(protected)/admin/settings/_components/AccountSettings.svelte +0 -177
  62. package/templates/base/src/routes/(protected)/admin/settings/_components/ApiKeysSettings.svelte +0 -472
  63. package/templates/base/src/routes/(protected)/admin/settings/_components/OrganizationsSettings.svelte +0 -182
  64. package/templates/base/src/routes/(protected)/admin/settings/account/+page.server.ts +0 -25
  65. package/templates/base/src/routes/(protected)/admin/settings/account/+page.svelte +0 -23
  66. package/templates/base/src/routes/(protected)/admin/settings/api-keys/+page.server.ts +0 -54
  67. package/templates/base/src/routes/(protected)/admin/settings/api-keys/+page.svelte +0 -14
  68. package/templates/base/src/routes/(protected)/admin/settings/members/+page.server.ts +0 -31
  69. package/templates/base/src/routes/(protected)/admin/settings/members/+page.svelte +0 -338
  70. package/templates/base/src/routes/(protected)/admin/settings/roles/+page.server.ts +0 -17
  71. package/templates/base/src/routes/(protected)/admin/settings/roles/+page.svelte +0 -339
  72. package/templates/base/src/routes/+layout.svelte +0 -12
  73. package/templates/base/src/routes/+page.svelte +0 -2
  74. package/templates/base/src/routes/api/[...slug]/+server.ts +0 -35
  75. package/templates/base/src/routes/api/instance-settings/+server.ts +0 -70
  76. package/templates/base/src/routes/api/invitations/+server.ts +0 -54
  77. package/templates/base/src/routes/api/invitations/[id]/accept/+server.ts +0 -54
  78. package/templates/base/src/routes/api/invitations/[id]/reject/+server.ts +0 -49
  79. package/templates/base/src/routes/api/settings/api-keys/+server.ts +0 -57
  80. package/templates/base/src/routes/api/settings/api-keys/[id]/+server.ts +0 -53
  81. package/templates/base/src/routes/god-mode/+layout.server.ts +0 -32
  82. package/templates/base/src/routes/god-mode/+layout.svelte +0 -155
  83. package/templates/base/src/routes/god-mode/+page.server.ts +0 -10
  84. package/templates/base/src/routes/god-mode/+page.svelte +0 -32
  85. package/templates/base/src/routes/god-mode/_components/CreateOrganization.svelte +0 -141
  86. package/templates/base/src/routes/god-mode/_components/OrganizationsList.svelte +0 -169
  87. package/templates/base/src/routes/god-mode/organizations/+page.server.ts +0 -43
  88. package/templates/base/src/routes/god-mode/organizations/+page.svelte +0 -74
  89. package/templates/base/src/routes/invitations/+page.server.ts +0 -48
  90. package/templates/base/src/routes/invitations/+page.svelte +0 -264
  91. package/templates/base/src/routes/invite/[token]/+page.server.ts +0 -59
  92. package/templates/base/src/routes/invite/[token]/+page.svelte +0 -109
  93. package/templates/base/src/routes/login/+page.server.ts +0 -14
  94. package/templates/base/src/routes/login/+page.svelte +0 -332
  95. package/templates/base/src/routes/media/[id]/[filename]/+server.ts +0 -3
  96. package/templates/base/src/routes/reset-password/[token]/+page.server.ts +0 -15
  97. package/templates/base/src/routes/reset-password/[token]/+page.svelte +0 -179
  98. package/templates/base/src/routes/verify-email/+page.svelte +0 -41
  99. package/templates/base/static/images/aphex-darkmode.png +0 -0
  100. package/templates/base/static/images/aphex-lightmode.png +0 -0
  101. package/templates/base/static/robots.txt +0 -3
  102. package/templates/base/svelte.config.js +0 -19
  103. package/templates/base/tsconfig.json +0 -20
  104. package/templates/base/vite.config.ts +0 -138
@@ -1,23 +0,0 @@
1
- <script lang="ts">
2
- import type { PageData } from './$types';
3
- import AccountSettings from '../_components/AccountSettings.svelte';
4
-
5
- let { data }: { data: PageData } = $props();
6
- </script>
7
-
8
- <svelte:head>
9
- <title>Aphex CMS - Account</title>
10
- </svelte:head>
11
-
12
- <div class="grid gap-6">
13
- <div class="hidden sm:block">
14
- <h2 class="text-xl font-semibold">Profile</h2>
15
- <p class="text-muted-foreground text-sm">Manage your personal account settings.</p>
16
- </div>
17
-
18
- <AccountSettings
19
- user={data.user}
20
- userPreferences={data.userPreferences}
21
- hasChildOrganizations={data.hasChildOrganizations}
22
- />
23
- </div>
@@ -1,54 +0,0 @@
1
- import type { PageServerLoad } from './$types';
2
- import { drizzleDb } from '$lib/server/db';
3
- import { apikey } from '$lib/server/db/auth-schema';
4
- import { eq } from 'drizzle-orm';
5
- import { error } from '@sveltejs/kit';
6
- import { hasCapability } from '@aphexcms/cms-core';
7
-
8
- export const load: PageServerLoad = async ({ locals }) => {
9
- const auth = locals.auth;
10
-
11
- if (!auth || auth.type !== 'session') {
12
- throw new Error('No session found');
13
- }
14
-
15
- if (!hasCapability(auth, 'apiKey.manage')) {
16
- throw error(403, 'You do not have permission to manage API keys');
17
- }
18
-
19
- const userApiKeys = await drizzleDb.query.apikey.findMany({
20
- where: eq(apikey.referenceId, auth.user.id),
21
- columns: {
22
- id: true,
23
- name: true,
24
- metadata: true,
25
- expiresAt: true,
26
- lastRequest: true,
27
- createdAt: true
28
- },
29
- orderBy: (apikey, { desc }) => [desc(apikey.createdAt)]
30
- });
31
-
32
- const apiKeysWithPermissions = userApiKeys
33
- .map((key) => {
34
- let metadata: any = key.metadata;
35
- if (typeof metadata === 'string') {
36
- metadata = JSON.parse(metadata);
37
- if (typeof metadata === 'string') {
38
- metadata = JSON.parse(metadata);
39
- }
40
- }
41
- metadata = metadata || null;
42
-
43
- return {
44
- ...key,
45
- permissions: metadata?.permissions || [],
46
- organizationId: metadata?.organizationId
47
- };
48
- })
49
- .filter((key) => auth.type === 'session' && key.organizationId === auth.organizationId);
50
-
51
- return {
52
- apiKeys: apiKeysWithPermissions
53
- };
54
- };
@@ -1,14 +0,0 @@
1
- <script lang="ts">
2
- import type { PageData } from './$types';
3
- import ApiKeysSettings from '../_components/ApiKeysSettings.svelte';
4
-
5
- let { data }: { data: PageData } = $props();
6
- </script>
7
-
8
- <svelte:head>
9
- <title>Aphex CMS - API Keys</title>
10
- </svelte:head>
11
-
12
- <div class="grid gap-6">
13
- <ApiKeysSettings apiKeys={data.apiKeys} organizationRole={data.user.organizationRole} />
14
- </div>
@@ -1,31 +0,0 @@
1
- import type { PageServerLoad } from './$types';
2
-
3
- export const load: PageServerLoad = async ({ locals }) => {
4
- const auth = locals.auth;
5
-
6
- if (!auth || auth.type !== 'session') {
7
- throw new Error('No session found');
8
- }
9
-
10
- const { databaseAdapter, rolesService } = locals.aphexCMS;
11
- let pendingInvitations: any[] = [];
12
-
13
- if (auth.organizationId) {
14
- const invitations = await databaseAdapter.findOrganizationInvitations(auth.organizationId);
15
- pendingInvitations = invitations.filter(
16
- (inv: any) => !inv.acceptedAt && inv.expiresAt && inv.expiresAt > new Date()
17
- );
18
- }
19
-
20
- // Load roles so the invite dropdown reflects custom roles defined for this
21
- // org. Owners are excluded — ownership is transferred, not invited.
22
- const allRoles = auth.organizationId ? await rolesService.listRoles(auth.organizationId) : [];
23
- const inviteRoles = allRoles
24
- .filter((r) => r.name !== 'owner')
25
- .map((r) => ({ name: r.name, description: r.description }));
26
-
27
- return {
28
- pendingInvitations,
29
- inviteRoles
30
- };
31
- };
@@ -1,338 +0,0 @@
1
- <script lang="ts">
2
- import * as Card from '@aphexcms/ui/shadcn/card';
3
- import * as Select from '@aphexcms/ui/shadcn/select';
4
- import * as Avatar from '@aphexcms/ui/shadcn/avatar';
5
- import { Button } from '@aphexcms/ui/shadcn/button';
6
- import { Input } from '@aphexcms/ui/shadcn/input';
7
- import { Badge } from '@aphexcms/ui/shadcn/badge';
8
- import { confirmDialog, usePermissions } from '@aphexcms/cms-core/client';
9
- import { invalidateAll } from '$app/navigation';
10
- import { Mail, Crown, Shield, Edit, Eye, Users, Send } from '@lucide/svelte';
11
- import { organizations } from '@aphexcms/cms-core/client';
12
- import { toast } from 'svelte-sonner';
13
- import type { PageData } from './$types';
14
-
15
- let { data }: { data: PageData } = $props();
16
-
17
- const activeOrganization = $derived(data.activeOrganization);
18
- const currentUserId = $derived(data.user.id);
19
- const pendingInvitations = $derived((data as any).pendingInvitations ?? []);
20
- const inviteRoles = $derived(
21
- ((data as any).inviteRoles ?? []) as Array<{ name: string; description: string | null }>
22
- );
23
-
24
- let inviteEmail = $state('');
25
- let inviteRole = $state<string>('editor');
26
- let isInviting = $state(false);
27
-
28
- // Ensure the selected invite role always exists in the available set.
29
- // Falls back to the first option if the previously-selected role was
30
- // deleted while the page was open.
31
- $effect(() => {
32
- if (inviteRoles.length > 0 && !inviteRoles.some((r) => r.name === inviteRole)) {
33
- inviteRole = inviteRoles[0].name;
34
- }
35
- });
36
-
37
- const currentUserRole = $derived(
38
- activeOrganization?.members.find((m: any) => m.userId === currentUserId)?.role
39
- );
40
-
41
- // Per-capability gates — replaces the coarse "owner/admin" role check.
42
- // Split per action so custom roles with just `member.invite` can invite
43
- // but not remove, etc.
44
- const perms = usePermissions();
45
- const canInvite = $derived(perms.can('member.invite'));
46
- const canRemoveMembers = $derived(perms.can('member.remove'));
47
-
48
- // function getRoleIcon(role: string) {
49
- // switch (role) {
50
- // case 'owner':
51
- // return Crown;
52
- // case 'admin':
53
- // return Shield;
54
- // case 'editor':
55
- // return Edit;
56
- // case 'viewer':
57
- // return Eye;
58
- // default:
59
- // return Users;
60
- // }
61
- // }
62
-
63
- function getRoleBadgeVariant(role: string): 'default' | 'secondary' | 'outline' {
64
- switch (role) {
65
- case 'owner':
66
- return 'default';
67
- case 'admin':
68
- return 'secondary';
69
- default:
70
- return 'outline';
71
- }
72
- }
73
-
74
- function getInitials(name: string | null, email: string): string {
75
- if (name) {
76
- return name
77
- .split(' ')
78
- .map((w) => w[0])
79
- .join('')
80
- .toUpperCase()
81
- .slice(0, 2);
82
- }
83
- return email[0].toUpperCase();
84
- }
85
-
86
- async function inviteMember() {
87
- if (!inviteEmail.trim()) return;
88
-
89
- isInviting = true;
90
- try {
91
- const result = await organizations.inviteMember({
92
- email: inviteEmail.trim(),
93
- role: inviteRole
94
- });
95
-
96
- if (!result.success) {
97
- throw new Error(result.error || result.message || 'Failed to invite member');
98
- }
99
-
100
- toast.success(`Invitation sent to ${inviteEmail.trim()}`);
101
- inviteEmail = '';
102
- inviteRole = 'editor';
103
- await invalidateAll();
104
- } catch (error) {
105
- toast.error(error instanceof Error ? error.message : 'Failed to invite member');
106
- } finally {
107
- isInviting = false;
108
- }
109
- }
110
-
111
- async function cancelInvitation(invitationId: string, email: string) {
112
- const confirmCancelInvitation = await confirmDialog({
113
- title: `Cancel invitation for ${email}?`,
114
- description:
115
- 'The user will not be able to join the organization if the invitation is revoked. They can still re-join with a new invitation later.',
116
- confirmText: 'Revoke',
117
- variant: 'destructive'
118
- });
119
- if (!confirmCancelInvitation) return;
120
-
121
- try {
122
- const result = await organizations.cancelInvitation({ invitationId });
123
- if (!result.success) throw new Error(result.error || 'Failed to cancel invitation');
124
- toast.success(`Invitation for ${email} revoked`);
125
- await invalidateAll();
126
- } catch (error) {
127
- toast.error(error instanceof Error ? error.message : 'Failed to cancel invitation');
128
- }
129
- }
130
-
131
- async function removeMember(userId: string, userName: string) {
132
- const confirmed = await confirmDialog({
133
- title: `Remove ${userName}?`,
134
- description: `${userName} will lose access to this organization. They can be re-invited later.`,
135
- confirmText: 'Remove',
136
- variant: 'destructive'
137
- });
138
- if (!confirmed) return;
139
-
140
- try {
141
- const result = await organizations.removeMember({ userId });
142
- if (!result.success) throw new Error(result.error || 'Failed to remove member');
143
- toast.success(`${userName} has been removed`);
144
- await invalidateAll();
145
- } catch (error) {
146
- toast.error(error instanceof Error ? error.message : 'Failed to remove member');
147
- }
148
- }
149
- </script>
150
-
151
- <svelte:head>
152
- <title>Aphex CMS - Members</title>
153
- </svelte:head>
154
-
155
- <div class="grid gap-6">
156
- <div class="hidden sm:block">
157
- <h2 class="text-xl font-semibold">Members</h2>
158
- <p class="text-muted-foreground text-sm">
159
- Manage members and invitations for your organization.
160
- </p>
161
- </div>
162
-
163
- {#if !activeOrganization}
164
- <Card.Root>
165
- <Card.Content class="py-12 text-center">
166
- <Users class="text-muted-foreground mx-auto mb-3 h-10 w-10" />
167
- <p class="text-muted-foreground text-lg">No active organization</p>
168
- </Card.Content>
169
- </Card.Root>
170
- {:else}
171
- <!-- Invite Member -->
172
- {#if canInvite}
173
- <Card.Root>
174
- <Card.Header>
175
- <Card.Title class="flex items-center gap-2">
176
- <Send class="h-4 w-4" />
177
- Invite Member
178
- </Card.Title>
179
- <Card.Description>
180
- Send an invite to add someone to {activeOrganization.name}
181
- </Card.Description>
182
- </Card.Header>
183
- <Card.Content>
184
- <div class="flex items-end gap-3">
185
- <div class="flex-1">
186
- <Input
187
- id="invite-email"
188
- type="email"
189
- bind:value={inviteEmail}
190
- placeholder="email@example.com"
191
- />
192
- </div>
193
- <div class="w-[160px]">
194
- <Select.Root type="single" name="role" bind:value={inviteRole}>
195
- <Select.Trigger>
196
- <span class="capitalize">{inviteRole}</span>
197
- </Select.Trigger>
198
- <Select.Content>
199
- {#each inviteRoles as option (option.name)}
200
- <Select.Item value={option.name} label={option.name}>
201
- <div>
202
- <div class="font-medium capitalize">{option.name}</div>
203
- {#if option.description}
204
- <div class="text-muted-foreground text-xs">{option.description}</div>
205
- {/if}
206
- </div>
207
- </Select.Item>
208
- {/each}
209
- </Select.Content>
210
- </Select.Root>
211
- </div>
212
- <Button onclick={inviteMember} disabled={isInviting}>
213
- {isInviting ? 'Sending...' : 'Send Invite'}
214
- </Button>
215
- </div>
216
- </Card.Content>
217
- </Card.Root>
218
- {/if}
219
-
220
- <!-- Pending Invitations -->
221
- {#if pendingInvitations.length > 0}
222
- <Card.Root class="border-dashed">
223
- <Card.Header>
224
- <div class="flex items-center gap-2">
225
- <Card.Title>Pending Invites</Card.Title>
226
- <Badge variant="secondary" class="text-xs">{pendingInvitations.length}</Badge>
227
- </div>
228
- <Card.Description>Invitations that haven't been accepted yet</Card.Description>
229
- </Card.Header>
230
- <Card.Content>
231
- <div class="divide-y">
232
- {#each pendingInvitations as invitation, i (invitation.id)}
233
- <div
234
- class="flex items-center justify-between gap-4 {i > 0 ? 'pt-3' : ''} {i <
235
- pendingInvitations.length - 1
236
- ? 'pb-3'
237
- : ''}"
238
- >
239
- <div class="flex items-center gap-3">
240
- <div
241
- class="border-muted-foreground/25 flex h-9 w-9 items-center justify-center rounded-full border border-dashed"
242
- >
243
- <Mail class="text-muted-foreground h-4 w-4" />
244
- </div>
245
- <div>
246
- <p class="text-sm font-medium">{invitation.email}</p>
247
- <p class="text-muted-foreground text-xs">
248
- Invited as <span class="capitalize">{invitation.role}</span>
249
- </p>
250
- </div>
251
- </div>
252
- {#if canInvite}
253
- <Button
254
- variant="outline"
255
- size="sm"
256
- onclick={() => cancelInvitation(invitation.id, invitation.email)}
257
- >
258
- Revoke
259
- </Button>
260
- {/if}
261
- </div>
262
- {/each}
263
- </div>
264
- </Card.Content>
265
- </Card.Root>
266
- {/if}
267
-
268
- <!-- Members -->
269
- <Card.Root>
270
- <Card.Header>
271
- <div class="flex items-center gap-2">
272
- <Card.Title>Members</Card.Title>
273
- <Badge variant="secondary" class="text-xs">
274
- {activeOrganization.members.length}
275
- </Badge>
276
- </div>
277
- <Card.Description>People with access to this organization</Card.Description>
278
- </Card.Header>
279
- <Card.Content>
280
- <div class="divide-y">
281
- {#each activeOrganization.members as member, i (member.id)}
282
- {@const isCurrentUser = member.userId === currentUserId}
283
- {@const canRemove = canRemoveMembers && !isCurrentUser && member.role !== 'owner'}
284
-
285
- <div
286
- class="flex items-center justify-between gap-4 {i > 0 ? 'pt-3' : ''} {i <
287
- activeOrganization.members.length - 1
288
- ? 'pb-3'
289
- : ''}"
290
- >
291
- <div class="flex items-center gap-3">
292
- <Avatar.Root class="h-9 w-9">
293
- {#if member.user.image}
294
- <Avatar.Image
295
- src={member.user.image}
296
- alt={member.user.name || member.user.email}
297
- />
298
- {/if}
299
- <Avatar.Fallback class="text-xs">
300
- {getInitials(member.user.name, member.user.email)}
301
- </Avatar.Fallback>
302
- </Avatar.Root>
303
- <div class="min-w-0">
304
- <p class="truncate text-sm font-medium">
305
- {member.user.name || member.user.email}
306
- {#if isCurrentUser}
307
- <span class="text-muted-foreground font-normal">(You)</span>
308
- {/if}
309
- </p>
310
- {#if member.user.name}
311
- <p class="text-muted-foreground truncate text-xs">
312
- {member.user.email}
313
- </p>
314
- {/if}
315
- </div>
316
- </div>
317
- <div class="flex items-center gap-2">
318
- <Badge variant={getRoleBadgeVariant(member.role)} class="capitalize">
319
- {member.role}
320
- </Badge>
321
- {#if canRemove}
322
- <Button
323
- variant="outline"
324
- size="sm"
325
- onclick={() =>
326
- removeMember(member.userId, member.user.name || member.user.email)}
327
- >
328
- Remove
329
- </Button>
330
- {/if}
331
- </div>
332
- </div>
333
- {/each}
334
- </div>
335
- </Card.Content>
336
- </Card.Root>
337
- {/if}
338
- </div>
@@ -1,17 +0,0 @@
1
- import type { PageServerLoad } from './$types';
2
- import { error } from '@sveltejs/kit';
3
-
4
- export const load: PageServerLoad = async ({ locals }) => {
5
- const auth = locals.auth;
6
- if (!auth || auth.type !== 'session') {
7
- throw error(401, 'Not authenticated');
8
- }
9
-
10
- const { rolesService } = locals.aphexCMS;
11
- const roles = await rolesService.listRoles(auth.organizationId);
12
-
13
- return {
14
- roles,
15
- canManageRoles: auth.capabilities?.includes('role.manage') ?? false
16
- };
17
- };