@mohsinonxrm/dataverse-sdk-metadata 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,602 @@
1
+ # @mohsinonxrm/dataverse-sdk-metadata
2
+
3
+ Complete TypeScript metadata management for Microsoft Dataverse - create, read, update, and delete entities, columns, relationships, and choices with full type safety.
4
+
5
+ ## Features
6
+
7
+ - ✅ **Entity definitions** - create, read, update, delete custom tables
8
+ - ✅ **Column definitions** - all attribute types with strict typing:
9
+ - Text (Single Line, Multiple Lines)
10
+ - Numbers (Integer, Decimal, Currency)
11
+ - Date & Time
12
+ - Choices (Local & Global)
13
+ - Yes/No (Boolean)
14
+ - Lookup (Single-table & Polymorphic)
15
+ - File & Image
16
+ - ✅ **Relationships** - one-to-many (1:N), many-to-one (N:1), many-to-many (N:N)
17
+ - ✅ **Global choices (option sets)** - create, update, delete global choice lists
18
+ - ✅ **Option value management** - insert, update, delete, reorder choice options
19
+ - ✅ **Polymorphic lookups** - customer and multi-table lookup columns
20
+ - ✅ **Relationship eligibility** - check which entities can participate in relationships
21
+ - ✅ **Metadata change tracking** - RetrieveMetadataChanges with version stamps
22
+ - ✅ **Strict typing** - separate Read/Create/Update types, internal fields excluded
23
+ - ✅ **ESM-only** - works in Node 18+ and browsers
24
+
25
+ ## Installation
26
+
27
+ ```bash
28
+ pnpm add @mohsinonxrm/dataverse-sdk-metadata @mohsinonxrm/dataverse-sdk-core
29
+ ```
30
+
31
+ ## Quick Start
32
+
33
+ ```typescript
34
+ import { DataverseClient } from "@mohsinonxrm/dataverse-sdk-core";
35
+ import { MetadataClient } from "@mohsinonxrm/dataverse-sdk-metadata";
36
+
37
+ const client = new DataverseClient({
38
+ baseUrl: "https://yourorg.crm.dynamics.com",
39
+ tokenProvider: yourTokenProvider,
40
+ });
41
+
42
+ const metadataClient = new MetadataClient(client);
43
+
44
+ // Create a custom table
45
+ const entityId = await metadataClient.createEntityDefinition({
46
+ "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata",
47
+ SchemaName: "new_Project",
48
+ DisplayName: {
49
+ LocalizedLabels: [{ Label: "Project", LanguageCode: 1033 }],
50
+ },
51
+ DisplayCollectionName: {
52
+ LocalizedLabels: [{ Label: "Projects", LanguageCode: 1033 }],
53
+ },
54
+ OwnershipType: 1, // UserOwned
55
+ HasActivities: true,
56
+ HasNotes: true,
57
+ Attributes: [
58
+ // Primary name column (required)
59
+ {
60
+ "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",
61
+ SchemaName: "new_Name",
62
+ RequiredLevel: { Value: "ApplicationRequired" },
63
+ MaxLength: 100,
64
+ DisplayName: {
65
+ LocalizedLabels: [{ Label: "Name", LanguageCode: 1033 }],
66
+ },
67
+ IsPrimaryName: true,
68
+ },
69
+ ],
70
+ });
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Entity Operations
76
+
77
+ ### Create Entity
78
+
79
+ ```typescript
80
+ const metadataId = await metadataClient.createEntityDefinition({
81
+ "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata",
82
+ SchemaName: "new_Task",
83
+ DisplayName: { LocalizedLabels: [{ Label: "Task", LanguageCode: 1033 }] },
84
+ DisplayCollectionName: { LocalizedLabels: [{ Label: "Tasks", LanguageCode: 1033 }] },
85
+ Description: { LocalizedLabels: [{ Label: "Project task tracking", LanguageCode: 1033 }] },
86
+ OwnershipType: 1, // UserOwned
87
+ IsActivity: false,
88
+ HasActivities: true,
89
+ HasNotes: true,
90
+ Attributes: [
91
+ {
92
+ "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",
93
+ SchemaName: "new_Name",
94
+ DisplayName: { LocalizedLabels: [{ Label: "Task Name", LanguageCode: 1033 }] },
95
+ RequiredLevel: { Value: "ApplicationRequired" },
96
+ MaxLength: 100,
97
+ IsPrimaryName: true,
98
+ },
99
+ ],
100
+ });
101
+ ```
102
+
103
+ ### Read Entities
104
+
105
+ ```typescript
106
+ // Get all custom entities
107
+ const customEntities = await metadataClient.getEntityDefinitions({
108
+ filter: "IsCustomEntity eq true",
109
+ select: ["LogicalName", "DisplayName", "SchemaName"],
110
+ });
111
+
112
+ // Get specific entity with attributes expanded
113
+ const projectEntity = await metadataClient.getEntityDefinition("new_project", {
114
+ expand: "Attributes",
115
+ });
116
+ ```
117
+
118
+ ### Update Entity
119
+
120
+ ```typescript
121
+ // Update entity display name
122
+ await metadataClient.updateEntityDefinition("new_project", {
123
+ "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata",
124
+ DisplayName: { LocalizedLabels: [{ Label: "Project (Updated)", LanguageCode: 1033 }] },
125
+ Description: { LocalizedLabels: [{ Label: "Manage projects and tasks", LanguageCode: 1033 }] },
126
+ });
127
+ ```
128
+
129
+ ### Delete Entity
130
+
131
+ ```typescript
132
+ await metadataClient.deleteEntityDefinition("new_obsoleteentity");
133
+ ```
134
+
135
+ ---
136
+
137
+ ## Column (Attribute) Operations
138
+
139
+ ### Text Columns
140
+
141
+ #### Single Line of Text
142
+
143
+ ```typescript
144
+ await metadataClient.createAttributeDefinition("new_project", {
145
+ "@odata.type": "Microsoft.Dynamics.CRM.StringAttributeMetadata",
146
+ SchemaName: "new_ProjectCode",
147
+ DisplayName: { LocalizedLabels: [{ Label: "Project Code", LanguageCode: 1033 }] },
148
+ RequiredLevel: { Value: "None" },
149
+ MaxLength: 50,
150
+ Format: "Text",
151
+ });
152
+ ```
153
+
154
+ #### Multiple Lines of Text
155
+
156
+ ```typescript
157
+ await metadataClient.createAttributeDefinition("new_project", {
158
+ "@odata.type": "Microsoft.Dynamics.CRM.MemoAttributeMetadata",
159
+ SchemaName: "new_Description",
160
+ DisplayName: { LocalizedLabels: [{ Label: "Description", LanguageCode: 1033 }] },
161
+ RequiredLevel: { Value: "None" },
162
+ MaxLength: 2000,
163
+ Format: "TextArea",
164
+ });
165
+ ```
166
+
167
+ ### Number Columns
168
+
169
+ #### Whole Number
170
+
171
+ ```typescript
172
+ await metadataClient.createAttributeDefinition("new_project", {
173
+ "@odata.type": "Microsoft.Dynamics.CRM.IntegerAttributeMetadata",
174
+ SchemaName: "new_Priority",
175
+ DisplayName: { LocalizedLabels: [{ Label: "Priority", LanguageCode: 1033 }] },
176
+ RequiredLevel: { Value: "None" },
177
+ MinValue: 1,
178
+ MaxValue: 100,
179
+ Format: "None",
180
+ });
181
+ ```
182
+
183
+ #### Decimal Number
184
+
185
+ ```typescript
186
+ await metadataClient.createAttributeDefinition("new_project", {
187
+ "@odata.type": "Microsoft.Dynamics.CRM.DecimalAttributeMetadata",
188
+ SchemaName: "new_CompletionPercentage",
189
+ DisplayName: { LocalizedLabels: [{ Label: "Completion %", LanguageCode: 1033 }] },
190
+ RequiredLevel: { Value: "None" },
191
+ MinValue: 0,
192
+ MaxValue: 100,
193
+ Precision: 2,
194
+ });
195
+ ```
196
+
197
+ #### Currency
198
+
199
+ ```typescript
200
+ await metadataClient.createAttributeDefinition("new_project", {
201
+ "@odata.type": "Microsoft.Dynamics.CRM.MoneyAttributeMetadata",
202
+ SchemaName: "new_Budget",
203
+ DisplayName: { LocalizedLabels: [{ Label: "Budget", LanguageCode: 1033 }] },
204
+ RequiredLevel: { Value: "None" },
205
+ MinValue: 0,
206
+ MaxValue: 1000000000,
207
+ Precision: 2,
208
+ PrecisionSource: 2, // Precision = 2
209
+ });
210
+ ```
211
+
212
+ ### Date & Time
213
+
214
+ ```typescript
215
+ await metadataClient.createAttributeDefinition("new_project", {
216
+ "@odata.type": "Microsoft.Dynamics.CRM.DateTimeAttributeMetadata",
217
+ SchemaName: "new_DueDate",
218
+ DisplayName: { LocalizedLabels: [{ Label: "Due Date", LanguageCode: 1033 }] },
219
+ RequiredLevel: { Value: "None" },
220
+ Format: "DateOnly", // or 'DateAndTime'
221
+ ImeMode: "Disabled",
222
+ });
223
+ ```
224
+
225
+ ### Choice (Local)
226
+
227
+ ```typescript
228
+ await metadataClient.createAttributeDefinition("new_project", {
229
+ "@odata.type": "Microsoft.Dynamics.CRM.PicklistAttributeMetadata",
230
+ SchemaName: "new_Status",
231
+ DisplayName: { LocalizedLabels: [{ Label: "Status", LanguageCode: 1033 }] },
232
+ RequiredLevel: { Value: "None" },
233
+ OptionSet: {
234
+ "@odata.type": "Microsoft.Dynamics.CRM.OptionSetMetadata",
235
+ IsGlobal: false,
236
+ Options: [
237
+ { Value: 1, Label: { LocalizedLabels: [{ Label: "Not Started", LanguageCode: 1033 }] } },
238
+ { Value: 2, Label: { LocalizedLabels: [{ Label: "In Progress", LanguageCode: 1033 }] } },
239
+ { Value: 3, Label: { LocalizedLabels: [{ Label: "Completed", LanguageCode: 1033 }] } },
240
+ ],
241
+ },
242
+ });
243
+ ```
244
+
245
+ ### Yes/No (Boolean)
246
+
247
+ ```typescript
248
+ await metadataClient.createAttributeDefinition("new_project", {
249
+ "@odata.type": "Microsoft.Dynamics.CRM.BooleanAttributeMetadata",
250
+ SchemaName: "new_IsActive",
251
+ DisplayName: { LocalizedLabels: [{ Label: "Is Active", LanguageCode: 1033 }] },
252
+ RequiredLevel: { Value: "None" },
253
+ DefaultValue: true,
254
+ OptionSet: {
255
+ "@odata.type": "Microsoft.Dynamics.CRM.BooleanOptionSetMetadata",
256
+ TrueOption: { Value: 1, Label: { LocalizedLabels: [{ Label: "Yes", LanguageCode: 1033 }] } },
257
+ FalseOption: { Value: 0, Label: { LocalizedLabels: [{ Label: "No", LanguageCode: 1033 }] } },
258
+ },
259
+ });
260
+ ```
261
+
262
+ ### Lookup (Single-table)
263
+
264
+ ```typescript
265
+ // Create 1:N relationship (creates lookup column on related entity)
266
+ const relationshipId = await metadataClient.createOneToManyRelationship({
267
+ "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
268
+ SchemaName: "new_project_tasks",
269
+ ReferencedEntity: "new_project",
270
+ ReferencedAttribute: "new_projectid",
271
+ ReferencingEntity: "new_task",
272
+ Lookup: {
273
+ SchemaName: "new_ProjectId",
274
+ DisplayName: { LocalizedLabels: [{ Label: "Project", LanguageCode: 1033 }] },
275
+ RequiredLevel: { Value: "ApplicationRequired" },
276
+ },
277
+ });
278
+ ```
279
+
280
+ ### File Column
281
+
282
+ ```typescript
283
+ await metadataClient.createAttributeDefinition("new_project", {
284
+ "@odata.type": "Microsoft.Dynamics.CRM.FileAttributeMetadata",
285
+ SchemaName: "new_Attachment",
286
+ DisplayName: { LocalizedLabels: [{ Label: "Attachment", LanguageCode: 1033 }] },
287
+ RequiredLevel: { Value: "None" },
288
+ MaxSizeInKB: 32768, // 32 MB
289
+ });
290
+ ```
291
+
292
+ ### Image Column
293
+
294
+ ```typescript
295
+ await metadataClient.createAttributeDefinition("new_project", {
296
+ "@odata.type": "Microsoft.Dynamics.CRM.ImageAttributeMetadata",
297
+ SchemaName: "new_Logo",
298
+ DisplayName: { LocalizedLabels: [{ Label: "Project Logo", LanguageCode: 1033 }] },
299
+ RequiredLevel: { Value: "None" },
300
+ MaxSizeInKB: 10240, // 10 MB
301
+ CanStoreFullImage: true,
302
+ });
303
+ ```
304
+
305
+ ---
306
+
307
+ ## Relationship Operations
308
+
309
+ ### One-to-Many (1:N) Relationship
310
+
311
+ ```typescript
312
+ // Create relationship (creates lookup on "many" side)
313
+ const relationshipId = await metadataClient.createOneToManyRelationship({
314
+ "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
315
+ SchemaName: "new_account_projects",
316
+ ReferencedEntity: "account", // "One" side (parent)
317
+ ReferencedAttribute: "accountid",
318
+ ReferencingEntity: "new_project", // "Many" side (child)
319
+ Lookup: {
320
+ SchemaName: "new_AccountId",
321
+ DisplayName: { LocalizedLabels: [{ Label: "Account", LanguageCode: 1033 }] },
322
+ RequiredLevel: { Value: "None" },
323
+ },
324
+ });
325
+ ```
326
+
327
+ ### Many-to-Many (N:N) Relationship
328
+
329
+ ```typescript
330
+ // Create N:N relationship (creates intersect table)
331
+ const relationshipId = await metadataClient.createManyToManyRelationship({
332
+ "@odata.type": "Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata",
333
+ SchemaName: "new_project_contact",
334
+ Entity1LogicalName: "new_project",
335
+ Entity2LogicalName: "contact",
336
+ IntersectEntityName: "new_project_contact",
337
+ Entity1NavigationPropertyName: "new_project_contact_projects",
338
+ Entity2NavigationPropertyName: "new_project_contact_contacts",
339
+ });
340
+ ```
341
+
342
+ ### Read Relationships
343
+
344
+ ```typescript
345
+ // Get all 1:N relationships for an entity
346
+ const oneToManyRels = await metadataClient.getOneToManyRelationships("new_project", {
347
+ select: ["SchemaName", "ReferencedEntity", "ReferencingEntity"],
348
+ });
349
+
350
+ // Get all N:N relationships
351
+ const manyToManyRels = await metadataClient.getManyToManyRelationships("new_project");
352
+ ```
353
+
354
+ ---
355
+
356
+ ## Global Choice (Option Set) Operations
357
+
358
+ ### Create Global Choice
359
+
360
+ ```typescript
361
+ const optionSetId = await metadataClient.createGlobalOptionSet({
362
+ "@odata.type": "Microsoft.Dynamics.CRM.OptionSetMetadata",
363
+ Name: "new_projecttype",
364
+ DisplayName: { LocalizedLabels: [{ Label: "Project Type", LanguageCode: 1033 }] },
365
+ IsGlobal: true,
366
+ OptionSetType: "Picklist",
367
+ Options: [
368
+ { Value: 100000, Label: { LocalizedLabels: [{ Label: "Internal", LanguageCode: 1033 }] } },
369
+ { Value: 100001, Label: { LocalizedLabels: [{ Label: "External", LanguageCode: 1033 }] } },
370
+ { Value: 100002, Label: { LocalizedLabels: [{ Label: "Research", LanguageCode: 1033 }] } },
371
+ ],
372
+ });
373
+ ```
374
+
375
+ ### Use Global Choice in Column
376
+
377
+ ```typescript
378
+ // Reference global choice when creating attribute
379
+ await metadataClient.createAttributeDefinition("new_project", {
380
+ "@odata.type": "Microsoft.Dynamics.CRM.PicklistAttributeMetadata",
381
+ SchemaName: "new_Type",
382
+ DisplayName: { LocalizedLabels: [{ Label: "Type", LanguageCode: 1033 }] },
383
+ RequiredLevel: { Value: "None" },
384
+ GlobalOptionSet: {
385
+ "@odata.bind": `/GlobalOptionSetDefinitions(Name='new_projecttype')`,
386
+ },
387
+ });
388
+ ```
389
+
390
+ ### Insert Option Value
391
+
392
+ ```typescript
393
+ // Add new option to existing global choice
394
+ const result = await metadataClient.insertOptionValue({
395
+ OptionSetName: "new_projecttype",
396
+ Label: { LocalizedLabels: [{ Label: "Maintenance", LanguageCode: 1033 }] },
397
+ Value: 100003, // Optional, auto-assigned if omitted
398
+ });
399
+
400
+ console.log("New option value:", result.NewOptionValue);
401
+ ```
402
+
403
+ ---
404
+
405
+ ## Polymorphic (Multi-table) Lookup Operations
406
+
407
+ ### Customer Lookup
408
+
409
+ ```typescript
410
+ // Create customer lookup (targets account OR contact)
411
+ const result = await metadataClient.createCustomerRelationships({
412
+ Lookup: {
413
+ "@odata.type": "Microsoft.Dynamics.CRM.LookupAttributeMetadata",
414
+ SchemaName: "new_CustomerId",
415
+ DisplayName: { LocalizedLabels: [{ Label: "Customer", LanguageCode: 1033 }] },
416
+ RequiredLevel: { Value: "ApplicationRequired" },
417
+ },
418
+ OneToManyRelationships: [
419
+ {
420
+ "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
421
+ SchemaName: "new_account_projects",
422
+ ReferencedEntity: "account",
423
+ ReferencedAttribute: "accountid",
424
+ ReferencingEntity: "new_project",
425
+ },
426
+ {
427
+ "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
428
+ SchemaName: "new_contact_projects",
429
+ ReferencedEntity: "contact",
430
+ ReferencedAttribute: "contactid",
431
+ ReferencingEntity: "new_project",
432
+ },
433
+ ],
434
+ });
435
+ ```
436
+
437
+ ### Custom Polymorphic Lookup
438
+
439
+ ```typescript
440
+ // Create lookup targeting multiple custom entities
441
+ const result = await metadataClient.createPolymorphicLookupAttribute({
442
+ OneToManyRelationships: [
443
+ {
444
+ "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
445
+ SchemaName: "new_task_regarding_project",
446
+ ReferencedEntity: "new_project",
447
+ ReferencedAttribute: "new_projectid",
448
+ ReferencingEntity: "new_task",
449
+ },
450
+ {
451
+ "@odata.type": "Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata",
452
+ SchemaName: "new_task_regarding_milestone",
453
+ ReferencedEntity: "new_milestone",
454
+ ReferencedAttribute: "new_milestoneid",
455
+ ReferencingEntity: "new_task",
456
+ },
457
+ ],
458
+ Lookup: {
459
+ SchemaName: "new_RegardingId",
460
+ DisplayName: { LocalizedLabels: [{ Label: "Regarding", LanguageCode: 1033 }] },
461
+ RequiredLevel: { Value: "None" },
462
+ },
463
+ });
464
+ ```
465
+
466
+ ---
467
+
468
+ ## Relationship Eligibility Checks
469
+
470
+ ```typescript
471
+ // Check if entity can be referenced (parent in 1:N)
472
+ const canBeReferenced = await metadataClient.canBeReferenced("new_project");
473
+ console.log("Can be parent:", canBeReferenced.CanBeReferenced);
474
+
475
+ // Check if entity can reference others (child in 1:N)
476
+ const canBeReferencing = await metadataClient.canBeReferencing("new_task");
477
+ console.log("Can be child:", canBeReferencing.CanBeReferencing);
478
+
479
+ // Check if entity can participate in N:N
480
+ const canManyToMany = await metadataClient.canManyToMany("new_project");
481
+ console.log("Can do N:N:", canManyToMany.CanManyToMany);
482
+
483
+ // Get valid entities for N:N relationships
484
+ const validEntities = await metadataClient.getValidManyToMany("new_project");
485
+ console.log("Valid N:N partners:", validEntities.EntityNames);
486
+ ```
487
+
488
+ ---
489
+
490
+ ## RetrieveMetadataChanges
491
+
492
+ Track metadata changes using version stamps for incremental sync:
493
+
494
+ ```typescript
495
+ // Initial query (get all + version stamp)
496
+ const result = await metadataClient.retrieveMetadataChanges(
497
+ {
498
+ Criteria: {
499
+ FilterOperator: "And",
500
+ Conditions: [{ PropertyName: "IsCustomEntity", Value: true }],
501
+ },
502
+ Properties: {
503
+ PropertyNames: ["LogicalName", "DisplayName", "Attributes"],
504
+ },
505
+ },
506
+ "Entity" // Track entity deletions
507
+ );
508
+
509
+ console.log("Entities:", result.EntityMetadata);
510
+ console.log("Server version:", result.ServerVersionStamp);
511
+
512
+ // Later: get only changes since last sync
513
+ const changes = await metadataClient.retrieveMetadataChanges(
514
+ {
515
+ Criteria: {
516
+ FilterOperator: "And",
517
+ Conditions: [{ PropertyName: "IsCustomEntity", Value: true }],
518
+ },
519
+ Properties: {
520
+ PropertyNames: ["LogicalName", "DisplayName"],
521
+ },
522
+ },
523
+ "Entity",
524
+ result.ServerVersionStamp // Pass previous stamp
525
+ );
526
+
527
+ console.log("Changed entities:", changes.EntityMetadata);
528
+ console.log("Deleted entities:", changes.DeletedMetadata);
529
+ ```
530
+
531
+ ---
532
+
533
+ ## Important Notes
534
+
535
+ ### Update Operations Use PUT
536
+
537
+ Per Microsoft documentation, all metadata update operations use HTTP PUT (not PATCH). This means you must send the complete definition with all properties, not just the changed ones:
538
+
539
+ ```typescript
540
+ // Update entity - requires complete definition
541
+ await metadataClient.updateEntityDefinition("new_project", {
542
+ "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata",
543
+ DisplayName: {
544
+ LocalizedLabels: [{ Label: "Updated Project", LanguageCode: 1033 }],
545
+ },
546
+ Description: {
547
+ LocalizedLabels: [{ Label: "Updated description", LanguageCode: 1033 }],
548
+ },
549
+ // Include all other properties you want to preserve
550
+ });
551
+ ```
552
+
553
+ The SDK automatically sets the `MSCRM.MergeLabels: true` header to merge labels instead of replacing them, preserving labels for other languages.
554
+
555
+ ### Strict Typing
556
+
557
+ The metadata package uses strict type separation:
558
+
559
+ - **Read types** - include all properties returned from the server (e.g., `EntityMetadata`)
560
+ - **Create types** - exclude read-only and internal properties (e.g., `EntityMetadataCreate`)
561
+ - **Update types** - similar to Create but may have different required fields (e.g., `EntityMetadataUpdate`)
562
+
563
+ This ensures you cannot accidentally send read-only fields like `MetadataId`, `ObjectTypeCode`, or internal-use fields in create/update operations.
564
+
565
+ ---
566
+
567
+ ## TypeScript Examples
568
+
569
+ All examples in this README use TypeScript. For pure JavaScript, omit type annotations:
570
+
571
+ ```javascript
572
+ // JavaScript equivalent
573
+ const metadataClient = new MetadataClient(client);
574
+
575
+ const entityId = await metadataClient.createEntityDefinition({
576
+ "@odata.type": "Microsoft.Dynamics.CRM.EntityMetadata",
577
+ SchemaName: "new_Project",
578
+ DisplayName: {
579
+ LocalizedLabels: [{ Label: "Project", LanguageCode: 1033 }],
580
+ },
581
+ // ... rest of definition
582
+ });
583
+ ```
584
+
585
+ ---
586
+
587
+ ## License
588
+
589
+ This package is part of the `dataverse-sdk-typescript` monorepo and is licensed under **GNU AGPL v3.0**. See [LICENSE](../../LICENSE) for details.
590
+
591
+ ### Publishing Changes
592
+
593
+ Metadata changes must be published before they take effect in the application. Use PublishXml or PublishAllXml actions from the messages package.
594
+
595
+ ## License
596
+
597
+ GNU AGPL v3.0
598
+
599
+ ## Related Packages
600
+
601
+ - [@mohsinonxrm/dataverse-sdk-core](../dataverse-sdk-core) - Core client and request builder
602
+ - [@mohsinonxrm/dataverse-sdk-messages](../dataverse-sdk-messages) - SDK messages including PublishXml