@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.
- package/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/index.cjs +730 -0
- package/package.json +32 -0
- package/src/generators/types/generator.d.ts +27 -0
- package/src/index.d.ts +14 -0
- package/src/lib/access/access-helpers.d.ts +212 -0
- package/src/lib/access/index.d.ts +6 -0
- package/src/lib/collections/collection.types.d.ts +279 -0
- package/src/lib/collections/define-collection.d.ts +53 -0
- package/src/lib/collections/index.d.ts +5 -0
- package/src/lib/collections/media.collection.d.ts +29 -0
- package/src/lib/config.d.ts +355 -0
- package/src/lib/fields/field-builders.d.ts +131 -0
- package/src/lib/fields/field-validators.d.ts +18 -0
- package/src/lib/fields/field.types.d.ts +271 -0
- package/src/lib/fields/humanize-field-name.d.ts +12 -0
- package/src/lib/fields/index.d.ts +6 -0
- package/src/lib/plugins.d.ts +176 -0
- package/src/lib/seeding/index.d.ts +7 -0
- package/src/lib/seeding/seed-helpers.d.ts +22 -0
- package/src/lib/seeding/seeding.types.d.ts +459 -0
- package/src/lib/storage/index.d.ts +86 -0
- package/src/lib/versions/index.d.ts +5 -0
- package/src/lib/versions/version.types.d.ts +149 -0
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@momentumcms/core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Core collection config, fields, hooks, and access control for Momentum CMS",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Momentum CMS Contributors",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/momentum-cms/momentum-cms.git",
|
|
10
|
+
"directory": "libs/core"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/momentum-cms/momentum-cms#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/momentum-cms/momentum-cms/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"cms",
|
|
18
|
+
"headless-cms",
|
|
19
|
+
"angular",
|
|
20
|
+
"momentum-cms",
|
|
21
|
+
"collections",
|
|
22
|
+
"fields",
|
|
23
|
+
"content-management"
|
|
24
|
+
],
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"type": "commonjs",
|
|
29
|
+
"main": "./index.cjs",
|
|
30
|
+
"types": "./src/index.d.ts",
|
|
31
|
+
"dependencies": {}
|
|
32
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Momentum CMS Type Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates TypeScript interfaces from collection definitions.
|
|
5
|
+
* Run via: nx run <app>:generate-types
|
|
6
|
+
*/
|
|
7
|
+
interface GeneratorSchema {
|
|
8
|
+
configPath: string;
|
|
9
|
+
outputPath: string;
|
|
10
|
+
watch?: boolean;
|
|
11
|
+
}
|
|
12
|
+
interface ExecutorContext {
|
|
13
|
+
root: string;
|
|
14
|
+
projectName?: string;
|
|
15
|
+
projectsConfigurations?: {
|
|
16
|
+
projects: Record<string, {
|
|
17
|
+
root: string;
|
|
18
|
+
}>;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Main executor function.
|
|
23
|
+
*/
|
|
24
|
+
export default function runExecutor(options: GeneratorSchema, context: ExecutorContext): Promise<{
|
|
25
|
+
success: boolean;
|
|
26
|
+
}>;
|
|
27
|
+
export {};
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @momentumcms/core
|
|
3
|
+
*
|
|
4
|
+
* Core package for Momentum CMS
|
|
5
|
+
* Contains collection types, field builders, and utility functions
|
|
6
|
+
*/
|
|
7
|
+
export * from './lib/collections';
|
|
8
|
+
export * from './lib/fields';
|
|
9
|
+
export * from './lib/access';
|
|
10
|
+
export * from './lib/config';
|
|
11
|
+
export * from './lib/plugins';
|
|
12
|
+
export * from './lib/storage';
|
|
13
|
+
export * from './lib/seeding';
|
|
14
|
+
export * from './lib/versions';
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access Control Helpers
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe helper functions for defining access control rules.
|
|
5
|
+
* These helpers improve DX by providing:
|
|
6
|
+
* - Full IntelliSense for user properties
|
|
7
|
+
* - Type-safe role checking
|
|
8
|
+
* - Common access patterns as simple functions
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { access, hasRole, hasAnyRole, isAuthenticated, allowAll } from '@momentumcms/core';
|
|
13
|
+
*
|
|
14
|
+
* // Using pre-built helpers
|
|
15
|
+
* access: {
|
|
16
|
+
* read: allowAll(),
|
|
17
|
+
* create: isAuthenticated(),
|
|
18
|
+
* update: hasAnyRole(['admin', 'editor']),
|
|
19
|
+
* delete: hasRole('admin'),
|
|
20
|
+
* }
|
|
21
|
+
*
|
|
22
|
+
* // Using typed custom access
|
|
23
|
+
* interface MyUser {
|
|
24
|
+
* id: string;
|
|
25
|
+
* role: 'admin' | 'editor' | 'viewer';
|
|
26
|
+
* permissions: string[];
|
|
27
|
+
* }
|
|
28
|
+
*
|
|
29
|
+
* access: {
|
|
30
|
+
* read: access<MyUser>(({ user }) => user?.permissions.includes('read') ?? false),
|
|
31
|
+
* create: access<MyUser>(({ user }) => user?.role !== 'viewer'),
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
import type { AccessFunction, UserContext } from '../collections/collection.types';
|
|
36
|
+
/**
|
|
37
|
+
* Arguments passed to access callback functions.
|
|
38
|
+
* Generic over user type for full type safety.
|
|
39
|
+
*/
|
|
40
|
+
export interface AccessCallbackArgs<TUser extends UserContext = UserContext> {
|
|
41
|
+
/** The authenticated user, or undefined if not authenticated */
|
|
42
|
+
user: TUser | undefined;
|
|
43
|
+
/** Document ID (for update/delete operations) */
|
|
44
|
+
id?: string | number;
|
|
45
|
+
/** Document data (for create/update operations) */
|
|
46
|
+
data?: Record<string, unknown>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Typed access callback function.
|
|
50
|
+
* Receives user-friendly arguments with full type inference.
|
|
51
|
+
*/
|
|
52
|
+
export type AccessCallback<TUser extends UserContext = UserContext> = (args: AccessCallbackArgs<TUser>) => boolean | Promise<boolean>;
|
|
53
|
+
/**
|
|
54
|
+
* Creates a typed access function with full IntelliSense support.
|
|
55
|
+
*
|
|
56
|
+
* Use this when you need custom access logic with type-safe user properties.
|
|
57
|
+
* The generic type parameter lets you define your user shape for autocomplete.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* // With default UserContext type
|
|
62
|
+
* access: {
|
|
63
|
+
* read: access(({ user }) => user?.role === 'admin'),
|
|
64
|
+
* }
|
|
65
|
+
*
|
|
66
|
+
* // With custom user type for full IntelliSense
|
|
67
|
+
* interface MyUser {
|
|
68
|
+
* id: string;
|
|
69
|
+
* email: string;
|
|
70
|
+
* role: 'admin' | 'editor' | 'viewer';
|
|
71
|
+
* teamId: string;
|
|
72
|
+
* }
|
|
73
|
+
*
|
|
74
|
+
* access: {
|
|
75
|
+
* read: access<MyUser>(({ user }) => user?.teamId === 'team-1'),
|
|
76
|
+
* create: access<MyUser>(({ user, data }) => {
|
|
77
|
+
* // user has full MyUser type with autocomplete
|
|
78
|
+
* return user?.role === 'admin' || user?.role === 'editor';
|
|
79
|
+
* }),
|
|
80
|
+
* }
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function access<TUser extends UserContext = UserContext>(callback: AccessCallback<TUser>): AccessFunction;
|
|
84
|
+
/**
|
|
85
|
+
* Allow all access (public).
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```typescript
|
|
89
|
+
* access: {
|
|
90
|
+
* read: allowAll(), // Anyone can read
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export declare function allowAll(): AccessFunction;
|
|
95
|
+
/**
|
|
96
|
+
* Deny all access.
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* ```typescript
|
|
100
|
+
* access: {
|
|
101
|
+
* delete: denyAll(), // No one can delete
|
|
102
|
+
* }
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function denyAll(): AccessFunction;
|
|
106
|
+
/**
|
|
107
|
+
* Require authentication (any logged-in user).
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* access: {
|
|
112
|
+
* create: isAuthenticated(), // Any logged-in user can create
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export declare function isAuthenticated(): AccessFunction;
|
|
117
|
+
/**
|
|
118
|
+
* Require a specific role.
|
|
119
|
+
*
|
|
120
|
+
* @param role - The role required for access
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* access: {
|
|
125
|
+
* delete: hasRole('admin'), // Only admins can delete
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
export declare function hasRole(role: string): AccessFunction;
|
|
130
|
+
/**
|
|
131
|
+
* Require any of the specified roles.
|
|
132
|
+
*
|
|
133
|
+
* @param roles - Array of roles, any of which grants access
|
|
134
|
+
*
|
|
135
|
+
* @example
|
|
136
|
+
* ```typescript
|
|
137
|
+
* access: {
|
|
138
|
+
* update: hasAnyRole(['admin', 'editor']), // Admins or editors can update
|
|
139
|
+
* }
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
export declare function hasAnyRole(roles: readonly string[]): AccessFunction;
|
|
143
|
+
/**
|
|
144
|
+
* Require all of the specified roles (for multi-role systems).
|
|
145
|
+
*
|
|
146
|
+
* @param roles - Array of roles, all of which are required
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```typescript
|
|
150
|
+
* // If user has multiple roles stored as an array
|
|
151
|
+
* access: {
|
|
152
|
+
* admin: hasAllRoles(['verified', 'admin']),
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare function hasAllRoles(roles: readonly string[]): AccessFunction;
|
|
157
|
+
/**
|
|
158
|
+
* Combine multiple access functions with AND logic.
|
|
159
|
+
* All conditions must pass for access to be granted.
|
|
160
|
+
*
|
|
161
|
+
* @param fns - Access functions to combine
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript
|
|
165
|
+
* access: {
|
|
166
|
+
* update: and(isAuthenticated(), hasAnyRole(['admin', 'editor'])),
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
export declare function and(...fns: AccessFunction[]): AccessFunction;
|
|
171
|
+
/**
|
|
172
|
+
* Combine multiple access functions with OR logic.
|
|
173
|
+
* Any condition passing grants access.
|
|
174
|
+
*
|
|
175
|
+
* @param fns - Access functions to combine
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* access: {
|
|
180
|
+
* read: or(allowAll(), hasRole('admin')), // Public read, but admin always allowed
|
|
181
|
+
* }
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
export declare function or(...fns: AccessFunction[]): AccessFunction;
|
|
185
|
+
/**
|
|
186
|
+
* Negate an access function.
|
|
187
|
+
*
|
|
188
|
+
* @param fn - Access function to negate
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* access: {
|
|
193
|
+
* read: not(hasRole('banned')), // Anyone except banned users
|
|
194
|
+
* }
|
|
195
|
+
* ```
|
|
196
|
+
*/
|
|
197
|
+
export declare function not(fn: AccessFunction): AccessFunction;
|
|
198
|
+
/**
|
|
199
|
+
* Check if the authenticated user owns the document.
|
|
200
|
+
* Compares user.id with the document's author/owner field.
|
|
201
|
+
*
|
|
202
|
+
* @param ownerField - The field name containing the owner's user ID (default: 'createdBy')
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* ```typescript
|
|
206
|
+
* access: {
|
|
207
|
+
* update: or(hasRole('admin'), isOwner()), // Admin or document owner
|
|
208
|
+
* delete: or(hasRole('admin'), isOwner('authorId')),
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
export declare function isOwner(ownerField?: string): AccessFunction;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Access Control Module
|
|
3
|
+
*
|
|
4
|
+
* Provides type-safe helper functions for defining access control rules.
|
|
5
|
+
*/
|
|
6
|
+
export { access, type AccessCallback, type AccessCallbackArgs, allowAll, denyAll, isAuthenticated, hasRole, hasAnyRole, hasAllRoles, and, or, not, isOwner, } from './access-helpers';
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collection Types for Momentum CMS
|
|
3
|
+
* Defines the structure of collections (similar to Payload CMS)
|
|
4
|
+
*/
|
|
5
|
+
import type { Field } from '../fields/field.types';
|
|
6
|
+
export interface AccessArgs {
|
|
7
|
+
req: RequestContext;
|
|
8
|
+
id?: string | number;
|
|
9
|
+
data?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export interface RequestContext {
|
|
12
|
+
user?: UserContext;
|
|
13
|
+
headers?: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
export interface UserContext {
|
|
16
|
+
id: string | number;
|
|
17
|
+
email?: string;
|
|
18
|
+
role?: string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
export type AccessFunction = (args: AccessArgs) => boolean | Promise<boolean>;
|
|
22
|
+
export interface AccessConfig {
|
|
23
|
+
create?: AccessFunction;
|
|
24
|
+
read?: AccessFunction;
|
|
25
|
+
update?: AccessFunction;
|
|
26
|
+
delete?: AccessFunction;
|
|
27
|
+
admin?: AccessFunction;
|
|
28
|
+
unlock?: AccessFunction;
|
|
29
|
+
/** Control who can restore soft-deleted documents (falls back to update access) */
|
|
30
|
+
restore?: AccessFunction;
|
|
31
|
+
/** Control who can permanently delete soft-deleted documents (falls back to delete access) */
|
|
32
|
+
forceDelete?: AccessFunction;
|
|
33
|
+
/** Control who can read version history */
|
|
34
|
+
readVersions?: AccessFunction;
|
|
35
|
+
/** Control who can publish/unpublish documents */
|
|
36
|
+
publishVersions?: AccessFunction;
|
|
37
|
+
/** Control who can restore previous versions */
|
|
38
|
+
restoreVersions?: AccessFunction;
|
|
39
|
+
}
|
|
40
|
+
export interface HookArgs {
|
|
41
|
+
req: RequestContext;
|
|
42
|
+
data?: Record<string, unknown>;
|
|
43
|
+
doc?: Record<string, unknown>;
|
|
44
|
+
operation?: 'create' | 'update' | 'delete' | 'softDelete' | 'restore';
|
|
45
|
+
originalDoc?: Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
export type HookFunction = (args: HookArgs) => Record<string, unknown> | void | Promise<Record<string, unknown> | void>;
|
|
48
|
+
export interface HooksConfig {
|
|
49
|
+
beforeValidate?: HookFunction[];
|
|
50
|
+
beforeChange?: HookFunction[];
|
|
51
|
+
afterChange?: HookFunction[];
|
|
52
|
+
beforeRead?: HookFunction[];
|
|
53
|
+
afterRead?: HookFunction[];
|
|
54
|
+
beforeDelete?: HookFunction[];
|
|
55
|
+
afterDelete?: HookFunction[];
|
|
56
|
+
beforeRestore?: HookFunction[];
|
|
57
|
+
afterRestore?: HookFunction[];
|
|
58
|
+
}
|
|
59
|
+
export interface AdminConfig {
|
|
60
|
+
/** Field to use as the document title in the admin UI */
|
|
61
|
+
useAsTitle?: string;
|
|
62
|
+
/** Default columns to show in list view */
|
|
63
|
+
defaultColumns?: string[];
|
|
64
|
+
/** Admin sidebar group */
|
|
65
|
+
group?: string;
|
|
66
|
+
/** Fields searchable in admin list */
|
|
67
|
+
listSearchableFields?: string[];
|
|
68
|
+
/** Pagination settings */
|
|
69
|
+
pagination?: {
|
|
70
|
+
defaultLimit?: number;
|
|
71
|
+
limits?: number[];
|
|
72
|
+
};
|
|
73
|
+
/** Custom description for admin UI */
|
|
74
|
+
description?: string;
|
|
75
|
+
/** Hide from admin navigation */
|
|
76
|
+
hidden?: boolean;
|
|
77
|
+
/** Enable preview mode */
|
|
78
|
+
preview?: boolean | ((doc: Record<string, unknown>) => string);
|
|
79
|
+
/** Custom action buttons displayed in the collection list header (alongside Create button) */
|
|
80
|
+
headerActions?: Array<{
|
|
81
|
+
id: string;
|
|
82
|
+
label: string;
|
|
83
|
+
/** HTTP endpoint path for the action (e.g., '/api/auth/api-keys') */
|
|
84
|
+
endpoint?: string;
|
|
85
|
+
}>;
|
|
86
|
+
}
|
|
87
|
+
export interface VersionsConfig {
|
|
88
|
+
/** Enable draft versions */
|
|
89
|
+
drafts?: boolean | DraftsConfig;
|
|
90
|
+
/** Maximum versions to keep per document */
|
|
91
|
+
maxPerDoc?: number;
|
|
92
|
+
}
|
|
93
|
+
export interface DraftsConfig {
|
|
94
|
+
/** Auto-save drafts */
|
|
95
|
+
autosave?: boolean | AutosaveConfig;
|
|
96
|
+
}
|
|
97
|
+
export interface AutosaveConfig {
|
|
98
|
+
/** Interval in milliseconds */
|
|
99
|
+
interval?: number;
|
|
100
|
+
}
|
|
101
|
+
export interface AuthConfig {
|
|
102
|
+
/** Enable token-based auth */
|
|
103
|
+
tokenExpiration?: number;
|
|
104
|
+
/** Verify email before login */
|
|
105
|
+
verify?: boolean;
|
|
106
|
+
/** Max login attempts before lockout */
|
|
107
|
+
maxLoginAttempts?: number;
|
|
108
|
+
/** Lockout interval in milliseconds */
|
|
109
|
+
lockTime?: number;
|
|
110
|
+
/** Cookies configuration */
|
|
111
|
+
cookies?: {
|
|
112
|
+
secure?: boolean;
|
|
113
|
+
sameSite?: 'strict' | 'lax' | 'none';
|
|
114
|
+
domain?: string;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
export interface SoftDeleteConfig {
|
|
118
|
+
/** Column name for the deletion timestamp. @default 'deletedAt' */
|
|
119
|
+
field?: string;
|
|
120
|
+
/** Auto-purge soft-deleted records after this many days. Undefined means never purge. */
|
|
121
|
+
retentionDays?: number;
|
|
122
|
+
}
|
|
123
|
+
export interface TimestampsConfig {
|
|
124
|
+
/** Add createdAt field */
|
|
125
|
+
createdAt?: boolean;
|
|
126
|
+
/** Add updatedAt field */
|
|
127
|
+
updatedAt?: boolean;
|
|
128
|
+
}
|
|
129
|
+
export interface IndexDefinition {
|
|
130
|
+
/** Column names to include in the index */
|
|
131
|
+
columns: string[];
|
|
132
|
+
/** Whether this index enforces uniqueness */
|
|
133
|
+
unique?: boolean;
|
|
134
|
+
/** Custom index name (auto-generated from columns if omitted) */
|
|
135
|
+
name?: string;
|
|
136
|
+
}
|
|
137
|
+
export interface CollectionConfig {
|
|
138
|
+
/** Unique identifier for the collection (used in URLs and database) */
|
|
139
|
+
slug: string;
|
|
140
|
+
/** Custom labels */
|
|
141
|
+
labels?: {
|
|
142
|
+
singular?: string;
|
|
143
|
+
plural?: string;
|
|
144
|
+
};
|
|
145
|
+
/** Field definitions */
|
|
146
|
+
fields: Field[];
|
|
147
|
+
/** Admin panel configuration */
|
|
148
|
+
admin?: AdminConfig;
|
|
149
|
+
/** Access control functions */
|
|
150
|
+
access?: AccessConfig;
|
|
151
|
+
/** Lifecycle hooks */
|
|
152
|
+
hooks?: HooksConfig;
|
|
153
|
+
/** Enable authentication for this collection (makes it a user collection) */
|
|
154
|
+
auth?: boolean | AuthConfig;
|
|
155
|
+
/** Enable versioning */
|
|
156
|
+
versions?: boolean | VersionsConfig;
|
|
157
|
+
/** Timestamps configuration */
|
|
158
|
+
timestamps?: boolean | TimestampsConfig;
|
|
159
|
+
/** Enable soft deletes (sets deletedAt instead of removing row) */
|
|
160
|
+
softDelete?: boolean | SoftDeleteConfig;
|
|
161
|
+
/**
|
|
162
|
+
* Mark this collection as managed — schema is created but no CRUD routes are generated.
|
|
163
|
+
* Useful for tables owned by external systems (e.g., Better Auth) that should participate
|
|
164
|
+
* in schema generation and optionally appear in the admin UI.
|
|
165
|
+
*/
|
|
166
|
+
managed?: boolean;
|
|
167
|
+
/** Custom database table/collection name */
|
|
168
|
+
dbName?: string;
|
|
169
|
+
/** Explicit database indexes for this collection */
|
|
170
|
+
indexes?: IndexDefinition[];
|
|
171
|
+
/** Default sort field */
|
|
172
|
+
defaultSort?: string;
|
|
173
|
+
/** GraphQL configuration */
|
|
174
|
+
graphQL?: {
|
|
175
|
+
singularName?: string;
|
|
176
|
+
pluralName?: string;
|
|
177
|
+
disableQueries?: boolean;
|
|
178
|
+
disableMutations?: boolean;
|
|
179
|
+
};
|
|
180
|
+
/**
|
|
181
|
+
* Default query constraints applied to all CRUD operations (find, findById, update, delete).
|
|
182
|
+
* For reads, constraints are injected into the query. For mutations, the document is checked
|
|
183
|
+
* post-fetch and rejected with DocumentNotFoundError if it falls outside the user's scope.
|
|
184
|
+
* Returns WHERE conditions to enforce, or undefined for no filtering.
|
|
185
|
+
*/
|
|
186
|
+
defaultWhere?: (req: RequestContext) => Record<string, unknown> | undefined;
|
|
187
|
+
/** Custom endpoints */
|
|
188
|
+
endpoints?: EndpointConfig[];
|
|
189
|
+
/** Webhook subscriptions for this collection */
|
|
190
|
+
webhooks?: WebhookConfig[];
|
|
191
|
+
}
|
|
192
|
+
/** Events that trigger webhooks. */
|
|
193
|
+
export type WebhookEvent = 'afterChange' | 'afterDelete' | 'afterCreate' | 'afterUpdate';
|
|
194
|
+
/** Configuration for a single webhook subscription. */
|
|
195
|
+
export interface WebhookConfig {
|
|
196
|
+
/** URL to send the webhook POST request to. */
|
|
197
|
+
url: string;
|
|
198
|
+
/** Events that trigger this webhook. Defaults to all events. */
|
|
199
|
+
events?: WebhookEvent[];
|
|
200
|
+
/** Secret for HMAC-SHA256 signature verification. */
|
|
201
|
+
secret?: string;
|
|
202
|
+
/** Maximum retries on failure. @default 0 */
|
|
203
|
+
retries?: number;
|
|
204
|
+
/** Custom headers to include in the request. */
|
|
205
|
+
headers?: Record<string, string>;
|
|
206
|
+
}
|
|
207
|
+
/** Payload sent in webhook POST requests. */
|
|
208
|
+
export interface WebhookPayload {
|
|
209
|
+
/** The event that triggered the webhook. */
|
|
210
|
+
event: WebhookEvent;
|
|
211
|
+
/** The collection slug. */
|
|
212
|
+
collection: string;
|
|
213
|
+
/** The operation type. */
|
|
214
|
+
operation: 'create' | 'update' | 'delete' | 'softDelete' | 'restore';
|
|
215
|
+
/** Timestamp of the event. */
|
|
216
|
+
timestamp: string;
|
|
217
|
+
/** The document data (after the operation). */
|
|
218
|
+
doc: Record<string, unknown>;
|
|
219
|
+
/** The previous document data (for updates). */
|
|
220
|
+
previousDoc?: Record<string, unknown>;
|
|
221
|
+
}
|
|
222
|
+
/** Response from a custom endpoint handler. */
|
|
223
|
+
export interface EndpointResponse {
|
|
224
|
+
status: number;
|
|
225
|
+
body: unknown;
|
|
226
|
+
}
|
|
227
|
+
/** Arguments passed to custom endpoint handlers. */
|
|
228
|
+
export interface EndpointArgs {
|
|
229
|
+
/** Request context (user, headers) */
|
|
230
|
+
req: RequestContext;
|
|
231
|
+
/** This collection's config */
|
|
232
|
+
collection: CollectionConfig;
|
|
233
|
+
/** Request body (for POST/PUT/PATCH endpoints) */
|
|
234
|
+
body?: Record<string, unknown>;
|
|
235
|
+
/**
|
|
236
|
+
* Async helper to query any collection.
|
|
237
|
+
* Returns the raw API result (find returns { docs, totalDocs }, findById returns doc, etc.).
|
|
238
|
+
* Abstracts away server-core imports so collections remain isomorphic.
|
|
239
|
+
*/
|
|
240
|
+
query: EndpointQueryHelper;
|
|
241
|
+
}
|
|
242
|
+
/** Query helper for custom endpoints - provides access to collection data without server-core imports. */
|
|
243
|
+
export interface EndpointQueryHelper {
|
|
244
|
+
find: (slug: string, options?: {
|
|
245
|
+
limit?: number;
|
|
246
|
+
page?: number;
|
|
247
|
+
}) => Promise<{
|
|
248
|
+
docs: Record<string, unknown>[];
|
|
249
|
+
totalDocs: number;
|
|
250
|
+
}>;
|
|
251
|
+
findById: (slug: string, id: string) => Promise<Record<string, unknown> | null>;
|
|
252
|
+
count: (slug: string) => Promise<number>;
|
|
253
|
+
create: (slug: string, data: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
254
|
+
update: (slug: string, id: string, data: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
255
|
+
delete: (slug: string, id: string) => Promise<{
|
|
256
|
+
id: string;
|
|
257
|
+
deleted: boolean;
|
|
258
|
+
}>;
|
|
259
|
+
/**
|
|
260
|
+
* Execute multiple operations within a database transaction.
|
|
261
|
+
* All operations succeed or all are rolled back.
|
|
262
|
+
* Falls back to non-transactional execution if adapter doesn't support transactions.
|
|
263
|
+
*/
|
|
264
|
+
transaction: <T>(callback: (query: EndpointQueryHelper) => Promise<T>) => Promise<T>;
|
|
265
|
+
}
|
|
266
|
+
export interface EndpointConfig {
|
|
267
|
+
path: string;
|
|
268
|
+
method: 'get' | 'post' | 'put' | 'patch' | 'delete';
|
|
269
|
+
handler: (args: EndpointArgs) => Promise<EndpointResponse>;
|
|
270
|
+
}
|
|
271
|
+
export interface GlobalConfig {
|
|
272
|
+
slug: string;
|
|
273
|
+
label?: string;
|
|
274
|
+
fields: Field[];
|
|
275
|
+
admin?: Omit<AdminConfig, 'useAsTitle' | 'defaultColumns' | 'pagination'>;
|
|
276
|
+
access?: Pick<AccessConfig, 'read' | 'update'>;
|
|
277
|
+
hooks?: Pick<HooksConfig, 'beforeValidate' | 'beforeChange' | 'afterChange' | 'beforeRead' | 'afterRead'>;
|
|
278
|
+
versions?: boolean | VersionsConfig;
|
|
279
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Define Collection Function
|
|
3
|
+
*
|
|
4
|
+
* Creates a collection configuration with proper typing.
|
|
5
|
+
* This is the main entry point for defining collections in Momentum CMS.
|
|
6
|
+
*
|
|
7
|
+
* Example:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* export const Posts = defineCollection({
|
|
10
|
+
* slug: 'posts',
|
|
11
|
+
* fields: [
|
|
12
|
+
* text('title', { required: true }),
|
|
13
|
+
* richText('content'),
|
|
14
|
+
* ],
|
|
15
|
+
* access: {
|
|
16
|
+
* read: () => true,
|
|
17
|
+
* create: ({ req }) => !!req.user,
|
|
18
|
+
* },
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
import type { CollectionConfig, GlobalConfig } from './collection.types';
|
|
23
|
+
/**
|
|
24
|
+
* Define a collection configuration
|
|
25
|
+
* @param config Collection configuration object
|
|
26
|
+
* @returns The same configuration with proper typing
|
|
27
|
+
*/
|
|
28
|
+
export declare function defineCollection(config: CollectionConfig): CollectionConfig;
|
|
29
|
+
/**
|
|
30
|
+
* Define a global configuration (single document, like site settings)
|
|
31
|
+
* @param config Global configuration object
|
|
32
|
+
* @returns The same configuration with proper typing
|
|
33
|
+
*/
|
|
34
|
+
export declare function defineGlobal(config: GlobalConfig): GlobalConfig;
|
|
35
|
+
/**
|
|
36
|
+
* Get the soft delete field name for a collection.
|
|
37
|
+
* Returns the field name (default 'deletedAt') if soft delete is enabled, or null if not.
|
|
38
|
+
*
|
|
39
|
+
* @param config - The collection configuration
|
|
40
|
+
* @returns The deletedAt field name, or null if soft delete is not enabled
|
|
41
|
+
*/
|
|
42
|
+
export declare function getSoftDeleteField(config: CollectionConfig): string | null;
|
|
43
|
+
/**
|
|
44
|
+
* Helper type to extract the document type from a collection
|
|
45
|
+
* Useful for typing API responses and database queries
|
|
46
|
+
*/
|
|
47
|
+
export type InferDocumentType<T extends CollectionConfig> = {
|
|
48
|
+
id: string | number;
|
|
49
|
+
createdAt?: Date;
|
|
50
|
+
updatedAt?: Date;
|
|
51
|
+
} & {
|
|
52
|
+
[K in T['fields'][number]['name']]?: unknown;
|
|
53
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './collection.types';
|
|
2
|
+
export { defineCollection, defineGlobal, getSoftDeleteField } from './define-collection';
|
|
3
|
+
export type { InferDocumentType } from './define-collection';
|
|
4
|
+
export { MediaCollection } from './media.collection';
|
|
5
|
+
export type { MediaDocument } from './media.collection';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in Media Collection for Momentum CMS
|
|
3
|
+
* Stores metadata for uploaded files
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Built-in Media collection for storing file upload metadata.
|
|
7
|
+
* Users can override this by defining their own 'media' collection.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MediaCollection: import("./collection.types").CollectionConfig;
|
|
10
|
+
/**
|
|
11
|
+
* Type for a media document.
|
|
12
|
+
*/
|
|
13
|
+
export interface MediaDocument {
|
|
14
|
+
id: string;
|
|
15
|
+
filename: string;
|
|
16
|
+
mimeType: string;
|
|
17
|
+
filesize?: number;
|
|
18
|
+
path: string;
|
|
19
|
+
url?: string;
|
|
20
|
+
alt?: string;
|
|
21
|
+
width?: number;
|
|
22
|
+
height?: number;
|
|
23
|
+
focalPoint?: {
|
|
24
|
+
x: number;
|
|
25
|
+
y: number;
|
|
26
|
+
};
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
}
|