@api-client/core 0.18.53 → 0.18.55

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 (32) hide show
  1. package/build/src/modeling/Semantics.d.ts +32 -5
  2. package/build/src/modeling/Semantics.d.ts.map +1 -1
  3. package/build/src/modeling/Semantics.js +129 -5
  4. package/build/src/modeling/Semantics.js.map +1 -1
  5. package/build/src/modeling/definitions/Country.d.ts +38 -0
  6. package/build/src/modeling/definitions/Country.d.ts.map +1 -0
  7. package/build/src/modeling/definitions/Country.js +22 -0
  8. package/build/src/modeling/definitions/Country.js.map +1 -0
  9. package/build/src/modeling/definitions/PostalCode.d.ts +48 -0
  10. package/build/src/modeling/definitions/PostalCode.d.ts.map +1 -0
  11. package/build/src/modeling/definitions/PostalCode.js +22 -0
  12. package/build/src/modeling/definitions/PostalCode.js.map +1 -0
  13. package/build/src/modeling/helpers/Intelisense.d.ts +7 -0
  14. package/build/src/modeling/helpers/Intelisense.d.ts.map +1 -1
  15. package/build/src/modeling/helpers/Intelisense.js +135 -0
  16. package/build/src/modeling/helpers/Intelisense.js.map +1 -1
  17. package/build/src/modeling/templates/verticals/business-services/ecommerce-domain.d.ts.map +1 -1
  18. package/build/src/modeling/templates/verticals/business-services/ecommerce-domain.js +10 -0
  19. package/build/src/modeling/templates/verticals/business-services/ecommerce-domain.js.map +1 -1
  20. package/build/src/modeling/templates/verticals/business-services/financial-services-domain.d.ts.map +1 -1
  21. package/build/src/modeling/templates/verticals/business-services/financial-services-domain.js +14 -2
  22. package/build/src/modeling/templates/verticals/business-services/financial-services-domain.js.map +1 -1
  23. package/build/tsconfig.tsbuildinfo +1 -1
  24. package/data/models/example-generator-api.json +12 -12
  25. package/package.json +1 -1
  26. package/src/modeling/Semantics.ts +132 -5
  27. package/src/modeling/definitions/Country.ts +62 -0
  28. package/src/modeling/definitions/PostalCode.ts +70 -0
  29. package/src/modeling/helpers/Intelisense.ts +144 -0
  30. package/src/modeling/templates/verticals/business-services/ecommerce-domain.ts +10 -0
  31. package/src/modeling/templates/verticals/business-services/financial-services-domain.ts +15 -2
  32. package/tests/unit/modeling/helpers/intellisense.spec.ts +268 -0
@@ -42065,10 +42065,10 @@
42065
42065
  "@id": "#191"
42066
42066
  },
42067
42067
  {
42068
- "@id": "#194"
42068
+ "@id": "#197"
42069
42069
  },
42070
42070
  {
42071
- "@id": "#197"
42071
+ "@id": "#194"
42072
42072
  },
42073
42073
  {
42074
42074
  "@id": "#200"
@@ -42816,10 +42816,10 @@
42816
42816
  "@id": "#213"
42817
42817
  },
42818
42818
  {
42819
- "@id": "#216"
42819
+ "@id": "#219"
42820
42820
  },
42821
42821
  {
42822
- "@id": "#219"
42822
+ "@id": "#216"
42823
42823
  }
42824
42824
  ],
42825
42825
  "doc:root": false,
@@ -43457,7 +43457,7 @@
43457
43457
  "doc:ExternalDomainElement",
43458
43458
  "doc:DomainElement"
43459
43459
  ],
43460
- "doc:raw": "addressType: 'REGISTERED-OFFICE-ADDRESS'\nstreetName: 'UITBREIDINGSTRAAT'\nhouseNumber: '84'\nhouseNumberAddition: '/1'\npostalCode: '2600'\ncity: 'BERCHEM (ANTWERPEN)'\ncountry: 'Belgium'\ncountryCode: 'BE'\nfullFormatedAddress: \"UITBREIDINGSTRAAT 84 /1, 2600 BERCHEM (ANTWERPEN), BELIUM\"\n",
43460
+ "doc:raw": "code: '5'\ndescription: 'Limited company'\n",
43461
43461
  "core:mediaType": "application/yaml",
43462
43462
  "sourcemaps:sources": [
43463
43463
  {
@@ -43478,7 +43478,7 @@
43478
43478
  "doc:ExternalDomainElement",
43479
43479
  "doc:DomainElement"
43480
43480
  ],
43481
- "doc:raw": "code: '5'\ndescription: 'Limited company'\n",
43481
+ "doc:raw": "addressType: 'REGISTERED-OFFICE-ADDRESS'\nstreetName: 'UITBREIDINGSTRAAT'\nhouseNumber: '84'\nhouseNumberAddition: '/1'\npostalCode: '2600'\ncity: 'BERCHEM (ANTWERPEN)'\ncountry: 'Belgium'\ncountryCode: 'BE'\nfullFormatedAddress: \"UITBREIDINGSTRAAT 84 /1, 2600 BERCHEM (ANTWERPEN), BELIUM\"\n",
43482
43482
  "core:mediaType": "application/yaml",
43483
43483
  "sourcemaps:sources": [
43484
43484
  {
@@ -44274,7 +44274,7 @@
44274
44274
  "doc:ExternalDomainElement",
44275
44275
  "doc:DomainElement"
44276
44276
  ],
44277
- "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44277
+ "doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
44278
44278
  "core:mediaType": "application/yaml",
44279
44279
  "sourcemaps:sources": [
44280
44280
  {
@@ -44295,7 +44295,7 @@
44295
44295
  "doc:ExternalDomainElement",
44296
44296
  "doc:DomainElement"
44297
44297
  ],
44298
- "doc:raw": "type: \"GENERAL\"\nvalue: \"www.company.be\"\n",
44298
+ "doc:raw": "-\n type: 'GENERAL'\n value: 'info@company.be'\n-\n type: 'IT_DEPT'\n value: 'it-service@company.be'\n",
44299
44299
  "core:mediaType": "application/yaml",
44300
44300
  "sourcemaps:sources": [
44301
44301
  {
@@ -44761,12 +44761,12 @@
44761
44761
  {
44762
44762
  "@id": "#196/source-map/lexical/element_0",
44763
44763
  "sourcemaps:element": "amf://id#196",
44764
- "sourcemaps:value": "[(1,0)-(10,0)]"
44764
+ "sourcemaps:value": "[(1,0)-(3,0)]"
44765
44765
  },
44766
44766
  {
44767
44767
  "@id": "#199/source-map/lexical/element_0",
44768
44768
  "sourcemaps:element": "amf://id#199",
44769
- "sourcemaps:value": "[(1,0)-(3,0)]"
44769
+ "sourcemaps:value": "[(1,0)-(10,0)]"
44770
44770
  },
44771
44771
  {
44772
44772
  "@id": "#202/source-map/lexical/element_0",
@@ -45126,12 +45126,12 @@
45126
45126
  {
45127
45127
  "@id": "#218/source-map/lexical/element_0",
45128
45128
  "sourcemaps:element": "amf://id#218",
45129
- "sourcemaps:value": "[(1,0)-(7,0)]"
45129
+ "sourcemaps:value": "[(1,0)-(3,0)]"
45130
45130
  },
45131
45131
  {
45132
45132
  "@id": "#221/source-map/lexical/element_0",
45133
45133
  "sourcemaps:element": "amf://id#221",
45134
- "sourcemaps:value": "[(1,0)-(3,0)]"
45134
+ "sourcemaps:value": "[(1,0)-(7,0)]"
45135
45135
  },
45136
45136
  {
45137
45137
  "@id": "#338/source-map/synthesized-field/element_1",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@api-client/core",
3
3
  "description": "The API Client's core client library. Works in NodeJS and in a ES enabled browser.",
4
- "version": "0.18.53",
4
+ "version": "0.18.55",
5
5
  "license": "Apache-2.0",
6
6
  "exports": {
7
7
  "./browser.js": {
@@ -15,6 +15,10 @@ export enum SemanticType {
15
15
  * Designates a Data Entity that represents users of the system.
16
16
  */
17
17
  User = 'Semantic#User',
18
+ /**
19
+ * Designates a Data Entity that represents a physical address.
20
+ */
21
+ Address = 'Semantic#Address',
18
22
 
19
23
  //
20
24
  // Property-Level Semantics
@@ -197,10 +201,33 @@ export enum SemanticType {
197
201
  Derived = 'Semantic#Derived',
198
202
  /**
199
203
  * Annotates a field that should automatically receive the client's IP address.
200
- * The runtime automatically populates this field with the request's IP address
201
204
  * when creating or updating records, providing audit trail and geolocation capabilities.
202
205
  */
203
206
  ClientIPAddress = 'Semantic#ClientIPAddress',
207
+ /**
208
+ * Designates a Data Property as the street address (e.g., "123 Main St").
209
+ */
210
+ StreetAddress = 'Semantic#StreetAddress',
211
+ /**
212
+ * This is a single semantic used for any additional lines (Unit, Suite, Apartment, Floor).
213
+ */
214
+ StreetAddressSupplemental = 'Semantic#StreetAddressSupplemental',
215
+ /**
216
+ * Designates a Data Property as the city or locality.
217
+ */
218
+ City = 'Semantic#City',
219
+ /**
220
+ * Designates a Data Property as the postal or zip code.
221
+ */
222
+ PostalCode = 'Semantic#PostalCode',
223
+ /**
224
+ * Designates a Data Property as the country.
225
+ */
226
+ Country = 'Semantic#Country',
227
+ /**
228
+ * Designates a Data Property as the state, province, or region.
229
+ */
230
+ Region = 'Semantic#Region',
204
231
 
205
232
  //
206
233
  // Association-Level Semantics
@@ -271,10 +298,6 @@ export enum SemanticCategory {
271
298
  * Business-specific data like pricing, inventory, status
272
299
  */
273
300
  Business = 'Business Data',
274
- /**
275
- * Contact information and communication
276
- */
277
- Contact = 'Contact Information',
278
301
  /**
279
302
  * Organization, categorization, and tagging
280
303
  */
@@ -283,6 +306,10 @@ export enum SemanticCategory {
283
306
  * Location and geographical data
284
307
  */
285
308
  Location = 'Location & Geography',
309
+ /**
310
+ * Contact information and communication
311
+ */
312
+ Contact = 'Contact Information',
286
313
  /**
287
314
  * Calculated and derived values
288
315
  */
@@ -792,6 +819,106 @@ export const DataSemantics: Record<SemanticType, DataSemantic> = {
792
819
  priority: 80,
793
820
  },
794
821
  },
822
+
823
+ //
824
+ // Contact & Address
825
+ //
826
+
827
+ [SemanticType.Address]: {
828
+ id: SemanticType.Address,
829
+ displayName: 'Address Entity',
830
+ scope: SemanticScope.Entity,
831
+ description: 'Physical address entity',
832
+ category: SemanticCategory.Contact,
833
+ // For now, the Address won't have configuration, but future-wise:
834
+ // - autoGeocode (boolean): If true, the runtime automatically generates latitude and longitude for the record whenever the address properties change.
835
+ // - validationProvider (enum): Options like None, GoogleMaps, or Loqate. This determines if the API returns an error for non-existent addresses.
836
+ // - strictness (enum): Lax (accept anything) vs. Strict (reject if not deliverable).
837
+ hasConfig: false,
838
+ runtime: {
839
+ timing: SemanticTiming.None,
840
+ operations: [],
841
+ },
842
+ },
843
+ [SemanticType.StreetAddress]: {
844
+ id: SemanticType.StreetAddress,
845
+ displayName: 'Street Address',
846
+ scope: SemanticScope.Property,
847
+ description: 'Street address line',
848
+ category: SemanticCategory.Contact,
849
+ applicableDataTypes: ['string'],
850
+ hasConfig: false,
851
+ runtime: {
852
+ timing: SemanticTiming.None,
853
+ operations: [],
854
+ },
855
+ },
856
+ [SemanticType.StreetAddressSupplemental]: {
857
+ id: SemanticType.StreetAddressSupplemental,
858
+ displayName: 'Street Address Supplemental',
859
+ scope: SemanticScope.Property,
860
+ description: 'Supplemental street address line (e.g., Unit, Suite, Apartment, Floor)',
861
+ category: SemanticCategory.Contact,
862
+ applicableDataTypes: ['string'],
863
+ hasConfig: false,
864
+ runtime: {
865
+ timing: SemanticTiming.None,
866
+ operations: [],
867
+ },
868
+ },
869
+ [SemanticType.City]: {
870
+ id: SemanticType.City,
871
+ displayName: 'City',
872
+ scope: SemanticScope.Property,
873
+ description: 'City or locality',
874
+ category: SemanticCategory.Contact,
875
+ applicableDataTypes: ['string'],
876
+ hasConfig: false,
877
+ runtime: {
878
+ timing: SemanticTiming.None,
879
+ operations: [],
880
+ },
881
+ },
882
+ [SemanticType.PostalCode]: {
883
+ id: SemanticType.PostalCode,
884
+ displayName: 'Postal Code',
885
+ scope: SemanticScope.Property,
886
+ description: 'Postal or zip code',
887
+ category: SemanticCategory.Contact,
888
+ applicableDataTypes: ['string'],
889
+ hasConfig: false,
890
+ runtime: {
891
+ timing: SemanticTiming.None,
892
+ operations: [],
893
+ },
894
+ },
895
+ [SemanticType.Country]: {
896
+ id: SemanticType.Country,
897
+ displayName: 'Country',
898
+ scope: SemanticScope.Property,
899
+ description: 'Country name or code',
900
+ category: SemanticCategory.Contact,
901
+ applicableDataTypes: ['string'],
902
+ hasConfig: true,
903
+ runtime: {
904
+ timing: SemanticTiming.None,
905
+ operations: [],
906
+ },
907
+ },
908
+ [SemanticType.Region]: {
909
+ id: SemanticType.Region,
910
+ displayName: 'Region',
911
+ scope: SemanticScope.Property,
912
+ description: 'State, province, or region',
913
+ category: SemanticCategory.Contact,
914
+ applicableDataTypes: ['string'],
915
+ hasConfig: false,
916
+ runtime: {
917
+ timing: SemanticTiming.None,
918
+ operations: [],
919
+ },
920
+ },
921
+
795
922
  [SemanticType.Version]: {
796
923
  id: SemanticType.Version,
797
924
  displayName: 'Version Number',
@@ -0,0 +1,62 @@
1
+ import type { AppliedDataSemantic } from '../Semantics.js'
2
+ import { SemanticType } from '../Semantics.js'
3
+
4
+ export type CountryFormat = 'ISO_3166_Alpha_2' | 'ISO_3166_Alpha_3' | 'Name'
5
+
6
+ export interface CountryConfig {
7
+ /**
8
+ * The format of the country code.
9
+ *
10
+ * @default 'Name'
11
+ */
12
+ format?: CountryFormat
13
+
14
+ /**
15
+ * The list of allowed countries.
16
+ */
17
+ allowedCountries?: string[]
18
+
19
+ /**
20
+ * The list of disallowed countries.
21
+ */
22
+ disallowedCountries?: string[]
23
+ /**
24
+ * Custom metadata for the country field.
25
+ */
26
+ metadata?: Record<string, unknown>
27
+ /**
28
+ * Index signature to allow additional properties.
29
+ */
30
+ [key: string]: unknown
31
+ }
32
+
33
+ /**
34
+ * Type-safe configuration for Country semantic.
35
+ */
36
+ export interface AppliedCountrySemantic extends AppliedDataSemantic {
37
+ id: SemanticType.Country
38
+ config?: CountryConfig
39
+ }
40
+
41
+ export const isCountrySemantic = (semantic: AppliedDataSemantic): semantic is AppliedCountrySemantic => {
42
+ return semantic.id === SemanticType.Country
43
+ }
44
+
45
+ export const createCountrySemantic = (config: CountryConfig = {}): AppliedCountrySemantic => {
46
+ const mergedConfig = {
47
+ ...DEFAULT_COUNTRY_CONFIG,
48
+ ...config,
49
+ }
50
+ // Merge metadata separately
51
+ if (config.metadata) {
52
+ mergedConfig.metadata = { ...config.metadata }
53
+ }
54
+ return {
55
+ id: SemanticType.Country,
56
+ config: mergedConfig,
57
+ }
58
+ }
59
+
60
+ export const DEFAULT_COUNTRY_CONFIG: CountryConfig = {
61
+ format: 'ISO_3166_Alpha_2',
62
+ }
@@ -0,0 +1,70 @@
1
+ import type { AppliedDataSemantic } from '../Semantics.js'
2
+ import { SemanticType } from '../Semantics.js'
3
+ /**
4
+ * Validation Logic Flow:
5
+ *
6
+ * When the API receives a POST or PATCH request, the following sequence occurs:
7
+ * 1. Semantic Trigger: The Runtime identifies a property with the PostalCode semantic and config.validate: true.
8
+ * 2. Country Lookup: The Runtime identifies the sibling property tagged with `SemanticType.Country`.
9
+ * 3. Regex Retrieval: The Runtime retrieves the appropriate regex pattern based on the country code.
10
+ * 4. Validation: The Runtime validates the postal code against the retrieved regex pattern.
11
+ * 5. Error Handling: If the validation fails, the Runtime returns a 400 Bad Request error with a descriptive message.
12
+ * - Example: "Invalid postal code format for country: [CountryCode]."
13
+ *
14
+ * Validation libraries:
15
+ * - https://www.npmjs.com/package/postcode-validator (MIT)
16
+ * - https://github.com/sashiksu/postal-code-checker (MIT)
17
+ */
18
+ export interface PostalCodeConfig {
19
+ /**
20
+ * Enables regex-based validation based on the value in the sibling property
21
+ * tagged with `SemanticType.Country`.
22
+ */
23
+ validate?: boolean
24
+
25
+ /**
26
+ * The list of allowed postal codes.
27
+ */
28
+ allowedPostalCodes?: string[]
29
+
30
+ /**
31
+ * The list of disallowed postal codes.
32
+ */
33
+ disallowedPostalCodes?: string[]
34
+ /**
35
+ * Custom metadata for the postal code field.
36
+ */
37
+ metadata?: Record<string, unknown>
38
+ /**
39
+ * Index signature to allow additional properties.
40
+ */
41
+ [key: string]: unknown
42
+ }
43
+
44
+ export interface AppliedPostalCodeSemantic extends AppliedDataSemantic {
45
+ id: SemanticType.PostalCode
46
+ config?: PostalCodeConfig
47
+ }
48
+
49
+ export const DEFAULT_POSTAL_CODE_CONFIG: PostalCodeConfig = {
50
+ validate: false,
51
+ }
52
+
53
+ export const isPostalCodeSemantic = (semantic: AppliedDataSemantic): semantic is AppliedPostalCodeSemantic => {
54
+ return semantic.id === SemanticType.PostalCode
55
+ }
56
+
57
+ export const createPostalCodeSemantic = (config: PostalCodeConfig = {}): AppliedPostalCodeSemantic => {
58
+ const mergedConfig = {
59
+ ...DEFAULT_POSTAL_CODE_CONFIG,
60
+ ...config,
61
+ }
62
+ // Merge metadata separately
63
+ if (config.metadata) {
64
+ mergedConfig.metadata = { ...config.metadata }
65
+ }
66
+ return {
67
+ id: SemanticType.PostalCode,
68
+ config: mergedConfig,
69
+ }
70
+ }
@@ -12,6 +12,8 @@ import { createDescriptionSemantic } from '../definitions/Description.js'
12
12
  import { CURRENCY_PRESETS } from '../definitions/Currency.js'
13
13
  import { createStatusSemantic } from '../definitions/Status.js'
14
14
  import { SKU_PRESETS } from '../definitions/SKU.js'
15
+ import { createCountrySemantic, DEFAULT_COUNTRY_CONFIG } from '../definitions/Country.js'
16
+ import { createPostalCodeSemantic, DEFAULT_POSTAL_CODE_CONFIG } from '../definitions/PostalCode.js'
15
17
 
16
18
  /**
17
19
  * Adds a field to the given entity that is automatically generated by the system.
@@ -29,6 +31,8 @@ export function addAutoField(entity: DomainEntity, autoField: string): DomainEle
29
31
  return addEmailField(entity)
30
32
  case 'name':
31
33
  return addNameField(entity)
34
+ case 'display-name':
35
+ return addDisplayNameField(entity)
32
36
  case 'description':
33
37
  return addDescriptionField(entity)
34
38
  case 'status':
@@ -49,6 +53,8 @@ export function addAutoField(entity: DomainEntity, autoField: string): DomainEle
49
53
  return addIsDeletedField(entity)
50
54
  case 'deleted':
51
55
  return addDeletedAtField(entity)
56
+ case 'role':
57
+ return addRoleField(entity)
52
58
  case 'first-name':
53
59
  return addFirstNameField(entity)
54
60
  case 'last-name':
@@ -70,11 +76,25 @@ export function addAutoField(entity: DomainEntity, autoField: string): DomainEle
70
76
  case 'images':
71
77
  return addImagesField(entity)
72
78
  case 'session-id':
79
+ // This was removed from the UI. We will not support session id configuration
80
+ // as the platform will handle it to separate the business logic from the transport layer.
73
81
  return addSessionIdField(entity)
74
82
  case 'expires-at':
83
+ // This was removed from the UI. We will not support expires at configuration
84
+ // as the platform will handle it to separate the business logic from the transport layer.
75
85
  return addExpiresAtField(entity)
76
86
  case 'unit-price':
77
87
  return addUnitPriceField(entity)
88
+ case 'street-address':
89
+ return addStreetAddressField(entity)
90
+ case 'city':
91
+ return addCityField(entity)
92
+ case 'postal-code':
93
+ return addPostalCodeField(entity)
94
+ case 'country':
95
+ return addCountryField(entity)
96
+ case 'region':
97
+ return addRegionField(entity)
78
98
  default:
79
99
  throw new Error(`Unsupported auto field: ${autoField}`)
80
100
  }
@@ -198,6 +218,21 @@ export function addNameField(entity: DomainEntity, info: Partial<IThing> = {}):
198
218
  return prop
199
219
  }
200
220
 
221
+ export function addDisplayNameField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
222
+ const existing = findDisplayNameField(entity, true)
223
+ if (existing) {
224
+ return existing
225
+ }
226
+ const prop = entity.addProperty({
227
+ info: { name: 'display-name', displayName: 'Display Name', ...info },
228
+ type: 'string',
229
+ })
230
+ prop.addSemantic({
231
+ id: SemanticType.Name,
232
+ })
233
+ return prop
234
+ }
235
+
201
236
  /**
202
237
  * Adds a description field to the specified entity.
203
238
  * If a description field already exists, it returns the existing field.
@@ -472,6 +507,24 @@ export function addDeletedAtField(entity: DomainEntity, info: Partial<IThing> =
472
507
  return prop
473
508
  }
474
509
 
510
+ export function addRoleField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
511
+ const existing = findRoleField(entity, true)
512
+ if (existing) {
513
+ return existing
514
+ }
515
+ const prop = entity.addProperty({
516
+ info: { name: 'role', displayName: 'Role', ...info },
517
+ type: 'string',
518
+ required: true,
519
+ index: true,
520
+ schema: { defaultValue: { type: 'literal', value: 'user' }, enum: ['user', 'admin'] },
521
+ })
522
+ prop.addSemantic({
523
+ id: SemanticType.UserRole,
524
+ })
525
+ return prop
526
+ }
527
+
475
528
  /**
476
529
  * Adds an is_deleted field to the specified entity.
477
530
  * If an is_deleted field already exists, it returns the existing field.
@@ -1134,6 +1187,10 @@ function findNameField(entity: DomainEntity, direct = false): DomainProperty | u
1134
1187
  return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.Title), direct)
1135
1188
  }
1136
1189
 
1190
+ function findDisplayNameField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1191
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.Name), direct)
1192
+ }
1193
+
1137
1194
  function findDescriptionField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1138
1195
  return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.Description), direct)
1139
1196
  }
@@ -1196,6 +1253,10 @@ function findDeletedAtField(entity: DomainEntity, direct = false): DomainPropert
1196
1253
  )
1197
1254
  }
1198
1255
 
1256
+ function findRoleField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1257
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.UserRole), direct)
1258
+ }
1259
+
1199
1260
  function findIsDeletedField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1200
1261
  return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.DeletedFlag), direct)
1201
1262
  }
@@ -1313,3 +1374,86 @@ function findExpiresAtField(entity: DomainEntity, direct = false): DomainPropert
1313
1374
  direct
1314
1375
  )
1315
1376
  }
1377
+
1378
+ export function addStreetAddressField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
1379
+ const existing = findStreetAddressField(entity, true)
1380
+ if (existing) return existing
1381
+ const prop = entity.addProperty({
1382
+ info: { name: 'street_address', displayName: 'Street Address', ...info },
1383
+ type: 'string',
1384
+ required: true,
1385
+ })
1386
+ prop.addSemantic({ id: SemanticType.StreetAddress })
1387
+ return prop
1388
+ }
1389
+
1390
+ function findStreetAddressField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1391
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.StreetAddress), direct)
1392
+ }
1393
+
1394
+ export function addCityField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
1395
+ const existing = findCityField(entity, true)
1396
+ if (existing) return existing
1397
+ const prop = entity.addProperty({
1398
+ info: { name: 'city', displayName: 'City', ...info },
1399
+ type: 'string',
1400
+ required: true,
1401
+ index: true,
1402
+ })
1403
+ prop.addSemantic({ id: SemanticType.City })
1404
+ return prop
1405
+ }
1406
+
1407
+ function findCityField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1408
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.City), direct)
1409
+ }
1410
+
1411
+ export function addPostalCodeField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
1412
+ const existing = findPostalCodeField(entity, true)
1413
+ if (existing) return existing
1414
+ const prop = entity.addProperty({
1415
+ info: { name: 'postal_code', displayName: 'Postal Code', ...info },
1416
+ type: 'string',
1417
+ required: true,
1418
+ index: true,
1419
+ })
1420
+ prop.addSemantic(createPostalCodeSemantic(DEFAULT_POSTAL_CODE_CONFIG))
1421
+ return prop
1422
+ }
1423
+
1424
+ function findPostalCodeField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1425
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.PostalCode), direct)
1426
+ }
1427
+
1428
+ export function addCountryField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
1429
+ const existing = findCountryField(entity, true)
1430
+ if (existing) return existing
1431
+ const prop = entity.addProperty({
1432
+ info: { name: 'country', displayName: 'Country', ...info },
1433
+ type: 'string',
1434
+ required: true,
1435
+ index: true,
1436
+ })
1437
+ prop.addSemantic(createCountrySemantic(DEFAULT_COUNTRY_CONFIG))
1438
+ return prop
1439
+ }
1440
+
1441
+ function findCountryField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1442
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.Country), direct)
1443
+ }
1444
+
1445
+ export function addRegionField(entity: DomainEntity, info: Partial<IThing> = {}): DomainProperty {
1446
+ const existing = findRegionField(entity, true)
1447
+ if (existing) return existing
1448
+ const prop = entity.addProperty({
1449
+ info: { name: 'region', displayName: 'Region', ...info },
1450
+ type: 'string',
1451
+ index: true,
1452
+ })
1453
+ prop.addSemantic({ id: SemanticType.Region })
1454
+ return prop
1455
+ }
1456
+
1457
+ function findRegionField(entity: DomainEntity, direct = false): DomainProperty | undefined {
1458
+ return findPropertyField(entity, (property) => property.hasSemantic(SemanticType.Region), direct)
1459
+ }
@@ -25,7 +25,9 @@
25
25
  import { DataDomain } from '../../../DataDomain.js'
26
26
  import { SemanticType } from '../../../Semantics.js'
27
27
  import { createCalculatedSemantic } from '../../../definitions/Calculated.js'
28
+ import { createCountrySemantic, DEFAULT_COUNTRY_CONFIG } from '../../../definitions/Country.js'
28
29
  import { createCurrencySemantic } from '../../../definitions/Currency.js'
30
+ import { createPostalCodeSemantic, DEFAULT_POSTAL_CODE_CONFIG } from '../../../definitions/PostalCode.js'
29
31
  import { createSummarySemantic } from '../../../definitions/Summary.js'
30
32
  import {
31
33
  addAvatarUrlField,
@@ -200,6 +202,7 @@ export default function createEcommerceDomain(options: CreateTemplateOptions = {
200
202
  displayName: 'Address',
201
203
  description: 'Physical address information',
202
204
  },
205
+ semantics: [{ id: SemanticType.Address }],
203
206
  })
204
207
 
205
208
  addIdField(addressEntity, { displayName: 'Address ID', description: 'Unique identifier for the address' })
@@ -221,6 +224,7 @@ export default function createEcommerceDomain(options: CreateTemplateOptions = {
221
224
  },
222
225
  type: 'string',
223
226
  required: true,
227
+ semantics: [{ id: SemanticType.StreetAddress }],
224
228
  })
225
229
 
226
230
  addressEntity.addProperty({
@@ -231,6 +235,7 @@ export default function createEcommerceDomain(options: CreateTemplateOptions = {
231
235
  },
232
236
  type: 'string',
233
237
  required: false,
238
+ semantics: [{ id: SemanticType.StreetAddressSupplemental }],
234
239
  })
235
240
 
236
241
  addressEntity.addProperty({
@@ -241,30 +246,35 @@ export default function createEcommerceDomain(options: CreateTemplateOptions = {
241
246
  },
242
247
  type: 'string',
243
248
  required: false,
249
+ semantics: [{ id: SemanticType.StreetAddressSupplemental }],
244
250
  })
245
251
 
246
252
  addressEntity.addProperty({
247
253
  info: { name: 'city', displayName: 'City', description: 'City name' },
248
254
  type: 'string',
249
255
  required: true,
256
+ semantics: [{ id: SemanticType.City }],
250
257
  })
251
258
 
252
259
  addressEntity.addProperty({
253
260
  info: { name: 'state', displayName: 'State/Province', description: 'State or province' },
254
261
  type: 'string',
255
262
  required: true,
263
+ semantics: [{ id: SemanticType.Region }],
256
264
  })
257
265
 
258
266
  addressEntity.addProperty({
259
267
  info: { name: 'postal_code', displayName: 'ZIP/Postal Code', description: 'ZIP or postal code' },
260
268
  type: 'string',
261
269
  required: true,
270
+ semantics: [createPostalCodeSemantic(DEFAULT_POSTAL_CODE_CONFIG)],
262
271
  })
263
272
 
264
273
  addressEntity.addProperty({
265
274
  info: { name: 'country', displayName: 'Country', description: 'Country name' },
266
275
  type: 'string',
267
276
  required: true,
277
+ semantics: [createCountrySemantic(DEFAULT_COUNTRY_CONFIG)],
268
278
  })
269
279
 
270
280
  // User-Address Association (One-to-Many)