@easy-cms/core 0.25.0 → 0.26.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/dist/index.d.ts +135 -56
- package/dist/index.js +148 -6
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -254,6 +254,58 @@ declare function consoleEmail(options?: {
|
|
|
254
254
|
})[];
|
|
255
255
|
};
|
|
256
256
|
|
|
257
|
+
interface ConfigIssue {
|
|
258
|
+
/** Where the problem is, e.g. `collections.posts.fields.slug.from`. */
|
|
259
|
+
readonly path: string;
|
|
260
|
+
readonly message: string;
|
|
261
|
+
/** How to fix it. */
|
|
262
|
+
readonly hint?: string;
|
|
263
|
+
}
|
|
264
|
+
declare class ConfigError extends Error {
|
|
265
|
+
readonly issues: readonly ConfigIssue[];
|
|
266
|
+
constructor(issues: readonly ConfigIssue[]);
|
|
267
|
+
static format(issues: readonly ConfigIssue[]): string;
|
|
268
|
+
}
|
|
269
|
+
/** Base class for errors that map to an HTTP status in the REST API. */
|
|
270
|
+
declare class EasyCMSError extends Error {
|
|
271
|
+
readonly status: number;
|
|
272
|
+
constructor(message: string, status: number);
|
|
273
|
+
}
|
|
274
|
+
interface FieldError {
|
|
275
|
+
/** Dotted path, e.g. `links.0.url`. */
|
|
276
|
+
readonly field: string;
|
|
277
|
+
readonly message: string;
|
|
278
|
+
}
|
|
279
|
+
declare class ValidationError extends EasyCMSError {
|
|
280
|
+
readonly errors: readonly FieldError[];
|
|
281
|
+
constructor(collection: string, errors: readonly FieldError[]);
|
|
282
|
+
}
|
|
283
|
+
declare class NotFoundError extends EasyCMSError {
|
|
284
|
+
constructor(collection: string, id: unknown);
|
|
285
|
+
}
|
|
286
|
+
/** A bad `where`, `sort` or unknown collection/global. */
|
|
287
|
+
declare class QueryError extends EasyCMSError {
|
|
288
|
+
constructor(message: string);
|
|
289
|
+
}
|
|
290
|
+
/** The database schema does not match the config (pending or missing migrations). */
|
|
291
|
+
declare class SchemaError extends EasyCMSError {
|
|
292
|
+
constructor(message: string);
|
|
293
|
+
}
|
|
294
|
+
/** Not logged in, or the session is invalid. */
|
|
295
|
+
declare class UnauthorizedError extends EasyCMSError {
|
|
296
|
+
constructor(message?: string);
|
|
297
|
+
}
|
|
298
|
+
/** Logged in, but not allowed to do this. */
|
|
299
|
+
declare class ForbiddenError extends EasyCMSError {
|
|
300
|
+
constructor(message?: string);
|
|
301
|
+
}
|
|
302
|
+
declare class TooManyRequestsError extends EasyCMSError {
|
|
303
|
+
constructor(message: string);
|
|
304
|
+
}
|
|
305
|
+
declare class PayloadTooLargeError extends EasyCMSError {
|
|
306
|
+
constructor(message: string);
|
|
307
|
+
}
|
|
308
|
+
|
|
257
309
|
/** What a preview token opens: one document of a collection, or one global. */
|
|
258
310
|
type PreviewTarget = {
|
|
259
311
|
readonly collection: string;
|
|
@@ -533,7 +585,13 @@ type FieldValue<F extends Field, C extends Config = Config> = F extends {
|
|
|
533
585
|
} ? FieldsValue<Sub, C> : F extends {
|
|
534
586
|
readonly type: 'blocks';
|
|
535
587
|
readonly blocks: infer B extends readonly Block[];
|
|
536
|
-
} ? BlockValue<B[number], C>[] :
|
|
588
|
+
} ? BlockValue<B[number], C>[] : CustomValue<F>;
|
|
589
|
+
/** The value of a field of an added type (`CustomFieldTypes`). */
|
|
590
|
+
type CustomValue<F> = F extends {
|
|
591
|
+
readonly type: infer T extends keyof CustomFieldTypes;
|
|
592
|
+
} ? CustomFieldTypes[T] extends {
|
|
593
|
+
value: infer V;
|
|
594
|
+
} ? V : unknown : never;
|
|
537
595
|
/** One row of a `blocks` field: the block's fields plus `id` and `blockType` (distributes over kinds). */
|
|
538
596
|
type BlockValue<B, C extends Config> = B extends {
|
|
539
597
|
readonly slug: infer S;
|
|
@@ -1082,7 +1140,31 @@ interface FieldAdmin {
|
|
|
1082
1140
|
readonly component?: AdminComponent;
|
|
1083
1141
|
/** Shown below the field, e.g. a length meter or a preview. */
|
|
1084
1142
|
readonly after?: readonly AdminComponent[];
|
|
1143
|
+
/** Shows the value in the admin's lists (e.g. a color swatch). Default: the plain value. */
|
|
1144
|
+
readonly cell?: AdminComponent;
|
|
1085
1145
|
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Field types that packages add (`fieldTypes` in the config), for the types inferred from the
|
|
1148
|
+
* config. A package declares its own by augmenting this interface:
|
|
1149
|
+
*
|
|
1150
|
+
* ```ts
|
|
1151
|
+
* declare module '@easy-cms/core' {
|
|
1152
|
+
* interface CustomFieldTypes {
|
|
1153
|
+
* color: { value: string; options: { readonly presets?: readonly string[] } }
|
|
1154
|
+
* }
|
|
1155
|
+
* }
|
|
1156
|
+
* ```
|
|
1157
|
+
*/
|
|
1158
|
+
interface CustomFieldTypes {
|
|
1159
|
+
}
|
|
1160
|
+
/** A field of a type from `CustomFieldTypes`: the common options, plus the type's own. */
|
|
1161
|
+
type CustomField = {
|
|
1162
|
+
[K in keyof CustomFieldTypes]: BaseField<K & string, CustomFieldTypes[K] extends {
|
|
1163
|
+
value: infer V;
|
|
1164
|
+
} ? V : unknown> & (CustomFieldTypes[K] extends {
|
|
1165
|
+
options: infer O;
|
|
1166
|
+
} ? O : unknown);
|
|
1167
|
+
}[keyof CustomFieldTypes];
|
|
1086
1168
|
interface BaseField<TType extends string, TValue> {
|
|
1087
1169
|
readonly type: TType;
|
|
1088
1170
|
readonly name: string;
|
|
@@ -1104,6 +1186,8 @@ interface BaseField<TType extends string, TValue> {
|
|
|
1104
1186
|
readonly position?: 'sidebar';
|
|
1105
1187
|
/** Custom admin components for this field. */
|
|
1106
1188
|
readonly admin?: FieldAdmin;
|
|
1189
|
+
/** Set by Easy CMS on fields of an added type (`fieldTypes`): the type's name, e.g. `color`. */
|
|
1190
|
+
readonly customType?: string;
|
|
1107
1191
|
}
|
|
1108
1192
|
interface TextField extends BaseField<'text', string> {
|
|
1109
1193
|
readonly minLength?: number;
|
|
@@ -1220,10 +1304,48 @@ declare function mimeAllowedBy(mimeType: string, patterns: readonly string[]): b
|
|
|
1220
1304
|
declare const hasRows: (field: Field) => field is ArrayField | BlocksField;
|
|
1221
1305
|
/** The fields of one row of an `array` or `blocks` field (`undefined` for an unknown block). */
|
|
1222
1306
|
declare function rowFields(field: ArrayField | BlocksField, row: unknown): readonly Field[] | undefined;
|
|
1223
|
-
type Field = TextField | TextareaField | NumberField | BooleanField | DateField | EmailField | JsonField | SelectField | SlugField | RichTextField | UploadField | RelationshipField | ArrayField | GroupField | BlocksField;
|
|
1307
|
+
type Field = CustomField | TextField | TextareaField | NumberField | BooleanField | DateField | EmailField | JsonField | SelectField | SlugField | RichTextField | UploadField | RelationshipField | ArrayField | GroupField | BlocksField;
|
|
1224
1308
|
type FieldType = Field['type'];
|
|
1225
1309
|
declare const FIELD_TYPES: readonly ["text", "textarea", "number", "boolean", "date", "email", "json", "select", "slug", "richText", "upload", "relationship", "array", "group", "blocks"];
|
|
1226
1310
|
|
|
1311
|
+
/** Built-in types a field type can be stored as. */
|
|
1312
|
+
declare const FIELD_TYPE_BASES: readonly ["text", "textarea", "email", "number", "boolean", "date", "json"];
|
|
1313
|
+
type FieldTypeBase = (typeof FIELD_TYPE_BASES)[number];
|
|
1314
|
+
/** What a field type's `validate` gets besides the value: the field, with its own options. */
|
|
1315
|
+
interface FieldTypeValidateContext extends FieldValidateContext {
|
|
1316
|
+
readonly field: Readonly<Record<string, unknown>> & {
|
|
1317
|
+
readonly name: string;
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
/**
|
|
1321
|
+
* A field type a package adds, e.g. `color`: stored, queried and translated like its `base`
|
|
1322
|
+
* type, with its own checks and admin components. List it in the config's `fieldTypes`.
|
|
1323
|
+
*/
|
|
1324
|
+
interface FieldTypeDefinition {
|
|
1325
|
+
/** The `type` fields use, e.g. `color`. Lowercase; not one of the built-in types. */
|
|
1326
|
+
readonly name: string;
|
|
1327
|
+
/** How values are stored and queried: one of the built-in scalar types. */
|
|
1328
|
+
readonly base: FieldTypeBase;
|
|
1329
|
+
/** Checks a value (not empty ones; `required` covers those). Return `true` or a message. */
|
|
1330
|
+
readonly validate?: (value: unknown, ctx: FieldTypeValidateContext) => true | string | Promise<true | string>;
|
|
1331
|
+
/** Checks a field's own options when the config loads; return a message for a mistake. */
|
|
1332
|
+
readonly checkOptions?: (field: Readonly<Record<string, unknown>>) => string | undefined;
|
|
1333
|
+
readonly admin?: {
|
|
1334
|
+
/** The input: a Web Component from `module`. */
|
|
1335
|
+
readonly component?: string;
|
|
1336
|
+
/** Shown in the admin's lists. */
|
|
1337
|
+
readonly cell?: string;
|
|
1338
|
+
/** The admin module (package export or file) that defines the components. */
|
|
1339
|
+
readonly module?: string;
|
|
1340
|
+
/** The field options its components get (as their `options`), e.g. `['presets']`. */
|
|
1341
|
+
readonly props?: readonly string[];
|
|
1342
|
+
};
|
|
1343
|
+
/** The value's TypeScript type for `generate:types`. Default: the base type's. */
|
|
1344
|
+
readonly typescript?: string;
|
|
1345
|
+
}
|
|
1346
|
+
/** Declares a field type; returns it unchanged. */
|
|
1347
|
+
declare function defineFieldType(definition: FieldTypeDefinition): FieldTypeDefinition;
|
|
1348
|
+
|
|
1227
1349
|
declare const WEBHOOK_EVENTS: readonly ["create", "update", "delete", "publish", "unpublish", "draft"];
|
|
1228
1350
|
/**
|
|
1229
1351
|
* `create`, `update`, `delete`: the stored document changed. `publish` / `unpublish`: its status
|
|
@@ -1621,6 +1743,11 @@ interface Config {
|
|
|
1621
1743
|
readonly endpoints?: readonly Endpoint[];
|
|
1622
1744
|
/** Extra `easy-cms <name>` CLI commands, e.g. from plugins. */
|
|
1623
1745
|
readonly commands?: readonly CliCommand[];
|
|
1746
|
+
/**
|
|
1747
|
+
* Field types from packages, e.g. `color` from `@easy-cms/fields`: fields then use
|
|
1748
|
+
* `type: 'color'`. See `defineFieldType`.
|
|
1749
|
+
*/
|
|
1750
|
+
readonly fieldTypes?: readonly FieldTypeDefinition[];
|
|
1624
1751
|
/**
|
|
1625
1752
|
* API keys for scripts and other apps (`Authorization: Bearer ecms_…`), managed in the admin
|
|
1626
1753
|
* under Settings. A key acts as its owner, limited to the collections and operations it lists.
|
|
@@ -1647,6 +1774,7 @@ interface ResolvedConfig extends Omit<Config, 'cors' | 'localization' | 'routes'
|
|
|
1647
1774
|
readonly globals: readonly GlobalConfig[];
|
|
1648
1775
|
readonly endpoints: readonly Endpoint[];
|
|
1649
1776
|
readonly commands: readonly CliCommand[];
|
|
1777
|
+
readonly fieldTypes: readonly FieldTypeDefinition[];
|
|
1650
1778
|
}
|
|
1651
1779
|
/**
|
|
1652
1780
|
* Declares the Easy CMS config. Returns it unchanged, keeping literal types
|
|
@@ -1720,58 +1848,6 @@ declare function copyDatabase(source: Database, target: Database, options?: {
|
|
|
1720
1848
|
onTable?: (progress: CopyProgress) => void;
|
|
1721
1849
|
}): Promise<CopyResult>;
|
|
1722
1850
|
|
|
1723
|
-
interface ConfigIssue {
|
|
1724
|
-
/** Where the problem is, e.g. `collections.posts.fields.slug.from`. */
|
|
1725
|
-
readonly path: string;
|
|
1726
|
-
readonly message: string;
|
|
1727
|
-
/** How to fix it. */
|
|
1728
|
-
readonly hint?: string;
|
|
1729
|
-
}
|
|
1730
|
-
declare class ConfigError extends Error {
|
|
1731
|
-
readonly issues: readonly ConfigIssue[];
|
|
1732
|
-
constructor(issues: readonly ConfigIssue[]);
|
|
1733
|
-
static format(issues: readonly ConfigIssue[]): string;
|
|
1734
|
-
}
|
|
1735
|
-
/** Base class for errors that map to an HTTP status in the REST API. */
|
|
1736
|
-
declare class EasyCMSError extends Error {
|
|
1737
|
-
readonly status: number;
|
|
1738
|
-
constructor(message: string, status: number);
|
|
1739
|
-
}
|
|
1740
|
-
interface FieldError {
|
|
1741
|
-
/** Dotted path, e.g. `links.0.url`. */
|
|
1742
|
-
readonly field: string;
|
|
1743
|
-
readonly message: string;
|
|
1744
|
-
}
|
|
1745
|
-
declare class ValidationError extends EasyCMSError {
|
|
1746
|
-
readonly errors: readonly FieldError[];
|
|
1747
|
-
constructor(collection: string, errors: readonly FieldError[]);
|
|
1748
|
-
}
|
|
1749
|
-
declare class NotFoundError extends EasyCMSError {
|
|
1750
|
-
constructor(collection: string, id: unknown);
|
|
1751
|
-
}
|
|
1752
|
-
/** A bad `where`, `sort` or unknown collection/global. */
|
|
1753
|
-
declare class QueryError extends EasyCMSError {
|
|
1754
|
-
constructor(message: string);
|
|
1755
|
-
}
|
|
1756
|
-
/** The database schema does not match the config (pending or missing migrations). */
|
|
1757
|
-
declare class SchemaError extends EasyCMSError {
|
|
1758
|
-
constructor(message: string);
|
|
1759
|
-
}
|
|
1760
|
-
/** Not logged in, or the session is invalid. */
|
|
1761
|
-
declare class UnauthorizedError extends EasyCMSError {
|
|
1762
|
-
constructor(message?: string);
|
|
1763
|
-
}
|
|
1764
|
-
/** Logged in, but not allowed to do this. */
|
|
1765
|
-
declare class ForbiddenError extends EasyCMSError {
|
|
1766
|
-
constructor(message?: string);
|
|
1767
|
-
}
|
|
1768
|
-
declare class TooManyRequestsError extends EasyCMSError {
|
|
1769
|
-
constructor(message: string);
|
|
1770
|
-
}
|
|
1771
|
-
declare class PayloadTooLargeError extends EasyCMSError {
|
|
1772
|
-
constructor(message: string);
|
|
1773
|
-
}
|
|
1774
|
-
|
|
1775
1851
|
type Localization = Required<LocalizationConfig>;
|
|
1776
1852
|
|
|
1777
1853
|
type Data = Record<string, unknown>;
|
|
@@ -1934,11 +2010,14 @@ interface AdminField {
|
|
|
1934
2010
|
localized?: boolean;
|
|
1935
2011
|
/** Shown in the edit page's side panel. */
|
|
1936
2012
|
position?: 'sidebar';
|
|
1937
|
-
/** Components from admin modules: instead of the input,
|
|
2013
|
+
/** Components from admin modules: instead of the input, below the field, and in lists. */
|
|
1938
2014
|
admin?: {
|
|
1939
2015
|
component?: AdminComponentRef;
|
|
1940
2016
|
after?: AdminComponentRef[];
|
|
2017
|
+
cell?: AdminComponentRef;
|
|
1941
2018
|
};
|
|
2019
|
+
/** A field of an added type (`fieldTypes`), e.g. `color`; `type` is the base it's stored as. */
|
|
2020
|
+
customType?: string;
|
|
1942
2021
|
}
|
|
1943
2022
|
interface AdminCollection {
|
|
1944
2023
|
slug: string;
|
|
@@ -2042,4 +2121,4 @@ declare const BUILTIN_COLLECTIONS: readonly ["users", "media"];
|
|
|
2042
2121
|
/** Checks a config and returns every problem found. An empty array means it is valid. */
|
|
2043
2122
|
declare function validateConfig(config: Config): ConfigIssue[];
|
|
2044
2123
|
|
|
2045
|
-
export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminField, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminSchema, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, Auth, type AuthConfig, type AuthUser, BUILTIN_COLLECTIONS, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinUsersCollection, type BundleHints, CONFIG_FILE_NAMES, CSRF_COOKIE, CSRF_HEADER, type CliCommand, type CollectionAccess, type CollectionAdmin, type CollectionConfig, type CollectionDocument, type CollectionHooks, type CollectionListAdmin, type CollectionSlug, type Config, ConfigError, type ConfigIssue, type ContainerAdmin, type CopyProgress, type CopyResult, type CreateEasyCMSOptions, type CreateInput, type CreateMigrationResult, DEFAULT_ADMIN_PATH, DEFAULT_API_PATH, DEFAULT_DEPTH, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_VERSIONS, DEFAULT_PASSWORD_EMAILS, DEFAULT_TOKEN_EXPIRATION, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DepthOptions, type DocumentOf, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailField, type EmailMessage, type Endpoint, type EndpointRequest, FIELD_TYPES, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldType, type FieldValidate, type FieldValidateContext, type FieldValue, type FieldsInput, type FieldsValue, type FilterOptions, type FilterOptionsArgs, type FindArgs, type FindOptions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type InferCollection, type InferGlobal, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type Operation, type PaginatedDocs, type PasswordEmail, type PasswordEmailArgs, type PasswordEmailFn, type PasswordLinkOptions, PayloadTooLargeError, type Plugin, type PluginTypes, type PreviewTarget, type PreviewURL, QueryError, type RawDocument, type ReadOptions, type RelationshipField, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoutesConfig, SESSION_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type SlugOf, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, type TypedPlugin, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, configSignature, consoleEmail, consoleLogger, copyDatabase, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, definePlugin, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, silentLogger, singularize, slugify, sniffMimeType, validateConfig, validateFields, verifyPassword };
|
|
2124
|
+
export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminField, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminSchema, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, Auth, type AuthConfig, type AuthUser, BUILTIN_COLLECTIONS, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinUsersCollection, type BundleHints, CONFIG_FILE_NAMES, CSRF_COOKIE, CSRF_HEADER, type CliCommand, type CollectionAccess, type CollectionAdmin, type CollectionConfig, type CollectionDocument, type CollectionHooks, type CollectionListAdmin, type CollectionSlug, type Config, ConfigError, type ConfigIssue, type ContainerAdmin, type CopyProgress, type CopyResult, type CreateEasyCMSOptions, type CreateInput, type CreateMigrationResult, type CustomField, type CustomFieldTypes, DEFAULT_ADMIN_PATH, DEFAULT_API_PATH, DEFAULT_DEPTH, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_VERSIONS, DEFAULT_PASSWORD_EMAILS, DEFAULT_TOKEN_EXPIRATION, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DepthOptions, type DocumentOf, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailField, type EmailMessage, type Endpoint, type EndpointRequest, FIELD_TYPES, FIELD_TYPE_BASES, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldType, type FieldTypeBase, type FieldTypeDefinition, type FieldTypeValidateContext, type FieldValidate, type FieldValidateContext, type FieldValue, type FieldsInput, type FieldsValue, type FilterOptions, type FilterOptionsArgs, type FindArgs, type FindOptions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type InferCollection, type InferGlobal, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type Operation, type PaginatedDocs, type PasswordEmail, type PasswordEmailArgs, type PasswordEmailFn, type PasswordLinkOptions, PayloadTooLargeError, type Plugin, type PluginTypes, type PreviewTarget, type PreviewURL, QueryError, type RawDocument, type ReadOptions, type RelationshipField, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoutesConfig, SESSION_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type SlugOf, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, type TypedPlugin, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, configSignature, consoleEmail, consoleLogger, copyDatabase, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, defineFieldType, definePlugin, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, silentLogger, singularize, slugify, sniffMimeType, validateConfig, validateFields, verifyPassword };
|
package/dist/index.js
CHANGED
|
@@ -1669,6 +1669,126 @@ var Mailer = class {
|
|
|
1669
1669
|
}
|
|
1670
1670
|
};
|
|
1671
1671
|
|
|
1672
|
+
// src/field-types.ts
|
|
1673
|
+
var FIELD_TYPE_BASES = [
|
|
1674
|
+
"text",
|
|
1675
|
+
"textarea",
|
|
1676
|
+
"email",
|
|
1677
|
+
"number",
|
|
1678
|
+
"boolean",
|
|
1679
|
+
"date",
|
|
1680
|
+
"json"
|
|
1681
|
+
];
|
|
1682
|
+
function defineFieldType(definition) {
|
|
1683
|
+
return definition;
|
|
1684
|
+
}
|
|
1685
|
+
var NAME = /^[a-z][a-zA-Z0-9]*$/;
|
|
1686
|
+
function fieldTypeModules(config) {
|
|
1687
|
+
const list = config.fieldTypes;
|
|
1688
|
+
if (!Array.isArray(list)) return [];
|
|
1689
|
+
return list.map((t) => t?.admin?.module).filter((m) => typeof m === "string");
|
|
1690
|
+
}
|
|
1691
|
+
function applyFieldTypes(config) {
|
|
1692
|
+
const issues = [];
|
|
1693
|
+
const list = config.fieldTypes;
|
|
1694
|
+
if (list === void 0) return { config, issues };
|
|
1695
|
+
if (!Array.isArray(list)) {
|
|
1696
|
+
issues.push({ path: "fieldTypes", message: "must be an array of field types" });
|
|
1697
|
+
return { config, issues };
|
|
1698
|
+
}
|
|
1699
|
+
const types = /* @__PURE__ */ new Map();
|
|
1700
|
+
for (const [i, type] of list.entries()) {
|
|
1701
|
+
const path = `fieldTypes[${i}]`;
|
|
1702
|
+
if (!type || typeof type.name !== "string" || !NAME.test(type.name)) {
|
|
1703
|
+
issues.push({ path: `${path}.name`, message: 'must be a lowercase name like "color"' });
|
|
1704
|
+
} else if (FIELD_TYPES.includes(type.name)) {
|
|
1705
|
+
issues.push({ path: `${path}.name`, message: `"${type.name}" is a built-in field type` });
|
|
1706
|
+
} else if (types.has(type.name)) {
|
|
1707
|
+
issues.push({ path: `${path}.name`, message: `"${type.name}" is listed twice` });
|
|
1708
|
+
} else if (!FIELD_TYPE_BASES.includes(type.base)) {
|
|
1709
|
+
issues.push({
|
|
1710
|
+
path: `${path}.base`,
|
|
1711
|
+
message: `must be one of ${FIELD_TYPE_BASES.join(", ")}`
|
|
1712
|
+
});
|
|
1713
|
+
} else {
|
|
1714
|
+
types.set(type.name, type);
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
if (types.size === 0) return { config, issues };
|
|
1718
|
+
const component = (tag, field, props) => {
|
|
1719
|
+
if (!tag) return void 0;
|
|
1720
|
+
const options = Object.fromEntries(
|
|
1721
|
+
(props ?? []).filter((key2) => field[key2] !== void 0).map((key2) => [key2, field[key2]])
|
|
1722
|
+
);
|
|
1723
|
+
return Object.keys(options).length ? { tag, props: options } : tag;
|
|
1724
|
+
};
|
|
1725
|
+
const convert = (fields, path) => fields.map((field, i) => {
|
|
1726
|
+
const here = `${path}[${i}]`;
|
|
1727
|
+
const own = field;
|
|
1728
|
+
const type = types.get(own.type);
|
|
1729
|
+
if (!type) {
|
|
1730
|
+
if ((field.type === "group" || field.type === "array") && Array.isArray(field.fields))
|
|
1731
|
+
return { ...field, fields: convert(field.fields, `${here}.fields`) };
|
|
1732
|
+
if (field.type === "blocks" && Array.isArray(field.blocks))
|
|
1733
|
+
return {
|
|
1734
|
+
...field,
|
|
1735
|
+
blocks: field.blocks.map((block, b) => ({
|
|
1736
|
+
...block,
|
|
1737
|
+
fields: convert(block.fields, `${here}.blocks[${b}].fields`)
|
|
1738
|
+
}))
|
|
1739
|
+
};
|
|
1740
|
+
return field;
|
|
1741
|
+
}
|
|
1742
|
+
const problem = type.checkOptions?.(own);
|
|
1743
|
+
if (problem) issues.push({ path: here, message: problem });
|
|
1744
|
+
const ownValidate = own.validate;
|
|
1745
|
+
const check = type.validate;
|
|
1746
|
+
const admin = own.admin ?? {};
|
|
1747
|
+
const input = admin.component ?? component(type.admin?.component, own, type.admin?.props);
|
|
1748
|
+
const cell = admin.cell ?? component(type.admin?.cell, own, type.admin?.props);
|
|
1749
|
+
return {
|
|
1750
|
+
...own,
|
|
1751
|
+
type: type.base,
|
|
1752
|
+
customType: type.name,
|
|
1753
|
+
...check || ownValidate ? {
|
|
1754
|
+
validate: async (value, ctx) => {
|
|
1755
|
+
const empty = value === null || value === void 0 || value === "";
|
|
1756
|
+
if (check && !empty) {
|
|
1757
|
+
const result = await check(value, { ...ctx, field: own });
|
|
1758
|
+
if (result !== true) return result;
|
|
1759
|
+
}
|
|
1760
|
+
return ownValidate ? ownValidate(value, ctx) : true;
|
|
1761
|
+
}
|
|
1762
|
+
} : {},
|
|
1763
|
+
...input || cell ? {
|
|
1764
|
+
admin: {
|
|
1765
|
+
...admin,
|
|
1766
|
+
...input ? { component: input } : {},
|
|
1767
|
+
...cell ? { cell } : {}
|
|
1768
|
+
}
|
|
1769
|
+
} : {}
|
|
1770
|
+
};
|
|
1771
|
+
});
|
|
1772
|
+
return {
|
|
1773
|
+
config: {
|
|
1774
|
+
...config,
|
|
1775
|
+
...config.collections ? {
|
|
1776
|
+
collections: config.collections.map((c, i) => ({
|
|
1777
|
+
...c,
|
|
1778
|
+
fields: convert(c.fields, `collections[${i}].fields`)
|
|
1779
|
+
}))
|
|
1780
|
+
} : {},
|
|
1781
|
+
...config.globals ? {
|
|
1782
|
+
globals: config.globals.map((g, i) => ({
|
|
1783
|
+
...g,
|
|
1784
|
+
fields: convert(g.fields, `globals[${i}].fields`)
|
|
1785
|
+
}))
|
|
1786
|
+
} : {}
|
|
1787
|
+
},
|
|
1788
|
+
issues
|
|
1789
|
+
};
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1672
1792
|
// src/load-config.ts
|
|
1673
1793
|
import { existsSync } from "fs";
|
|
1674
1794
|
import { resolve } from "path";
|
|
@@ -2326,9 +2446,10 @@ function validateField(field, path, siblings, collectionSlugs, add) {
|
|
|
2326
2446
|
if (typeof admin !== "object" || admin === null) {
|
|
2327
2447
|
add(`${path}.admin`, "must be an object", "e.g. admin: { component: 'ecms-color-picker' }");
|
|
2328
2448
|
} else {
|
|
2329
|
-
const { component, after } = admin;
|
|
2449
|
+
const { component, after, cell } = admin;
|
|
2330
2450
|
if (component !== void 0) validateComponent(component, `${path}.admin.component`, add);
|
|
2331
2451
|
if (after !== void 0) validateComponents(after, `${path}.admin.after`, add);
|
|
2452
|
+
if (cell !== void 0) validateComponent(cell, `${path}.admin.cell`, add);
|
|
2332
2453
|
}
|
|
2333
2454
|
}
|
|
2334
2455
|
switch (field.type) {
|
|
@@ -2593,6 +2714,15 @@ async function applyPlugins(input) {
|
|
|
2593
2714
|
if (typeof plugin !== "function") break;
|
|
2594
2715
|
config = await plugin(config);
|
|
2595
2716
|
}
|
|
2717
|
+
const modules = fieldTypeModules(config);
|
|
2718
|
+
if (modules.length > 0)
|
|
2719
|
+
config = {
|
|
2720
|
+
...config,
|
|
2721
|
+
admin: {
|
|
2722
|
+
...config.admin,
|
|
2723
|
+
modules: [.../* @__PURE__ */ new Set([...config.admin?.modules ?? [], ...modules])]
|
|
2724
|
+
}
|
|
2725
|
+
};
|
|
2596
2726
|
return config;
|
|
2597
2727
|
}
|
|
2598
2728
|
async function resolveConfig(input) {
|
|
@@ -2601,7 +2731,9 @@ async function resolveConfig(input) {
|
|
|
2601
2731
|
if (typeof config === "object" && config !== null && Array.isArray(config.collections ?? [])) {
|
|
2602
2732
|
config = withMedia(withUsers(config));
|
|
2603
2733
|
}
|
|
2604
|
-
const
|
|
2734
|
+
const applied = applyFieldTypes(config);
|
|
2735
|
+
config = applied.config;
|
|
2736
|
+
const issues = [...applied.issues, ...validateConfig(config)];
|
|
2605
2737
|
if (issues.length > 0) throw new ConfigError(issues);
|
|
2606
2738
|
const { plugins: _plugins, ...rest } = config;
|
|
2607
2739
|
const result = {
|
|
@@ -2649,7 +2781,8 @@ async function resolveConfig(input) {
|
|
|
2649
2781
|
],
|
|
2650
2782
|
globals: config.globals ?? [],
|
|
2651
2783
|
endpoints: config.endpoints ?? [],
|
|
2652
|
-
commands: config.commands ?? []
|
|
2784
|
+
commands: config.commands ?? [],
|
|
2785
|
+
fieldTypes: config.fieldTypes ?? []
|
|
2653
2786
|
};
|
|
2654
2787
|
resolved.add(result);
|
|
2655
2788
|
return result;
|
|
@@ -4740,12 +4873,14 @@ async function serializeFields(fields, update, localized) {
|
|
|
4740
4873
|
if (!await update.allows(field)) f.readOnly = true;
|
|
4741
4874
|
if (field.localized && localized) f.localized = true;
|
|
4742
4875
|
if (field.position === "sidebar") f.position = "sidebar";
|
|
4743
|
-
if (field.admin?.component || field.admin?.after?.length) {
|
|
4876
|
+
if (field.admin?.component || field.admin?.after?.length || field.admin?.cell) {
|
|
4744
4877
|
f.admin = {
|
|
4745
4878
|
...field.admin.component ? { component: componentRef(field.admin.component) } : {},
|
|
4746
|
-
...field.admin.after?.length ? { after: field.admin.after.map(componentRef) } : {}
|
|
4879
|
+
...field.admin.after?.length ? { after: field.admin.after.map(componentRef) } : {},
|
|
4880
|
+
...field.admin.cell ? { cell: componentRef(field.admin.cell) } : {}
|
|
4747
4881
|
};
|
|
4748
4882
|
}
|
|
4883
|
+
if (field.customType) f.customType = field.customType;
|
|
4749
4884
|
switch (field.type) {
|
|
4750
4885
|
case "text":
|
|
4751
4886
|
case "textarea":
|
|
@@ -5680,9 +5815,14 @@ function names(config) {
|
|
|
5680
5815
|
}
|
|
5681
5816
|
const globals = /* @__PURE__ */ new Map();
|
|
5682
5817
|
for (const g of config.globals) globals.set(g.slug, claim(pascal(g.slug), "Global"));
|
|
5683
|
-
|
|
5818
|
+
const custom = new Map(
|
|
5819
|
+
(config.fieldTypes ?? []).filter((t) => t.typescript).map((t) => [t.name, t.typescript])
|
|
5820
|
+
);
|
|
5821
|
+
return { collections, globals, custom };
|
|
5684
5822
|
}
|
|
5685
5823
|
function fieldType(field, n, indent) {
|
|
5824
|
+
const custom = field.customType ? n.custom.get(field.customType) : void 0;
|
|
5825
|
+
if (custom) return custom;
|
|
5686
5826
|
switch (field.type) {
|
|
5687
5827
|
case "text":
|
|
5688
5828
|
case "textarea":
|
|
@@ -5836,6 +5976,7 @@ export {
|
|
|
5836
5976
|
EasyCMS,
|
|
5837
5977
|
EasyCMSError,
|
|
5838
5978
|
FIELD_TYPES,
|
|
5979
|
+
FIELD_TYPE_BASES,
|
|
5839
5980
|
ForbiddenError,
|
|
5840
5981
|
INTERNAL_COLLECTIONS,
|
|
5841
5982
|
MAX_DEPTH,
|
|
@@ -5862,6 +6003,7 @@ export {
|
|
|
5862
6003
|
createRestHandler,
|
|
5863
6004
|
createRootEndpointHandler,
|
|
5864
6005
|
defineConfig,
|
|
6006
|
+
defineFieldType,
|
|
5865
6007
|
definePlugin,
|
|
5866
6008
|
fillMissing,
|
|
5867
6009
|
findConfigFile,
|