@easy-cms/core 0.45.0 → 0.46.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.
Files changed (3) hide show
  1. package/dist/index.d.ts +244 -18
  2. package/dist/index.js +446 -49
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -12,6 +12,11 @@ interface AuthUser {
12
12
  * backups, roles, other users' API keys).
13
13
  */
14
14
  readonly scoped?: boolean;
15
+ /**
16
+ * A member of the site, e.g. a customer (`auth.members.roles`): signs in on the site, never to
17
+ * the admin, and `isLoggedIn` doesn't count them.
18
+ */
19
+ readonly member?: boolean;
15
20
  readonly [field: string]: unknown;
16
21
  }
17
22
  /**
@@ -71,7 +76,13 @@ interface FieldAccess {
71
76
  readonly update?: FieldAccessFn;
72
77
  }
73
78
  declare const anyone: Access;
79
+ /**
80
+ * A signed-in user of the admin: not a site member (`auth.members`). What collections allow by
81
+ * default.
82
+ */
74
83
  declare const isLoggedIn: Access;
84
+ /** Anyone signed in, site members (e.g. customers) included. */
85
+ declare const isSignedIn: Access;
75
86
  declare const isAdmin: Access;
76
87
 
77
88
  /** What a preview token opens: one document of a collection, or one global. */
@@ -81,8 +92,11 @@ type PreviewTarget = {
81
92
  } | {
82
93
  readonly global: string;
83
94
  };
84
- /** Why a password link was sent: a forgotten password, or an invitation to a new account. */
85
- type PasswordPurpose = 'reset' | 'invite';
95
+ /**
96
+ * Why a link was sent: a forgotten password, an invitation to a new account, or (`verify`) to
97
+ * confirm the email of an account made by signing up.
98
+ */
99
+ type PasswordPurpose = 'reset' | 'invite' | 'verify';
86
100
 
87
101
  /** The cookie that carries a sign-in through the provider and back. */
88
102
  declare const SSO_COOKIE = "ecms-sso";
@@ -195,6 +209,29 @@ interface Session {
195
209
  readonly csrfToken: string;
196
210
  readonly expiresAt: string;
197
211
  }
212
+ interface SignupArgs {
213
+ readonly email: string;
214
+ readonly password: string;
215
+ readonly name?: string | undefined;
216
+ /** From `GET <api>/users/signup`: the form was loaded a moment ago. */
217
+ readonly token?: unknown;
218
+ /** The hidden field; bots fill it in. */
219
+ readonly honeypot?: unknown;
220
+ /** The Cloudflare Turnstile response, with `signup.turnstile`. */
221
+ readonly turnstile?: unknown;
222
+ readonly ip?: string | undefined;
223
+ /** The request's origin: used for the link only in development, without a site URL. */
224
+ readonly origin?: string | undefined;
225
+ readonly locale?: string | undefined;
226
+ /** The request's context (`onRequest`), e.g. the tenant: given to the users' hooks. */
227
+ readonly context?: RequestContext;
228
+ }
229
+ /** What signing up did: a link was emailed to confirm, or (without `verifyEmail`) a session. */
230
+ type SignupResult = {
231
+ readonly verify: true;
232
+ } | (Session & {
233
+ readonly verify: false;
234
+ });
198
235
  /** Where a password link is opened from, and the language of its email. */
199
236
  interface PasswordLinkOptions {
200
237
  /** The request's origin: used for the link only in development, when `serverURL` is not set. */
@@ -223,6 +260,29 @@ declare class Auth {
223
260
  setupCode?: string;
224
261
  ip?: string | undefined;
225
262
  }): Promise<Session>;
263
+ /** What a sign-up form needs: a token proving when it was loaded, and Turnstile's site key. */
264
+ signupForm(): {
265
+ token: string;
266
+ turnstile: string | null;
267
+ verifyEmail: boolean;
268
+ };
269
+ /**
270
+ * Creates a member's account (`auth.members.signup`). With `verifyEmail` (the default), emails
271
+ * a link to confirm the address and answers the same whether or not the email has an account;
272
+ * otherwise starts a session. Throws `ValidationError` for spam checks and bad input.
273
+ */
274
+ signup(args: SignupArgs): Promise<SignupResult>;
275
+ /** Confirms a member's email from the link, and signs them in. */
276
+ verifyEmail(args: {
277
+ token: string;
278
+ ip?: string | undefined;
279
+ }): Promise<Session>;
280
+ private mailVerifyLink;
281
+ /**
282
+ * A link to one of the site's pages for members (`auth.members.pages`), else to the admin's
283
+ * page of the same purpose.
284
+ */
285
+ private memberLink;
226
286
  hasUsers(): Promise<boolean>;
227
287
  /** Ends the session for a signed token. Unknown tokens are ignored. */
228
288
  logout(signedToken: string): Promise<void>;
@@ -374,12 +434,35 @@ interface Database {
374
434
  collection: string;
375
435
  data: Record<string, unknown>;
376
436
  }): Promise<RawDocument>;
377
- /** `data` holds the whole document after merging. Runs in one transaction. */
437
+ /**
438
+ * `data` holds the whole document after merging. Runs in one transaction. With `where`, only
439
+ * when the stored document matches it at the moment of writing (compare and set): `null` when
440
+ * it doesn't, and nothing is written.
441
+ */
378
442
  update(args: {
379
443
  collection: string;
380
444
  id: ID;
381
445
  data: Record<string, unknown>;
382
446
  }): Promise<RawDocument>;
447
+ update(args: {
448
+ collection: string;
449
+ id: ID;
450
+ data: Record<string, unknown>;
451
+ where: Where;
452
+ }): Promise<RawDocument | null>;
453
+ /**
454
+ * Adds `by` to a top-level number field in one statement, safe against concurrent calls; an
455
+ * empty value counts as 0. With `min` / `max`, only when the result stays within them. Returns
456
+ * the new value, or `null` when it would leave the bounds or the document is gone.
457
+ */
458
+ increment(args: {
459
+ collection: string;
460
+ id: ID;
461
+ field: string;
462
+ by: number;
463
+ min?: number | undefined;
464
+ max?: number | undefined;
465
+ }): Promise<number | null>;
383
466
  delete(args: {
384
467
  collection: string;
385
468
  id: ID;
@@ -623,8 +706,13 @@ type WithPluginFields<C extends Config, T extends {
623
706
  }, Key extends 'fields' | 'globalFields'> = [PluginFields<C, T['slug'], Key>] extends [never] ? T : Omit<T, 'fields'> & {
624
707
  readonly fields: readonly (T['fields'][number] | PluginFields<C, T['slug'], Key>)[];
625
708
  };
709
+ /**
710
+ * The config's own collections. A literal config without `collections` has none (only plugins
711
+ * add some); a loosely typed `Config` has any.
712
+ */
713
+ type OwnCollections<C extends Config> = 'collections' extends keyof C ? NonNullable<C['collections']>[number] : never;
626
714
  /** Every collection of a config, including the built-in ones and those plugins add. */
627
- type AllCollections<C extends Config> = NonNullable<C['collections']>[number] | BuiltinUsersCollection | BuiltinMediaCollection | ApiKeysOf<C> | FoldersOf<C> | PluginCollections<C>;
715
+ type AllCollections<C extends Config> = OwnCollections<C> | BuiltinUsersCollection | BuiltinMediaCollection | ApiKeysOf<C> | FoldersOf<C> | PluginCollections<C>;
628
716
  /** The built-in media collection; its documents are typed as `MediaDocument`. */
629
717
  interface BuiltinMediaCollection {
630
718
  readonly slug: 'media';
@@ -766,7 +854,7 @@ type InferGlobal<T extends FieldsOwner, C extends Config = Config> = Simplify<
766
854
  } ? {
767
855
  status: 'draft' | 'published';
768
856
  } : unknown) & FieldsValue<T['fields'], C>>;
769
- type CollectionSlug<C extends Config> = NonNullable<C['collections']>[number]['slug'] | 'users' | 'media' | ApiKeysOf<C>['slug'] | FoldersOf<C>['slug'] | PluginCollections<C>['slug'];
857
+ type CollectionSlug<C extends Config> = OwnCollections<C>['slug'] | 'users' | 'media' | ApiKeysOf<C>['slug'] | FoldersOf<C>['slug'] | PluginCollections<C>['slug'];
770
858
  type GlobalSlug<C extends Config> = NonNullable<C['globals']>[number]['slug'];
771
859
  /** Document type of a collection, e.g. `CollectionDocument<typeof config, 'posts'>`. */
772
860
  type CollectionDocument<C extends Config, S extends CollectionSlug<C>> = S extends 'media' ? MediaDocument : InferCollection<CollectionBySlug<C, S>, C>;
@@ -1237,6 +1325,18 @@ interface UpdateOptions extends DepthOptions {
1237
1325
  * stays, and no version is added to the history.
1238
1326
  */
1239
1327
  readonly live?: boolean;
1328
+ /**
1329
+ * Saves only when the stored document still matches this at the moment of writing (compare and
1330
+ * set), e.g. `{ status: { equals: 'pending' } }` so that one of two concurrent calls wins.
1331
+ * `update()` then returns `null` when it doesn't match, after its `before*` hooks ran.
1332
+ */
1333
+ readonly where?: Where;
1334
+ }
1335
+ interface IncrementOptions {
1336
+ /** Only when the result stays at or above this, e.g. `0` for stock. */
1337
+ readonly min?: number;
1338
+ /** Only when the result stays at or below this. */
1339
+ readonly max?: number;
1240
1340
  }
1241
1341
  interface ReadOptions extends DepthOptions {
1242
1342
  /**
@@ -1261,8 +1361,8 @@ interface CreateEasyCMSOptions {
1261
1361
  readonly cwd?: string;
1262
1362
  /**
1263
1363
  * Run due scheduled jobs and webhook retries every minute in this process. Default: on when
1264
- * a collection or global has `schedule`, or `webhooks` is set. Turn it off where a cron calls
1265
- * `runJobs` (or `GET <api>/jobs/run`) instead.
1364
+ * a collection or global has `schedule`, or `webhooks`, `email` or `jobs` is set. Turn it off
1365
+ * where a cron calls `runJobs` (or `GET <api>/jobs/run`) instead.
1266
1366
  */
1267
1367
  readonly scheduler?: boolean;
1268
1368
  /** Default `verify` when `NODE_ENV=production`, otherwise `push`. */
@@ -1426,7 +1526,18 @@ declare class EasyCMS<C extends Config = Config> {
1426
1526
  /** Files at the top level are public. */
1427
1527
  private settleTopLevel;
1428
1528
  private settleFiles;
1429
- update<S extends Slug<C>>(collection: S, id: ID, data: Update<C, S>, options?: UpdateOptions): Promise<Doc<C, S>>;
1529
+ update<S extends Slug<C>>(collection: S, id: ID, data: Update<C, S>, options: UpdateOptions & {
1530
+ where: Where;
1531
+ }): Promise<Doc<C, S> | null>;
1532
+ update<S extends Slug<C>>(collection: S, id: ID, data: Update<C, S>, options?: UpdateOptions & {
1533
+ where?: undefined;
1534
+ }): Promise<Doc<C, S>>;
1535
+ /**
1536
+ * Adds `by` (negative to take away) to a top-level number field in one database statement, so
1537
+ * concurrent calls never lose a change, e.g. stock or a counter. Skips hooks, validation, access
1538
+ * and versions. Returns the new value, or `null` when `min` / `max` would be passed.
1539
+ */
1540
+ increment<S extends Slug<C>>(collection: S, id: ID, field: string, by: number, options?: IncrementOptions): Promise<number | null>;
1430
1541
  /**
1431
1542
  * Takes a document off the site: its status becomes `draft`. With versions and drafts, a plain
1432
1543
  * `update` with `status: 'draft'` only saves a draft and leaves the published document live;
@@ -1556,7 +1667,21 @@ declare class EasyCMS<C extends Config = Config> {
1556
1667
  sent: number;
1557
1668
  failed: number;
1558
1669
  };
1670
+ jobs: {
1671
+ ran: number;
1672
+ failed: number;
1673
+ };
1559
1674
  }>;
1675
+ /** `jobs` of the config that are due; when each last ran is kept in the database. */
1676
+ private runConfigJobs;
1677
+ /**
1678
+ * Sends an event of the app or a plugin (`events` in the config, e.g. `order.paid`) to the
1679
+ * webhooks that list it. Returns at once; deliveries are queued and retried like content changes.
1680
+ */
1681
+ emit(event: string, data: Record<string, unknown>, about?: {
1682
+ collection: string;
1683
+ id: ID;
1684
+ }): void;
1560
1685
  /**
1561
1686
  * Tries webhook deliveries that are due for another attempt. Deliveries are kept in the
1562
1687
  * database until they succeed, so they survive restarts.
@@ -1654,7 +1779,7 @@ declare class EasyCMS<C extends Config = Config> {
1654
1779
  /** Replaces published documents that have a newer draft with that draft. */
1655
1780
  private withDrafts;
1656
1781
  /** Sends webhook events for a change; `before` is the stored status before it, if any. */
1657
- private emit;
1782
+ private emitChange;
1658
1783
  /**
1659
1784
  * Writes the audit log entry for a change (`audit`): publishing, unpublishing and restoring
1660
1785
  * are told apart from other saves.
@@ -2097,6 +2222,7 @@ declare const DEFAULT_PASSWORD_EMAILS: {
2097
2222
  resetPassword: PasswordEmailFn;
2098
2223
  invite: PasswordEmailFn;
2099
2224
  passwordChanged: PasswordEmailFn;
2225
+ verifyEmail: PasswordEmailFn;
2100
2226
  };
2101
2227
 
2102
2228
  /**
@@ -2243,8 +2369,11 @@ type WebhookEvent = (typeof WEBHOOK_EVENTS)[number];
2243
2369
  interface WebhookConfig {
2244
2370
  /** Where to POST events. */
2245
2371
  readonly url: string;
2246
- /** Events to send. Default: all. */
2247
- readonly events?: readonly WebhookEvent[];
2372
+ /**
2373
+ * Events to send. Default: every content change. Events of the app or its plugins (`events`
2374
+ * in the config, e.g. `order.paid`) are sent only when listed here.
2375
+ */
2376
+ readonly events?: readonly (WebhookEvent | (string & {}))[];
2248
2377
  /** Collections to send events for. Default: all; `[]` for none. */
2249
2378
  readonly collections?: readonly string[];
2250
2379
  /** Globals to send events for. Default: all; `[]` for none. */
@@ -2256,11 +2385,15 @@ interface WebhookConfig {
2256
2385
  }
2257
2386
  /** What a webhook receives as JSON. */
2258
2387
  interface WebhookPayload {
2259
- readonly event: WebhookEvent;
2388
+ /** A content change (`WebhookEvent`), or an event of the app or a plugin, e.g. `order.paid`. */
2389
+ readonly event: string;
2260
2390
  readonly collection?: string;
2261
2391
  readonly global?: string;
2262
2392
  readonly id?: ID;
2263
- /** The stored document (every locale, no hidden fields); for `delete`, as it was. */
2393
+ /**
2394
+ * The stored document (every locale, no hidden fields); for `delete`, as it was. For an event of
2395
+ * the app or a plugin: what `cms.emit()` was given.
2396
+ */
2264
2397
  readonly doc: Record<string, unknown>;
2265
2398
  /** ISO time of the change. */
2266
2399
  readonly timestamp: string;
@@ -2346,9 +2479,10 @@ interface ContainerAdmin {
2346
2479
  interface CollectionAdmin extends ContainerAdmin {
2347
2480
  /**
2348
2481
  * `settings` lists the collection under Settings in the admin menu (with Users and API keys)
2349
- * instead of with the content, e.g. for redirects or forms settings.
2482
+ * instead of with the content, e.g. for redirects or forms settings. A label (e.g.
2483
+ * `{ en: 'Shop', th: 'ร้านค้า' }`) lists it under a heading of that name, after the content.
2350
2484
  */
2351
- readonly group?: 'settings';
2485
+ readonly group?: 'settings' | Label;
2352
2486
  readonly list?: CollectionListAdmin;
2353
2487
  /**
2354
2488
  * With `auth.rbac`: the relationship field to `users` that names a document's owner, e.g.
@@ -2581,6 +2715,44 @@ interface RoutesConfig {
2581
2715
  /** Where the REST API is served. Default `/api/cms`. */
2582
2716
  readonly api?: string;
2583
2717
  }
2718
+ /**
2719
+ * People who sign in on the site rather than to the admin, e.g. customers of a shop.
2720
+ */
2721
+ interface MembersConfig {
2722
+ /**
2723
+ * Their roles, also listed in `roles`. Members never get into the admin, and access that
2724
+ * defaults to logged-in users (`isLoggedIn`) doesn't count them: give them access in the
2725
+ * collections they use, e.g. with `isSignedIn`.
2726
+ */
2727
+ readonly roles: readonly string[];
2728
+ /** Visitors create their own account: `POST <api>/users/signup`. */
2729
+ readonly signup?: MembersSignup;
2730
+ /**
2731
+ * The site's pages that open the links of members' emails, given `?token=`: paths on
2732
+ * `admin.siteUrl` (else `serverURL`), or full URLs. Without them, links go to the admin's pages.
2733
+ */
2734
+ readonly pages?: {
2735
+ /** Confirms the email of a new account: `POST <api>/users/verify-email` with the token. */
2736
+ readonly verifyEmail?: string;
2737
+ /** Sets a forgotten password: `POST <api>/users/reset-password` with the token. */
2738
+ readonly resetPassword?: string;
2739
+ };
2740
+ /** Your own text for the email that confirms an address. Default: English or Thai. */
2741
+ readonly emails?: {
2742
+ readonly verifyEmail?: PasswordEmailFn;
2743
+ };
2744
+ }
2745
+ interface MembersSignup {
2746
+ /** The role new accounts get: one of `members.roles`. */
2747
+ readonly role: string;
2748
+ /** New accounts confirm their email with a link before signing in. Default `true`. */
2749
+ readonly verifyEmail?: boolean;
2750
+ /** Cloudflare Turnstile, checked on every sign-up when set. */
2751
+ readonly turnstile?: {
2752
+ readonly siteKey: string;
2753
+ readonly secretKey: string;
2754
+ };
2755
+ }
2584
2756
  interface AuthConfig {
2585
2757
  /**
2586
2758
  * Roles a user can have. Must include `admin`. Default `['admin', 'editor']`. With `rbac`, these
@@ -2634,6 +2806,11 @@ interface AuthConfig {
2634
2806
  * no code is asked.
2635
2807
  */
2636
2808
  readonly setupCode?: string;
2809
+ /**
2810
+ * People who sign in on the site, not to the admin, e.g. customers: their roles, signing up,
2811
+ * and the pages their email links open.
2812
+ */
2813
+ readonly members?: MembersConfig;
2637
2814
  /** Your own text for the password emails, e.g. in your brand's voice. Default: English or Thai. */
2638
2815
  readonly emails?: {
2639
2816
  readonly resetPassword?: PasswordEmailFn;
@@ -2677,9 +2854,22 @@ interface EndpointRequest {
2677
2854
  json(): Promise<Record<string, unknown>>;
2678
2855
  }
2679
2856
  /**
2680
- * A custom REST endpoint, served under `routes.api`. Writes from the browser pass the same
2681
- * CSRF check as the built-in endpoints.
2857
+ * Work that runs with the scheduled jobs: every minute in a server, or each time a cron calls
2858
+ * `GET <api>/jobs/run`. E.g. a plugin's clean-up.
2682
2859
  */
2860
+ interface JobConfig {
2861
+ /** Unique, e.g. `ecommerce:carts`. */
2862
+ readonly name: string;
2863
+ /**
2864
+ * At most this often, in seconds. Default: every run. The last run is kept in the database, so
2865
+ * it holds across processes and serverless invocations.
2866
+ */
2867
+ readonly every?: number;
2868
+ readonly run: (args: {
2869
+ readonly cms: EasyCMS;
2870
+ readonly now: Date;
2871
+ }) => MaybePromise<unknown>;
2872
+ }
2683
2873
  /** An `easy-cms <name> [args…]` command. Built-in commands keep their names. */
2684
2874
  interface CliCommand {
2685
2875
  /** Lowercase, e.g. `nested:rebuild`. */
@@ -2696,6 +2886,10 @@ interface CliCommand {
2696
2886
  readonly log: (line: string) => void;
2697
2887
  }) => MaybePromise<number | undefined>;
2698
2888
  }
2889
+ /**
2890
+ * A custom REST endpoint, served under `routes.api`. Writes from the browser pass the same
2891
+ * CSRF check as the built-in endpoints.
2892
+ */
2699
2893
  interface Endpoint {
2700
2894
  /**
2701
2895
  * Path under the API, e.g. `/seo/generate` or `/stats/:collection`. The first segment must
@@ -2804,6 +2998,13 @@ interface Config {
2804
2998
  readonly cronSecret?: string;
2805
2999
  /** Endpoints notified when content changes, e.g. to rebuild a static site. */
2806
3000
  readonly webhooks?: readonly WebhookConfig[];
3001
+ /**
3002
+ * Events of the app or its plugins besides content changes, e.g. `order.paid`: sent with
3003
+ * `cms.emit()` to the webhooks that list them in `events`. Named `<area>.<what>`.
3004
+ */
3005
+ readonly events?: readonly string[];
3006
+ /** Work run with the scheduled jobs, e.g. a plugin's clean-up. */
3007
+ readonly jobs?: readonly JobConfig[];
2807
3008
  /** Content in several languages: fields with `localized: true` hold one value per locale. */
2808
3009
  readonly localization?: LocalizationConfig | null;
2809
3010
  readonly routes?: RoutesConfig;
@@ -2865,6 +3066,8 @@ interface ResolvedConfig extends Omit<Config, 'cors' | 'localization' | 'routes'
2865
3066
  readonly globals: readonly GlobalConfig[];
2866
3067
  readonly endpoints: readonly Endpoint[];
2867
3068
  readonly commands: readonly CliCommand[];
3069
+ readonly events: readonly string[];
3070
+ readonly jobs: readonly JobConfig[];
2868
3071
  readonly fieldTypes: readonly FieldTypeDefinition[];
2869
3072
  /** The config's plugins in order, with their `info` where they give one. */
2870
3073
  readonly installedPlugins: readonly Partial<PluginInfo>[];
@@ -3293,6 +3496,8 @@ interface AdminCollection {
3293
3496
  sidebar?: AdminComponentRef[];
3294
3497
  /** Listed under Settings in the menu (users, API keys, `admin.group: 'settings'`). */
3295
3498
  group?: 'settings';
3499
+ /** Listed under a heading of its own in the menu (`admin.group` with a label). */
3500
+ section?: Label;
3296
3501
  /** The list is a tree along this relationship field (`admin.list.tree`). */
3297
3502
  tree?: string;
3298
3503
  /** The list's default order (`admin.list.sort`). */
@@ -3495,6 +3700,27 @@ declare function createRestHandler<C extends Config>(instance: EasyCMS<C>, optio
3495
3700
  declare function createRootEndpointHandler<C extends Config>(instance: EasyCMS<C>, options?: Pick<RestHandlerOptions, 'getClientIp'>): (request: Request) => Promise<Response | undefined>;
3496
3701
  declare function readCookie(request: Request, name: string): string | undefined;
3497
3702
 
3703
+ /** A token that proves the form `purpose` names was loaded at `now`: `<time>.<signature>`. */
3704
+ declare function formToken(secret: string, purpose: string, now?: number): string;
3705
+ /**
3706
+ * Checks a token: `ok` when the form was loaded at least `minTime` ms ago (people take a few
3707
+ * seconds; bots don't) and less than a day ago.
3708
+ */
3709
+ declare function checkFormToken(secret: string, purpose: string, token: unknown, minTime: number, now?: number): 'ok' | 'invalid' | 'too-fast' | 'expired';
3710
+ /**
3711
+ * Rate-limit keys for `subject` (e.g. an IP and a form) in the current and previous window of
3712
+ * `window` seconds. A hash with the window in it: no IP is kept, and keys from different
3713
+ * windows can't be linked.
3714
+ */
3715
+ declare function rateKeys(secret: string, subject: string, window: number, now?: number): {
3716
+ current: string;
3717
+ previous: string;
3718
+ };
3719
+ /** The hidden field bots fill in: a common name the form doesn't use. */
3720
+ declare function honeypotName(names: readonly string[]): string;
3721
+ /** Checks a Cloudflare Turnstile response with Cloudflare. */
3722
+ declare function verifyTurnstile(secretKey: string, response: unknown, ip: string | undefined, fetcher?: typeof fetch): Promise<boolean>;
3723
+
3498
3724
  /** Best-effort English singular: "categories" → "category". */
3499
3725
  declare function singularize(word: string): string;
3500
3726
  /**
@@ -3512,4 +3738,4 @@ declare function validateConfig(config: Config): ConfigIssue[];
3512
3738
  /** The version of `@easy-cms/core`, set when the package is built. */
3513
3739
  declare const VERSION: string;
3514
3740
 
3515
- export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminAttention, type AdminBackup, type AdminBackups, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminDeliveries, type AdminDelivery, type AdminEmail, type AdminEmailDelivery, type AdminField, type AdminFieldArgs, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminPage, type AdminPageRef, type AdminRole, type AdminRoleChange, type AdminRoleField, type AdminRoleTarget, type AdminRoleView, type AdminRoles, type AdminSchema, type AdminSso, type AdminStatus, type AdminSwitcher, type AdminViewAccess, type AdminWebhookDelivery, type AdminWidgetRef, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiHandlerOptions, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, type AuditChange, type AuditConfig, type AuditEntry, AuditLog, type AuditPage, type AuditVerification, Auth, type AuthConfig, type AuthProvider, type AuthProviderProfile, type AuthProviderRequest, type AuthUser, BUILTIN_COLLECTIONS, type BackupState, type BackupsConfig, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinMediaFoldersCollection, 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 DashboardWidget, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DeliveryKind, type DeliveryState, type DepthOptions, type DirectUpload, type DocumentOf, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailCheck, type EmailField, type EmailMessage, type EmailSetting, type Endpoint, type EndpointRequest, FIELD_TYPES, FIELD_TYPE_BASES, FOLDER_LEVELS, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldRule, 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, type FolderLevel, type FolderPermissions, 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, MEDIA_FOLDERS, MIME_GROUPS, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, MediaFolders, type MediaSize, type MigrationInfo, NotFoundError, type NumberField, type OnRequest, type OnRequestArgs, type Operation, type PaginatedDocs, type PasswordEmail, type PasswordEmailArgs, type PasswordEmailFn, type PasswordLinkOptions, PayloadTooLargeError, type Plugin, type PluginInfo, type PluginTypes, type PreviewTarget, type PreviewURL, QueryError, ROLE_OPERATIONS, type RawDocument, type ReadOptions, type RelationshipField, type RequestContext, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoleOperation, type RolePermissions, Roles, type RoutesConfig, SESSION_COOKIE, SSO_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SlugField, type SlugOf, type SsoOutcome, type SsoProviderRef, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, type TypedPlugin, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, type UploadFromURLConfig, type UserIdentity, VERSION, 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, createApiHandler, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, defineFieldType, definePlugin, expandMimeTypes, fillMissing, findConfigFile, generateSlugs, generateTypes, hasRows, hashPassword, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, isSystemAdmin, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, readCookie, resolveAdminModule, resolveConfig, rowFields, sharedEasyCMS, silentLogger, singularize, slugify, sniffMimeType, uniqueWithinOf, validateConfig, validateFields, verifyPassword, writeBackupFile };
3741
+ export { ADMIN_ICONS, API_KEYS, API_KEY_GLOBAL_OPERATIONS, API_KEY_OPERATIONS, type Access, type AccessArgs, type AccessOptions, type AdminAttention, type AdminBackup, type AdminBackups, type AdminBrand, type AdminCollection, type AdminComponent, type AdminComponentRef, type AdminConfig, type AdminDeliveries, type AdminDelivery, type AdminEmail, type AdminEmailDelivery, type AdminField, type AdminFieldArgs, type AdminGlobal, type AdminIcon, type AdminLocale, type AdminPage, type AdminPageRef, type AdminRole, type AdminRoleChange, type AdminRoleField, type AdminRoleTarget, type AdminRoleView, type AdminRoles, type AdminSchema, type AdminSso, type AdminStatus, type AdminSwitcher, type AdminViewAccess, type AdminWebhookDelivery, type AdminWidgetRef, type AfterChangeHook, type AfterDeleteHook, type AfterReadHook, type ApiHandlerOptions, type ApiKeyContext, type ApiKeyGlobalOperation, type ApiKeyOperation, type ApiKeyPermissions, type ArrayField, type AuditChange, type AuditConfig, type AuditEntry, AuditLog, type AuditPage, type AuditVerification, Auth, type AuthConfig, type AuthProvider, type AuthProviderProfile, type AuthProviderRequest, type AuthUser, BUILTIN_COLLECTIONS, type BackupState, type BackupsConfig, type BeforeChangeHook, type BeforeDeleteHook, type BeforeValidateHook, type Block, type BlocksField, type BooleanField, type BuiltinApiKeysCollection, type BuiltinMediaCollection, type BuiltinMediaFoldersCollection, 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 DashboardWidget, type Database, type DatabaseAdapter, type DatabaseInitArgs, type DatabaseTransfer, type DateField, type DeliveryKind, type DeliveryState, type DepthOptions, type DirectUpload, type DocumentOf, EXTENSIONS, EasyCMS, EasyCMSError, type EmailAdapter, type EmailCheck, type EmailField, type EmailMessage, type EmailSetting, type Endpoint, type EndpointRequest, FIELD_TYPES, FIELD_TYPE_BASES, FOLDER_LEVELS, type Field, type FieldAccess, type FieldAccessFn, type FieldAdmin, type FieldError, type FieldRule, 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, type FolderLevel, type FolderPermissions, ForbiddenError, type GlobalAccess, type GlobalConfig, type GlobalDocument, type GlobalHooks, type GlobalInput, type GlobalSlug, type GroupField, type ID, INTERNAL_COLLECTIONS, type ImageSize, type IncrementOptions, type InferCollection, type InferGlobal, type JobConfig, type JsonField, type Label, type LivePreview, type LoadConfigOptions, type LocalStorageOptions, type LocalizationConfig, type Logger, type LoginArgs, MAX_DEPTH, MEDIA, MEDIA_FOLDERS, MIME_GROUPS, MIN_PASSWORD_LENGTH, MIN_SECRET_LENGTH, type MediaDocument, MediaFolders, type MediaSize, type MembersConfig, type MembersSignup, type MigrationInfo, NotFoundError, type NumberField, type OnRequest, type OnRequestArgs, type Operation, type PaginatedDocs, type PasswordEmail, type PasswordEmailArgs, type PasswordEmailFn, type PasswordLinkOptions, PayloadTooLargeError, type Plugin, type PluginInfo, type PluginTypes, type PreviewTarget, type PreviewURL, QueryError, ROLE_OPERATIONS, type RawDocument, type ReadOptions, type RelationshipField, type RequestContext, type ResolvedConfig, type RestHandler, type RestHandlerOptions, type RichTextDocument, type RichTextField, type Role, type RoleOperation, type RolePermissions, Roles, type RoutesConfig, SESSION_COOKIE, SSO_COOKIE, type ScheduledJob, SchemaError, type SchemaMode, type SelectField, type SelectOption, type Session, type SignupArgs, type SignupResult, type SlugField, type SlugOf, type SsoOutcome, type SsoProviderRef, type StorageAdapter, type StoredFile, type TextField, type TextareaField, TooManyRequestsError, type TypedPlugin, UnauthorizedError, type UpdateInput, type UpdateOptions, type UploadConfig, type UploadField, type UploadFromURLConfig, type UserIdentity, VERSION, ValidationError, type Version, type VersionSummary, type VersionsConfig, WEBHOOK_EVENTS, type WebhookConfig, type WebhookEvent, type WebhookPayload, type Where, type WhereOperators, anyone, applyDefaults, applyPlugins, checkFormToken, configSignature, consoleEmail, consoleLogger, copyDatabase, createApiHandler, createEasyCMS, createRestHandler, createRootEndpointHandler, defineConfig, defineFieldType, definePlugin, expandMimeTypes, fillMissing, findConfigFile, formToken, generateSlugs, generateTypes, hasRows, hashPassword, honeypotName, imageDimensions, importConfig, isAdmin, isHasMany, isLoggedIn, isSignedIn, isSystemAdmin, keyAllows, loadConfig, localStorage, mergeForUpdate, mimeAllowed, mimeAllowedBy, parseId, populate, rateKeys, readCookie, resolveAdminModule, resolveConfig, rowFields, sharedEasyCMS, silentLogger, singularize, slugify, sniffMimeType, uniqueWithinOf, validateConfig, validateFields, verifyPassword, verifyTurnstile, writeBackupFile };