@api-client/core 0.18.17 → 0.18.19

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 (75) hide show
  1. package/build/src/{modeling → decorators}/observed.d.ts +3 -3
  2. package/build/src/decorators/observed.d.ts.map +1 -0
  3. package/build/src/{modeling → decorators}/observed.js +4 -4
  4. package/build/src/decorators/observed.js.map +1 -0
  5. package/build/src/modeling/ApiModel.js +1 -1
  6. package/build/src/modeling/ApiModel.js.map +1 -1
  7. package/build/src/modeling/DataDomain.d.ts +35 -1
  8. package/build/src/modeling/DataDomain.d.ts.map +1 -1
  9. package/build/src/modeling/DataDomain.js +120 -0
  10. package/build/src/modeling/DataDomain.js.map +1 -1
  11. package/build/src/modeling/DomainAssociation.d.ts +7 -0
  12. package/build/src/modeling/DomainAssociation.d.ts.map +1 -1
  13. package/build/src/modeling/DomainAssociation.js +44 -1
  14. package/build/src/modeling/DomainAssociation.js.map +1 -1
  15. package/build/src/modeling/DomainEntity.d.ts +6 -0
  16. package/build/src/modeling/DomainEntity.d.ts.map +1 -1
  17. package/build/src/modeling/DomainEntity.js +21 -1
  18. package/build/src/modeling/DomainEntity.js.map +1 -1
  19. package/build/src/modeling/DomainModel.js +1 -1
  20. package/build/src/modeling/DomainModel.js.map +1 -1
  21. package/build/src/modeling/DomainNamespace.js +1 -1
  22. package/build/src/modeling/DomainNamespace.js.map +1 -1
  23. package/build/src/modeling/DomainProperty.d.ts +15 -0
  24. package/build/src/modeling/DomainProperty.d.ts.map +1 -1
  25. package/build/src/modeling/DomainProperty.js +64 -3
  26. package/build/src/modeling/DomainProperty.js.map +1 -1
  27. package/build/src/modeling/DomainSerialization.d.ts.map +1 -1
  28. package/build/src/modeling/DomainSerialization.js +2 -2
  29. package/build/src/modeling/DomainSerialization.js.map +1 -1
  30. package/build/src/modeling/definitions/SKU.d.ts.map +1 -1
  31. package/build/src/modeling/definitions/SKU.js +2 -0
  32. package/build/src/modeling/definitions/SKU.js.map +1 -1
  33. package/build/src/modeling/helpers/Intelisense.d.ts +472 -0
  34. package/build/src/modeling/helpers/Intelisense.d.ts.map +1 -0
  35. package/build/src/modeling/helpers/Intelisense.js +1200 -0
  36. package/build/src/modeling/helpers/Intelisense.js.map +1 -0
  37. package/build/src/modeling/templates/blog-domain.d.ts +40 -0
  38. package/build/src/modeling/templates/blog-domain.d.ts.map +1 -0
  39. package/build/src/modeling/templates/blog-domain.js +621 -0
  40. package/build/src/modeling/templates/blog-domain.js.map +1 -0
  41. package/build/src/modeling/templates/ecommerce-domain.d.ts +39 -0
  42. package/build/src/modeling/templates/ecommerce-domain.d.ts.map +1 -0
  43. package/build/src/modeling/templates/ecommerce-domain.js +663 -0
  44. package/build/src/modeling/templates/ecommerce-domain.js.map +1 -0
  45. package/build/src/modeling/types.d.ts +49 -0
  46. package/build/src/modeling/types.d.ts.map +1 -1
  47. package/build/src/modeling/types.js.map +1 -1
  48. package/build/src/models/Thing.js +1 -1
  49. package/build/src/models/Thing.js.map +1 -1
  50. package/build/tsconfig.tsbuildinfo +1 -1
  51. package/data/models/example-generator-api.json +6 -6
  52. package/package.json +2 -1
  53. package/src/{modeling → decorators}/observed.ts +5 -5
  54. package/src/modeling/ApiModel.ts +1 -1
  55. package/src/modeling/DataDomain.ts +144 -0
  56. package/src/modeling/DomainAssociation.ts +51 -1
  57. package/src/modeling/DomainEntity.ts +24 -1
  58. package/src/modeling/DomainModel.ts +1 -1
  59. package/src/modeling/DomainNamespace.ts +1 -1
  60. package/src/modeling/DomainProperty.ts +66 -1
  61. package/src/modeling/DomainSerialization.ts +2 -4
  62. package/src/modeling/definitions/SKU.ts +2 -0
  63. package/src/modeling/helpers/Intelisense.ts +1345 -0
  64. package/src/modeling/templates/blog-domain.ts +787 -0
  65. package/src/modeling/templates/ecommerce-domain.ts +834 -0
  66. package/src/modeling/types.ts +63 -0
  67. package/src/models/Thing.ts +1 -1
  68. package/tests/unit/decorators/observed.spec.ts +527 -0
  69. package/tests/unit/modeling/DataDomain.search.spec.ts +188 -0
  70. package/tests/unit/modeling/data_domain_serialization.spec.ts +6 -2
  71. package/tests/unit/modeling/domain_asociation.spec.ts +376 -0
  72. package/tests/unit/modeling/domain_entity.spec.ts +147 -0
  73. package/tests/unit/modeling/domain_property.spec.ts +273 -0
  74. package/build/src/modeling/observed.d.ts.map +0 -1
  75. package/build/src/modeling/observed.js.map +0 -1
@@ -0,0 +1,621 @@
1
+ /**
2
+ * Blog/Publishing Data Domain Example
3
+ *
4
+ * This file demonstrates how to create a comprehensive blog/publishing data domain
5
+ * using the API Client Core modeling system. It follows the business-first approach
6
+ * and demonstrates proper use of namespaces, models, entities, properties,
7
+ * associations, and semantic annotations.
8
+ *
9
+ * The example includes:
10
+ * - Content Management with posts, pages, and media
11
+ * - User Management with authors, editors, and subscribers
12
+ * - Publishing Workflow with drafts, reviews, and publication
13
+ * - Social Features with comments, likes, and sharing
14
+ * - Analytics and SEO with metadata and tracking
15
+ * - Multi-tenant support for multiple blogs/publications
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * import { createBlogDomain } from './blog-domain.js'
20
+ *
21
+ * const domain = createBlogDomain()
22
+ * console.log('Blog domain created with', domain.graph.nodeCount(), 'nodes')
23
+ * ```
24
+ */
25
+ import { DataDomain } from '../DataDomain.js';
26
+ import { SemanticType } from '../Semantics.js';
27
+ import { createCalculatedSemantic } from '../definitions/Calculated.js';
28
+ import { createURLSemantic } from '../definitions/URL.js';
29
+ import { addIdField, addNameField, addDescriptionField, addPublicUniqueNameField, addCustomStatusField, addCreatedAtField, addUpdatedAtField, addEmailField, addPasswordField, addFirstNameField, addLastNameField, addAvatarUrlField, addBooleanField, addQuantityField, } from '../helpers/Intelisense.js';
30
+ /**
31
+ * Creates a comprehensive blog/publishing data domain following domain-driven design principles.
32
+ *
33
+ * This function demonstrates the proper hierarchy and organization for a publishing platform:
34
+ * 1. Creates the root DataDomain for the publishing platform
35
+ * 2. Organizes functionality into logical namespaces (Content, Users, Publishing, etc.)
36
+ * 3. Groups related entities into models within each namespace
37
+ * 4. Defines entities with proper semantic annotations for publishing workflows
38
+ * 5. Establishes associations with appropriate cardinality for content relationships
39
+ *
40
+ * @returns A fully configured DataDomain with all blog/publishing entities and relationships
41
+ */
42
+ export function createBlogDomain() {
43
+ // Create the root data domain
44
+ const domain = new DataDomain({
45
+ info: {
46
+ name: 'Blog Publishing Platform',
47
+ displayName: 'Blog Publishing Platform',
48
+ description: 'A comprehensive content management and publishing platform for blogs, magazines, and digital publications',
49
+ version: '1.0.0',
50
+ },
51
+ });
52
+ //
53
+ // 1. CONTENT MANAGEMENT NAMESPACE
54
+ //
55
+ const contentManagement = domain.addNamespace({
56
+ info: {
57
+ name: 'ContentManagement',
58
+ displayName: 'Content Management',
59
+ description: 'Core content creation, editing, and organization features',
60
+ },
61
+ });
62
+ // Publication Model - Multi-tenant support
63
+ const publicationModel = contentManagement.addModel({
64
+ info: {
65
+ name: 'Publications',
66
+ displayName: 'Publications Management',
67
+ description: 'Individual blogs, magazines, or publications within the platform',
68
+ },
69
+ });
70
+ // Publication Entity - Represents individual blogs/publications
71
+ const publicationEntity = publicationModel.addEntity({
72
+ info: {
73
+ name: 'publication',
74
+ displayName: 'Publication',
75
+ description: 'Individual blog or publication site',
76
+ },
77
+ });
78
+ addIdField(publicationEntity, { displayName: 'Publication ID', description: 'Unique identifier for the publication' });
79
+ addNameField(publicationEntity, { displayName: 'Publication Name', description: 'Display name of the publication' });
80
+ addPublicUniqueNameField(publicationEntity, {
81
+ name: 'slug',
82
+ displayName: 'URL Slug',
83
+ description: 'URL-friendly identifier for the publication',
84
+ });
85
+ addDescriptionField(publicationEntity, { description: 'Publication description and tagline' });
86
+ publicationEntity.addProperty({
87
+ info: { name: 'domain', displayName: 'Custom Domain', description: 'Custom domain name for the publication' },
88
+ type: 'string',
89
+ // semantics: [{ id: SemanticType.DomainName }],
90
+ });
91
+ publicationEntity.addProperty({
92
+ info: { name: 'logo_url', displayName: 'Logo URL', description: 'URL to publication logo image' },
93
+ type: 'string',
94
+ semantics: [{ id: SemanticType.ImageURL }],
95
+ });
96
+ addCustomStatusField(publicationEntity, ['active', 'suspended', 'archived'], {
97
+ displayName: 'Publication Status',
98
+ description: 'Current status of the publication',
99
+ });
100
+ addCreatedAtField(publicationEntity, { description: 'When the publication was created' });
101
+ // Content Model
102
+ const contentModel = contentManagement.addModel({
103
+ info: {
104
+ name: 'Content',
105
+ displayName: 'Content Management',
106
+ description: 'Posts, pages, and other content types',
107
+ },
108
+ });
109
+ // Category Entity
110
+ const categoryEntity = contentModel.addEntity({
111
+ info: {
112
+ name: 'category',
113
+ displayName: 'Content Category',
114
+ description: 'Content categorization for organization and navigation',
115
+ },
116
+ });
117
+ addIdField(categoryEntity, { displayName: 'Category ID', description: 'Unique identifier for the category' });
118
+ addNameField(categoryEntity, { displayName: 'Category Name', description: 'Display name of the category' });
119
+ addPublicUniqueNameField(categoryEntity, {
120
+ name: 'slug',
121
+ displayName: 'URL Slug',
122
+ description: 'URL-friendly identifier for the category',
123
+ });
124
+ addDescriptionField(categoryEntity, { description: 'Category description' });
125
+ categoryEntity.addProperty({
126
+ info: { name: 'color', displayName: 'Color', description: 'Theme color for the category' },
127
+ type: 'string',
128
+ // semantics: [{ id: SemanticType.Color }],
129
+ });
130
+ // Category-Publication Association (Many-to-One)
131
+ categoryEntity.addAssociation({ key: publicationEntity.key }, {
132
+ info: { name: 'publication', displayName: 'Publication', description: 'Publication this category belongs to' },
133
+ required: true,
134
+ multiple: false,
135
+ });
136
+ // Self-referencing association for category hierarchy
137
+ categoryEntity.addAssociation({ key: categoryEntity.key }, {
138
+ info: {
139
+ name: 'parentCategory',
140
+ displayName: 'Parent Category',
141
+ description: 'Parent category for hierarchical organization',
142
+ },
143
+ required: false,
144
+ multiple: false,
145
+ });
146
+ // Tag Entity
147
+ const tagEntity = contentModel.addEntity({
148
+ info: {
149
+ name: 'Tag',
150
+ displayName: 'Content Tag',
151
+ description: 'Tags for flexible content labeling and discovery',
152
+ },
153
+ });
154
+ addIdField(tagEntity, { displayName: 'Tag ID', description: 'Unique identifier for the tag' });
155
+ addNameField(tagEntity, { displayName: 'Tag Name', description: 'Display name of the tag' });
156
+ addPublicUniqueNameField(tagEntity, {
157
+ name: 'slug',
158
+ displayName: 'URL Slug',
159
+ description: 'URL-friendly identifier for the tag',
160
+ });
161
+ // Tag-Publication Association (Many-to-One)
162
+ tagEntity.addAssociation({ key: publicationEntity.key }, {
163
+ info: { name: 'publication', displayName: 'Publication', description: 'Publication this tag belongs to' },
164
+ required: true,
165
+ multiple: false,
166
+ });
167
+ // Post Entity - Main content type
168
+ const postEntity = contentModel.addEntity({
169
+ info: {
170
+ name: 'Post',
171
+ displayName: 'Blog Post',
172
+ description: 'Individual blog posts and articles',
173
+ },
174
+ });
175
+ addIdField(postEntity, { displayName: 'Post ID', description: 'Unique identifier for the post' });
176
+ postEntity.addProperty({
177
+ info: { name: 'title', displayName: 'Post Title', description: 'Title of the blog post' },
178
+ type: 'string',
179
+ required: true,
180
+ semantics: [{ id: SemanticType.Title }],
181
+ });
182
+ addPublicUniqueNameField(postEntity, {
183
+ name: 'slug',
184
+ displayName: 'URL Slug',
185
+ description: 'URL-friendly identifier for the post',
186
+ });
187
+ postEntity.addProperty({
188
+ info: { name: 'excerpt', displayName: 'Excerpt', description: 'Brief summary or excerpt of the post' },
189
+ type: 'string',
190
+ semantics: [{ id: SemanticType.Summary }],
191
+ });
192
+ postEntity.addProperty({
193
+ info: { name: 'content', displayName: 'Content', description: 'Full content of the post in HTML or Markdown' },
194
+ type: 'string',
195
+ required: true,
196
+ semantics: [{ id: SemanticType.HTML }],
197
+ });
198
+ postEntity.addProperty({
199
+ info: {
200
+ name: 'content_format',
201
+ displayName: 'Content Format',
202
+ description: 'Format of the content (HTML, Markdown, etc.)',
203
+ },
204
+ type: 'string',
205
+ required: true,
206
+ schema: {
207
+ enum: ['html', 'markdown', 'richtext'],
208
+ defaultValue: { type: 'literal', value: 'markdown' },
209
+ },
210
+ });
211
+ postEntity.addProperty({
212
+ info: { name: 'featured_image_url', displayName: 'Featured Image URL', description: 'URL to featured image' },
213
+ type: 'string',
214
+ semantics: [{ id: SemanticType.ImageURL }],
215
+ });
216
+ addCustomStatusField(postEntity, ['draft', 'pending_review', 'scheduled', 'published', 'archived'], {
217
+ displayName: 'Post Status',
218
+ description: 'Current publishing status of the post',
219
+ });
220
+ addCreatedAtField(postEntity, {
221
+ name: 'published_at',
222
+ displayName: 'Published At',
223
+ description: 'When the post was published',
224
+ });
225
+ postEntity.addProperty({
226
+ info: {
227
+ name: 'scheduled_at',
228
+ displayName: 'Scheduled At',
229
+ description: 'When the post is scheduled to be published',
230
+ },
231
+ type: 'datetime',
232
+ });
233
+ addQuantityField(postEntity, {
234
+ name: 'view_count',
235
+ displayName: 'View Count',
236
+ description: 'Number of times the post has been viewed',
237
+ });
238
+ postEntity.addProperty({
239
+ info: { name: 'reading_time', displayName: 'Reading Time', description: 'Estimated reading time in minutes' },
240
+ type: 'number',
241
+ readOnly: true,
242
+ semantics: [
243
+ createCalculatedSemantic({
244
+ formula: 'CEILING(LENGTH(REPLACE({{content}}, " ", "")) / 250)',
245
+ dependencies: [],
246
+ recalculateOnUpdate: true,
247
+ }),
248
+ ],
249
+ });
250
+ postEntity.addProperty({
251
+ info: { name: 'word_count', displayName: 'Word Count', description: 'Number of words in the post content' },
252
+ type: 'number',
253
+ readOnly: true,
254
+ semantics: [
255
+ createCalculatedSemantic({
256
+ formula: 'LENGTH({{content}}) - LENGTH(REPLACE({{content}}, " ", "")) + 1',
257
+ dependencies: [],
258
+ recalculateOnUpdate: true,
259
+ }),
260
+ ],
261
+ });
262
+ postEntity.addProperty({
263
+ info: { name: 'meta_title', displayName: 'Meta Title', description: 'SEO meta title' },
264
+ type: 'string',
265
+ // semantics: [{ id: SemanticType.SEOTitle }],
266
+ });
267
+ postEntity.addProperty({
268
+ info: { name: 'meta_description', displayName: 'Meta Description', description: 'SEO meta description' },
269
+ type: 'string',
270
+ // semantics: [{ id: SemanticType.SEODescription }],
271
+ });
272
+ addCreatedAtField(postEntity, { description: 'When the post was created' });
273
+ addUpdatedAtField(postEntity, { description: 'When the post was last updated' });
274
+ // Post-Publication Association (Many-to-One)
275
+ postEntity.addAssociation({ key: publicationEntity.key }, {
276
+ info: { name: 'publication', displayName: 'Publication', description: 'Publication this post belongs to' },
277
+ required: true,
278
+ multiple: false,
279
+ });
280
+ // Post-Category Association (Many-to-Many)
281
+ postEntity.addAssociation({ key: categoryEntity.key }, {
282
+ info: { name: 'categories', displayName: 'Post Categories', description: 'Categories this post belongs to' },
283
+ required: false,
284
+ multiple: true,
285
+ semantics: [{ id: SemanticType.Categories }],
286
+ });
287
+ // Post-Tag Association (Many-to-Many)
288
+ postEntity.addAssociation({ key: tagEntity.key }, {
289
+ info: { name: 'tags', displayName: 'Post Tags', description: 'Tags associated with this post' },
290
+ required: false,
291
+ multiple: true,
292
+ semantics: [{ id: SemanticType.Tags }],
293
+ });
294
+ //
295
+ // 2. USER MANAGEMENT NAMESPACE
296
+ //
297
+ const userManagement = domain.addNamespace({
298
+ info: {
299
+ name: 'UserManagement',
300
+ displayName: 'User Management',
301
+ description: 'Authors, editors, subscribers, and user roles management',
302
+ },
303
+ });
304
+ // User Model
305
+ const userModel = userManagement.addModel({
306
+ info: {
307
+ name: 'Users',
308
+ displayName: 'User Management',
309
+ description: 'User accounts and authentication',
310
+ },
311
+ });
312
+ // User Entity
313
+ const userEntity = userModel.addEntity({
314
+ info: {
315
+ name: 'user',
316
+ displayName: 'User Account',
317
+ description: 'User account for authors, editors, and subscribers',
318
+ },
319
+ semantics: [{ id: SemanticType.User }],
320
+ });
321
+ addIdField(userEntity, { displayName: 'User ID', description: 'Unique identifier for the user' });
322
+ addEmailField(userEntity, { description: 'User email address for login and communication' });
323
+ addPasswordField(userEntity, { description: 'Encrypted password for authentication' });
324
+ userEntity.addProperty({
325
+ info: { name: 'username', displayName: 'Username', description: 'Unique username for the user' },
326
+ type: 'string',
327
+ required: true,
328
+ unique: true,
329
+ semantics: [{ id: SemanticType.PublicUniqueName }],
330
+ });
331
+ userEntity.addProperty({
332
+ info: { name: 'display_name', displayName: 'Display Name', description: 'Public display name for the user' },
333
+ type: 'string',
334
+ required: true,
335
+ });
336
+ addFirstNameField(userEntity, { description: 'User first name' });
337
+ addLastNameField(userEntity, { description: 'User last name' });
338
+ userEntity.addProperty({
339
+ info: { name: 'bio', displayName: 'Biography', description: 'User biography and description' },
340
+ type: 'string',
341
+ semantics: [{ id: SemanticType.Description }],
342
+ });
343
+ addAvatarUrlField(userEntity, { description: 'URL to user profile picture' });
344
+ userEntity.addProperty({
345
+ info: { name: 'website', displayName: 'Website', description: 'User personal website URL' },
346
+ type: 'string',
347
+ semantics: [createURLSemantic()],
348
+ });
349
+ // userEntity.addProperty({
350
+ // info: {
351
+ // name: 'social_links',
352
+ // displayName: 'Social Links',
353
+ // description: 'JSON object containing social media links',
354
+ // },
355
+ // type: 'string',
356
+ // // semantics: [{ id: SemanticType.SocialMediaLinks }],
357
+ // })
358
+ addCustomStatusField(userEntity, ['subscriber', 'author', 'editor', 'admin', 'super_admin'], {
359
+ name: 'role',
360
+ displayName: 'User Role',
361
+ description: 'User role for permission management',
362
+ });
363
+ addCustomStatusField(userEntity, ['active', 'inactive', 'suspended', 'pending_verification'], {
364
+ displayName: 'User Status',
365
+ description: 'Current status of the user account',
366
+ });
367
+ addBooleanField(userEntity, 'emailVerified', 'false', {
368
+ displayName: 'Email Verified',
369
+ description: 'Whether the user has verified their email',
370
+ });
371
+ // userEntity.addProperty({
372
+ // info: { name: 'last_login_at', displayName: 'Last Login At', description: 'When the user last logged in' },
373
+ // type: 'datetime',
374
+ // readOnly: true,
375
+ // semantics: [{ id: SemanticType.LastLoginTimestamp }],
376
+ // })
377
+ addCreatedAtField(userEntity, { description: 'When the user account was created' });
378
+ // Post-Author Association (Many-to-One)
379
+ postEntity.addAssociation({ key: userEntity.key }, {
380
+ info: { name: 'author', displayName: 'Post Author', description: 'Author who wrote this post' },
381
+ required: true,
382
+ multiple: false,
383
+ semantics: [{ id: SemanticType.ResourceOwnerIdentifier }],
384
+ });
385
+ //
386
+ // 3. SOCIAL FEATURES NAMESPACE
387
+ //
388
+ const socialFeatures = domain.addNamespace({
389
+ info: {
390
+ name: 'SocialFeatures',
391
+ displayName: 'Social Features',
392
+ description: 'Comments, likes, shares, and social interactions',
393
+ },
394
+ });
395
+ // Comment Model
396
+ const commentModel = socialFeatures.addModel({
397
+ info: {
398
+ name: 'Comments',
399
+ displayName: 'Comment System',
400
+ description: 'Post comments and replies',
401
+ },
402
+ });
403
+ // Comment Entity
404
+ const commentEntity = commentModel.addEntity({
405
+ info: {
406
+ name: 'comment',
407
+ displayName: 'Comment',
408
+ description: 'User comments on posts',
409
+ },
410
+ });
411
+ addIdField(commentEntity, { displayName: 'Comment ID', description: 'Unique identifier for the comment' });
412
+ commentEntity.addProperty({
413
+ info: { name: 'content', displayName: 'Comment Content', description: 'Content of the comment' },
414
+ type: 'string',
415
+ required: true,
416
+ });
417
+ commentEntity.addProperty({
418
+ info: {
419
+ name: 'author_name',
420
+ displayName: 'Author Name',
421
+ description: 'Name of the comment author (for guest comments)',
422
+ },
423
+ type: 'string',
424
+ });
425
+ addEmailField(commentEntity, {
426
+ name: 'author_email',
427
+ displayName: 'Author Email',
428
+ description: 'Email of the comment author (for guest comments)',
429
+ });
430
+ addCustomStatusField(commentEntity, ['pending', 'approved', 'rejected', 'spam'], {
431
+ displayName: 'Comment Status',
432
+ description: 'Moderation status of the comment',
433
+ });
434
+ // commentEntity.addProperty({
435
+ // info: { name: 'ip_address', displayName: 'IP Address', description: 'IP address of the commenter' },
436
+ // type: 'string',
437
+ // semantics: [{ id: SemanticType.IPAddress }],
438
+ // })
439
+ commentEntity.addProperty({
440
+ info: { name: 'user_agent', displayName: 'User Agent', description: 'Browser user agent string' },
441
+ type: 'string',
442
+ });
443
+ addCreatedAtField(commentEntity, { description: 'When the comment was created' });
444
+ // Comment-Post Association (Many-to-One)
445
+ commentEntity.addAssociation({ key: postEntity.key }, {
446
+ info: { name: 'post', displayName: 'Post', description: 'Post this comment belongs to' },
447
+ required: true,
448
+ multiple: false,
449
+ });
450
+ // Comment-User Association (Many-to-One) - Optional for guest comments
451
+ commentEntity.addAssociation({ key: userEntity.key }, {
452
+ info: { name: 'author', displayName: 'Comment Author', description: 'Registered user who wrote this comment' },
453
+ required: false,
454
+ multiple: false,
455
+ semantics: [{ id: SemanticType.ResourceOwnerIdentifier }],
456
+ });
457
+ // Self-referencing association for comment replies
458
+ commentEntity.addAssociation({ key: commentEntity.key }, {
459
+ info: { name: 'parent_comment', displayName: 'Parent Comment', description: 'Parent comment for replies' },
460
+ required: false,
461
+ multiple: false,
462
+ });
463
+ //
464
+ // 4. ANALYTICS NAMESPACE
465
+ //
466
+ const analytics = domain.addNamespace({
467
+ info: {
468
+ name: 'Analytics',
469
+ displayName: 'Analytics & Tracking',
470
+ description: 'Analytics, metrics, and performance tracking',
471
+ },
472
+ });
473
+ // Analytics Model
474
+ const analyticsModel = analytics.addModel({
475
+ info: {
476
+ name: 'Analytics',
477
+ displayName: 'Content Analytics',
478
+ description: 'Content performance and user engagement metrics',
479
+ },
480
+ });
481
+ // Page View Entity
482
+ const pageViewEntity = analyticsModel.addEntity({
483
+ info: {
484
+ name: 'page_view',
485
+ displayName: 'Page View',
486
+ description: 'Individual page view tracking record',
487
+ },
488
+ });
489
+ addIdField(pageViewEntity, { displayName: 'Page View ID', description: 'Unique identifier for the page view' });
490
+ pageViewEntity.addProperty({
491
+ info: { name: 'path', displayName: 'Page Path', description: 'URL path of the viewed page' },
492
+ type: 'string',
493
+ required: true,
494
+ });
495
+ pageViewEntity.addProperty({
496
+ info: { name: 'referrer', displayName: 'Referrer', description: 'Referring URL' },
497
+ type: 'string',
498
+ semantics: [createURLSemantic()],
499
+ });
500
+ // pageViewEntity.addProperty({
501
+ // info: { name: 'ip_address', displayName: 'IP Address', description: 'Visitor IP address' },
502
+ // type: 'string',
503
+ // semantics: [{ id: SemanticType.IPAddress }],
504
+ // })
505
+ pageViewEntity.addProperty({
506
+ info: { name: 'user_agent', displayName: 'User Agent', description: 'Browser user agent string' },
507
+ type: 'string',
508
+ });
509
+ pageViewEntity.addProperty({
510
+ info: { name: 'session_id', displayName: 'Session ID', description: 'Visitor session identifier' },
511
+ type: 'string',
512
+ });
513
+ addCreatedAtField(pageViewEntity, {
514
+ name: 'viewed_at',
515
+ displayName: 'Viewed At',
516
+ description: 'When the page was viewed',
517
+ });
518
+ // PageView-Post Association (Many-to-One) - Optional, only for post views
519
+ pageViewEntity.addAssociation({ key: postEntity.key }, {
520
+ info: { name: 'post', displayName: 'Viewed Post', description: 'Post that was viewed (if applicable)' },
521
+ required: false,
522
+ multiple: false,
523
+ });
524
+ // PageView-Publication Association (Many-to-One)
525
+ pageViewEntity.addAssociation({ key: publicationEntity.key }, {
526
+ info: { name: 'publication', displayName: 'Publication', description: 'Publication this page view belongs to' },
527
+ required: true,
528
+ multiple: false,
529
+ });
530
+ //
531
+ // 5. MEDIA MANAGEMENT NAMESPACE
532
+ //
533
+ const mediaManagement = domain.addNamespace({
534
+ info: {
535
+ name: 'MediaManagement',
536
+ displayName: 'Media Management',
537
+ description: 'Image, video, and file upload management',
538
+ },
539
+ });
540
+ // Media Model
541
+ const mediaModel = mediaManagement.addModel({
542
+ info: {
543
+ name: 'Media',
544
+ displayName: 'Media Library',
545
+ description: 'Uploaded files, images, and media assets',
546
+ },
547
+ });
548
+ // Media File Entity
549
+ const mediaFileEntity = mediaModel.addEntity({
550
+ info: {
551
+ name: 'media_file',
552
+ displayName: 'Media File',
553
+ description: 'Uploaded media files (images, videos, documents)',
554
+ },
555
+ });
556
+ addIdField(mediaFileEntity, { displayName: 'Media File ID', description: 'Unique identifier for the media file' });
557
+ mediaFileEntity.addProperty({
558
+ info: { name: 'filename', displayName: 'File Name', description: 'Original filename of the uploaded file' },
559
+ type: 'string',
560
+ required: true,
561
+ });
562
+ mediaFileEntity.addProperty({
563
+ info: { name: 'storage_key', displayName: 'Storage Key', description: 'Unique storage key for the file' },
564
+ type: 'string',
565
+ required: true,
566
+ unique: true,
567
+ });
568
+ mediaFileEntity.addProperty({
569
+ info: { name: 'url', displayName: 'File URL', description: 'Public URL to access the file' },
570
+ type: 'string',
571
+ required: true,
572
+ semantics: [createURLSemantic()],
573
+ });
574
+ mediaFileEntity.addProperty({
575
+ info: { name: 'mime_type', displayName: 'MIME Type', description: 'MIME type of the file' },
576
+ type: 'string',
577
+ required: true,
578
+ });
579
+ addQuantityField(mediaFileEntity, {
580
+ name: 'file_size',
581
+ displayName: 'File Size',
582
+ description: 'File size in bytes',
583
+ });
584
+ addQuantityField(mediaFileEntity, {
585
+ name: 'width',
586
+ displayName: 'Image Width',
587
+ description: 'Width in pixels (for images)',
588
+ });
589
+ addQuantityField(mediaFileEntity, {
590
+ name: 'height',
591
+ displayName: 'Image Height',
592
+ description: 'Height in pixels (for images)',
593
+ });
594
+ mediaFileEntity.addProperty({
595
+ info: { name: 'alt_text', displayName: 'Alt Text', description: 'Alternative text for accessibility' },
596
+ type: 'string',
597
+ // semantics: [{ id: SemanticType.ImageAltText }],
598
+ });
599
+ addCreatedAtField(mediaFileEntity, {
600
+ name: 'uploaded_at',
601
+ displayName: 'Uploaded At',
602
+ description: 'When the file was uploaded',
603
+ });
604
+ // MediaFile-User Association (Many-to-One)
605
+ mediaFileEntity.addAssociation({ key: userEntity.key }, {
606
+ info: { name: 'uploader', displayName: 'File Uploader', description: 'User who uploaded this file' },
607
+ required: true,
608
+ multiple: false,
609
+ semantics: [{ id: SemanticType.ResourceOwnerIdentifier }],
610
+ });
611
+ // MediaFile-Publication Association (Many-to-One)
612
+ mediaFileEntity.addAssociation({ key: publicationEntity.key }, {
613
+ info: { name: 'publication', displayName: 'Publication', description: 'Publication this media file belongs to' },
614
+ required: true,
615
+ multiple: false,
616
+ });
617
+ return domain;
618
+ }
619
+ // Export the creation function for use in other files
620
+ export default createBlogDomain;
621
+ //# sourceMappingURL=blog-domain.js.map