includio-cms 0.7.0 → 0.7.2
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/CHANGELOG.md +21 -0
- package/ROADMAP.md +12 -0
- package/dist/admin/client/admin/admin-layout.svelte +5 -1
- package/dist/admin/client/admin/admin-layout.svelte.d.ts +2 -0
- package/dist/admin/client/index.d.ts +1 -0
- package/dist/admin/client/index.js +1 -0
- package/dist/admin/components/fields/field-renderer.svelte +9 -0
- package/dist/admin/helpers/build-custom-fields-map.d.ts +7 -0
- package/dist/admin/helpers/build-custom-fields-map.js +13 -0
- package/dist/admin/helpers/index.d.ts +7 -0
- package/dist/admin/helpers/index.js +7 -0
- package/dist/admin/helpers/use-field.d.ts +26 -0
- package/dist/admin/helpers/use-field.js +9 -0
- package/dist/admin/state/custom-fields.svelte.d.ts +3 -0
- package/dist/admin/state/custom-fields.svelte.js +10 -0
- package/dist/admin/ui/index.d.ts +12 -0
- package/dist/admin/ui/index.js +14 -0
- package/dist/cli/create-user.d.ts +2 -0
- package/dist/cli/create-user.js +81 -0
- package/dist/cli/index.js +5 -0
- package/dist/components/ui/accordion/accordion.svelte.d.ts +1 -1
- package/dist/components/ui/calendar/calendar.svelte.d.ts +1 -1
- package/dist/components/ui/command/command-dialog.svelte.d.ts +1 -1
- package/dist/components/ui/command/command-input.svelte.d.ts +1 -1
- package/dist/components/ui/command/command.svelte.d.ts +1 -1
- package/dist/components/ui/dropdown-menu/dropdown-menu-radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/input-group/input-group-input.svelte.d.ts +2 -2
- package/dist/components/ui/input-group/input-group-textarea.svelte.d.ts +1 -1
- package/dist/components/ui/radio-group/radio-group.svelte.d.ts +1 -1
- package/dist/components/ui/sidebar/sidebar-input.svelte.d.ts +2 -2
- package/dist/components/ui/tabs/tabs.svelte.d.ts +1 -1
- package/dist/components/ui/textarea/textarea.svelte.d.ts +1 -1
- package/dist/components/ui/toggle-group/toggle-group-item.svelte.d.ts +1 -1
- package/dist/components/ui/toggle-group/toggle-group.svelte.d.ts +1 -1
- package/dist/core/cms.d.ts +2 -1
- package/dist/core/cms.js +11 -0
- package/dist/core/fields/fieldSchemaToTs.d.ts +11 -0
- package/dist/core/fields/fieldSchemaToTs.js +30 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +1 -0
- package/dist/core/server/fields/populateEntry.js +50 -0
- package/dist/core/server/fields/resolveRichtextLinks.js +3 -2
- package/dist/core/server/fields/resolveUrlFields.js +2 -2
- package/dist/core/server/fields/slugResolver.d.ts +5 -0
- package/dist/core/server/fields/slugResolver.js +16 -0
- package/dist/core/server/fields/utils/resolveMedia.d.ts +12 -0
- package/dist/core/server/fields/utils/resolveMedia.js +23 -0
- package/dist/core/server/generator/fields.d.ts +2 -0
- package/dist/core/server/generator/fields.js +8 -0
- package/dist/core/server/generator/generator.js +9 -1
- package/dist/paraglide/messages/_index.d.ts +3 -36
- package/dist/paraglide/messages/_index.js +3 -71
- package/dist/paraglide/messages/hello_world.d.ts +5 -0
- package/dist/paraglide/messages/hello_world.js +33 -0
- package/dist/paraglide/messages/login_hello.d.ts +16 -0
- package/dist/paraglide/messages/login_hello.js +34 -0
- package/dist/paraglide/messages/login_please_login.d.ts +16 -0
- package/dist/paraglide/messages/login_please_login.js +34 -0
- package/dist/sveltekit/index.d.ts +1 -0
- package/dist/sveltekit/index.js +1 -0
- package/dist/types/cms.d.ts +2 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/fields.d.ts +9 -2
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/plugins.d.ts +19 -1
- package/dist/updates/0.7.1/index.d.ts +2 -0
- package/dist/updates/0.7.1/index.js +16 -0
- package/dist/updates/0.7.2/index.d.ts +2 -0
- package/dist/updates/0.7.2/index.js +10 -0
- package/dist/updates/index.js +3 -1
- package/package.json +10 -1
- package/dist/paraglide/messages/en.d.ts +0 -5
- package/dist/paraglide/messages/en.js +0 -14
- package/dist/paraglide/messages/pl.d.ts +0 -5
- package/dist/paraglide/messages/pl.js +0 -14
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,27 @@
|
|
|
3
3
|
All notable changes to includio-cms are documented here.
|
|
4
4
|
Generated from `src/lib/updates/` — do not edit manually.
|
|
5
5
|
|
|
6
|
+
## 0.7.2 — 2026-03-16
|
|
7
|
+
|
|
8
|
+
CLI create-user command
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- CLI `create-user` command — interactive user creation with email, password (auto-generate option), name, and role via better-auth
|
|
12
|
+
|
|
13
|
+
## 0.7.1 — 2026-03-13
|
|
14
|
+
|
|
15
|
+
Custom fields plugin system, pathTemplate, admin public API
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
- Custom fields plugin system — type definition, zod/TS codegen, field renderer, populate resolver
|
|
19
|
+
- pathTemplate support — configurable URL paths for collections/singles
|
|
20
|
+
- Admin public exports: admin/helpers (useField, contexts) & admin/ui (shadcn primitives, MediaSelector)
|
|
21
|
+
- resolveMediaWithStyles utility — resolve media files with image styles
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
- Schema serialization type cast fix (stricter TS)
|
|
25
|
+
- Core svelte export condition added to package.json
|
|
26
|
+
|
|
6
27
|
## 0.7.0 — 2026-03-11
|
|
7
28
|
|
|
8
29
|
Auth core refactor & design system alignment
|
package/ROADMAP.md
CHANGED
|
@@ -155,6 +155,18 @@
|
|
|
155
155
|
- [x] `[fix]` `[P2]` Blocks field accordion: rounded borders, card background
|
|
156
156
|
- [x] `[fix]` `[P2]` Media file miniature: reset img/svg margins
|
|
157
157
|
|
|
158
|
+
## 0.7.1 — Custom fields & admin DX
|
|
159
|
+
|
|
160
|
+
- [x] `[feature]` `[P0]` Custom fields plugin system — type, zod/TS codegen, field renderer, populate resolver
|
|
161
|
+
- [x] `[feature]` `[P1]` pathTemplate — configurable URL paths for collections/singles
|
|
162
|
+
- [x] `[feature]` `[P1]` Admin public exports: admin/helpers & admin/ui for plugin authors
|
|
163
|
+
- [x] `[feature]` `[P2]` resolveMediaWithStyles utility & core svelte export
|
|
164
|
+
- [x] `[fix]` `[P1]` Schema serialization type cast (stricter TS compatibility)
|
|
165
|
+
|
|
166
|
+
## 0.7.2 — CLI create-user
|
|
167
|
+
|
|
168
|
+
- [x] `[feature]` `[P1]` CLI `create-user` command — interactive user creation with role assignment <!-- files: src/lib/cli/create-user.ts, src/lib/cli/index.ts -->
|
|
169
|
+
|
|
158
170
|
## 0.8.0 — SEO module
|
|
159
171
|
|
|
160
172
|
- [ ] `[feature]` `[P1]` SERP preview + character limits for title/description <!-- files: src/lib/admin/components/fields/seo-field.svelte -->
|
|
@@ -3,12 +3,16 @@
|
|
|
3
3
|
import '../../styles/admin.css';
|
|
4
4
|
import { Toaster } from '../../../components/ui/sonner/index.js';
|
|
5
5
|
import { MediaSort, setMediaSort } from '../../state/media-sort.svelte.js';
|
|
6
|
+
import { setCustomFields } from '../../state/custom-fields.svelte.js';
|
|
7
|
+
import type { CustomFieldDefinition } from '../../../types/plugins.js';
|
|
6
8
|
import AdminPreloader from './admin-preloader.svelte';
|
|
7
9
|
import { onMount } from 'svelte';
|
|
8
10
|
|
|
9
11
|
setMediaSort(new MediaSort());
|
|
10
12
|
|
|
11
|
-
let { children }: { children: Snippet } = $props();
|
|
13
|
+
let { children, customFields }: { children: Snippet; customFields?: Map<string, CustomFieldDefinition> } = $props();
|
|
14
|
+
|
|
15
|
+
setCustomFields(customFields ?? new Map());
|
|
12
16
|
|
|
13
17
|
let mounted = $state(false);
|
|
14
18
|
onMount(() => {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Snippet } from 'svelte';
|
|
2
2
|
import '../../styles/admin.css';
|
|
3
|
+
import type { CustomFieldDefinition } from '../../../types/plugins.js';
|
|
3
4
|
type $$ComponentProps = {
|
|
4
5
|
children: Snippet;
|
|
6
|
+
customFields?: Map<string, CustomFieldDefinition>;
|
|
5
7
|
};
|
|
6
8
|
declare const AdminLayout: import("svelte").Component<$$ComponentProps, {}, "">;
|
|
7
9
|
type AdminLayout = ReturnType<typeof AdminLayout>;
|
|
@@ -10,3 +10,4 @@ export { default as FormSubmissionPage } from './form/form-submission/form-submi
|
|
|
10
10
|
export { default as UsersPage } from './users/users-page.svelte';
|
|
11
11
|
export { default as AcceptInvitePage } from './users/accept-invite-page.svelte';
|
|
12
12
|
export { default as MaintenancePage } from './maintenance/maintenance-page.svelte';
|
|
13
|
+
export { default as MediaSelector } from '../components/media/media-selector.svelte';
|
|
@@ -10,3 +10,4 @@ export { default as FormSubmissionPage } from './form/form-submission/form-submi
|
|
|
10
10
|
export { default as UsersPage } from './users/users-page.svelte';
|
|
11
11
|
export { default as AcceptInvitePage } from './users/accept-invite-page.svelte';
|
|
12
12
|
export { default as MaintenancePage } from './maintenance/maintenance-page.svelte';
|
|
13
|
+
export { default as MediaSelector } from '../components/media/media-selector.svelte';
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import LazyField from './lazy-field.svelte';
|
|
17
17
|
import { useInterfaceLanguage } from '../../state/interface-language.svelte.js';
|
|
18
18
|
import { getLocalizedLabel } from '../../utils/collectionLabel.js';
|
|
19
|
+
import { getCustomFields } from '../../state/custom-fields.svelte.js';
|
|
19
20
|
|
|
20
21
|
type Props = {
|
|
21
22
|
objectFieldType?: 'default' | 'inline';
|
|
@@ -31,6 +32,7 @@
|
|
|
31
32
|
let { field, form, path, objectFieldType = 'default', focusedPath = null, flashingPath = null, depth = 0, distributed = false, ...props }: Props = $props();
|
|
32
33
|
|
|
33
34
|
const interfaceLanguage = useInterfaceLanguage();
|
|
35
|
+
const customFieldDefs = getCustomFields();
|
|
34
36
|
|
|
35
37
|
// Bridge: SuperForm store → $bindable for leaf components
|
|
36
38
|
// Cast to any: runtime types enforced by child components via $bindable
|
|
@@ -159,6 +161,13 @@
|
|
|
159
161
|
<DateTimeField {field} bind:value={$value} />
|
|
160
162
|
{:else if field.type === 'select'}
|
|
161
163
|
<SelectField {field} bind:value={$value} />
|
|
164
|
+
{:else if field.type === 'custom'}
|
|
165
|
+
{@const customDef = customFieldDefs.get(field.fieldType)}
|
|
166
|
+
{#if customDef}
|
|
167
|
+
<LazyField loader={customDef.component} props={{ field, form, path }} skeletonClass="h-20" />
|
|
168
|
+
{:else}
|
|
169
|
+
<p>Nieznany custom field: {field.fieldType}</p>
|
|
170
|
+
{/if}
|
|
162
171
|
{:else}
|
|
163
172
|
<p>Nieobsługiwany typ pola: {field.type}</p>
|
|
164
173
|
{/if}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PluginConfig } from '../../types/plugins.js';
|
|
2
|
+
import type { CustomFieldDefinition } from '../../types/plugins.js';
|
|
3
|
+
/**
|
|
4
|
+
* Build a Map<fieldType, CustomFieldDefinition> from plugin configs.
|
|
5
|
+
* Use in consumer's admin layout to pass customFields to AdminLayout.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildCustomFieldsMap(...plugins: PluginConfig[]): Map<string, CustomFieldDefinition>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build a Map<fieldType, CustomFieldDefinition> from plugin configs.
|
|
3
|
+
* Use in consumer's admin layout to pass customFields to AdminLayout.
|
|
4
|
+
*/
|
|
5
|
+
export function buildCustomFieldsMap(...plugins) {
|
|
6
|
+
const map = new Map();
|
|
7
|
+
for (const p of plugins) {
|
|
8
|
+
for (const f of p.fields ?? []) {
|
|
9
|
+
map.set(f.fieldType, f);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return map;
|
|
13
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { useField } from './use-field.js';
|
|
2
|
+
export { buildCustomFieldsMap } from './build-custom-fields-map.js';
|
|
3
|
+
export { useInterfaceLanguage } from '../state/interface-language.svelte.js';
|
|
4
|
+
export { getContentLanguage } from '../state/content-language.svelte.js';
|
|
5
|
+
export { getRemotes } from '../context/remotes.js';
|
|
6
|
+
export { getCustomFields } from '../state/custom-fields.svelte.js';
|
|
7
|
+
export { getLocalizedLabel } from '../utils/collectionLabel.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { useField } from './use-field.js';
|
|
2
|
+
export { buildCustomFieldsMap } from './build-custom-fields-map.js';
|
|
3
|
+
export { useInterfaceLanguage } from '../state/interface-language.svelte.js';
|
|
4
|
+
export { getContentLanguage } from '../state/content-language.svelte.js';
|
|
5
|
+
export { getRemotes } from '../context/remotes.js';
|
|
6
|
+
export { getCustomFields } from '../state/custom-fields.svelte.js';
|
|
7
|
+
export { getLocalizedLabel } from '../utils/collectionLabel.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type SuperForm, type FormPathLeaves } from 'sveltekit-superforms';
|
|
2
|
+
/**
|
|
3
|
+
* Simplified wrapper around sveltekit-superforms' formFieldProxy.
|
|
4
|
+
* Plugin authors don't need to know the superforms API.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useField(form: SuperForm<Record<string, unknown>>, path: FormPathLeaves<Record<string, unknown>>): {
|
|
7
|
+
value: {
|
|
8
|
+
subscribe: (this: void, run: import("svelte/store").Subscriber<unknown>, invalidate?: () => void) => import("svelte/store").Unsubscriber;
|
|
9
|
+
set(this: void, value: unknown, options?: {
|
|
10
|
+
taint?: import("sveltekit-superforms").TaintOption;
|
|
11
|
+
}): void;
|
|
12
|
+
update(this: void, updater: import("svelte/store").Updater<unknown>, options?: {
|
|
13
|
+
taint?: import("sveltekit-superforms").TaintOption;
|
|
14
|
+
}): void;
|
|
15
|
+
};
|
|
16
|
+
errors: import("svelte/store").Writable<string[] | undefined>;
|
|
17
|
+
constraints: import("svelte/store").Writable<Partial<{
|
|
18
|
+
pattern: string;
|
|
19
|
+
min: number | string;
|
|
20
|
+
max: number | string;
|
|
21
|
+
required: boolean;
|
|
22
|
+
step: number | "any";
|
|
23
|
+
minlength: number;
|
|
24
|
+
maxlength: number;
|
|
25
|
+
}> | undefined>;
|
|
26
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { formFieldProxy } from 'sveltekit-superforms';
|
|
2
|
+
/**
|
|
3
|
+
* Simplified wrapper around sveltekit-superforms' formFieldProxy.
|
|
4
|
+
* Plugin authors don't need to know the superforms API.
|
|
5
|
+
*/
|
|
6
|
+
export function useField(form, path) {
|
|
7
|
+
const { value, errors, constraints } = formFieldProxy(form, path);
|
|
8
|
+
return { value, errors, constraints };
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getContext, setContext } from 'svelte';
|
|
2
|
+
import { setSchemaCustomFields } from '../../core/fields/fieldSchemaToTs.js';
|
|
3
|
+
const contextKey = Symbol('customFields');
|
|
4
|
+
export function setCustomFields(defs) {
|
|
5
|
+
setContext(contextKey, defs);
|
|
6
|
+
setSchemaCustomFields(defs);
|
|
7
|
+
}
|
|
8
|
+
export function getCustomFields() {
|
|
9
|
+
return getContext(contextKey) ?? new Map();
|
|
10
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { Button, type ButtonProps } from '../../components/ui/button/index.js';
|
|
2
|
+
export * as Dialog from '../../components/ui/dialog/index.js';
|
|
3
|
+
export { Input } from '../../components/ui/input/index.js';
|
|
4
|
+
export * as Card from '../../components/ui/card/index.js';
|
|
5
|
+
export { Label } from '../../components/ui/label/index.js';
|
|
6
|
+
export { Separator } from '../../components/ui/separator/index.js';
|
|
7
|
+
export { Badge } from '../../components/ui/badge/index.js';
|
|
8
|
+
export { Skeleton } from '../../components/ui/skeleton/index.js';
|
|
9
|
+
export * as Tabs from '../../components/ui/tabs/index.js';
|
|
10
|
+
export * as Tooltip from '../../components/ui/tooltip/index.js';
|
|
11
|
+
export { default as FileMiniature } from '../components/media/file/file-miniature.svelte';
|
|
12
|
+
export { default as MediaSelector } from '../components/media/media-selector.svelte';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// shadcn-svelte UI primitives
|
|
2
|
+
export { Button } from '../../components/ui/button/index.js';
|
|
3
|
+
export * as Dialog from '../../components/ui/dialog/index.js';
|
|
4
|
+
export { Input } from '../../components/ui/input/index.js';
|
|
5
|
+
export * as Card from '../../components/ui/card/index.js';
|
|
6
|
+
export { Label } from '../../components/ui/label/index.js';
|
|
7
|
+
export { Separator } from '../../components/ui/separator/index.js';
|
|
8
|
+
export { Badge } from '../../components/ui/badge/index.js';
|
|
9
|
+
export { Skeleton } from '../../components/ui/skeleton/index.js';
|
|
10
|
+
export * as Tabs from '../../components/ui/tabs/index.js';
|
|
11
|
+
export * as Tooltip from '../../components/ui/tooltip/index.js';
|
|
12
|
+
// Admin components
|
|
13
|
+
export { default as FileMiniature } from '../components/media/file/file-miniature.svelte';
|
|
14
|
+
export { default as MediaSelector } from '../components/media/media-selector.svelte';
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import readline from 'readline';
|
|
4
|
+
import z from 'zod';
|
|
5
|
+
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
6
|
+
import postgres from 'postgres';
|
|
7
|
+
import { betterAuth } from 'better-auth';
|
|
8
|
+
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
|
9
|
+
import { admin } from 'better-auth/plugins';
|
|
10
|
+
import * as authSchema from '../server/db/schema/auth-schema.js';
|
|
11
|
+
const emailSchema = z.string().email();
|
|
12
|
+
const passwordSchema = z.string().min(6).max(255, 'Invalid password (min 6, max 255 characters)');
|
|
13
|
+
const nameSchema = z.string().min(1);
|
|
14
|
+
const roleSchema = z.enum(['admin', 'user']);
|
|
15
|
+
function generatePassword(length = 24) {
|
|
16
|
+
return crypto.randomBytes(length).toString('base64url').slice(0, length);
|
|
17
|
+
}
|
|
18
|
+
export async function createUser() {
|
|
19
|
+
const DATABASE_URL = process.env.DATABASE_URL;
|
|
20
|
+
if (!DATABASE_URL) {
|
|
21
|
+
console.error('DATABASE_URL is not set. Check your .env file.');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
const client = postgres(DATABASE_URL);
|
|
25
|
+
const db = drizzle(client);
|
|
26
|
+
const auth = betterAuth({
|
|
27
|
+
database: drizzleAdapter(db, { provider: 'pg', schema: authSchema }),
|
|
28
|
+
emailAndPassword: { enabled: true },
|
|
29
|
+
plugins: [admin()]
|
|
30
|
+
});
|
|
31
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
32
|
+
function ask(q) {
|
|
33
|
+
return new Promise((resolve) => rl.question(q, resolve));
|
|
34
|
+
}
|
|
35
|
+
console.log('Please provide the following information to create a new user:');
|
|
36
|
+
const name = await ask('Name: ');
|
|
37
|
+
const parsedName = nameSchema.safeParse(name);
|
|
38
|
+
if (!parsedName.success) {
|
|
39
|
+
console.error(parsedName.error.flatten());
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
const email = await ask('E-mail: ');
|
|
43
|
+
const parsedEmail = emailSchema.safeParse(email);
|
|
44
|
+
if (!parsedEmail.success) {
|
|
45
|
+
console.error(parsedEmail.error.flatten());
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
const passwordInput = await ask('Password (leave empty to generate): ');
|
|
49
|
+
const password = passwordInput.trim() || generatePassword();
|
|
50
|
+
const wasGenerated = !passwordInput.trim();
|
|
51
|
+
const parsedPassword = passwordSchema.safeParse(password);
|
|
52
|
+
if (!parsedPassword.success) {
|
|
53
|
+
console.error(parsedPassword.error.flatten());
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
const roleInput = await ask('Role (admin/user) [admin]: ');
|
|
57
|
+
const role = roleInput.trim() || 'admin';
|
|
58
|
+
const parsedRole = roleSchema.safeParse(role);
|
|
59
|
+
if (!parsedRole.success) {
|
|
60
|
+
console.error('Invalid role. Must be "admin" or "user".');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
rl.close();
|
|
64
|
+
const response = await auth.api.createUser({
|
|
65
|
+
body: {
|
|
66
|
+
email: parsedEmail.data,
|
|
67
|
+
name: parsedName.data,
|
|
68
|
+
password: parsedPassword.data,
|
|
69
|
+
role: parsedRole.data
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const user = response.user;
|
|
73
|
+
console.log(`\nUser created successfully:
|
|
74
|
+
ID: ${user.id}
|
|
75
|
+
Email: ${user.email}
|
|
76
|
+
Name: ${user.name}
|
|
77
|
+
Role: ${parsedRole.data}
|
|
78
|
+
Password: ${parsedPassword.data}${wasGenerated ? ' (generated)' : ''}
|
|
79
|
+
Please store the password securely, as it is not retrievable later.`);
|
|
80
|
+
await client.end();
|
|
81
|
+
}
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { scaffoldAdmin } from './scaffold/admin.js';
|
|
3
3
|
import { installPeers } from './install-peers.js';
|
|
4
|
+
import { createUser } from './create-user.js';
|
|
4
5
|
import path from 'node:path';
|
|
5
6
|
const args = process.argv.slice(2);
|
|
6
7
|
const command = args[0];
|
|
@@ -11,6 +12,7 @@ function printUsage() {
|
|
|
11
12
|
Commands:
|
|
12
13
|
scaffold admin Generate admin route files
|
|
13
14
|
install-peers Install missing peer dependencies
|
|
15
|
+
create-user Create a new admin/user account
|
|
14
16
|
|
|
15
17
|
Options:
|
|
16
18
|
--force Overwrite existing files
|
|
@@ -29,6 +31,9 @@ else if (command === 'install-peers') {
|
|
|
29
31
|
const dryRun = args.includes('--dry-run');
|
|
30
32
|
installPeers({ dryRun });
|
|
31
33
|
}
|
|
34
|
+
else if (command === 'create-user') {
|
|
35
|
+
createUser();
|
|
36
|
+
}
|
|
32
37
|
else {
|
|
33
38
|
printUsage();
|
|
34
39
|
process.exit(command ? 1 : 0);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Accordion as AccordionPrimitive } from "bits-ui";
|
|
2
|
-
declare const Accordion: import("svelte").Component<AccordionPrimitive.RootProps, {}, "
|
|
2
|
+
declare const Accordion: import("svelte").Component<AccordionPrimitive.RootProps, {}, "value" | "ref">;
|
|
3
3
|
type Accordion = ReturnType<typeof Accordion>;
|
|
4
4
|
export default Accordion;
|
|
@@ -16,6 +16,6 @@ type $$ComponentProps = WithoutChildrenOrChild<CalendarPrimitive.RootProps> & {
|
|
|
16
16
|
outsideMonth: boolean;
|
|
17
17
|
}]>;
|
|
18
18
|
};
|
|
19
|
-
declare const Calendar: import("svelte").Component<$$ComponentProps, {}, "
|
|
19
|
+
declare const Calendar: import("svelte").Component<$$ComponentProps, {}, "value" | "ref" | "placeholder">;
|
|
20
20
|
type Calendar = ReturnType<typeof Calendar>;
|
|
21
21
|
export default Calendar;
|
|
@@ -7,6 +7,6 @@ type $$ComponentProps = WithoutChildrenOrChild<DialogPrimitive.RootProps> & With
|
|
|
7
7
|
title?: string;
|
|
8
8
|
description?: string;
|
|
9
9
|
};
|
|
10
|
-
declare const CommandDialog: import("svelte").Component<$$ComponentProps, {}, "
|
|
10
|
+
declare const CommandDialog: import("svelte").Component<$$ComponentProps, {}, "value" | "ref" | "open">;
|
|
11
11
|
type CommandDialog = ReturnType<typeof CommandDialog>;
|
|
12
12
|
export default CommandDialog;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Command as CommandPrimitive } from "bits-ui";
|
|
2
|
-
declare const CommandInput: import("svelte").Component<CommandPrimitive.InputProps, {}, "
|
|
2
|
+
declare const CommandInput: import("svelte").Component<CommandPrimitive.InputProps, {}, "value" | "ref">;
|
|
3
3
|
type CommandInput = ReturnType<typeof CommandInput>;
|
|
4
4
|
export default CommandInput;
|
|
@@ -3,6 +3,6 @@ export type CommandRootApi = CommandPrimitive.Root;
|
|
|
3
3
|
type $$ComponentProps = CommandPrimitive.RootProps & {
|
|
4
4
|
api?: CommandRootApi | null;
|
|
5
5
|
};
|
|
6
|
-
declare const Command: import("svelte").Component<$$ComponentProps, {}, "
|
|
6
|
+
declare const Command: import("svelte").Component<$$ComponentProps, {}, "value" | "ref" | "api">;
|
|
7
7
|
type Command = ReturnType<typeof Command>;
|
|
8
8
|
export default Command;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
|
2
|
-
declare const DropdownMenuRadioGroup: import("svelte").Component<DropdownMenuPrimitive.RadioGroupProps, {}, "
|
|
2
|
+
declare const DropdownMenuRadioGroup: import("svelte").Component<DropdownMenuPrimitive.RadioGroupProps, {}, "value" | "ref">;
|
|
3
3
|
type DropdownMenuRadioGroup = ReturnType<typeof DropdownMenuRadioGroup>;
|
|
4
4
|
export default DropdownMenuRadioGroup;
|
|
@@ -8,6 +8,6 @@ type Props = WithElementRef<Omit<HTMLInputAttributes, "type"> & ({
|
|
|
8
8
|
type?: InputType;
|
|
9
9
|
files?: undefined;
|
|
10
10
|
})>;
|
|
11
|
-
declare const Input: import("svelte").Component<Props, {}, "files" | "
|
|
11
|
+
declare const Input: import("svelte").Component<Props, {}, "files" | "value" | "ref">;
|
|
12
12
|
type Input = ReturnType<typeof Input>;
|
|
13
13
|
export default Input;
|
|
@@ -2,10 +2,10 @@ declare const InputGroupInput: import("svelte").Component<(Omit<import("svelte/e
|
|
|
2
2
|
type: "file";
|
|
3
3
|
files?: FileList;
|
|
4
4
|
} | {
|
|
5
|
-
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "color" | "button" | "checkbox" | "search" | (string & {}) | "email" | "
|
|
5
|
+
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "color" | "button" | "checkbox" | "search" | (string & {}) | "email" | "time" | "password" | "hidden" | "reset" | "submit" | "tel" | "datetime-local" | "month" | "range" | "week";
|
|
6
6
|
files?: undefined;
|
|
7
7
|
})) & {
|
|
8
8
|
ref?: HTMLElement | null | undefined;
|
|
9
|
-
}, {}, "
|
|
9
|
+
}, {}, "value" | "ref">;
|
|
10
10
|
type InputGroupInput = ReturnType<typeof InputGroupInput>;
|
|
11
11
|
export default InputGroupInput;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
declare const InputGroupTextarea: import("svelte").Component<Omit<import("../../../utils.js").WithElementRef<import("svelte/elements").HTMLTextareaAttributes>, "children">, {}, "
|
|
1
|
+
declare const InputGroupTextarea: import("svelte").Component<Omit<import("../../../utils.js").WithElementRef<import("svelte/elements").HTMLTextareaAttributes>, "children">, {}, "value" | "ref">;
|
|
2
2
|
type InputGroupTextarea = ReturnType<typeof InputGroupTextarea>;
|
|
3
3
|
export default InputGroupTextarea;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { RadioGroup as RadioGroupPrimitive } from "bits-ui";
|
|
2
|
-
declare const RadioGroup: import("svelte").Component<RadioGroupPrimitive.RootProps, {}, "
|
|
2
|
+
declare const RadioGroup: import("svelte").Component<RadioGroupPrimitive.RootProps, {}, "value" | "ref">;
|
|
3
3
|
type RadioGroup = ReturnType<typeof RadioGroup>;
|
|
4
4
|
export default RadioGroup;
|
|
@@ -2,10 +2,10 @@ declare const SidebarInput: import("svelte").Component<(Omit<import("svelte/elem
|
|
|
2
2
|
type: "file";
|
|
3
3
|
files?: FileList;
|
|
4
4
|
} | {
|
|
5
|
-
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "color" | "button" | "checkbox" | "search" | (string & {}) | "email" | "
|
|
5
|
+
type?: "number" | "image" | "url" | "text" | "date" | "radio" | "color" | "button" | "checkbox" | "search" | (string & {}) | "email" | "time" | "password" | "hidden" | "reset" | "submit" | "tel" | "datetime-local" | "month" | "range" | "week";
|
|
6
6
|
files?: undefined;
|
|
7
7
|
})) & {
|
|
8
8
|
ref?: HTMLElement | null | undefined;
|
|
9
|
-
}, {}, "
|
|
9
|
+
}, {}, "value" | "ref">;
|
|
10
10
|
type SidebarInput = ReturnType<typeof SidebarInput>;
|
|
11
11
|
export default SidebarInput;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { Tabs as TabsPrimitive } from "bits-ui";
|
|
2
|
-
declare const Tabs: import("svelte").Component<TabsPrimitive.RootProps, {}, "
|
|
2
|
+
declare const Tabs: import("svelte").Component<TabsPrimitive.RootProps, {}, "value" | "ref">;
|
|
3
3
|
type Tabs = ReturnType<typeof Tabs>;
|
|
4
4
|
export default Tabs;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type WithElementRef } from "../../../utils.js";
|
|
2
2
|
import type { HTMLTextareaAttributes } from "svelte/elements";
|
|
3
|
-
declare const Textarea: import("svelte").Component<Omit<WithElementRef<HTMLTextareaAttributes>, "children">, {}, "
|
|
3
|
+
declare const Textarea: import("svelte").Component<Omit<WithElementRef<HTMLTextareaAttributes>, "children">, {}, "value" | "ref">;
|
|
4
4
|
type Textarea = ReturnType<typeof Textarea>;
|
|
5
5
|
export default Textarea;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ToggleGroup as ToggleGroupPrimitive } from "bits-ui";
|
|
2
2
|
import { type ToggleVariants } from "../toggle/index.js";
|
|
3
3
|
type $$ComponentProps = ToggleGroupPrimitive.ItemProps & ToggleVariants;
|
|
4
|
-
declare const ToggleGroupItem: import("svelte").Component<$$ComponentProps, {}, "
|
|
4
|
+
declare const ToggleGroupItem: import("svelte").Component<$$ComponentProps, {}, "value" | "ref">;
|
|
5
5
|
type ToggleGroupItem = ReturnType<typeof ToggleGroupItem>;
|
|
6
6
|
export default ToggleGroupItem;
|
|
@@ -3,6 +3,6 @@ export declare function setToggleGroupCtx(props: ToggleVariants): void;
|
|
|
3
3
|
export declare function getToggleGroupCtx(): ToggleVariants;
|
|
4
4
|
import { ToggleGroup as ToggleGroupPrimitive } from "bits-ui";
|
|
5
5
|
type $$ComponentProps = ToggleGroupPrimitive.RootProps & ToggleVariants;
|
|
6
|
-
declare const ToggleGroup: import("svelte").Component<$$ComponentProps, {}, "
|
|
6
|
+
declare const ToggleGroup: import("svelte").Component<$$ComponentProps, {}, "value" | "ref">;
|
|
7
7
|
type ToggleGroup = ReturnType<typeof ToggleGroup>;
|
|
8
8
|
export default ToggleGroup;
|
package/dist/core/cms.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { ApiKeyConfig, AuthConfig, CMSConfig, ICMS, MediaConfig } from '../
|
|
|
4
4
|
import type { CollectionConfigWithType } from '../types/collections.js';
|
|
5
5
|
import type { Language } from '../types/languages.js';
|
|
6
6
|
import type { SingleConfigWithType } from '../types/singles.js';
|
|
7
|
-
import type { PluginConfig } from '../types/plugins.js';
|
|
7
|
+
import type { CustomFieldDefinition, PluginConfig } from '../types/plugins.js';
|
|
8
8
|
import type { FormConfig } from '../types/forms.js';
|
|
9
9
|
import type { AIAdapter } from '../types/adapters/ai.js';
|
|
10
10
|
import type { EmailAdapter } from '../types/adapters/email.js';
|
|
@@ -23,6 +23,7 @@ export declare class CMS implements ICMS {
|
|
|
23
23
|
languages: Language[];
|
|
24
24
|
mediaConfig: MediaConfig;
|
|
25
25
|
plugins: PluginConfig[];
|
|
26
|
+
customFields: Map<string, CustomFieldDefinition>;
|
|
26
27
|
apiKeys: ApiKeyConfig[];
|
|
27
28
|
constructor(config: CMSConfig);
|
|
28
29
|
get auth(): ReturnType<typeof betterAuth>;
|
package/dist/core/cms.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { setSchemaGetCMS } from './fields/fieldSchemaToTs.js';
|
|
1
2
|
import { betterAuth } from 'better-auth';
|
|
2
3
|
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
|
3
4
|
import { admin } from 'better-auth/plugins';
|
|
@@ -17,6 +18,7 @@ export class CMS {
|
|
|
17
18
|
languages;
|
|
18
19
|
mediaConfig;
|
|
19
20
|
plugins = [];
|
|
21
|
+
customFields = new Map();
|
|
20
22
|
apiKeys = [];
|
|
21
23
|
constructor(config) {
|
|
22
24
|
this.config = config;
|
|
@@ -50,7 +52,16 @@ export class CMS {
|
|
|
50
52
|
this.apiKeys = config.apiKeys || [];
|
|
51
53
|
if (config.plugins) {
|
|
52
54
|
this.plugins = config.plugins;
|
|
55
|
+
for (const plugin of this.plugins) {
|
|
56
|
+
for (const def of plugin.fields ?? []) {
|
|
57
|
+
if (this.customFields.has(def.fieldType)) {
|
|
58
|
+
throw new Error(`Duplicate custom field type: "${def.fieldType}" (plugin: "${plugin.slug}")`);
|
|
59
|
+
}
|
|
60
|
+
this.customFields.set(def.fieldType, def);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
53
63
|
}
|
|
64
|
+
setSchemaGetCMS(() => this);
|
|
54
65
|
}
|
|
55
66
|
get auth() {
|
|
56
67
|
if (!this._betterAuth) {
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { Field } from '../../types/fields.js';
|
|
2
|
+
import type { CustomFieldDefinition } from '../../types/plugins.js';
|
|
2
3
|
import { z } from 'zod';
|
|
4
|
+
/**
|
|
5
|
+
* Set custom fields map for client-side use (where getCMS() is unavailable).
|
|
6
|
+
*/
|
|
7
|
+
export declare function setSchemaCustomFields(customFields: Map<string, CustomFieldDefinition>): void;
|
|
8
|
+
/**
|
|
9
|
+
* Set CMS getter for server-side use (avoids static import of server-only cms.ts).
|
|
10
|
+
*/
|
|
11
|
+
export declare function setSchemaGetCMS(getter: () => {
|
|
12
|
+
customFields: Map<string, CustomFieldDefinition>;
|
|
13
|
+
}): void;
|
|
3
14
|
type AnyZodObject = z.ZodObject<any, any>;
|
|
4
15
|
interface GenerateZodSchemaOptions {
|
|
5
16
|
parentRequired?: boolean;
|
|
@@ -1,4 +1,28 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
let _customFieldsOverride = null;
|
|
3
|
+
/**
|
|
4
|
+
* Set custom fields map for client-side use (where getCMS() is unavailable).
|
|
5
|
+
*/
|
|
6
|
+
export function setSchemaCustomFields(customFields) {
|
|
7
|
+
_customFieldsOverride = customFields;
|
|
8
|
+
}
|
|
9
|
+
let _getCMS = null;
|
|
10
|
+
/**
|
|
11
|
+
* Set CMS getter for server-side use (avoids static import of server-only cms.ts).
|
|
12
|
+
*/
|
|
13
|
+
export function setSchemaGetCMS(getter) {
|
|
14
|
+
_getCMS = getter;
|
|
15
|
+
}
|
|
16
|
+
function getCustomFieldDef(fieldType) {
|
|
17
|
+
if (_customFieldsOverride)
|
|
18
|
+
return _customFieldsOverride.get(fieldType);
|
|
19
|
+
try {
|
|
20
|
+
return _getCMS?.().customFields.get(fieldType);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
2
26
|
export function generateZodSchemaFromField(field, languages, options = {
|
|
3
27
|
parentRequired: true
|
|
4
28
|
}) {
|
|
@@ -283,6 +307,12 @@ export function generateZodSchemaFromField(field, languages, options = {
|
|
|
283
307
|
}
|
|
284
308
|
return schema;
|
|
285
309
|
}
|
|
310
|
+
case 'custom': {
|
|
311
|
+
const customDef = getCustomFieldDef(field.fieldType);
|
|
312
|
+
if (!customDef)
|
|
313
|
+
return z.any();
|
|
314
|
+
return customDef.zodSchema(field, languages);
|
|
315
|
+
}
|
|
286
316
|
default:
|
|
287
317
|
return z.any();
|
|
288
318
|
}
|
package/dist/core/index.d.ts
CHANGED
package/dist/core/index.js
CHANGED