@momentumcms/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,355 @@
1
+ import type { CollectionConfig, GlobalConfig } from './collections';
2
+ import type { SeedingConfig, SeedingOptions } from './seeding';
3
+ import type { DocumentVersion, DocumentStatus, VersionQueryOptions, VersionCountOptions, CreateVersionOptions } from './versions';
4
+ import type { MomentumPlugin } from './plugins';
5
+ import type { StorageAdapter } from './storage';
6
+ /**
7
+ * Minimum password length for user accounts.
8
+ * Shared across seeding, user sync hooks, and setup middleware.
9
+ */
10
+ export declare const MIN_PASSWORD_LENGTH = 8;
11
+ /**
12
+ * Database adapter type for Momentum CMS.
13
+ * This is a placeholder type - actual adapters implement this interface.
14
+ */
15
+ export interface DatabaseAdapter {
16
+ find(collection: string, query: Record<string, unknown>): Promise<Record<string, unknown>[]>;
17
+ findById(collection: string, id: string): Promise<Record<string, unknown> | null>;
18
+ create(collection: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
19
+ update(collection: string, id: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
20
+ delete(collection: string, id: string): Promise<boolean>;
21
+ /**
22
+ * Soft delete a document by setting its deletedAt timestamp.
23
+ * @param collection - The collection slug
24
+ * @param id - The document ID
25
+ * @param field - The name of the deletedAt column (default: 'deletedAt')
26
+ * @returns Whether the update was successful
27
+ */
28
+ softDelete?(collection: string, id: string, field?: string): Promise<boolean>;
29
+ /**
30
+ * Restore a soft-deleted document by clearing its deletedAt timestamp.
31
+ * @param collection - The collection slug
32
+ * @param id - The document ID
33
+ * @param field - The name of the deletedAt column (default: 'deletedAt')
34
+ * @returns The restored document
35
+ */
36
+ restore?(collection: string, id: string, field?: string): Promise<Record<string, unknown>>;
37
+ /**
38
+ * Initialize database schema based on collections.
39
+ * Called once when the server starts.
40
+ */
41
+ initialize?(collections: CollectionConfig[]): Promise<void>;
42
+ /**
43
+ * Create a new version for a document.
44
+ * @param collection - The collection slug
45
+ * @param parentId - The parent document ID
46
+ * @param data - The document data to snapshot
47
+ * @param options - Version creation options
48
+ */
49
+ createVersion?(collection: string, parentId: string, data: Record<string, unknown>, options?: CreateVersionOptions): Promise<DocumentVersion>;
50
+ /**
51
+ * Find all versions for a document.
52
+ * @param collection - The collection slug
53
+ * @param parentId - The parent document ID
54
+ * @param options - Query options (limit, page, etc.)
55
+ */
56
+ findVersions?(collection: string, parentId: string, options?: VersionQueryOptions): Promise<DocumentVersion[]>;
57
+ /**
58
+ * Find a specific version by ID.
59
+ * @param collection - The collection slug
60
+ * @param versionId - The version ID
61
+ */
62
+ findVersionById?(collection: string, versionId: string): Promise<DocumentVersion | null>;
63
+ /**
64
+ * Restore a document to a previous version.
65
+ * Creates a new version with the restored data.
66
+ * @param collection - The collection slug
67
+ * @param versionId - The version ID to restore
68
+ */
69
+ restoreVersion?(collection: string, versionId: string): Promise<Record<string, unknown>>;
70
+ /**
71
+ * Delete old versions for a document.
72
+ * @param collection - The collection slug
73
+ * @param parentId - The parent document ID
74
+ * @param keepLatest - Number of latest versions to keep (default: all)
75
+ * @returns Number of versions deleted
76
+ */
77
+ deleteVersions?(collection: string, parentId: string, keepLatest?: number): Promise<number>;
78
+ /**
79
+ * Count versions for a document.
80
+ * @param collection - The collection slug
81
+ * @param parentId - The parent document ID
82
+ * @param options - Filter options (includeAutosave, status) to match findVersions filters
83
+ */
84
+ countVersions?(collection: string, parentId: string, options?: VersionCountOptions): Promise<number>;
85
+ /**
86
+ * Update a document's status (draft/published).
87
+ * @param collection - The collection slug
88
+ * @param id - The document ID
89
+ * @param status - The new status
90
+ */
91
+ updateStatus?(collection: string, id: string, status: DocumentStatus): Promise<void>;
92
+ /**
93
+ * Set or clear the scheduled publish date on a document.
94
+ * @param collection - The collection slug
95
+ * @param id - The document ID
96
+ * @param publishAt - ISO date string for scheduled publish, or null to cancel
97
+ */
98
+ setScheduledPublishAt?(collection: string, id: string, publishAt: string | null): Promise<void>;
99
+ /**
100
+ * Find all documents scheduled for publishing at or before the given date.
101
+ * @param collection - The collection slug
102
+ * @param before - ISO date string; returns docs with scheduledPublishAt <= this value
103
+ */
104
+ findScheduledDocuments?(collection: string, before: string): Promise<Array<{
105
+ id: string;
106
+ scheduledPublishAt: string;
107
+ }>>;
108
+ /**
109
+ * Full-text search across specified fields.
110
+ * Uses PostgreSQL tsvector/tsquery for efficient text search.
111
+ *
112
+ * @param collection - The collection slug
113
+ * @param query - The search query string
114
+ * @param fields - Field names to search in
115
+ * @param options - Pagination options
116
+ * @returns Array of matching documents sorted by relevance
117
+ */
118
+ search?(collection: string, query: string, fields: string[], options?: {
119
+ limit?: number;
120
+ page?: number;
121
+ }): Promise<Record<string, unknown>[]>;
122
+ /**
123
+ * Execute multiple operations within a database transaction.
124
+ * All operations succeed or all are rolled back.
125
+ *
126
+ * @param callback - Async function receiving a transactional adapter.
127
+ * All adapter calls inside this callback share the same transaction.
128
+ * @returns The value returned by the callback
129
+ */
130
+ transaction?<T>(callback: (txAdapter: DatabaseAdapter) => Promise<T>): Promise<T>;
131
+ /**
132
+ * Initialize the globals table.
133
+ * Called once when the server starts if globals are configured.
134
+ * @param globals - The global configurations
135
+ */
136
+ initializeGlobals?(globals: GlobalConfig[]): Promise<void>;
137
+ /**
138
+ * Find a global document by slug.
139
+ * @param slug - The global slug
140
+ * @returns The global data or null if not found
141
+ */
142
+ findGlobal?(slug: string): Promise<Record<string, unknown> | null>;
143
+ /**
144
+ * Update (or create) a global document.
145
+ * Uses upsert semantics: creates if missing, updates if exists.
146
+ * @param slug - The global slug
147
+ * @param data - The global data to store
148
+ * @returns The full global record after update
149
+ */
150
+ updateGlobal?(slug: string, data: Record<string, unknown>): Promise<Record<string, unknown>>;
151
+ }
152
+ /**
153
+ * Database configuration options.
154
+ */
155
+ export interface DatabaseConfig {
156
+ /**
157
+ * Database adapter instance.
158
+ * Use @momentumcms/db-drizzle for Drizzle ORM support.
159
+ */
160
+ adapter: DatabaseAdapter;
161
+ }
162
+ /**
163
+ * Global admin panel configuration.
164
+ * (Distinct from collection-level AdminConfig)
165
+ */
166
+ export interface AdminPanelConfig {
167
+ /**
168
+ * Base path for admin routes.
169
+ * @default '/admin'
170
+ */
171
+ basePath?: string;
172
+ /**
173
+ * Branding options for admin panel.
174
+ */
175
+ branding?: {
176
+ logo?: string;
177
+ title?: string;
178
+ };
179
+ /**
180
+ * Auto-show toast notifications on CUD (Create, Update, Delete) operations.
181
+ * When enabled, the admin UI shows success/error toasts for all database
182
+ * modification operations without manual calls in each component.
183
+ * Only active in the browser, not during SSR.
184
+ * @default true
185
+ */
186
+ toasts?: boolean;
187
+ }
188
+ /**
189
+ * Server configuration.
190
+ */
191
+ export interface ServerConfig {
192
+ /**
193
+ * Port to run the server on.
194
+ * @default 3000
195
+ */
196
+ port?: number;
197
+ /**
198
+ * CORS configuration.
199
+ */
200
+ cors?: {
201
+ origin?: string | string[];
202
+ methods?: string[];
203
+ headers?: string[];
204
+ };
205
+ }
206
+ /**
207
+ * Storage configuration for file uploads.
208
+ */
209
+ export interface StorageConfig {
210
+ /**
211
+ * Storage adapter instance.
212
+ * Use localStorageAdapter or s3StorageAdapter from @momentumcms/storage.
213
+ */
214
+ adapter: StorageAdapter;
215
+ /**
216
+ * Directory for file uploads (for local storage).
217
+ * @default './uploads'
218
+ */
219
+ uploadDir?: string;
220
+ /**
221
+ * Maximum file size in bytes.
222
+ * @default 10485760 (10MB)
223
+ */
224
+ maxFileSize?: number;
225
+ /**
226
+ * Allowed MIME types. Defaults to common image and document types.
227
+ */
228
+ allowedMimeTypes?: string[];
229
+ }
230
+ /**
231
+ * Log level for Momentum CMS logging.
232
+ */
233
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'silent';
234
+ /**
235
+ * Log output format.
236
+ */
237
+ export type LogFormat = 'pretty' | 'json';
238
+ /**
239
+ * Logging configuration for Momentum CMS.
240
+ * Runtime implementation is in @momentumcms/logger.
241
+ */
242
+ export interface LoggingConfig {
243
+ /** Minimum log level. @default 'info' */
244
+ level?: LogLevel;
245
+ /** Output format. @default 'pretty' */
246
+ format?: LogFormat;
247
+ /** Whether to include timestamps. @default true */
248
+ timestamps?: boolean;
249
+ }
250
+ /**
251
+ * Resolved logging config with defaults applied.
252
+ */
253
+ export type ResolvedLoggingConfig = Required<LoggingConfig>;
254
+ /**
255
+ * Momentum CMS configuration.
256
+ */
257
+ export interface MomentumConfig {
258
+ /**
259
+ * Database configuration.
260
+ */
261
+ db: DatabaseConfig;
262
+ /**
263
+ * Collection definitions.
264
+ */
265
+ collections: CollectionConfig[];
266
+ /**
267
+ * Global definitions (singleton documents like site settings).
268
+ */
269
+ globals?: GlobalConfig[];
270
+ /**
271
+ * Admin panel configuration.
272
+ */
273
+ admin?: AdminPanelConfig;
274
+ /**
275
+ * Server configuration.
276
+ */
277
+ server?: ServerConfig;
278
+ /**
279
+ * Storage configuration for file uploads.
280
+ */
281
+ storage?: StorageConfig;
282
+ /**
283
+ * Seeding configuration for initial data.
284
+ * Provides declarative data seeding with strict typing.
285
+ */
286
+ seeding?: SeedingConfig;
287
+ /**
288
+ * Logging configuration.
289
+ * Controls log level, format, and timestamps.
290
+ */
291
+ logging?: LoggingConfig;
292
+ /**
293
+ * Plugins to register.
294
+ * Plugins run in array order during init/ready, reverse during shutdown.
295
+ */
296
+ plugins?: MomentumPlugin[];
297
+ }
298
+ /**
299
+ * Resolved seeding options with defaults applied.
300
+ */
301
+ export type ResolvedSeedingOptions = Required<SeedingOptions>;
302
+ /**
303
+ * Resolved seeding config with defaults applied.
304
+ */
305
+ export interface ResolvedSeedingConfig extends SeedingConfig {
306
+ options: ResolvedSeedingOptions;
307
+ }
308
+ /**
309
+ * Internal config with resolved defaults.
310
+ */
311
+ export interface ResolvedMomentumConfig extends MomentumConfig {
312
+ admin: Required<AdminPanelConfig>;
313
+ server: Required<ServerConfig>;
314
+ seeding?: ResolvedSeedingConfig;
315
+ logging: ResolvedLoggingConfig;
316
+ }
317
+ /**
318
+ * Defines Momentum CMS configuration.
319
+ * This is the main entry point for configuring the CMS.
320
+ *
321
+ * @example
322
+ * ```typescript
323
+ * // momentum.config.ts
324
+ * import { defineMomentumConfig } from '@momentumcms/core';
325
+ * import { sqliteAdapter } from '@momentumcms/db-drizzle';
326
+ * import { Posts } from './collections/posts';
327
+ * import { Users } from './collections/users';
328
+ *
329
+ * export default defineMomentumConfig({
330
+ * db: {
331
+ * adapter: sqliteAdapter({ filename: './data/momentum.db' }),
332
+ * },
333
+ * collections: [Posts, Users],
334
+ * admin: {
335
+ * basePath: '/admin',
336
+ * branding: {
337
+ * title: 'My CMS',
338
+ * },
339
+ * },
340
+ * });
341
+ * ```
342
+ */
343
+ export declare function defineMomentumConfig(config: MomentumConfig): ResolvedMomentumConfig;
344
+ /**
345
+ * Gets the database adapter from the config.
346
+ */
347
+ export declare function getDbAdapter(config: MomentumConfig): DatabaseAdapter;
348
+ /**
349
+ * Gets collections from the config.
350
+ */
351
+ export declare function getCollections(config: MomentumConfig): CollectionConfig[];
352
+ /**
353
+ * Gets globals from the config.
354
+ */
355
+ export declare function getGlobals(config: MomentumConfig): GlobalConfig[];
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Field Builder Functions for Momentum CMS
3
+ *
4
+ * These functions provide a clean API for defining collection fields.
5
+ * Example:
6
+ * fields: [
7
+ * text('title', { required: true }),
8
+ * richText('content'),
9
+ * relationship('author', { collection: () => Users }),
10
+ * ]
11
+ */
12
+ import type { TextField, TextareaField, RichTextField, NumberField, DateField, CheckboxField, SelectField, RadioField, EmailField, PasswordField, UploadField, RelationshipField, ArrayField, GroupField, BlocksField, JSONField, PointField, SlugField, TabsField, CollapsibleField, RowField, SelectOption, BlockConfig, TabConfig, Field, BaseFieldOptions, OnDeleteAction, NumberDisplayFormat, DateDisplayFormat } from './field.types';
13
+ export interface TextFieldOptions extends BaseFieldOptions {
14
+ minLength?: number;
15
+ maxLength?: number;
16
+ }
17
+ export declare function text(name: string, options?: TextFieldOptions): TextField;
18
+ export interface TextareaFieldOptions extends BaseFieldOptions {
19
+ minLength?: number;
20
+ maxLength?: number;
21
+ rows?: number;
22
+ }
23
+ export declare function textarea(name: string, options?: TextareaFieldOptions): TextareaField;
24
+ export type RichTextFieldOptions = BaseFieldOptions;
25
+ export declare function richText(name: string, options?: RichTextFieldOptions): RichTextField;
26
+ export interface NumberFieldOptions extends BaseFieldOptions {
27
+ min?: number;
28
+ max?: number;
29
+ step?: number;
30
+ /** Display format for read-only views (e.g. currency, percent) */
31
+ displayFormat?: NumberDisplayFormat;
32
+ }
33
+ export declare function number(name: string, options?: NumberFieldOptions): NumberField;
34
+ export interface DateFieldOptions extends BaseFieldOptions {
35
+ /** Display format for read-only views (e.g. preset style, locale) */
36
+ displayFormat?: DateDisplayFormat;
37
+ }
38
+ export declare function date(name: string, options?: DateFieldOptions): DateField;
39
+ export type CheckboxFieldOptions = BaseFieldOptions;
40
+ export declare function checkbox(name: string, options?: CheckboxFieldOptions): CheckboxField;
41
+ export interface SelectFieldOptions extends BaseFieldOptions {
42
+ options: SelectOption[];
43
+ hasMany?: boolean;
44
+ }
45
+ export declare function select(name: string, options: SelectFieldOptions): SelectField;
46
+ export interface RadioFieldOptions extends BaseFieldOptions {
47
+ options: SelectOption[];
48
+ }
49
+ export declare function radio(name: string, options: RadioFieldOptions): RadioField;
50
+ export type EmailFieldOptions = BaseFieldOptions;
51
+ export declare function email(name: string, options?: EmailFieldOptions): EmailField;
52
+ export interface PasswordFieldOptions extends BaseFieldOptions {
53
+ minLength?: number;
54
+ }
55
+ export declare function password(name: string, options?: PasswordFieldOptions): PasswordField;
56
+ export interface UploadFieldOptions extends BaseFieldOptions {
57
+ /** Collection slug where media documents are stored (default: 'media') */
58
+ relationTo?: string;
59
+ /** Allowed MIME types (e.g., ['image/*', 'application/pdf']) */
60
+ mimeTypes?: string[];
61
+ /** Maximum file size in bytes */
62
+ maxSize?: number;
63
+ /** Allow multiple file uploads */
64
+ hasMany?: boolean;
65
+ }
66
+ export declare function upload(name: string, options?: UploadFieldOptions): UploadField;
67
+ export interface RelationshipFieldOptions extends BaseFieldOptions {
68
+ collection: () => unknown;
69
+ /** Multiple target collections for polymorphic relationships */
70
+ relationTo?: Array<() => unknown>;
71
+ hasMany?: boolean;
72
+ /**
73
+ * Behavior when the referenced document is deleted.
74
+ * @default 'set-null'
75
+ */
76
+ onDelete?: OnDeleteAction;
77
+ /** Filter which related documents can be selected */
78
+ filterOptions?: (args: {
79
+ data: Record<string, unknown>;
80
+ }) => Record<string, unknown>;
81
+ }
82
+ export declare function relationship(name: string, options: RelationshipFieldOptions): RelationshipField;
83
+ export interface ArrayFieldOptions extends BaseFieldOptions {
84
+ fields: Field[];
85
+ minRows?: number;
86
+ maxRows?: number;
87
+ /** Name of the sub-field to use as summary label in read-only views. Falls back to first text sub-field. */
88
+ displayField?: string;
89
+ }
90
+ export declare function array(name: string, options: ArrayFieldOptions): ArrayField;
91
+ export interface GroupFieldOptions extends BaseFieldOptions {
92
+ fields: Field[];
93
+ }
94
+ export declare function group(name: string, options: GroupFieldOptions): GroupField;
95
+ export interface BlocksFieldOptions extends BaseFieldOptions {
96
+ blocks: BlockConfig[];
97
+ minRows?: number;
98
+ maxRows?: number;
99
+ }
100
+ export declare function blocks(name: string, options: BlocksFieldOptions): BlocksField;
101
+ export type JSONFieldOptions = BaseFieldOptions;
102
+ export declare function json(name: string, options?: JSONFieldOptions): JSONField;
103
+ export type PointFieldOptions = BaseFieldOptions;
104
+ export declare function point(name: string, options?: PointFieldOptions): PointField;
105
+ export interface SlugFieldOptions extends BaseFieldOptions {
106
+ from: string;
107
+ }
108
+ export declare function slug(name: string, options: SlugFieldOptions): SlugField;
109
+ export interface TabsFieldOptions {
110
+ tabs: TabConfig[];
111
+ label?: string;
112
+ description?: string;
113
+ }
114
+ /** Organizes fields into tabbed sections. Does not store data. */
115
+ export declare function tabs(name: string, options: TabsFieldOptions): TabsField;
116
+ export interface CollapsibleFieldOptions {
117
+ fields: Field[];
118
+ label?: string;
119
+ description?: string;
120
+ /** Whether the section starts expanded (default: false) */
121
+ defaultOpen?: boolean;
122
+ }
123
+ /** Wraps fields in a collapsible/expandable section. Does not store data. */
124
+ export declare function collapsible(name: string, options: CollapsibleFieldOptions): CollapsibleField;
125
+ export interface RowFieldOptions {
126
+ fields: Field[];
127
+ label?: string;
128
+ description?: string;
129
+ }
130
+ /** Displays child fields in a horizontal row layout. Does not store data. */
131
+ export declare function row(name: string, options: RowFieldOptions): RowField;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Built-in field constraint validators for Momentum CMS.
3
+ *
4
+ * Pure functions that validate field values against type-specific constraints
5
+ * (minLength, maxLength, min, max, step, minRows, maxRows, email format, select options).
6
+ * Shared by server-core (server-side validation) and admin (client-side validation).
7
+ */
8
+ import type { Field } from './field.types';
9
+ export interface FieldConstraintError {
10
+ field: string;
11
+ message: string;
12
+ }
13
+ /**
14
+ * Validates a field's value against its built-in constraints.
15
+ * Returns an array of errors (empty if valid).
16
+ * Skips validation for null/undefined values (required-check is separate).
17
+ */
18
+ export declare function validateFieldConstraints(field: Field, value: unknown): FieldConstraintError[];