@contember/bindx 0.1.5 → 0.1.8

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 (76) hide show
  1. package/dist/adapter/ContemberAdapter.d.ts +11 -14
  2. package/dist/adapter/ContemberAdapter.d.ts.map +1 -1
  3. package/dist/brand/ComponentBrand.d.ts +1 -24
  4. package/dist/brand/ComponentBrand.d.ts.map +1 -1
  5. package/dist/contember/index.d.ts +1 -2
  6. package/dist/contember/index.d.ts.map +1 -1
  7. package/dist/handles/EntityHandle.d.ts +18 -29
  8. package/dist/handles/EntityHandle.d.ts.map +1 -1
  9. package/dist/handles/FieldHandle.d.ts +5 -3
  10. package/dist/handles/FieldHandle.d.ts.map +1 -1
  11. package/dist/handles/HasManyListHandle.d.ts +4 -3
  12. package/dist/handles/HasManyListHandle.d.ts.map +1 -1
  13. package/dist/handles/HasOneHandle.d.ts +33 -36
  14. package/dist/handles/HasOneHandle.d.ts.map +1 -1
  15. package/dist/handles/PlaceholderHandle.d.ts +9 -19
  16. package/dist/handles/PlaceholderHandle.d.ts.map +1 -1
  17. package/dist/handles/proxyFactory.d.ts +9 -37
  18. package/dist/handles/proxyFactory.d.ts.map +1 -1
  19. package/dist/handles/types.d.ts +4 -0
  20. package/dist/handles/types.d.ts.map +1 -1
  21. package/dist/index.d.ts +3 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/persistence/ContemberSchemaMutationAdapter.d.ts +24 -1
  24. package/dist/persistence/ContemberSchemaMutationAdapter.d.ts.map +1 -1
  25. package/dist/schema/ContemberSchema.d.ts +1 -97
  26. package/dist/schema/ContemberSchema.d.ts.map +1 -1
  27. package/dist/schema/SchemaLoader.d.ts +1 -27
  28. package/dist/schema/SchemaLoader.d.ts.map +1 -1
  29. package/dist/schema/SchemaRegistry.d.ts +1 -94
  30. package/dist/schema/SchemaRegistry.d.ts.map +1 -1
  31. package/dist/schema/roles.d.ts +1 -61
  32. package/dist/schema/roles.d.ts.map +1 -1
  33. package/dist/schema/types.d.ts +1 -178
  34. package/dist/schema/types.d.ts.map +1 -1
  35. package/dist/selection/SelectionMetaCollector.d.ts +1 -31
  36. package/dist/selection/SelectionMetaCollector.d.ts.map +1 -1
  37. package/dist/selection/SelectionScope.d.ts +1 -76
  38. package/dist/selection/SelectionScope.d.ts.map +1 -1
  39. package/dist/selection/buildQuery.d.ts +1 -44
  40. package/dist/selection/buildQuery.d.ts.map +1 -1
  41. package/dist/selection/createFragment.d.ts +1 -28
  42. package/dist/selection/createFragment.d.ts.map +1 -1
  43. package/dist/selection/createSelectionBuilder.d.ts +1 -17
  44. package/dist/selection/createSelectionBuilder.d.ts.map +1 -1
  45. package/dist/selection/queryTypes.d.ts +1 -83
  46. package/dist/selection/queryTypes.d.ts.map +1 -1
  47. package/dist/selection/types.d.ts +1 -237
  48. package/dist/selection/types.d.ts.map +1 -1
  49. package/dist/utils/aliasGenerator.d.ts +1 -24
  50. package/dist/utils/aliasGenerator.d.ts.map +1 -1
  51. package/package.json +4 -4
  52. package/src/adapter/ContemberAdapter.ts +193 -123
  53. package/src/brand/ComponentBrand.ts +1 -28
  54. package/src/contember/index.ts +1 -8
  55. package/src/handles/EntityHandle.ts +131 -61
  56. package/src/handles/FieldHandle.ts +19 -3
  57. package/src/handles/HasManyListHandle.ts +15 -12
  58. package/src/handles/HasOneHandle.ts +98 -66
  59. package/src/handles/PlaceholderHandle.ts +26 -24
  60. package/src/handles/proxyFactory.ts +29 -128
  61. package/src/handles/types.ts +6 -0
  62. package/src/index.ts +22 -3
  63. package/src/persistence/ContemberSchemaMutationAdapter.ts +19 -1
  64. package/src/schema/ContemberSchema.ts +14 -132
  65. package/src/schema/SchemaLoader.ts +1 -93
  66. package/src/schema/SchemaRegistry.ts +1 -286
  67. package/src/schema/roles.ts +10 -83
  68. package/src/schema/types.ts +21 -238
  69. package/src/selection/SelectionMetaCollector.ts +1 -122
  70. package/src/selection/SelectionScope.ts +1 -208
  71. package/src/selection/buildQuery.ts +1 -134
  72. package/src/selection/createFragment.ts +1 -50
  73. package/src/selection/createSelectionBuilder.ts +1 -283
  74. package/src/selection/queryTypes.ts +8 -135
  75. package/src/selection/types.ts +13 -320
  76. package/src/utils/aliasGenerator.ts +1 -56
@@ -1,132 +1,14 @@
1
- /**
2
- * Types matching the Contember API schema introspection format.
3
- * These types are compatible with binding-common's Schema.
4
- */
5
-
6
- export type SchemaColumnType = 'Bool' | 'Date' | 'DateTime' | 'Double' | 'Enum' | 'Integer' | 'String' | 'Uuid' | 'Json' | string
7
-
8
- export interface SchemaColumn {
9
- __typename: '_Column'
10
- name: string
11
- nullable: boolean
12
- type: SchemaColumnType
13
- enumName: string | null
14
- defaultValue: string | number | boolean | null
15
- }
16
-
17
- export interface SchemaRelationOrderBy {
18
- path: string[]
19
- direction: 'asc' | 'desc'
20
- }
21
-
22
- interface BaseRelation {
23
- __typename: '_Relation'
24
- name: string
25
- nullable: boolean | null
26
- onDelete: 'restrict' | 'cascade' | 'setNull' | null
27
- orderBy: SchemaRelationOrderBy[] | null
28
- orphanRemoval: boolean | null
29
- targetEntity: string
30
- type: 'OneHasOne' | 'OneHasMany' | 'ManyHasOne' | 'ManyHasMany'
31
- }
32
-
33
- export interface OwningRelation extends BaseRelation {
34
- side: 'owning'
35
- inversedBy: string | null
36
- ownedBy?: never
37
- }
38
-
39
- export interface InverseRelation extends BaseRelation {
40
- side: 'inverse'
41
- ownedBy: string
42
- inversedBy?: never
43
- }
44
-
45
- export type SchemaRelation = OwningRelation | InverseRelation
46
-
47
- export type SchemaField = SchemaColumn | SchemaRelation
48
-
49
- export interface SchemaEntity {
50
- name: string
51
- customPrimaryAllowed: boolean
52
- fields: Map<string, SchemaField>
53
- unique: { fields: Set<string> }[]
54
- }
55
-
56
- export interface SchemaEnum {
57
- name: string
58
- values: string[]
59
- }
60
-
61
- /**
62
- * Processed schema store with Maps for efficient lookup.
63
- * This is the format used internally after loading from API.
64
- */
65
- export interface ContemberSchemaStore {
66
- entities: Map<string, SchemaEntity>
67
- enums: Map<string, Set<string>>
68
- }
69
-
70
- /**
71
- * Raw schema format as returned by the Contember API.
72
- */
73
- export interface RawContemberSchema {
74
- enums: { name: string; values: string[] }[]
75
- entities: {
76
- name: string
77
- customPrimaryAllowed: boolean
78
- fields: (SchemaColumn | (Omit<SchemaRelation, 'side'> & { side: 'owning' | 'inverse'; ownedBy?: string; inversedBy?: string | null }))[]
79
- unique: { fields: string[] }[]
80
- }[]
81
- }
82
-
83
- /**
84
- * Schema class compatible with binding-common's Schema.
85
- * Can be used directly or created from API response.
86
- */
87
- export class ContemberSchema {
88
- constructor(private readonly store: ContemberSchemaStore) {}
89
-
90
- getEntity(entityName: string): SchemaEntity | undefined {
91
- return this.store.entities.get(entityName)
92
- }
93
-
94
- getEntityNames(): string[] {
95
- return Array.from(this.store.entities.keys())
96
- }
97
-
98
- getEntityField(entityName: string, fieldName: string): SchemaField | undefined {
99
- return this.store.entities.get(entityName)?.fields.get(fieldName)
100
- }
101
-
102
- getEnumValues(enumName: string): string[] | undefined {
103
- const values = this.store.enums.get(enumName)
104
- return values ? Array.from(values) : undefined
105
- }
106
-
107
- /**
108
- * Creates a ContemberSchema from raw API response.
109
- */
110
- static fromRaw(raw: RawContemberSchema): ContemberSchema {
111
- const enums = new Map<string, Set<string>>()
112
- for (const { name, values } of raw.enums) {
113
- enums.set(name, new Set(values))
114
- }
115
-
116
- const entities = new Map<string, SchemaEntity>()
117
- for (const entity of raw.entities) {
118
- const fields = new Map<string, SchemaField>()
119
- for (const field of entity.fields) {
120
- fields.set(field.name, field as SchemaField)
121
- }
122
- entities.set(entity.name, {
123
- name: entity.name,
124
- customPrimaryAllowed: entity.customPrimaryAllowed,
125
- fields,
126
- unique: entity.unique.map(u => ({ fields: new Set(u.fields) })),
127
- })
128
- }
129
-
130
- return new ContemberSchema({ entities, enums })
131
- }
132
- }
1
+ export {
2
+ ContemberSchema,
3
+ type SchemaColumnType,
4
+ type SchemaColumn,
5
+ type SchemaRelationOrderBy,
6
+ type OwningRelation,
7
+ type InverseRelation,
8
+ type SchemaRelation,
9
+ type SchemaField,
10
+ type SchemaEntity,
11
+ type SchemaEnum,
12
+ type ContemberSchemaStore,
13
+ type RawContemberSchema,
14
+ } from '@contember/bindx-client'
@@ -1,93 +1 @@
1
- /**
2
- * Loads schema from Contember Content API via GraphQL introspection.
3
- */
4
-
5
- import { ContemberSchema, type RawContemberSchema } from './ContemberSchema.js'
6
-
7
- export interface SchemaLoaderClient {
8
- execute<T>(query: string, options?: unknown): Promise<T>
9
- apiUrl?: string
10
- }
11
-
12
- const SCHEMA_QUERY = `query {
13
- schema {
14
- enums {
15
- name
16
- values
17
- }
18
- entities {
19
- name
20
- customPrimaryAllowed
21
- unique {
22
- fields
23
- }
24
- fields {
25
- __typename
26
- name
27
- type
28
- nullable
29
- ... on _Column {
30
- enumName
31
- defaultValue
32
- }
33
- ... on _Relation {
34
- side
35
- targetEntity
36
- ownedBy
37
- inversedBy
38
- onDelete
39
- orphanRemoval
40
- orderBy {
41
- path
42
- direction
43
- }
44
- }
45
- }
46
- }
47
- }
48
- }`
49
-
50
- /**
51
- * Loads and caches schema from Contember Content API.
52
- * Instance-level cache avoids cross-tenant collisions and test pollution.
53
- */
54
- export class SchemaLoader {
55
- private readonly cache = new Map<string, Promise<ContemberSchema>>()
56
-
57
- /**
58
- * Loads schema from the API, with caching per API URL.
59
- */
60
- async loadSchema(
61
- client: SchemaLoaderClient,
62
- options?: unknown,
63
- ): Promise<ContemberSchema> {
64
- const cacheKey = client.apiUrl ?? 'default'
65
-
66
- const existing = this.cache.get(cacheKey)
67
- if (existing) {
68
- return existing
69
- }
70
-
71
- const promise = (async () => {
72
- const response = await client.execute<{ schema: RawContemberSchema }>(SCHEMA_QUERY, options)
73
- return ContemberSchema.fromRaw(response.schema)
74
- })()
75
-
76
- this.cache.set(cacheKey, promise)
77
- return promise
78
- }
79
-
80
- /**
81
- * Clears the schema cache.
82
- */
83
- clearCache(): void {
84
- this.cache.clear()
85
- }
86
-
87
- /**
88
- * Clears cache for a specific API URL.
89
- */
90
- clearCacheFor(apiUrl: string): void {
91
- this.cache.delete(apiUrl)
92
- }
93
- }
1
+ export { SchemaLoader, type SchemaLoaderClient } from '@contember/bindx-client'
@@ -1,286 +1 @@
1
- import type { ContemberSchema } from './ContemberSchema.js'
2
- import type {
3
- EntitySchemaDef,
4
- FieldDef,
5
- HasManyRelationDef,
6
- HasOneRelationDef,
7
- RelationType,
8
- SchemaDefinition,
9
- } from './types.js'
10
-
11
- /**
12
- * Runtime registry for entity schemas.
13
- * Provides lookups for entity definitions, relation targets, and field types.
14
- */
15
- export class SchemaRegistry<TModels extends Record<string, object> = Record<string, object>> {
16
- private readonly entityDefs: Map<string, EntitySchemaDef>
17
-
18
- constructor(definition: SchemaDefinition<TModels>) {
19
- this.entityDefs = new Map()
20
-
21
- for (const [entityName, entityDef] of Object.entries(definition.entities)) {
22
- this.entityDefs.set(entityName, normalizeEntityDef(entityDef as EntitySchemaDef))
23
- }
24
- }
25
-
26
- /**
27
- * Creates a SchemaRegistry from a ContemberSchema (loaded from API or injected).
28
- * This is the preferred way to create a SchemaRegistry at runtime.
29
- */
30
- static fromContemberSchema(schema: ContemberSchema): SchemaRegistry {
31
- const entities: Record<string, EntitySchemaDef> = {}
32
-
33
- for (const entityName of schema.getEntityNames()) {
34
- const entity = schema.getEntity(entityName)
35
- if (!entity) continue
36
-
37
- const fields: Record<string, FieldDef> = {}
38
-
39
- for (const [fieldName, field] of entity.fields) {
40
- if (field.__typename === '_Column') {
41
- fields[fieldName] = { type: 'scalar' }
42
- } else if (field.__typename === '_Relation') {
43
- const isMany = field.type === 'OneHasMany' || field.type === 'ManyHasMany'
44
- if (isMany) {
45
- fields[fieldName] = {
46
- type: 'hasMany',
47
- target: field.targetEntity,
48
- inverse: field.side === 'owning' ? field.inversedBy ?? undefined : field.ownedBy,
49
- }
50
- } else {
51
- fields[fieldName] = {
52
- type: 'hasOne',
53
- target: field.targetEntity,
54
- inverse: field.side === 'owning' ? field.inversedBy ?? undefined : field.ownedBy,
55
- }
56
- }
57
- }
58
- }
59
-
60
- entities[entityName] = { fields }
61
- }
62
-
63
- return new SchemaRegistry({ entities } as SchemaDefinition<Record<string, object>>)
64
- }
65
-
66
- /**
67
- * Gets the entity names defined in the schema
68
- */
69
- getEntityNames(): string[] {
70
- return Array.from(this.entityDefs.keys())
71
- }
72
-
73
- /**
74
- * Checks if an entity type exists in the schema
75
- */
76
- hasEntity(entityType: string): boolean {
77
- return this.entityDefs.has(entityType)
78
- }
79
-
80
- /**
81
- * Gets the schema definition for an entity type
82
- */
83
- getEntityDef(entityType: string): EntitySchemaDef | undefined {
84
- return this.entityDefs.get(entityType)
85
- }
86
-
87
- /**
88
- * Gets the field definition for a specific field on an entity
89
- */
90
- getFieldDef(entityType: string, fieldName: string): FieldDef | undefined {
91
- const entityDef = this.entityDefs.get(entityType)
92
- if (!entityDef) return undefined
93
- return entityDef.fields[fieldName]
94
- }
95
-
96
- /**
97
- * Gets the enum values for an enum field.
98
- * Returns undefined if the field is not an enum or doesn't exist.
99
- */
100
- getEnumValues(entityType: string, fieldName: string): readonly string[] | undefined {
101
- const fieldDef = this.getFieldDef(entityType, fieldName)
102
- if (!fieldDef || fieldDef.type !== 'enum') return undefined
103
- return fieldDef.values
104
- }
105
-
106
- /**
107
- * Gets the enum name for an enum field.
108
- * Returns undefined if the field is not an enum or doesn't exist.
109
- */
110
- getEnumName(entityType: string, fieldName: string): string | undefined {
111
- const fieldDef = this.getFieldDef(entityType, fieldName)
112
- if (!fieldDef || fieldDef.type !== 'enum') return undefined
113
- return fieldDef.enumName
114
- }
115
-
116
- /**
117
- * Gets the column type for a scalar field (e.g. 'String', 'Integer', 'Date').
118
- * Returns undefined if the field is not a scalar or doesn't exist.
119
- */
120
- getColumnType(entityType: string, fieldName: string): string | undefined {
121
- const fieldDef = this.getFieldDef(entityType, fieldName)
122
- if (!fieldDef || fieldDef.type !== 'scalar') return undefined
123
- return fieldDef.columnType
124
- }
125
-
126
- /**
127
- * Gets the target entity type for a relation field.
128
- * Returns undefined if the field is not a relation or doesn't exist.
129
- */
130
- getRelationTarget(entityType: string, fieldName: string): string | undefined {
131
- const fieldDef = this.getFieldDef(entityType, fieldName)
132
- if (!fieldDef) return undefined
133
-
134
- if (fieldDef.type === 'hasOne' || fieldDef.type === 'hasMany') {
135
- return fieldDef.target
136
- }
137
-
138
- return undefined
139
- }
140
-
141
- /**
142
- * Gets the relation type for a field (hasOne or hasMany).
143
- * Returns undefined if the field is not a relation.
144
- */
145
- getRelationType(entityType: string, fieldName: string): RelationType | undefined {
146
- const fieldDef = this.getFieldDef(entityType, fieldName)
147
- if (!fieldDef) return undefined
148
-
149
- if (fieldDef.type === 'hasOne' || fieldDef.type === 'hasMany') {
150
- return fieldDef.type
151
- }
152
-
153
- return undefined
154
- }
155
-
156
- /**
157
- * Checks if a field is a relation (hasOne or hasMany)
158
- */
159
- isRelation(entityType: string, fieldName: string): boolean {
160
- return this.getRelationType(entityType, fieldName) !== undefined
161
- }
162
-
163
- /**
164
- * Checks if a field is a has-one relation
165
- */
166
- isHasOne(entityType: string, fieldName: string): boolean {
167
- return this.getRelationType(entityType, fieldName) === 'hasOne'
168
- }
169
-
170
- /**
171
- * Checks if a field is a has-many relation
172
- */
173
- isHasMany(entityType: string, fieldName: string): boolean {
174
- return this.getRelationType(entityType, fieldName) === 'hasMany'
175
- }
176
-
177
- /**
178
- * Checks if a field is a scalar (non-relation) field
179
- */
180
- isScalar(entityType: string, fieldName: string): boolean {
181
- const fieldDef = this.getFieldDef(entityType, fieldName)
182
- return fieldDef?.type === 'scalar'
183
- }
184
-
185
- /**
186
- * Gets the inverse field name for a relation.
187
- * Returns undefined if no inverse is defined.
188
- */
189
- getInverseField(entityType: string, fieldName: string): string | undefined {
190
- const fieldDef = this.getFieldDef(entityType, fieldName)
191
- if (!fieldDef) return undefined
192
- if (fieldDef.type === 'scalar') return undefined
193
-
194
- return (fieldDef as HasOneRelationDef | HasManyRelationDef).inverse
195
- }
196
-
197
- /**
198
- * Gets all scalar field names for an entity
199
- */
200
- getScalarFields(entityType: string): string[] {
201
- const entityDef = this.entityDefs.get(entityType)
202
- if (!entityDef) return []
203
-
204
- return Object.entries(entityDef.fields)
205
- .filter(([_, def]) => def.type === 'scalar')
206
- .map(([name]) => name)
207
- }
208
-
209
- /**
210
- * Gets all relation field names for an entity
211
- */
212
- getRelationFields(entityType: string): string[] {
213
- const entityDef = this.entityDefs.get(entityType)
214
- if (!entityDef) return []
215
-
216
- return Object.entries(entityDef.fields)
217
- .filter(([_, def]) => def.type === 'hasOne' || def.type === 'hasMany')
218
- .map(([name]) => name)
219
- }
220
-
221
- /**
222
- * Gets all field names for an entity
223
- */
224
- getAllFields(entityType: string): string[] {
225
- const entityDef = this.entityDefs.get(entityType)
226
- if (!entityDef) return []
227
-
228
- return Object.keys(entityDef.fields)
229
- }
230
-
231
- /**
232
- * Validates that all relation targets exist in the schema.
233
- * Throws an error if any target is missing.
234
- */
235
- validate(): void {
236
- for (const [entityName, entityDef] of this.entityDefs) {
237
- for (const [fieldName, fieldDef] of Object.entries(entityDef.fields)) {
238
- if (fieldDef.type === 'hasOne' || fieldDef.type === 'hasMany') {
239
- if (!this.entityDefs.has(fieldDef.target)) {
240
- throw new Error(
241
- `Invalid schema: Entity "${entityName}" field "${fieldName}" references ` +
242
- `unknown entity "${fieldDef.target}"`,
243
- )
244
- }
245
- }
246
- }
247
- }
248
- }
249
- }
250
-
251
- /**
252
- * Normalizes field definitions from Contember SchemaNames format
253
- * (column/one/many with entity) to bindx FieldDef format (scalar/hasOne/hasMany with target).
254
- */
255
- function normalizeEntityDef(entityDef: EntitySchemaDef): EntitySchemaDef {
256
- const fields: Record<string, FieldDef> = {}
257
- let needsNormalization = false
258
-
259
- for (const [fieldName, fieldDef] of Object.entries(entityDef.fields)) {
260
- const raw = fieldDef as unknown as Record<string, unknown>
261
- const type = raw['type'] as string
262
-
263
- if (type === 'column') {
264
- fields[fieldName] = { type: 'scalar' }
265
- needsNormalization = true
266
- } else if (type === 'one') {
267
- fields[fieldName] = {
268
- type: 'hasOne',
269
- target: (raw['entity'] as string) ?? (raw['target'] as string),
270
- inverse: raw['inverse'] as string | undefined,
271
- }
272
- needsNormalization = true
273
- } else if (type === 'many') {
274
- fields[fieldName] = {
275
- type: 'hasMany',
276
- target: (raw['entity'] as string) ?? (raw['target'] as string),
277
- inverse: raw['inverse'] as string | undefined,
278
- }
279
- needsNormalization = true
280
- } else {
281
- fields[fieldName] = fieldDef
282
- }
283
- }
284
-
285
- return needsNormalization ? { fields } : entityDef
286
- }
1
+ export { SchemaRegistry } from '@contember/bindx-client'
@@ -1,83 +1,10 @@
1
- /**
2
- * Role-aware type utilities for bindx.
3
- *
4
- * The role system allows per-role field access control at the type level.
5
- * Default (no role) = narrowest scope (fields ALL roles can access).
6
- * Specifying roles = expanding scope (union of capabilities for those roles).
7
- */
8
-
9
- // ============================================================================
10
- // Core Utility Types
11
- // ============================================================================
12
-
13
- /**
14
- * Converts a union type to an intersection type.
15
- * Used to merge field sets from multiple roles.
16
- *
17
- * @example
18
- * UnionToIntersection<{ a: 1 } | { b: 2 }> = { a: 1 } & { b: 2 }
19
- */
20
- export type UnionToIntersection<U> =
21
- (U extends unknown ? (x: U) => void : never) extends (x: infer I) => void ? I : never
22
-
23
- // ============================================================================
24
- // Role Map Types
25
- // ============================================================================
26
-
27
- /**
28
- * Extracts all role names from a role map.
29
- */
30
- export type RoleNames<TRoleMap extends Record<string, object>> = keyof TRoleMap & string
31
-
32
- /**
33
- * Default entity type — the narrowest scope.
34
- * Returns a union of all role entity types, so only common fields are accessible via keyof.
35
- *
36
- * @example
37
- * CommonEntity<{ admin: { id: string; secret: string }; public: { id: string } }>
38
- * // = { id: string; secret: string } | { id: string }
39
- * // Only `id` is accessible (common to all roles)
40
- */
41
- export type CommonEntity<TRoleMap extends Record<string, object>> = TRoleMap[keyof TRoleMap]
42
-
43
- /**
44
- * Entity type for specific roles — expanded scope.
45
- * Returns an intersection of the specified roles' entity types,
46
- * giving access to all fields from any of those roles.
47
- *
48
- * @example
49
- * EntityForRoles<{ admin: { id: string; secret: string }; editor: { id: string; notes: string } }, 'admin'>
50
- * // = { id: string; secret: string }
51
- *
52
- * EntityForRoles<{ admin: { id: string; secret: string }; editor: { id: string; notes: string } }, 'admin' | 'editor'>
53
- * // = { id: string; secret: string } & { id: string; notes: string }
54
- * // = { id: string; secret: string; notes: string }
55
- */
56
- export type EntityForRoles<
57
- TRoleMap extends Record<string, object>,
58
- TRoles extends keyof TRoleMap,
59
- > = UnionToIntersection<TRoleMap[TRoles]> & object
60
-
61
- /**
62
- * Resolves the entity type based on whether roles are specified.
63
- * - No roles (TRoles = never): returns CommonEntity (narrowest)
64
- * - With roles: returns EntityForRoles (expanded)
65
- */
66
- export type ResolveEntity<
67
- TRoleMap extends Record<string, object>,
68
- TRoles extends string,
69
- > = [TRoles] extends [never]
70
- ? CommonEntity<TRoleMap>
71
- : EntityForRoles<TRoleMap, TRoles & keyof TRoleMap>
72
-
73
- /**
74
- * Sentinel role name used when no ACL roles are defined.
75
- * entityDef<Article>('Article') wraps as { _default: Article }.
76
- */
77
- export const DEFAULT_ROLE = '_default' as const
78
- export type DefaultRole = typeof DEFAULT_ROLE
79
-
80
- /**
81
- * Wraps a single entity type as a single-role map with the _default role.
82
- */
83
- export type SingleRoleMap<TEntity extends object> = { readonly [K in DefaultRole]: TEntity }
1
+ export {
2
+ type UnionToIntersection,
3
+ type RoleNames,
4
+ type CommonEntity,
5
+ type EntityForRoles,
6
+ type ResolveEntity,
7
+ type SingleRoleMap,
8
+ type DefaultRole,
9
+ DEFAULT_ROLE,
10
+ } from '@contember/bindx-client'