@easy-cms/core 0.24.0 → 0.25.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 CHANGED
@@ -439,16 +439,41 @@ interface BuiltinApiKeysCollection {
439
439
  type ApiKeysOf<C extends Config> = C extends {
440
440
  readonly apiKeys: true;
441
441
  } ? BuiltinApiKeysCollection : never;
442
- /** Every collection of a config, including the built-in ones. */
443
- type AllCollections<C extends Config> = NonNullable<C['collections']>[number] | BuiltinUsersCollection | BuiltinMediaCollection | ApiKeysOf<C>;
442
+ /** The `PluginTypes` of each plugin in the config (a union). */
443
+ type PluginTypesOf<C extends Config> = C extends {
444
+ readonly plugins: readonly (infer P)[];
445
+ } ? P extends TypedPlugin<infer T extends PluginTypes> ? T : never : never;
446
+ /** Fields that plugins add to the collection (or global) `S`, as a union. */
447
+ type AddedFields<T, S> = T extends {
448
+ readonly [K in 'fields' | 'globalFields']?: infer M;
449
+ } ? M extends {
450
+ readonly [slug: string]: readonly Field[];
451
+ } ? string extends keyof M ? never : S extends keyof M ? M[S][number] : never : never : never;
452
+ type PluginFields<C extends Config, S, Key extends 'fields' | 'globalFields'> = AddedFields<PluginTypesOf<C> extends infer T ? T extends PluginTypes ? Pick<T, Key & keyof T> : never : never, S>;
453
+ /** Collections that plugins add. */
454
+ type PluginCollections<C extends Config> = PluginTypesOf<C> extends infer T ? T extends {
455
+ readonly collections: readonly (infer K extends CollectionConfig)[];
456
+ } ? K : never : never;
457
+ /** A collection or global with the fields plugins add to it. */
458
+ type WithPluginFields<C extends Config, T extends {
459
+ readonly slug: string;
460
+ readonly fields: readonly Field[];
461
+ }, Key extends 'fields' | 'globalFields'> = [PluginFields<C, T['slug'], Key>] extends [never] ? T : Omit<T, 'fields'> & {
462
+ readonly fields: readonly (T['fields'][number] | PluginFields<C, T['slug'], Key>)[];
463
+ };
464
+ /** Every collection of a config, including the built-in ones and those plugins add. */
465
+ type AllCollections<C extends Config> = NonNullable<C['collections']>[number] | BuiltinUsersCollection | BuiltinMediaCollection | ApiKeysOf<C> | PluginCollections<C>;
444
466
  /** The built-in media collection; its documents are typed as `MediaDocument`. */
445
467
  interface BuiltinMediaCollection {
446
468
  readonly slug: 'media';
447
469
  readonly fields: readonly [];
448
470
  }
449
- type CollectionBySlug<C extends Config, S> = Extract<AllCollections<C>, {
471
+ type CollectionBySlug<C extends Config, S> = WithPluginFields<C, Extract<AllCollections<C>, {
450
472
  readonly slug: S;
451
- }>;
473
+ }>, 'fields'>;
474
+ type GlobalBySlug<C extends Config, S> = WithPluginFields<C, Extract<NonNullable<C['globals']>[number], {
475
+ readonly slug: S;
476
+ }>, 'globalFields'>;
452
477
  /** Relationships are ids at depth 0 and documents when populated. */
453
478
  type RelationValue<C extends Config, S> = [CollectionBySlug<C, S>] extends [never] ? ID | Record<string, unknown> : ID | CollectionDocument<C, S & string>;
454
479
  interface MediaSize {
@@ -544,7 +569,7 @@ type FieldsValue<Fs extends readonly Field[], C extends Config = Config> = Simpl
544
569
  -readonly [F in OptionalFields<Fs> as F['name']]?: FieldValue<F, C> | null;
545
570
  }>;
546
571
  type SystemFields<T extends {
547
- readonly drafts?: boolean;
572
+ readonly drafts?: unknown;
548
573
  }> = {
549
574
  id: ID;
550
575
  createdAt: string;
@@ -554,8 +579,13 @@ type SystemFields<T extends {
554
579
  } ? {
555
580
  status: 'draft' | 'published';
556
581
  } : unknown);
557
- type InferCollection<T extends CollectionConfig, C extends Config = Config> = Simplify<SystemFields<T> & FieldsValue<T['fields'], C>>;
558
- type InferGlobal<T extends GlobalConfig, C extends Config = Config> = Simplify<
582
+ /** What document types are inferred from: a collection's or global's fields and drafts. */
583
+ type FieldsOwner = {
584
+ readonly fields: readonly Field[];
585
+ readonly drafts?: unknown;
586
+ };
587
+ type InferCollection<T extends FieldsOwner, C extends Config = Config> = Simplify<SystemFields<T> & FieldsValue<T['fields'], C>>;
588
+ type InferGlobal<T extends FieldsOwner, C extends Config = Config> = Simplify<
559
589
  /** `null` until the global is saved for the first time. */
560
590
  {
561
591
  updatedAt: string | null;
@@ -564,14 +594,12 @@ type InferGlobal<T extends GlobalConfig, C extends Config = Config> = Simplify<
564
594
  } ? {
565
595
  status: 'draft' | 'published';
566
596
  } : unknown) & FieldsValue<T['fields'], C>>;
567
- type CollectionSlug<C extends Config> = NonNullable<C['collections']>[number]['slug'] | 'users' | 'media' | ApiKeysOf<C>['slug'];
597
+ type CollectionSlug<C extends Config> = NonNullable<C['collections']>[number]['slug'] | 'users' | 'media' | ApiKeysOf<C>['slug'] | PluginCollections<C>['slug'];
568
598
  type GlobalSlug<C extends Config> = NonNullable<C['globals']>[number]['slug'];
569
599
  /** Document type of a collection, e.g. `CollectionDocument<typeof config, 'posts'>`. */
570
600
  type CollectionDocument<C extends Config, S extends CollectionSlug<C>> = S extends 'media' ? MediaDocument : InferCollection<CollectionBySlug<C, S>, C>;
571
601
  /** Data type of a global, e.g. `GlobalDocument<typeof config, 'site'>`. */
572
- type GlobalDocument<C extends Config, S extends GlobalSlug<C>> = InferGlobal<Extract<NonNullable<C['globals']>[number], {
573
- readonly slug: S;
574
- }>, C>;
602
+ type GlobalDocument<C extends Config, S extends GlobalSlug<C>> = InferGlobal<GlobalBySlug<C, S>, C>;
575
603
  type InputValue<F extends Field> = F extends {
576
604
  readonly type: 'relationship';
577
605
  } ? F extends {
@@ -630,11 +658,7 @@ type CreateInput<C extends Config, S extends CollectionSlug<C>> = Simplify<Field
630
658
  /** Data accepted by `update`: any subset of `CreateInput`. */
631
659
  type UpdateInput<C extends Config, S extends CollectionSlug<C>> = Partial<CreateInput<C, S>>;
632
660
  /** Data accepted by `updateGlobal`. */
633
- type GlobalInput<C extends Config, S extends GlobalSlug<C>> = Partial<Simplify<FieldsInput<Extract<NonNullable<C['globals']>[number], {
634
- readonly slug: S;
635
- }>['fields']> & StatusInput<Extract<NonNullable<C['globals']>[number], {
636
- readonly slug: S;
637
- }>>>>;
661
+ type GlobalInput<C extends Config, S extends GlobalSlug<C>> = Partial<Simplify<FieldsInput<GlobalBySlug<C, S>['fields']> & StatusInput<GlobalBySlug<C, S>>>>;
638
662
 
639
663
  interface StoredFile {
640
664
  readonly body: Uint8Array;
@@ -690,6 +714,13 @@ type Create<C extends Config, S> = string extends CollectionSlug<C> ? Data$2 : C
690
714
  type Update<C extends Config, S> = string extends CollectionSlug<C> ? Data$2 : UpdateInput<C, S & CollectionSlug<C>>;
691
715
  type GDoc<C extends Config, S> = string extends GlobalSlug<C> ? Data$2 : GlobalDocument<C, S & GlobalSlug<C>>;
692
716
  type GInput<C extends Config, S> = string extends GlobalSlug<C> ? Data$2 : GlobalInput<C, S & GlobalSlug<C>>;
717
+ /** A collection slug of the config `C` (any string when the config isn't a literal). */
718
+ type SlugOf<C extends Config> = Slug<C>;
719
+ /**
720
+ * A document of collection `S` as the Local API returns it, e.g. for helpers that take an
721
+ * `EasyCMS<C>`: inferred from a literal config, loose otherwise.
722
+ */
723
+ type DocumentOf<C extends Config, S> = Doc<C, S>;
693
724
  interface AccessOptions {
694
725
  /**
695
726
  * The Local API trusts its caller and skips access rules by default.
@@ -1519,6 +1550,38 @@ interface Endpoint {
1519
1550
  }
1520
1551
  /** Receives the config and returns a modified copy. Runs before validation. */
1521
1552
  type Plugin = (config: Config) => MaybePromise<Config>;
1553
+ /** Holds a plugin's `PluginTypes` at the type level only: nothing is stored at runtime. */
1554
+ declare const PLUGIN_TYPES: unique symbol;
1555
+ /**
1556
+ * What a plugin adds, for the document types inferred from the config: fields on collections
1557
+ * and globals (by slug), and whole collections. Field types are written like config fields,
1558
+ * e.g. `{ fields: { posts: readonly [{ readonly name: 'meta'; readonly type: 'group'; … }] } }`.
1559
+ */
1560
+ interface PluginTypes {
1561
+ readonly fields?: {
1562
+ readonly [collection: string]: readonly Field[];
1563
+ };
1564
+ readonly globalFields?: {
1565
+ readonly [global: string]: readonly Field[];
1566
+ };
1567
+ readonly collections?: readonly CollectionConfig[];
1568
+ }
1569
+ /** A plugin that tells the type system what it adds (see `definePlugin`). */
1570
+ type TypedPlugin<T extends PluginTypes> = Plugin & {
1571
+ readonly [PLUGIN_TYPES]?: T;
1572
+ };
1573
+ /**
1574
+ * Returns the plugin unchanged, with what it adds as types, so `cms.find()` and
1575
+ * `CollectionDocument` know the plugin's fields:
1576
+ *
1577
+ * ```ts
1578
+ * export const colorPlugin = (options: { collections: readonly string[] }) =>
1579
+ * definePlugin<{ fields: { posts: readonly [{ readonly name: 'color'; readonly type: 'text' }] } }>(
1580
+ * (config) => ({ ...config, collections: … }),
1581
+ * )
1582
+ * ```
1583
+ */
1584
+ declare function definePlugin<const T extends PluginTypes = Record<never, never>>(plugin: Plugin): TypedPlugin<T>;
1522
1585
  interface Config {
1523
1586
  /** Signs sessions. At least 32 characters; read it from `process.env.EASY_CMS_SECRET`. */
1524
1587
  readonly secret: string;
@@ -1979,4 +2042,4 @@ declare const BUILTIN_COLLECTIONS: readonly ["users", "media"];
1979
2042
  /** Checks a config and returns every problem found. An empty array means it is valid. */
1980
2043
  declare function validateConfig(config: Config): ConfigIssue[];
1981
2044
 
1982
- 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, 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 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 StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, 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, 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 };
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 };
package/dist/index.js CHANGED
@@ -1140,6 +1140,9 @@ var ADMIN_ICONS = [
1140
1140
  "camera",
1141
1141
  "key"
1142
1142
  ];
1143
+ function definePlugin(plugin) {
1144
+ return plugin;
1145
+ }
1143
1146
  function defineConfig(config) {
1144
1147
  return config;
1145
1148
  }
@@ -5859,6 +5862,7 @@ export {
5859
5862
  createRestHandler,
5860
5863
  createRootEndpointHandler,
5861
5864
  defineConfig,
5865
+ definePlugin,
5862
5866
  fillMissing,
5863
5867
  findConfigFile,
5864
5868
  generateSlugs,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easy-cms/core",
3
- "version": "0.24.0",
3
+ "version": "0.25.0",
4
4
  "description": "Embedded, code-first headless CMS for Nuxt and Next.js",
5
5
  "license": "MIT",
6
6
  "type": "module",