@dyrected/core 2.13.4 → 2.13.6

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
@@ -1,5 +1,5 @@
1
- import { F as Field, B as Block, D as DyrectedConfig, C as CollectionConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, G as GlobalConfig, a as DeclarativeHookExpression, W as WorkflowConfig, b as AuthenticatedUser, c as WorkflowTransition, L as LifecycleEventName, d as LifecycleEvent, e as BaseDocument, H as HookRequestContext, f as DetailComputedOptions, g as ComputedHandler, h as DetailComputed, i as DetailCustomOptions, j as DetailCustom, k as DetailDividerOptions, l as DetailDivider, m as DisplayFieldOptions, n as DetailField, o as DetailItem, p as DetailGridOptions, q as DetailGrid, r as DetailRepeatOptions, s as DetailRepeat, t as DetailSectionOptions, u as DetailSection, v as DetailTabOptions, w as DetailTab, x as DetailTabsOptions, y as DetailTabs, z as DetailTextOptions, E as DetailText, I as DetailSchema, J as DyrectedContext, K as AIConfig, M as AIPIIConfig, N as ArrayField, O as BlocksField, Q as BooleanField, R as AuthConfig, S as AccessPolicyResolver, T as DateField, U as DateTimeField, V as EmailField, X as IconField, Y as ImageField, Z as JoinField, _ as JsonField, $ as MultiSelectField, a0 as NumberField, a1 as ObjectField, a2 as RadioField, a3 as RelationshipField, a4 as RichTextField, a5 as RowField, a6 as SelectField, a7 as TextField, a8 as TextareaField, a9 as TimeField, aa as UrlField } from './app-De-3eNn1.js';
2
- export { ab as AIAction, ac as AIActionStatus, ad as AIActionType, ae as AIAuditActionType, af as AIAuditRecord, ag as AIChunk, ah as AIMessage, ai as AIPIIPattern, aj as AIRateLimitResult, ak as AIRateLimitStore, al as AIThread, am as AIToolContext, an as AIToolDefinition, ao as AI_ACTIONS_COLLECTION, ap as AI_AUDIT_COLLECTION, aq as AI_CHUNKS_COLLECTION, ar as AI_MESSAGES_COLLECTION, as as AI_THREADS_COLLECTION, at as AccessConfig, au as AccessFunction, av as AccessFunctionArgs, aw as AccessResult, ax as AccessRule, ay as ActionConfig, az as ActionContext, aA as ActionType, aB as AdminAuthAccessResolution, aC as AdminAuthClaimMapping, aD as AdminAuthMember, aE as AdminAuthProvider, aF as AdminAuthProviderMembersConfig, aG as AdminAuthProvisioningMode, aH as AdminAuthResolveAccessArgs, aI as AdminAuthResolvedIdentity, aJ as AdminConfig, aK as AdminDashboardComponentSlots, aL as AdminIconName, aM as AggregateArgs, aN as AggregateCastType, aO as AggregateCollectionResult, aP as AggregateInput, aQ as AggregateOperation, aR as AggregateResult, aS as BaseAdminAuthProvider, aT as BaseFieldAdmin, aU as BlockVariant, aV as BooleanFieldAdmin, aW as BooleanFormat, aX as CharacterLimitFieldAdmin, aY as CharacterLimitFieldConfig, aZ as CollectionAfterChangeHook, a_ as CollectionAfterDeleteHook, a$ as CollectionAfterReadHook, b0 as CollectionAfterReadHookEntry, b1 as CollectionAfterTransitionHook, b2 as CollectionBeforeChangeHook, b3 as CollectionBeforeChangeHookEntry, b4 as CollectionBeforeDeleteHook, b5 as CollectionBeforeReadHook, b6 as CollectionBeforeReadHookEntry, b7 as CollectionBeforeTransitionHook, b8 as CollectionListComponentSlots, b9 as CollectionRAGConfig, ba as CollectionSchemaResult, bb as CollectionSummaryResult, bc as CollectionViewComponentSlots, bd as CountOperation, be as CustomAdminAuthProvider, bf as DatabaseAdapter, bg as DateFieldAdmin, bh as DateFormat, bi as DefineActionOptions, bj as DefineViewOptions, bk as DetailSpan, bl as DisplayTone, bm as DisplayVariant, bn as DistinctCountOperation, bo as DistinctValuesOperation, bp as DynamicOptionItem, bq as DynamicOptionsConfig, br as DynamicOptionsResolver, bs as DynamicOptionsResolverArgs, bt as DyrectedAIContext, bu as DyrectedLoggerConfig, bv as DyrectedObservabilityConfig, bw as EmailFieldAdmin, bx as FieldAdminHooks, by as FieldAdminOnChangeHook, bz as FieldAdminOnChangeHookArgs, bA as FieldAdminOptionsHook, bB as FieldAdminOptionsHookArgs, bC as FieldAdminOptionsHookResult, bD as FieldAfterReadHook, bE as FieldAfterReadHookArgs, bF as FieldBase, bG as FieldBeforeChangeHook, bH as FieldBeforeChangeHookArgs, bI as FieldHook, bJ as FieldHooks, bK as FieldType, bL as FileData, bM as GetDocumentResult, bN as GlobalAfterChangeHook, bO as GlobalAfterReadHook, bP as GlobalAfterReadHookEntry, bQ as GlobalBeforeChangeHook, bR as GlobalBeforeChangeHookEntry, bS as GlobalBeforeReadHook, bT as GlobalBeforeReadHookEntry, bU as GlobalRAGConfig, bV as GlobalSchemaResult, bW as GlobalSummaryResult, bX as HeadingLevel, bY as HookFunction, bZ as IconFieldAdmin, b_ as ImageService, b$ as ImageTransformOptions, c0 as InferAggregateResult, c1 as JoinFieldAdmin, c2 as JsonFieldAdmin, c3 as JsonFormat, c4 as LIFECYCLE_EVENT_NAMES, c5 as LifecycleEventHandler, c6 as LinkFormat, c7 as MetricColor, c8 as MultiSelectFieldAdmin, c9 as NamedAccessPolicy, ca as NumberFieldAdmin, cb as NumberFormat, cc as NumberLimitFieldAdmin, cd as NumberLimitFieldConfig, ce as NumericOperation, cf as OIDCAdminAuthProvider, cg as OptionFormat, ch as PaginatedResult, ci as PublicAdminAuthProvider, cj as QueryCollectionResult, ck as RAGSearchResult, cl as RadioFieldAdmin, cm as RateLimitConfig, cn as ReadonlyDatabaseAdapter, co as RichTextFeature, cp as RichTextFieldConfig, cq as SelectFieldAdmin, cr as SqlWhereResult, cs as StorageAdapter, ct as TextFieldAdmin, cu as TextFormat, cv as TextareaFieldAdmin, cw as TrustProxyConfig, cx as TypedField, cy as UploadConfig, cz as UrlFieldAdmin, cA as UrlLinkValue, cB as ViewActionFeatures, cC as ViewComponentSlots, cD as ViewConfig, cE as ViewLayout, cF as ViewMetric, cG as ViewSubMetric, cH as WhereClause, cI as WhereOperator, cJ as WhereOperatorName, cK as WordLimitFieldAdmin, cL as WordLimitFieldConfig, cM as WorkflowMetadata, cN as WorkflowRole, cO as WorkflowState, cP as WorkflowTransitionContext, cQ as defineAction, cR as defineView, cS as isAICollection, cT as parseMongoWhere, cU as parseSqlWhere } from './app-De-3eNn1.js';
1
+ import { F as Field, B as Block, C as CollectionConfig, D as DyrectedConfig, A as AdminAuthConfig, P as PublicAdminAuthConfig, G as GlobalConfig, a as DeclarativeHookExpression, W as WorkflowConfig, b as AuthenticatedUser, c as WorkflowTransition, L as LifecycleEventName, d as LifecycleEvent, e as BaseDocument, H as HookRequestContext, f as DetailComputedOptions, g as ComputedHandler, h as DetailComputed, i as DetailCustomOptions, j as DetailCustom, k as DetailDividerOptions, l as DetailDivider, m as DisplayFieldOptions, n as DetailField, o as DetailItem, p as DetailGridOptions, q as DetailGrid, r as DetailRepeatOptions, s as DetailRepeat, t as DetailSectionOptions, u as DetailSection, v as DetailTabOptions, w as DetailTab, x as DetailTabsOptions, y as DetailTabs, z as DetailTextOptions, E as DetailText, I as DetailSchema, J as DyrectedContext, K as AIConfig, M as AIPIIConfig, N as ArrayField, O as FieldType, Q as BooleanField, R as AuthConfig, S as AccessPolicyResolver, T as DateField, U as DateTimeField, V as EmailField, X as IconField, Y as ImageField, Z as JoinField, _ as JsonField, $ as MultiSelectField, a0 as NumberField, a1 as ObjectField, a2 as RadioField, a3 as RelationshipField, a4 as RichTextField, a5 as RowField, a6 as SelectField, a7 as TextField, a8 as TextareaField, a9 as TimeField, aa as UrlField } from './app-phLVsEOM.js';
2
+ export { ab as AIAction, ac as AIActionStatus, ad as AIActionType, ae as AIAuditActionType, af as AIAuditRecord, ag as AIChunk, ah as AIMessage, ai as AIPIIPattern, aj as AIRateLimitResult, ak as AIRateLimitStore, al as AIThread, am as AIToolContext, an as AIToolDefinition, ao as AI_ACTIONS_COLLECTION, ap as AI_AUDIT_COLLECTION, aq as AI_CHUNKS_COLLECTION, ar as AI_MESSAGES_COLLECTION, as as AI_THREADS_COLLECTION, at as AccessConfig, au as AccessFunction, av as AccessFunctionArgs, aw as AccessResult, ax as AccessRule, ay as ActionConfig, az as ActionConfigBase, aA as ActionConfigWithHandler, aB as ActionConfigWithMutation, aC as ActionContext, aD as ActionType, aE as AdminAuthAccessResolution, aF as AdminAuthClaimMapping, aG as AdminAuthMember, aH as AdminAuthProvider, aI as AdminAuthProviderMembersConfig, aJ as AdminAuthProvisioningMode, aK as AdminAuthResolveAccessArgs, aL as AdminAuthResolvedIdentity, aM as AdminConfig, aN as AdminDashboardComponentSlots, aO as AdminIconName, aP as AggregateArgs, aQ as AggregateCastType, aR as AggregateCollectionResult, aS as AggregateInput, aT as AggregateOperation, aU as AggregateResult, aV as BaseAdminAuthProvider, aW as BaseFieldAdmin, aX as BlockVariant, aY as BlocksField, aZ as BooleanFieldAdmin, a_ as BooleanFormat, a$ as CharacterLimitFieldAdmin, b0 as CharacterLimitFieldConfig, b1 as CollectionAfterChangeHook, b2 as CollectionAfterDeleteHook, b3 as CollectionAfterReadHook, b4 as CollectionAfterReadHookEntry, b5 as CollectionAfterTransitionHook, b6 as CollectionBeforeChangeHook, b7 as CollectionBeforeChangeHookEntry, b8 as CollectionBeforeDeleteHook, b9 as CollectionBeforeReadHook, ba as CollectionBeforeReadHookEntry, bb as CollectionBeforeTransitionHook, bc as CollectionListComponentSlots, bd as CollectionRAGConfig, be as CollectionSchemaResult, bf as CollectionSummaryResult, bg as CollectionViewComponentSlots, bh as CountOperation, bi as CustomAdminAuthProvider, bj as DatabaseAdapter, bk as DateFieldAdmin, bl as DateFormat, bm as DefaultValueContext, bn as DefineActionOptions, bo as DefineCalendarViewOptions, bp as DefineCardsViewOptions, bq as DefineGanttViewOptions, br as DefineKanbanViewOptions, bs as DefineTableViewOptions, bt as DefineViewBaseOptions, bu as DefineViewOptions, bv as DetailSpan, bw as DisplayTone, bx as DisplayVariant, by as DistinctCountOperation, bz as DistinctValuesOperation, bA as DynamicOptionItem, bB as DynamicOptionsConfig, bC as DynamicOptionsResolver, bD as DynamicOptionsResolverArgs, bE as DyrectedAIContext, bF as DyrectedLoggerConfig, bG as DyrectedObservabilityConfig, bH as EmailFieldAdmin, bI as FieldAdminHooks, bJ as FieldAdminOnChangeHook, bK as FieldAdminOnChangeHookArgs, bL as FieldAdminOptionsHook, bM as FieldAdminOptionsHookArgs, bN as FieldAdminOptionsHookResult, bO as FieldAfterReadHook, bP as FieldAfterReadHookArgs, bQ as FieldBase, bR as FieldBeforeChangeHook, bS as FieldBeforeChangeHookArgs, bT as FieldHook, bU as FieldHooks, bV as FileData, bW as GetDocumentResult, bX as GlobalAfterChangeHook, bY as GlobalAfterReadHook, bZ as GlobalAfterReadHookEntry, b_ as GlobalBeforeChangeHook, b$ as GlobalBeforeChangeHookEntry, c0 as GlobalBeforeReadHook, c1 as GlobalBeforeReadHookEntry, c2 as GlobalRAGConfig, c3 as GlobalSchemaResult, c4 as GlobalSummaryResult, c5 as HeadingLevel, c6 as HookFunction, c7 as IconFieldAdmin, c8 as ImageService, c9 as ImageTransformOptions, ca as InferAggregateResult, cb as JoinFieldAdmin, cc as JsonFieldAdmin, cd as JsonFormat, ce as LIFECYCLE_EVENT_NAMES, cf as LifecycleEventHandler, cg as LinkFormat, ch as MetricColor, ci as MultiSelectFieldAdmin, cj as NamedAccessPolicy, ck as NumberFieldAdmin, cl as NumberFormat, cm as NumberLimitFieldAdmin, cn as NumberLimitFieldConfig, co as NumericOperation, cp as OIDCAdminAuthProvider, cq as OptionFormat, cr as PaginatedResult, cs as PublicAdminAuthProvider, ct as QueryCollectionResult, cu as RAGSearchResult, cv as RadioFieldAdmin, cw as RateLimitConfig, cx as ReadonlyDatabaseAdapter, cy as RichTextFeature, cz as RichTextFieldConfig, cA as SelectFieldAdmin, cB as SqlWhereResult, cC as StorageAdapter, cD as TextFieldAdmin, cE as TextFormat, cF as TextareaFieldAdmin, cG as TrustProxyConfig, cH as TypedField, cI as UploadConfig, cJ as UrlFieldAdmin, cK as UrlLinkValue, cL as ViewActionFeatures, cM as ViewComponentSlots, cN as ViewConfig, cO as ViewLayout, cP as ViewMetric, cQ as ViewSubMetric, cR as WhereClause, cS as WhereOperator, cT as WhereOperatorName, cU as WordLimitFieldAdmin, cV as WordLimitFieldConfig, cW as WorkflowMetadata, cX as WorkflowRole, cY as WorkflowState, cZ as WorkflowTransitionContext, c_ as defineAction, c$ as defineCalendarView, d0 as defineCardsView, d1 as defineGanttView, d2 as defineKanbanView, d3 as defineTableView, d4 as defineView, d5 as isAICollection, d6 as parseMongoWhere, d7 as parseSqlWhere } from './app-phLVsEOM.js';
3
3
  import jexl from 'jexl';
4
4
  import { Context } from 'hono';
5
5
  export { z } from 'zod';
@@ -96,6 +96,43 @@ declare class DyrectedAIError extends Error {
96
96
  };
97
97
  }
98
98
 
99
+ /**
100
+ * Helper to work around TypeScript readonly inference issues with `const` collection definitions.
101
+ *
102
+ * When using `const Collection = defineCollection({...})`, TypeScript may infer all properties
103
+ * as readonly, which can cause type compatibility issues with the schema type system in complex
104
+ * nested field scenarios. This is a known TypeScript limitation with deep readonly inference.
105
+ *
106
+ * **Note**: The collection works perfectly at runtime. This is purely a type-checking limitation.
107
+ *
108
+ * Use this helper or `satisfies` when you hit type errors:
109
+ *
110
+ * Option 1: Wrap with asCollection (automatic in defineCollection):
111
+ * ```ts
112
+ * const Pages = asCollection(defineCollection({
113
+ * slug: "pages",
114
+ * fields: [...]
115
+ * }))
116
+ * ```
117
+ *
118
+ * Option 2: Use `satisfies` pattern:
119
+ * ```ts
120
+ * const Pages = {
121
+ * slug: "pages",
122
+ * fields: [...]
123
+ * } satisfies CollectionConfig
124
+ * ```
125
+ *
126
+ * Option 3: Use // @ts-expect-error for readonly inference only:
127
+ * ```ts
128
+ * // @ts-expect-error TypeScript readonly inference limitation with deeply nested fields
129
+ * const Pages = defineCollection({...})
130
+ * ```
131
+ *
132
+ * The collection functions and APIs work correctly despite the type error.
133
+ */
134
+ declare function asCollection<T extends CollectionConfig<any>>(config: T): T;
135
+
99
136
  /**
100
137
  * Normalizes the Dyrected configuration by injecting system fields
101
138
  * (createdAt, updatedAt, createdBy, updatedBy) into every collection and
@@ -1311,24 +1348,27 @@ type TypedBlockForConfig<TBlock extends Block, TCollections extends readonly unk
1311
1348
  type TypedBlocksForConfig<TBlocks extends readonly Block[], TCollections extends readonly unknown[], TRootBlocks extends readonly Block[], TPolicyNames extends string> = {
1312
1349
  [K in keyof TBlocks]: TBlocks[K] extends Block ? TypedBlockForConfig<TBlocks[K], TCollections, TRootBlocks, TPolicyNames> : TBlocks[K];
1313
1350
  };
1351
+ type MutableOmit<T, K extends PropertyKey> = {
1352
+ [P in keyof T as P extends K ? never : P]: T[P];
1353
+ };
1314
1354
  type TypedFieldForConfig<TField extends Field, TCollections extends readonly unknown[], TBlocks extends readonly Block[], TPolicyNames extends string> = TField extends {
1315
1355
  type: "relationship";
1316
- } ? Omit<TField, "relationTo" | "access"> & {
1356
+ } ? MutableOmit<TField, "relationTo" | "access"> & {
1317
1357
  relationTo?: TypedReference<PropertyType<TField, "relationTo">, CollectionSlug<TCollections>, "collection slug">;
1318
1358
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1319
1359
  } : TField extends {
1320
1360
  type: "image";
1321
- } ? Omit<TField, "relationTo" | "access"> & {
1361
+ } ? MutableOmit<TField, "relationTo" | "access"> & {
1322
1362
  relationTo?: TypedReference<PropertyType<TField, "relationTo">, UploadCollectionSlug<TCollections>, "upload collection slug">;
1323
1363
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1324
1364
  } : TField extends {
1325
1365
  type: "richText";
1326
- } ? Omit<TField, "uploadCollection" | "access"> & {
1366
+ } ? MutableOmit<TField, "uploadCollection" | "access"> & {
1327
1367
  uploadCollection?: TypedReference<PropertyType<TField, "uploadCollection">, UploadCollectionSlug<TCollections>, "upload collection slug">;
1328
1368
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1329
1369
  } : TField extends {
1330
1370
  type: "join";
1331
- } ? Omit<TField, "collection" | "on" | "access"> & {
1371
+ } ? MutableOmit<TField, "collection" | "on" | "access"> & {
1332
1372
  collection?: TypedReference<PropertyType<TField, "collection">, CollectionSlug<TCollections>, "collection slug">;
1333
1373
  on?: TypedReference<PropertyType<TField, "on">, CollectionFieldNamesBySlug<TCollections, Extract<PropertyType<TField, "collection">, string>> | TopLevelFieldName<Extract<CollectionBySlug<TCollections, CollectionSlug<TCollections>>, {
1334
1374
  fields: readonly Field[];
@@ -1336,30 +1376,30 @@ type TypedFieldForConfig<TField extends Field, TCollections extends readonly unk
1336
1376
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1337
1377
  } : TField extends {
1338
1378
  type: "blocks";
1339
- } ? Omit<TField, "blocks" | "blockReferences" | "access"> & {
1379
+ } ? MutableOmit<TField, "blocks" | "blockReferences" | "access"> & {
1340
1380
  blocks?: TField["blocks"] extends readonly Block[] ? TypedBlocksForConfig<TField["blocks"], TCollections, TBlocks, TPolicyNames> : TField["blocks"];
1341
1381
  blockReferences?: TypedReferenceList<PropertyType<TField, "blockReferences">, BlockSlug<TBlocks>, "block slug">;
1342
1382
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1343
1383
  } : TField extends {
1344
1384
  type: "array";
1345
1385
  fields: infer TSubFields extends readonly Field[];
1346
- } ? Omit<TField, "fields" | "access" | "admin"> & {
1386
+ } ? MutableOmit<TField, "fields" | "access" | "admin"> & {
1347
1387
  fields: TypedFields<TSubFields, TCollections, TBlocks, TPolicyNames>;
1348
1388
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1349
1389
  admin?: TypedNestedFieldAdmin<TSubFields, PropertyType<TField, "admin">>;
1350
1390
  } : TField extends {
1351
1391
  type: "object";
1352
1392
  fields: infer TSubFields extends readonly Field[];
1353
- } ? Omit<TField, "fields" | "access" | "admin"> & {
1393
+ } ? MutableOmit<TField, "fields" | "access" | "admin"> & {
1354
1394
  fields: TypedFields<TSubFields, TCollections, TBlocks, TPolicyNames>;
1355
1395
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1356
1396
  admin?: TypedNestedFieldAdmin<TSubFields, PropertyType<TField, "admin">>;
1357
1397
  } : TField extends {
1358
1398
  fields: infer TSubFields extends readonly Field[];
1359
- } ? Omit<TField, "fields" | "access"> & {
1399
+ } ? MutableOmit<TField, "fields" | "access"> & {
1360
1400
  fields: TypedFields<TSubFields, TCollections, TBlocks, TPolicyNames>;
1361
1401
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1362
- } : Omit<TField, "access"> & {
1402
+ } : MutableOmit<TField, "access"> & {
1363
1403
  access?: TypedFieldAccess<NonNullable<TField["access"]>, TPolicyNames>;
1364
1404
  };
1365
1405
  type TypedFields<TFields extends readonly Field[], TCollections extends readonly unknown[], TBlocks extends readonly Block[], TPolicyNames extends string> = {
@@ -1527,6 +1567,10 @@ declare function defineField<const T extends Field>(field: T): T;
1527
1567
  * ```
1528
1568
  */
1529
1569
  declare function defineBlock<const T extends Block>(block: T): T;
1570
+ /** The member of the {@link Field} union that has the given `type`. */
1571
+ type FieldOfType<TType extends FieldType> = Extract<Field, {
1572
+ type: TType;
1573
+ }>;
1530
1574
  /** Define a `text` field. */
1531
1575
  declare const defineTextField: <const T extends Omit<TextField, "type">>(field: T) => T & {
1532
1576
  type: "text";
@@ -1571,10 +1615,6 @@ declare const defineMultiSelectField: <const T extends Omit<MultiSelectField, "t
1571
1615
  declare const defineRadioField: <const T extends Omit<RadioField, "type">>(field: T) => T & {
1572
1616
  type: "radio";
1573
1617
  };
1574
- /** Define a `relationship` field. */
1575
- declare const defineRelationshipField: <const T extends Omit<RelationshipField, "type">>(field: T) => T & {
1576
- type: "relationship";
1577
- };
1578
1618
  /** Define an `array` field. */
1579
1619
  declare const defineArrayField: <const T extends Omit<ArrayField, "type">>(field: T) => T & {
1580
1620
  type: "array";
@@ -1588,13 +1628,9 @@ declare const defineJsonField: <const T extends Omit<JsonField, "type">>(field:
1588
1628
  type: "json";
1589
1629
  };
1590
1630
  /** Define a `blocks` field. */
1591
- declare const defineBlocksField: <const T extends Omit<BlocksField, "type">>(field: T) => T & {
1631
+ declare const defineBlocksField: <const T extends Omit<FieldOfType<"blocks">, "type">>(field: T) => T & {
1592
1632
  type: "blocks";
1593
1633
  };
1594
- /** Define an `image` field. */
1595
- declare const defineImageField: <const T extends Omit<ImageField, "type">>(field: T) => T & {
1596
- type: "image";
1597
- };
1598
1634
  /** Define an `email` field. */
1599
1635
  declare const defineEmailField: <const T extends Omit<EmailField, "type">>(field: T) => T & {
1600
1636
  type: "email";
@@ -1607,14 +1643,92 @@ declare const defineUrlField: <const T extends Omit<UrlField, "type">>(field: T)
1607
1643
  declare const defineIconField: <const T extends Omit<IconField, "type">>(field: T) => T & {
1608
1644
  type: "icon";
1609
1645
  };
1610
- /** Define a `join` field. */
1611
- declare const defineJoinField: <const T extends Omit<JoinField, "type">>(field: T) => T & {
1612
- type: "join";
1613
- };
1614
1646
  /** Define a layout-only `row` field. */
1615
1647
  declare const defineRowField: <const T extends Omit<RowField, "type">>(field: T) => T & {
1616
1648
  type: "row";
1617
1649
  };
1650
+ /**
1651
+ * Extract valid collection slugs from a collection config array.
1652
+ * Used to type-safe `relationTo` and `collection` field properties.
1653
+ * @example
1654
+ * ```ts
1655
+ * type ValidSlugs = ExtractCollectionSlugs<typeof collections>;
1656
+ * // ValidSlugs = "posts" | "comments" | "users"
1657
+ * ```
1658
+ */
1659
+ type ExtractCollectionSlugs<TCollections extends readonly CollectionConfig<any>[]> = Extract<TCollections[number], {
1660
+ slug: string;
1661
+ }>["slug"];
1662
+ /** Base relationship field definer (internal). */
1663
+ declare const _defineRelationshipFieldBase: <const T extends Omit<RelationshipField, "type">>(field: T) => T & {
1664
+ type: "relationship";
1665
+ };
1666
+ /** Base image field definer (internal). */
1667
+ declare const _defineImageFieldBase: <const T extends Omit<ImageField, "type">>(field: T) => T & {
1668
+ type: "image";
1669
+ };
1670
+ /** Base join field definer (internal). */
1671
+ declare const _defineJoinFieldBase: <const T extends Omit<JoinField, "type">>(field: T) => T & {
1672
+ type: "join";
1673
+ };
1674
+ /**
1675
+ * Define a `relationship` field with automatic slug inference from your collection config.
1676
+ * The `relationTo` parameter is type-checked at compile time against available collections.
1677
+ *
1678
+ * @example
1679
+ * ```ts
1680
+ * import { dyrectedSchema } from './schema';
1681
+ * type ValidSlugs = ExtractCollectionSlugs<typeof dyrectedSchema.collections>;
1682
+ *
1683
+ * defineRelationshipField<ValidSlugs>({
1684
+ * name: 'author',
1685
+ * relationTo: 'users', // ✅ TypeScript validates against your collections
1686
+ * })
1687
+ * ```
1688
+ */
1689
+ declare function defineRelationshipField<TValidSlugs extends string = string>(config: Omit<Omit<Parameters<typeof _defineRelationshipFieldBase>[0], "type">, "relationTo"> & {
1690
+ relationTo: TValidSlugs;
1691
+ }): RelationshipField;
1692
+ declare function defineRelationshipField(config: Parameters<typeof _defineRelationshipFieldBase>[0]): RelationshipField;
1693
+ /**
1694
+ * Define an `image` field with automatic slug inference from your collection config.
1695
+ * The `relationTo` parameter is type-checked at compile time against available collections.
1696
+ *
1697
+ * @example
1698
+ * ```ts
1699
+ * import { dyrectedSchema } from './schema';
1700
+ * type ValidSlugs = ExtractCollectionSlugs<typeof dyrectedSchema.collections>;
1701
+ *
1702
+ * defineImageField<ValidSlugs>({
1703
+ * name: 'cover',
1704
+ * relationTo: 'media', // ✅ TypeScript validates against your collections
1705
+ * })
1706
+ * ```
1707
+ */
1708
+ declare function defineImageField<TValidSlugs extends string = string>(config: Omit<Omit<Parameters<typeof _defineImageFieldBase>[0], "type">, "relationTo"> & {
1709
+ relationTo: TValidSlugs;
1710
+ }): ImageField;
1711
+ declare function defineImageField(config: Parameters<typeof _defineImageFieldBase>[0]): ImageField;
1712
+ /**
1713
+ * Define a `join` field with automatic slug inference from your collection config.
1714
+ * The `collection` parameter is type-checked at compile time against available collections.
1715
+ *
1716
+ * @example
1717
+ * ```ts
1718
+ * import { dyrectedSchema } from './schema';
1719
+ * type ValidSlugs = ExtractCollectionSlugs<typeof dyrectedSchema.collections>;
1720
+ *
1721
+ * defineJoinField<ValidSlugs>({
1722
+ * name: 'post_comments',
1723
+ * collection: 'posts', // ✅ TypeScript validates against your collections
1724
+ * on: 'comments',
1725
+ * })
1726
+ * ```
1727
+ */
1728
+ declare function defineJoinField<TValidSlugs extends string = string>(config: Omit<Omit<Parameters<typeof _defineJoinFieldBase>[0], "type">, "collection"> & {
1729
+ collection: TValidSlugs;
1730
+ }): JoinField;
1731
+ declare function defineJoinField(config: Parameters<typeof _defineJoinFieldBase>[0]): JoinField;
1618
1732
  /**
1619
1733
  * Group fields under a named tab in the Admin edit form. Tabs are presentational
1620
1734
  * only: `defineTab` returns the given fields unchanged except that each one's
@@ -1649,4 +1763,4 @@ declare function defineTab<const T extends readonly Field[]>(args: {
1649
1763
  fields: T;
1650
1764
  }): T;
1651
1765
 
1652
- export { AIConfig, type AIErrorCode, AIPIIConfig, type AccessConditions, AccessPolicyResolver, AdminAuthConfig, ArrayField, AuthConfig, type AuthDocFields, AuthenticatedUser, BUILTIN_JEXL_HELPERS, BaseDocument, Block, BlocksField, BooleanField, CollectionConfig, ComputedHandler, type ConfigDiagnostic, ConfigValidationError, DateField, DateTimeField, type DeclarativeAccessSurface, type DeclarativeAccessValidationIssue, type DeclarativeAdminSurface, type DeclarativeAdminValidationIssue, DeclarativeHookExpression, type DeclarativeHookSurface, type DeclarativeHookValidationIssue, type DeclarativePreviewSurface, type DeclarativePreviewValidationIssue, DetailComputed, DetailComputedOptions, DetailCustom, DetailCustomOptions, DetailDivider, DetailDividerOptions, DetailField, DetailGrid, DetailGridOptions, DetailItem, DetailRepeat, DetailRepeatOptions, DetailSchema, DetailSection, DetailSectionOptions, DetailTab, DetailTabOptions, DetailTabs, DetailTabsOptions, DetailText, DetailTextOptions, DisplayFieldOptions, DyrectedAIError, DyrectedConfig, EmailField, type ExprFunction, Field, FieldConditionBuilder, GlobalConfig, HookRequestContext, IconField, ImageField, type InferDocShape, JoinField, JsonField, LIFECYCLE_EVENTS_COLLECTION, LifecycleEvent, LifecycleEventName, MatchBuilder, MultiSelectField, NON_NEGOTIABLE_CREDENTIAL_FIELDS, NumberField, ObjectField, PII_REGEX_PATTERNS, type Prettify, PublicAdminAuthConfig, type PublishingWorkflowOptions, RadioField, RelationshipField, RichTextField, RowField, type SanitizeDocForAIOptions, SelectField, type SortClause, type SortDirection, type SqlSortDialect, type SystemDocFields, TextField, TextareaField, TimeField, type UploadDocFields, UrlField, WORKFLOW_HISTORY_COLLECTION, type WhenFunction, WorkflowConfig, WorkflowTransition, abs, addDays, assertValidAdminConditionsInConfig, assertValidDeclarativeAccessInConfig, assertValidDeclarativeHookExpression, assertValidDeclarativeHookResult, assertValidDeclarativeHooksInConfig, assertValidPreviewUrlsInConfig, availableWorkflowTransitions, buildSqlOrderBy, canViewWorkflowDraft, capitalize, ceil, clamp, coalesce, collectAdminConditionValidationIssues, collectConfigDiagnostics, collectDeclarativeAccessValidationIssues, collectDeclarativeHookValidationIssues, collectPreviewUrlValidationIssues, compact, count, createLifecycleEvent, createWorkflowDocument, defaultValue, defineArrayField, defineBlock, defineBlocksField, defineBooleanField, defineCollection, defineConfig, defineDateField, defineDateTimeField, defineEmailField, defineField, defineGlobal, defineIconField, defineImageField, defineJoinField, defineJsonField, defineMultiSelectField, defineNumberField, defineObjectField, definePublishingWorkflow, defineRadioField, defineRelationshipField, defineRichTextField, defineRowField, defineSelectField, defineTab, defineTextField, defineTextareaField, defineTimeField, defineUrlField, diffDays, dispatchLifecycleEvent, dispatchPendingLifecycleEvents, displayComputed, displayCustom, displayCustomComponent, displayDivider, displayField, displayGrid, displayRepeat, displaySection, displayTab, displayTabs, displayText, endsWith, evaluateDetailComputed, evaluateJexl, evaluateJexlSync, executeFieldAfterRead, executeFieldBeforeChange, expr, first, floor, formatConfigDiagnostics, formatDate, formatJexlValue, generateDefaultDetailSchema, generateOpenApi, get, getAdminAuthCollection, getAdminRoleForCollection, getAllowedSitesForUser, getPublicAdminAuthConfig, includes, initializeWorkflowDocument, isConfigValidationError, isDetailItemVisible, isEmpty, isFuture, isPast, isSiteAuthorized, isUserAdmin, join, last, length, lower, maskEmail, maskPhone, maskTextPII, materializeWorkflowDocument, max, min, normalizeConfig, normalizeDetailItem, now, numericFieldNames, parseSort, pow, publishedStateName, publishingWorkflow, readingTime, registerJexlHelpers, replace, resolveAdminAuthCollection, resolveAuthorizedSiteId, round, runCollectionHooks, sanitizeDocForAI, saveWorkflowDraft, simplePublishingWorkflow, slugify, sqrt, startsWith, sum, today, transitionWorkflow, trim, truncate, unique, upper, validateAdminConditionExpression, validateDeclarativeAccessExpression, validateDeclarativeHookExpression, validatePreviewUrlExpression, when, wordCount, workflowCapabilities };
1766
+ export { AIConfig, type AIErrorCode, AIPIIConfig, type AccessConditions, AccessPolicyResolver, AdminAuthConfig, ArrayField, AuthConfig, type AuthDocFields, AuthenticatedUser, BUILTIN_JEXL_HELPERS, BaseDocument, Block, BooleanField, CollectionConfig, ComputedHandler, type ConfigDiagnostic, ConfigValidationError, DateField, DateTimeField, type DeclarativeAccessSurface, type DeclarativeAccessValidationIssue, type DeclarativeAdminSurface, type DeclarativeAdminValidationIssue, DeclarativeHookExpression, type DeclarativeHookSurface, type DeclarativeHookValidationIssue, type DeclarativePreviewSurface, type DeclarativePreviewValidationIssue, DetailComputed, DetailComputedOptions, DetailCustom, DetailCustomOptions, DetailDivider, DetailDividerOptions, DetailField, DetailGrid, DetailGridOptions, DetailItem, DetailRepeat, DetailRepeatOptions, DetailSchema, DetailSection, DetailSectionOptions, DetailTab, DetailTabOptions, DetailTabs, DetailTabsOptions, DetailText, DetailTextOptions, DisplayFieldOptions, DyrectedAIError, DyrectedConfig, EmailField, type ExprFunction, type ExtractCollectionSlugs, Field, FieldConditionBuilder, FieldType, GlobalConfig, HookRequestContext, IconField, ImageField, type InferDocShape, JoinField, JsonField, LIFECYCLE_EVENTS_COLLECTION, LifecycleEvent, LifecycleEventName, MatchBuilder, MultiSelectField, NON_NEGOTIABLE_CREDENTIAL_FIELDS, NumberField, ObjectField, PII_REGEX_PATTERNS, type Prettify, PublicAdminAuthConfig, type PublishingWorkflowOptions, RadioField, RelationshipField, RichTextField, RowField, type SanitizeDocForAIOptions, SelectField, type SortClause, type SortDirection, type SqlSortDialect, type SystemDocFields, TextField, TextareaField, TimeField, type UploadDocFields, UrlField, WORKFLOW_HISTORY_COLLECTION, type WhenFunction, WorkflowConfig, WorkflowTransition, abs, addDays, asCollection, assertValidAdminConditionsInConfig, assertValidDeclarativeAccessInConfig, assertValidDeclarativeHookExpression, assertValidDeclarativeHookResult, assertValidDeclarativeHooksInConfig, assertValidPreviewUrlsInConfig, availableWorkflowTransitions, buildSqlOrderBy, canViewWorkflowDraft, capitalize, ceil, clamp, coalesce, collectAdminConditionValidationIssues, collectConfigDiagnostics, collectDeclarativeAccessValidationIssues, collectDeclarativeHookValidationIssues, collectPreviewUrlValidationIssues, compact, count, createLifecycleEvent, createWorkflowDocument, defaultValue, defineArrayField, defineBlock, defineBlocksField, defineBooleanField, defineCollection, defineConfig, defineDateField, defineDateTimeField, defineEmailField, defineField, defineGlobal, defineIconField, defineImageField, defineJoinField, defineJsonField, defineMultiSelectField, defineNumberField, defineObjectField, definePublishingWorkflow, defineRadioField, defineRelationshipField, defineRichTextField, defineRowField, defineSelectField, defineTab, defineTextField, defineTextareaField, defineTimeField, defineUrlField, diffDays, dispatchLifecycleEvent, dispatchPendingLifecycleEvents, displayComputed, displayCustom, displayCustomComponent, displayDivider, displayField, displayGrid, displayRepeat, displaySection, displayTab, displayTabs, displayText, endsWith, evaluateDetailComputed, evaluateJexl, evaluateJexlSync, executeFieldAfterRead, executeFieldBeforeChange, expr, first, floor, formatConfigDiagnostics, formatDate, formatJexlValue, generateDefaultDetailSchema, generateOpenApi, get, getAdminAuthCollection, getAdminRoleForCollection, getAllowedSitesForUser, getPublicAdminAuthConfig, includes, initializeWorkflowDocument, isConfigValidationError, isDetailItemVisible, isEmpty, isFuture, isPast, isSiteAuthorized, isUserAdmin, join, last, length, lower, maskEmail, maskPhone, maskTextPII, materializeWorkflowDocument, max, min, normalizeConfig, normalizeDetailItem, now, numericFieldNames, parseSort, pow, publishedStateName, publishingWorkflow, readingTime, registerJexlHelpers, replace, resolveAdminAuthCollection, resolveAuthorizedSiteId, round, runCollectionHooks, sanitizeDocForAI, saveWorkflowDraft, simplePublishingWorkflow, slugify, sqrt, startsWith, sum, today, transitionWorkflow, trim, truncate, unique, upper, validateAdminConditionExpression, validateDeclarativeAccessExpression, validateDeclarativeHookExpression, validatePreviewUrlExpression, when, wordCount, workflowCapabilities };
package/dist/index.js CHANGED
@@ -1775,6 +1775,11 @@ var require_Jexl = __commonJS({
1775
1775
  }
1776
1776
  });
1777
1777
 
1778
+ // src/types/readonly-fix.ts
1779
+ function asCollection(config) {
1780
+ return config;
1781
+ }
1782
+
1778
1783
  // src/types/workflows.ts
1779
1784
  var LIFECYCLE_EVENT_NAMES = [
1780
1785
  "revision.created",
@@ -1787,6 +1792,21 @@ var LIFECYCLE_EVENT_NAMES = [
1787
1792
  function defineView(config) {
1788
1793
  return config;
1789
1794
  }
1795
+ function defineTableView(config) {
1796
+ return config;
1797
+ }
1798
+ function defineKanbanView(config) {
1799
+ return config;
1800
+ }
1801
+ function defineCalendarView(config) {
1802
+ return config;
1803
+ }
1804
+ function defineGanttView(config) {
1805
+ return config;
1806
+ }
1807
+ function defineCardsView(config) {
1808
+ return config;
1809
+ }
1790
1810
  function defineAction(config) {
1791
1811
  return config;
1792
1812
  }
@@ -1911,7 +1931,7 @@ function publicMetadata(meta) {
1911
1931
  }
1912
1932
  function workflowCapabilities(workflow, user) {
1913
1933
  const capabilities = new Set(Array.isArray(user?.capabilities) ? user.capabilities : []);
1914
- const roles = Array.isArray(user?.roles) ? user.roles : [];
1934
+ const roles = Array.isArray(user?.roles) ? user.roles : typeof user?.role === "string" ? [user.role] : [];
1915
1935
  for (const mapping of workflow.roles ?? []) {
1916
1936
  if (roles.includes(mapping.role)) mapping.capabilities.forEach((capability) => capabilities.add(capability));
1917
1937
  }
@@ -2302,10 +2322,12 @@ function getAdminRoleForCollection(collection) {
2302
2322
  return "admin";
2303
2323
  }
2304
2324
  function isUserAdmin(user, collection) {
2305
- if (!user || !Array.isArray(user.roles)) return false;
2325
+ if (!user) return false;
2326
+ const roles = Array.isArray(user.roles) ? user.roles : typeof user.role === "string" ? [user.role] : [];
2327
+ if (roles.length === 0) return false;
2306
2328
  const configuredRole = getAdminRoleForCollection(collection);
2307
- if (user.roles.includes(configuredRole)) return true;
2308
- return user.roles.includes("admin") || user.roles.includes("super_admin");
2329
+ if (roles.includes(configuredRole)) return true;
2330
+ return roles.includes("admin") || roles.includes("super_admin");
2309
2331
  }
2310
2332
 
2311
2333
  // src/utils/block-references.ts
@@ -3531,21 +3553,21 @@ function normalizeConfig(config) {
3531
3553
  }
3532
3554
  ];
3533
3555
  }
3534
- if (!existingFieldNames.has("roles")) {
3556
+ if (!existingFieldNames.has("roles") && !existingFieldNames.has("role")) {
3535
3557
  fields = [
3536
3558
  ...fields,
3537
3559
  {
3538
3560
  name: "roles",
3539
3561
  type: "select",
3540
3562
  label: "Roles",
3541
- defaultValue: [],
3563
+ defaultValue: "viewer",
3542
3564
  options: [
3543
3565
  { value: "admin", label: "Admin" },
3544
3566
  { value: "editor", label: "Editor" },
3545
3567
  { value: "viewer", label: "Viewer" }
3546
3568
  ],
3547
3569
  access: {
3548
- update: "user.roles && 'admin' in user.roles"
3570
+ update: "user.role == 'admin' || (user.roles != null && 'admin' in user.roles)"
3549
3571
  }
3550
3572
  }
3551
3573
  ];
@@ -3563,10 +3585,10 @@ function normalizeConfig(config) {
3563
3585
  { value: "pending", label: "Pending" }
3564
3586
  ],
3565
3587
  access: {
3566
- update: "user.roles && 'admin' in user.roles && user.id != id"
3588
+ update: "(user.role == 'admin' || (user.roles != null && 'admin' in user.roles)) && user.id != id"
3567
3589
  },
3568
3590
  admin: {
3569
- condition: `!(data.roles && "admin" in data.roles)`
3591
+ condition: `!(data.roles && "admin" in data.roles) && data.role != "admin"`
3570
3592
  }
3571
3593
  }
3572
3594
  ];
@@ -3600,13 +3622,13 @@ function normalizeConfig(config) {
3600
3622
  }
3601
3623
  };
3602
3624
  }
3603
- if (field.name === "roles") {
3625
+ if (field.name === "roles" || field.name === "role") {
3604
3626
  return {
3605
3627
  ...field,
3606
3628
  access: {
3607
3629
  ...field.access || {},
3608
3630
  // Must be an admin; cannot edit own roles (no self-elevation).
3609
- update: "user.roles && 'admin' in user.roles && user.id != id"
3631
+ update: "(user.role == 'admin' || (user.roles != null && 'admin' in user.roles)) && user.id != id"
3610
3632
  }
3611
3633
  };
3612
3634
  }
@@ -3615,7 +3637,7 @@ function normalizeConfig(config) {
3615
3637
  ...field,
3616
3638
  access: {
3617
3639
  ...field.access || {},
3618
- update: "user.roles && 'admin' in user.roles && user.id != id"
3640
+ update: "(user.role == 'admin' || (user.roles != null && 'admin' in user.roles)) && user.id != id"
3619
3641
  }
3620
3642
  };
3621
3643
  }
@@ -6298,7 +6320,7 @@ function sanitizeDocForAI(options) {
6298
6320
  // src/index.ts
6299
6321
  import { z } from "zod";
6300
6322
  function defineCollection(config) {
6301
- return config;
6323
+ return asCollection(config);
6302
6324
  }
6303
6325
  function defineGlobal(config) {
6304
6326
  return config;
@@ -6326,17 +6348,26 @@ var defineTimeField = createFieldDefiner("time");
6326
6348
  var defineSelectField = createFieldDefiner("select");
6327
6349
  var defineMultiSelectField = createFieldDefiner("multiSelect");
6328
6350
  var defineRadioField = createFieldDefiner("radio");
6329
- var defineRelationshipField = createFieldDefiner("relationship");
6330
6351
  var defineArrayField = createFieldDefiner("array");
6331
6352
  var defineObjectField = createFieldDefiner("object");
6332
6353
  var defineJsonField = createFieldDefiner("json");
6333
6354
  var defineBlocksField = createFieldDefiner("blocks");
6334
- var defineImageField = createFieldDefiner("image");
6335
6355
  var defineEmailField = createFieldDefiner("email");
6336
6356
  var defineUrlField = createFieldDefiner("url");
6337
6357
  var defineIconField = createFieldDefiner("icon");
6338
- var defineJoinField = createFieldDefiner("join");
6339
6358
  var defineRowField = createFieldDefiner("row");
6359
+ var _defineRelationshipFieldBase = createFieldDefiner("relationship");
6360
+ var _defineImageFieldBase = createFieldDefiner("image");
6361
+ var _defineJoinFieldBase = createFieldDefiner("join");
6362
+ function defineRelationshipField(config) {
6363
+ return _defineRelationshipFieldBase(config);
6364
+ }
6365
+ function defineImageField(config) {
6366
+ return _defineImageFieldBase(config);
6367
+ }
6368
+ function defineJoinField(config) {
6369
+ return _defineJoinFieldBase(config);
6370
+ }
6340
6371
  function defineTab(args) {
6341
6372
  return args.fields.map((field) => ({
6342
6373
  ...field,
@@ -6361,6 +6392,7 @@ export {
6361
6392
  WORKFLOW_HISTORY_COLLECTION,
6362
6393
  abs,
6363
6394
  addDays,
6395
+ asCollection,
6364
6396
  assertValidAdminConditionsInConfig,
6365
6397
  assertValidDeclarativeAccessInConfig,
6366
6398
  assertValidDeclarativeHookExpression,
@@ -6389,17 +6421,21 @@ export {
6389
6421
  defineBlock,
6390
6422
  defineBlocksField,
6391
6423
  defineBooleanField,
6424
+ defineCalendarView,
6425
+ defineCardsView,
6392
6426
  defineCollection,
6393
6427
  defineConfig,
6394
6428
  defineDateField,
6395
6429
  defineDateTimeField,
6396
6430
  defineEmailField,
6397
6431
  defineField,
6432
+ defineGanttView,
6398
6433
  defineGlobal,
6399
6434
  defineIconField,
6400
6435
  defineImageField,
6401
6436
  defineJoinField,
6402
6437
  defineJsonField,
6438
+ defineKanbanView,
6403
6439
  defineMultiSelectField,
6404
6440
  defineNumberField,
6405
6441
  defineObjectField,
@@ -6410,6 +6446,7 @@ export {
6410
6446
  defineRowField,
6411
6447
  defineSelectField,
6412
6448
  defineTab,
6449
+ defineTableView,
6413
6450
  defineTextField,
6414
6451
  defineTextareaField,
6415
6452
  defineTimeField,
package/dist/server.cjs CHANGED
@@ -6190,10 +6190,12 @@ function getAdminRoleForCollection(collection) {
6190
6190
  return "admin";
6191
6191
  }
6192
6192
  function isUserAdmin(user, collection) {
6193
- if (!user || !Array.isArray(user.roles)) return false;
6193
+ if (!user) return false;
6194
+ const roles = Array.isArray(user.roles) ? user.roles : typeof user.role === "string" ? [user.role] : [];
6195
+ if (roles.length === 0) return false;
6194
6196
  const configuredRole = getAdminRoleForCollection(collection);
6195
- if (user.roles.includes(configuredRole)) return true;
6196
- return user.roles.includes("admin") || user.roles.includes("super_admin");
6197
+ if (roles.includes(configuredRole)) return true;
6198
+ return roles.includes("admin") || roles.includes("super_admin");
6197
6199
  }
6198
6200
 
6199
6201
  // src/utils/collection-search.ts
@@ -6449,7 +6451,7 @@ function publicMetadata(meta) {
6449
6451
  }
6450
6452
  function workflowCapabilities(workflow, user) {
6451
6453
  const capabilities = new Set(Array.isArray(user?.capabilities) ? user.capabilities : []);
6452
- const roles = Array.isArray(user?.roles) ? user.roles : [];
6454
+ const roles = Array.isArray(user?.roles) ? user.roles : typeof user?.role === "string" ? [user.role] : [];
6453
6455
  for (const mapping of workflow.roles ?? []) {
6454
6456
  if (roles.includes(mapping.role)) mapping.capabilities.forEach((capability) => capabilities.add(capability));
6455
6457
  }
@@ -9526,7 +9528,14 @@ var AuthController = class {
9526
9528
  lockedUntil: _lockedUntil,
9527
9529
  ...safeUser
9528
9530
  } = user;
9529
- return safeUser;
9531
+ const roles = Array.isArray(safeUser.roles) ? safeUser.roles : typeof safeUser.role === "string" ? [safeUser.role] : [];
9532
+ const role = typeof safeUser.role === "string" ? safeUser.role : roles[0];
9533
+ return {
9534
+ ...safeUser,
9535
+ collection: safeUser.collection || this.collection.slug,
9536
+ ...role !== void 0 ? { role } : {},
9537
+ roles
9538
+ };
9530
9539
  }
9531
9540
  hasField(name) {
9532
9541
  return (this.collection.fields || []).some((field) => field.name === name);
@@ -9654,13 +9663,16 @@ var AuthController = class {
9654
9663
  }
9655
9664
  }
9656
9665
  }
9666
+ const hasRoleField = this.collection.fields?.some((f) => f.name === "role");
9667
+ const hasRolesField = this.collection.fields?.some((f) => f.name === "roles");
9668
+ const rolePayload = hasRoleField && !hasRolesField ? { role: initialRole } : { roles: [initialRole] };
9657
9669
  const hashedPassword = await hashPassword(body.password);
9658
9670
  const user = await db.create({
9659
9671
  collection: this.collection.slug,
9660
9672
  data: {
9661
9673
  ...body,
9662
9674
  password: hashedPassword,
9663
- roles: [initialRole]
9675
+ ...rolePayload
9664
9676
  }
9665
9677
  });
9666
9678
  const token = await issueAuthSessionToken({
@@ -9828,7 +9840,10 @@ var AuthController = class {
9828
9840
  return c.json({ error: true, message: "User not found." }, 404);
9829
9841
  }
9830
9842
  const safeUser = this.sanitizeUser(user);
9831
- return c.json(safeUser);
9843
+ return c.json({
9844
+ ...safeUser,
9845
+ collection: this.collection.slug
9846
+ });
9832
9847
  }
9833
9848
  // ---------------------------------------------------------------------------
9834
9849
  // POST /refresh-token
@@ -12054,8 +12069,12 @@ async function resolveUser(payload, config) {
12054
12069
  return null;
12055
12070
  }
12056
12071
  const { password: _password, ...safe } = doc;
12072
+ const roles = Array.isArray(safe.roles) ? safe.roles : typeof safe.role === "string" ? [safe.role] : [];
12073
+ const role = typeof safe.role === "string" ? safe.role : roles[0];
12057
12074
  return {
12058
12075
  ...safe,
12076
+ ...role !== void 0 ? { role } : {},
12077
+ roles,
12059
12078
  sub: payload.sub,
12060
12079
  email: payload.email ?? safe.email,
12061
12080
  collection: payload.collection
@@ -12137,7 +12156,12 @@ function optionalAuth(config) {
12137
12156
  c.set("user", user);
12138
12157
  }
12139
12158
  c.set("authTokenPayload", resolved.payload);
12140
- } catch {
12159
+ } catch (err) {
12160
+ getConfigLogger(config ?? c.get("config"), "auth").warn({
12161
+ err,
12162
+ msg: "optionalAuth failed to resolve token",
12163
+ path: c.req.path
12164
+ });
12141
12165
  }
12142
12166
  }
12143
12167
  await next();
@@ -14638,21 +14662,21 @@ function normalizeConfig(config) {
14638
14662
  }
14639
14663
  ];
14640
14664
  }
14641
- if (!existingFieldNames.has("roles")) {
14665
+ if (!existingFieldNames.has("roles") && !existingFieldNames.has("role")) {
14642
14666
  fields = [
14643
14667
  ...fields,
14644
14668
  {
14645
14669
  name: "roles",
14646
14670
  type: "select",
14647
14671
  label: "Roles",
14648
- defaultValue: [],
14672
+ defaultValue: "viewer",
14649
14673
  options: [
14650
14674
  { value: "admin", label: "Admin" },
14651
14675
  { value: "editor", label: "Editor" },
14652
14676
  { value: "viewer", label: "Viewer" }
14653
14677
  ],
14654
14678
  access: {
14655
- update: "user.roles && 'admin' in user.roles"
14679
+ update: "user.role == 'admin' || (user.roles != null && 'admin' in user.roles)"
14656
14680
  }
14657
14681
  }
14658
14682
  ];
@@ -14670,10 +14694,10 @@ function normalizeConfig(config) {
14670
14694
  { value: "pending", label: "Pending" }
14671
14695
  ],
14672
14696
  access: {
14673
- update: "user.roles && 'admin' in user.roles && user.id != id"
14697
+ update: "(user.role == 'admin' || (user.roles != null && 'admin' in user.roles)) && user.id != id"
14674
14698
  },
14675
14699
  admin: {
14676
- condition: `!(data.roles && "admin" in data.roles)`
14700
+ condition: `!(data.roles && "admin" in data.roles) && data.role != "admin"`
14677
14701
  }
14678
14702
  }
14679
14703
  ];
@@ -14707,13 +14731,13 @@ function normalizeConfig(config) {
14707
14731
  }
14708
14732
  };
14709
14733
  }
14710
- if (field.name === "roles") {
14734
+ if (field.name === "roles" || field.name === "role") {
14711
14735
  return {
14712
14736
  ...field,
14713
14737
  access: {
14714
14738
  ...field.access || {},
14715
14739
  // Must be an admin; cannot edit own roles (no self-elevation).
14716
- update: "user.roles && 'admin' in user.roles && user.id != id"
14740
+ update: "(user.role == 'admin' || (user.roles != null && 'admin' in user.roles)) && user.id != id"
14717
14741
  }
14718
14742
  };
14719
14743
  }
@@ -14722,7 +14746,7 @@ function normalizeConfig(config) {
14722
14746
  ...field,
14723
14747
  access: {
14724
14748
  ...field.access || {},
14725
- update: "user.roles && 'admin' in user.roles && user.id != id"
14749
+ update: "(user.role == 'admin' || (user.roles != null && 'admin' in user.roles)) && user.id != id"
14726
14750
  }
14727
14751
  };
14728
14752
  }