@datocms/cma-client 5.1.12 → 5.1.13

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 CHANGED
@@ -1,20 +1,195 @@
1
- [![Node.js CI](https://github.com/datocms/js-rest-api-clients/actions/workflows/node.js.yml/badge.svg)](https://github.com/datocms/js-rest-api-clients/actions/workflows/node.js.yml)
1
+ # DatoCMS Content Management API Utilities
2
2
 
3
- # DatoCMS Content Management JS API Client (Common)
3
+ Take a look at the full [API documentation](https://www.datocms.com/docs/content-management-api) for examples!
4
4
 
5
- API client for [DatoCMS](https://www.datocms.com). Take a look at the full [API documentation](https://www.datocms.com/docs/content-management-api) for examples.
5
+ ## Field Types
6
6
 
7
- <br /><br />
8
- <a href="https://www.datocms.com/">
9
- <img src="https://www.datocms.com/images/full_logo.svg" height="60">
10
- </a>
11
- <br /><br />
7
+ This library provides comprehensive TypeScript type definitions and utilities for all DatoCMS field types. Each field type includes type guards, validation functions, localization support, and editor appearance configurations.
12
8
 
13
- ## Utility Functions
9
+ ### What's available
14
10
 
15
- This library provides a comprehensive set of utility functions to work with DatoCMS records, blocks, and field values. These utilities make it easier to manipulate, traverse, and inspect your content programmatically.
11
+ Every field type follows a consistent pattern providing:
16
12
 
17
- ### 1. Record Inspection Utilities
13
+ - **Field value types**: TypeScript definitions for the field's data structure
14
+ - **Type guards**: Functions to validate field values at runtime
15
+ - **Localization support**: Utilities for handling localized field variants
16
+ - **Validation types**: Supported validators for the field type
17
+ - **Appearance configuration**: Editor types and their configuration options
18
+
19
+ **Example: `lat_lon` Field Type**
20
+
21
+ ```typescript
22
+ import { LatLonFieldValue, isLatLonFieldValue, isLocalizedLatLonFieldValue } from '@datocms/cma-client';
23
+ import type { LatLonFieldValidators, LatLonFieldAppearance } from '@datocms/cma-client';
24
+
25
+ // Field value type - can be boolean or null
26
+ const value: LatLonFieldValue = true;
27
+
28
+ // Type guard functions for validation
29
+ if (isLatLonFieldValue(someValue)) {
30
+ // someValue is guaranteed to be boolean | null
31
+ }
32
+
33
+ if (isLocalizedLatLonFieldValue(localizedValue)) {
34
+ // localizedValue is a localized boolean field
35
+ }
36
+
37
+ // Validator and appearance types available for type-safe configuration
38
+ type Validators = LatLonFieldValidators;
39
+ type Appearance = LatLonFieldAppearance;
40
+ ```
41
+
42
+ ### Context-Dependent field types
43
+
44
+ Some field types have different value formats depending on the API context (request vs response) or query parameters:
45
+
46
+ #### Request vs Response variations
47
+
48
+ **File and Gallery fields** have different type requirements for API requests versus responses:
49
+
50
+ ```typescript
51
+ import {
52
+ FileFieldValue,
53
+ FileFieldValueInRequest,
54
+ GalleryFieldValue,
55
+ GalleryFieldValueInRequest,
56
+ // Type guards for runtime validation
57
+ isFileFieldValue,
58
+ isFileFieldValueInRequest,
59
+ isGalleryFieldValue,
60
+ isGalleryFieldValueInRequest
61
+ } from '@datocms/cma-client';
62
+
63
+ // API Response format - all metadata fields present with defaults
64
+ const fileResponse: FileFieldValue = {
65
+ upload_id: "12345",
66
+ alt: null, // Always present (default: null)
67
+ title: null, // Always present (default: null)
68
+ custom_data: {}, // Always present (default: {})
69
+ focal_point: null // Always present (default: null)
70
+ };
71
+
72
+ // API Request format - metadata fields are optional
73
+ const fileRequest: FileFieldValueInRequest = {
74
+ upload_id: "12345"
75
+ // alt, title, custom_data, focal_point are optional
76
+ };
77
+
78
+ // Runtime validation for different contexts
79
+ if (isFileFieldValueInRequest(someFileValue)) {
80
+ // someFileValue has optional metadata fields
81
+ }
82
+
83
+ if (isGalleryFieldValue(someGalleryValue)) {
84
+ // someGalleryValue is array of files with all metadata present
85
+ }
86
+ ```
87
+
88
+ #### "Nested Mode" Response variations
89
+
90
+ **Block-containing fields** (`structured_text`, `single_block`, `rich_text`) support different block representations for regular responses, for ["Nested Mode" responses](https://www.datocms.com/docs/content-management-api/resources/item#api-response-modes-regular-vs-nested), and for requests:
91
+
92
+ ```typescript
93
+ import {
94
+ StructuredTextFieldValue,
95
+ StructuredTextFieldValueInRequest,
96
+ StructuredTextFieldValueInNestedResponse,
97
+ // Type guards for all variations (also available for single_block and rich_text)
98
+ isStructuredTextFieldValue,
99
+ isStructuredTextFieldValueInRequest,
100
+ isStructuredTextFieldValueInNestedResponse
101
+ } from '@datocms/cma-client';
102
+
103
+ // Regular response - blocks as string IDs
104
+ const standard: StructuredTextFieldValue = {
105
+ document: {
106
+ type: "root",
107
+ children: [
108
+ {
109
+ type: "block",
110
+ // String ID reference
111
+ item: "IdMLV2GJTXyQ0Bfns7R4IQ"
112
+ }
113
+ ]
114
+ }
115
+ };
116
+
117
+ // Nested Mode response (?nested=true) - blocks as full objects
118
+ const nested: StructuredTextFieldValueInNestedResponse = {
119
+ document: {
120
+ type: "root",
121
+ children: [
122
+ {
123
+ type: "block",
124
+ // Always full block object
125
+ item: {
126
+ id: "IdMLV2GJTXyQ0Bfns7R4IQ",
127
+ type: "item",
128
+ attributes: { /* ... */ },
129
+ relationships: { /* ... */ }
130
+ }
131
+ }
132
+ ]
133
+ }
134
+ };
135
+
136
+ // Request format - flexible block representation
137
+ const request: StructuredTextFieldValueInRequest = {
138
+ document: {
139
+ type: "root",
140
+ children: [
141
+ {
142
+ type: "block",
143
+ // Can be string ID, to keep block unchanged...
144
+ item: "FicV5CxCSQ6yOrgfwRoiKA"
145
+ },
146
+ {
147
+ type: "block",
148
+ // ...or full block object (to create new blocks or update existing ones)
149
+ item: {
150
+ type: "item",
151
+ attributes: { /* ... */ },
152
+ relationships: { /* ... */ }
153
+ }
154
+ }
155
+ ]
156
+ }
157
+ };
158
+
159
+ // Runtime validation for different contexts
160
+ if (isStructuredTextFieldValueInNestedResponse(someStructuredText)) {
161
+ // someStructuredText has blocks as full objects
162
+ }
163
+
164
+ if (isStructuredTextFieldValueInRequest(requestData)) {
165
+ // requestData allows flexible block representations
166
+ }
167
+ ```
168
+
169
+ These variants ensure type safety across different API contexts while maintaining the same conceptual data structure. All localized variants also have corresponding type guards (e.g., `isLocalizedStructuredTextFieldValueInRequest`, `isLocalizedStructuredTextFieldValueInNestedResponse`, etc.).
170
+
171
+ **TypeScript Generics Support:** For maximum type safety, all field value types and type guards for block-containing fields accept [`ItemTypeDefinition` generics](https://www.datocms.com/docs/content-management-api/resources/item#type-safe-development-with-typescript) to provide precise typing for your specific schema:
172
+
173
+ ```typescript
174
+ import type { MyArticle, MyArticleSection } from './schema';
175
+
176
+ // Fully typed structured text with specific block types
177
+ const content: StructuredTextFieldValueInRequest<MyArticleSection> = {
178
+ document: {
179
+ type: "root",
180
+ children: [/* ... */]
181
+ }
182
+ };
183
+
184
+ // Type guard with generic for precise validation
185
+ if (isStructuredTextFieldValueInNestedResponse<MyArticleSection>(value)) {
186
+ // value is now typed with your specific block schema
187
+ }
188
+ ```
189
+
190
+ ## Block Processing Utilities
191
+
192
+ ### Inspecting Records and Blocks
18
193
 
19
194
  The `inspectItem()` function provides a visual, tree-structured representation of DatoCMS records in the console, making it easier to debug and understand complex content structures.
20
195
 
@@ -59,13 +234,49 @@ console.log(inspectItem(record));
59
234
  ```
60
235
  </details>
61
236
 
62
- ### 2. Block Processing Utilities
237
+ ### Creating and Duplicating Blocks
238
+
239
+ <details>
240
+ <summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
241
+
242
+ Converts a block data object into the proper format for API requests.
243
+
244
+ **TypeScript Signature:**
245
+ ```typescript
246
+ function buildBlockRecord<D extends ItemTypeDefinition>(
247
+ body: ItemUpdateSchema<ToItemDefinitionInRequest<D>>
248
+ ): NewBlockInRequest<ToItemDefinitionInRequest<D>>
249
+ ```
250
+
251
+ **Parameters:**
252
+ - `body`: Block data in update schema format
253
+
254
+ **Returns:** Formatted block record ready for API requests
255
+ </details>
256
+
257
+ <details>
258
+ <summary><strong>duplicateBlockRecord()</strong> - Deep clone blocks with nested content</summary>
259
+
260
+ Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
261
+
262
+ **TypeScript Signature:**
263
+ ```typescript
264
+ async function duplicateBlockRecord<D extends ItemTypeDefinition>(
265
+ existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionInNestedResponse<D>>,
266
+ schemaRepository: SchemaRepository
267
+ ): Promise<NewBlockInRequest<ToItemDefinitionInRequest<D>>>
268
+ ```
269
+
270
+ **Parameters:**
271
+ - `existingBlock`: The block to duplicate
272
+ - `schemaRepository`: Repository for schema lookups
63
273
 
64
- These utilities provide a unified interface for working with blocks embedded within DatoCMS field values. DatoCMS supports three field types that can contain blocks: Modular Content (arrays of blocks), Single Block fields, and Structured Text (with embedded blocks). These functions abstract away the differences between field types, providing consistent APIs for common operations.
274
+ **Returns:** New block record without IDs, ready to be created
275
+ </details>
65
276
 
66
- #### Recursive Block Operations
277
+ ### Recursive Block Operations
67
278
 
68
- These functions traverse blocks recursively, processing nested blocks within blocks. They require a `SchemaRepository` instance to look up field definitions for nested blocks.
279
+ DatoCMS supports three field types that can contain blocks: Modular Content (arrays of blocks), Single Block fields, and Structured Text (rich-text with embedded blocks). These functions abstract away the differences between field types and can traverse blocks recursively, processing nested blocks within blocks. They require a `SchemaRepository` instance to look up field definitions for nested blocks.
69
280
 
70
281
  <details>
71
282
  <summary><strong>visitBlocksInNonLocalizedFieldValue()</strong> - Recursively visit all blocks</summary>
@@ -79,17 +290,14 @@ async function visitBlocksInNonLocalizedFieldValue(
79
290
  fieldType: string,
80
291
  schemaRepository: SchemaRepository,
81
292
  visitor: (item: BlockInRequest, path: TreePath) => void | Promise<void>,
82
- path?: TreePath
83
293
  ): Promise<void>
84
294
  ```
85
295
 
86
296
  **Parameters:**
87
297
  - `nonLocalizedFieldValue`: The non-localized field value
88
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
298
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
89
299
  - `schemaRepository`: Repository for caching schema lookups
90
300
  - `visitor`: Function called for each block (including nested)
91
- - `path`: Optional base path for tracking location
92
- ```
93
301
  </details>
94
302
 
95
303
  <details>
@@ -104,13 +312,12 @@ async function mapBlocksInNonLocalizedFieldValue(
104
312
  fieldType: string,
105
313
  schemaRepository: SchemaRepository,
106
314
  mapper: (item: BlockInRequest, path: TreePath) => BlockInRequest | Promise<BlockInRequest>,
107
- path?: TreePath
108
315
  ): Promise<unknown>
109
316
  ```
110
317
 
111
318
  **Parameters:**
112
319
  - `nonLocalizedFieldValue`: The non-localized field value
113
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
320
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
114
321
  - `schemaRepository`: Repository for caching schema lookups
115
322
  - `mapper`: Function that transforms each block
116
323
 
@@ -129,13 +336,12 @@ async function filterBlocksInNonLocalizedFieldValue(
129
336
  fieldType: string,
130
337
  schemaRepository: SchemaRepository,
131
338
  predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
132
- path?: TreePath
133
339
  ): Promise<unknown>
134
340
  ```
135
341
 
136
342
  **Parameters:**
137
343
  - `nonLocalizedFieldValue`: The non-localized field value to filter
138
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
344
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
139
345
  - `schemaRepository`: Repository for caching schema lookups
140
346
  - `predicate`: Function that tests each block
141
347
 
@@ -165,13 +371,12 @@ async function findAllBlocksInNonLocalizedFieldValue(
165
371
  fieldType: string,
166
372
  schemaRepository: SchemaRepository,
167
373
  predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
168
- path?: TreePath
169
374
  ): Promise<Array<{ item: BlockInRequest; path: TreePath }>>
170
375
  ```
171
376
 
172
377
  **Parameters:**
173
378
  - `nonLocalizedFieldValue`: The non-localized field value to search
174
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
379
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
175
380
  - `schemaRepository`: Repository for caching schema lookups
176
381
  - `predicate`: Function that tests each block
177
382
 
@@ -191,19 +396,17 @@ async function reduceBlocksInNonLocalizedFieldValue<R>(
191
396
  schemaRepository: SchemaRepository,
192
397
  reducer: (accumulator: R, item: BlockInRequest, path: TreePath) => R | Promise<R>,
193
398
  initialValue: R,
194
- path?: TreePath
195
399
  ): Promise<R>
196
400
  ```
197
401
 
198
402
  **Parameters:**
199
403
  - `nonLocalizedFieldValue`: The non-localized field value to reduce
200
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
404
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
201
405
  - `schemaRepository`: Repository for caching schema lookups
202
406
  - `reducer`: Function that processes each block
203
407
  - `initialValue`: Initial accumulator value
204
408
 
205
409
  **Returns:** The final accumulated value
206
- ```
207
410
  </details>
208
411
 
209
412
  <details>
@@ -218,18 +421,16 @@ async function someBlocksInNonLocalizedFieldValue(
218
421
  fieldType: string,
219
422
  schemaRepository: SchemaRepository,
220
423
  predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
221
- path?: TreePath
222
424
  ): Promise<boolean>
223
425
  ```
224
426
 
225
427
  **Parameters:**
226
428
  - `nonLocalizedFieldValue`: The non-localized field value to test
227
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
429
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
228
430
  - `schemaRepository`: Repository for caching schema lookups
229
431
  - `predicate`: Function that tests each block
230
432
 
231
433
  **Returns:** True if any block matches
232
- ```
233
434
  </details>
234
435
 
235
436
  <details>
@@ -244,79 +445,22 @@ async function everyBlockInNonLocalizedFieldValue(
244
445
  fieldType: string,
245
446
  schemaRepository: SchemaRepository,
246
447
  predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
247
- path?: TreePath
248
448
  ): Promise<boolean>
249
449
  ```
250
450
 
251
451
  **Parameters:**
252
452
  - `nonLocalizedFieldValue`: The non-localized field value to test
253
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
453
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
254
454
  - `schemaRepository`: Repository for caching schema lookups
255
455
  - `predicate`: Function that tests each block
256
456
 
257
457
  **Returns:** True if all blocks match
258
458
  </details>
259
459
 
260
- #### Block Record Management
261
-
262
- <details>
263
- <summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
264
-
265
- Converts a block data object into the proper format for API requests.
266
-
267
- **TypeScript Signature:**
268
- ```typescript
269
- function buildBlockRecord<D extends ItemTypeDefinition>(
270
- body: ItemUpdateSchema<ToItemDefinitionInRequest<D>>
271
- ): NewBlockInRequest<ToItemDefinitionInRequest<D>>
272
- ```
273
-
274
- **Parameters:**
275
- - `body`: Block data in update schema format
276
-
277
- **Returns:** Formatted block record ready for API requests
278
- </details>
279
-
280
- <details>
281
- <summary><strong>duplicateBlockRecord()</strong> - Deep clone blocks with nested content</summary>
282
-
283
- Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
284
-
285
- **TypeScript Signature:**
286
- ```typescript
287
- async function duplicateBlockRecord<D extends ItemTypeDefinition>(
288
- existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionInNestedResponse<D>>,
289
- schemaRepository: SchemaRepository
290
- ): Promise<NewBlockInRequest<ToItemDefinitionInRequest<D>>>
291
- ```
292
-
293
- **Parameters:**
294
- - `existingBlock`: The block to duplicate
295
- - `schemaRepository`: Repository for schema lookups
296
-
297
- **Returns:** New block record without IDs, ready to be created
298
- </details>
299
-
300
- ### 3. Localization-Aware Field Utilities
460
+ ## Unified Field Processing (Localized & Non-Localized)
301
461
 
302
462
  These utilities provide a unified interface for working with DatoCMS field values that may or may not be localized. They eliminate the need for conditional logic when processing fields that could be either localized or non-localized.
303
463
 
304
- <details>
305
- <summary><strong>isLocalized()</strong> - Check if a field is localized</summary>
306
-
307
- Determines whether a DatoCMS field is configured for localization.
308
-
309
- **TypeScript Signature:**
310
- ```typescript
311
- function isLocalized(field: Field): boolean
312
- ```
313
-
314
- **Parameters:**
315
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
316
-
317
- **Returns:** True if the field is localized, false otherwise
318
- </details>
319
-
320
464
  <details>
321
465
  <summary><strong>mapNormalizedFieldValues() / mapNormalizedFieldValuesAsync()</strong> - Transform field values</summary>
322
466
 
@@ -338,7 +482,7 @@ async function mapNormalizedFieldValuesAsync<TInput, TOutput>(
338
482
  ```
339
483
 
340
484
  **Parameters:**
341
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
485
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
342
486
  - `nonLocalizedFieldValue`: The non-localized field value (localized or non-localized)
343
487
  - `mapFn`: Function to transform each value (receives locale for localized fields, undefined for non-localized)
344
488
 
@@ -366,7 +510,7 @@ async function filterNormalizedFieldValuesAsync<T>(
366
510
  ```
367
511
 
368
512
  **Parameters:**
369
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
513
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
370
514
  - `nonLocalizedFieldValue`: The non-localized field value to filter
371
515
  - `filterFn`: Predicate function for filtering
372
516
 
@@ -394,7 +538,7 @@ async function visitNormalizedFieldValuesAsync<T>(
394
538
  ```
395
539
 
396
540
  **Parameters:**
397
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
541
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
398
542
  - `nonLocalizedFieldValue`: The non-localized field value to visit
399
543
  - `visitFn`: Function called for each value
400
544
  </details>
@@ -420,7 +564,7 @@ async function someNormalizedFieldValuesAsync<T>(
420
564
  ```
421
565
 
422
566
  **Parameters:**
423
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
567
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
424
568
  - `nonLocalizedFieldValue`: The non-localized field value to test
425
569
  - `testFn`: Predicate function
426
570
 
@@ -448,7 +592,7 @@ async function everyNormalizedFieldValueAsync<T>(
448
592
  ```
449
593
 
450
594
  **Parameters:**
451
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
595
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
452
596
  - `nonLocalizedFieldValue`: The non-localized field value to test
453
597
  - `testFn`: Predicate function
454
598
 
@@ -479,7 +623,7 @@ type NormalizedFieldValueEntry<T> = {
479
623
  ```
480
624
 
481
625
  **Parameters:**
482
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
626
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
483
627
  - `nonLocalizedFieldValue`/`entries non-localized`: Value to convert from/to
484
628
 
485
629
  **Returns:** Normalized entries array or reconstructed field value
@@ -497,25 +641,57 @@ const processed = entries.map(({ locale, value }) => ({
497
641
 
498
642
  // Convert back to field value format
499
643
  const result = fromNormalizedFieldValueEntries(field, processed);
500
- ```
501
644
  </details>
502
645
 
503
- ### 4. Schema Repository
646
+ ### 4. SchemaRepository
504
647
 
505
- The `SchemaRepository` class provides an in-memory caching system for DatoCMS schema entities, significantly improving performance when working with complex content structures.
648
+ The `SchemaRepository` class provides a lightweight, in-memory cache for DatoCMS schema entities (item types, fields, fieldsets, and plugins). It helps avoid redundant API calls when working across multiple functions or utilities that require schema lookups.
506
649
 
507
- <details>
508
- <summary><strong>SchemaRepository</strong> - Cache schema entities for performance</summary>
650
+ **Why use it?**
651
+
652
+ - **Cache once, reuse everywhere**: The first API call stores results in memory; all subsequent lookups are instant.
653
+ - **Efficient schema access**: Retrieve entities by ID, API key, or package name without re-fetching.
654
+ - **Optimized for block processing**: Essential for utilities like `mapBlocksInNonLocalizedFieldValue`.
655
+ - **Fewer API calls**: Dramatically speeds up bulk operations and complex traversals.
656
+
657
+ **Usage Example:**
658
+ ```typescript
659
+ const schemaRepository = new SchemaRepository(client);
660
+
661
+ // First call: fetches from API and caches result
662
+ const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
663
+ const fields = await schemaRepository.getItemTypeFields(blogPost);
664
+
665
+ // Next calls: resolved instantly from cache (no API calls)
666
+ const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
667
+ const sameFields = await schemaRepository.getItemTypeFields(blogPost);
668
+
669
+ // Works seamlessly with block-processing utilities
670
+ await mapBlocksInNonLocalizedFieldValue(
671
+ fieldValue,
672
+ field,
673
+ schemaRepository, // share cached lookups
674
+ async (block) => {
675
+ // transform block here
676
+ }
677
+ );
678
+ ```
679
+
680
+ **When to Use**
681
+
682
+ * Traversing relationships that repeatedly query schema
683
+ * Bulk record processing scripts
684
+ * Block-processing utilities that need frequent lookups
685
+ * Any script where reducing API calls matters
509
686
 
510
- Repository for DatoCMS schema entities including item types, fields, fieldsets, and plugins. Provides caching and efficient lookup functionality for schema-related operations.
687
+ **When Not to Use**
511
688
 
512
- **Key Features:**
513
- - Automatic caching of schema entities after first fetch
514
- - Efficient lookups by ID, API key, or package name
515
- - Essential for recursive block operations
516
- - Dramatically reduces API calls during complex traversals
689
+ * Scripts that modify schema (models, fields, etc.)
690
+ * Long-running applications (cache never expires)
691
+ * Situations where the schema might change during execution
692
+
693
+ <details><summary><strong>Class signature</strong></summary>
517
694
 
518
- **TypeScript Class:**
519
695
  ```typescript
520
696
  class SchemaRepository {
521
697
  constructor(client: GenericClient)
@@ -542,41 +718,6 @@ class SchemaRepository {
542
718
  // ... and more raw variants
543
719
  }
544
720
  ```
545
-
546
- **When to Use:**
547
- - Complex traversal operations that repeatedly lookup schema
548
- - Bulk operations processing multiple records
549
- - Scripts that need efficient access to schema information
550
- - Working with recursive block utilities
551
-
552
- **When NOT to Use:**
553
- - Scripts that modify schema (models, fields, etc.)
554
- - Long-running applications (no cache expiration)
555
- - When schema might change during execution
556
-
557
- **Usage Example:**
558
- ```typescript
559
- const schemaRepository = new SchemaRepository(client);
560
-
561
- // First call fetches from API and caches
562
- const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
563
- const fields = await schemaRepository.getItemTypeFields(blogPost);
564
-
565
- // Subsequent calls use cached data (no API calls)
566
- const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
567
- const sameFields = await schemaRepository.getItemTypeFields(blogPost);
568
-
569
- // Use with recursive utilities for optimal performance
570
- await mapBlocksInNonLocalizedFieldValue(
571
- schemaRepository, // Pass repository for efficient lookups
572
- field,
573
- fieldValue,
574
- async (block) => { /* transform */ }
575
- );
576
- ```
577
-
578
- **Performance Impact:**
579
- Without SchemaRepository, a script processing structured text with nested blocks might make the same API calls dozens of times. SchemaRepository ensures each unique schema request is made only once, dramatically improving performance for complex operations.
580
721
  </details>
581
722
 
582
723
  ## Contributing
@@ -88,7 +88,7 @@ class Client {
88
88
  return this.config.baseUrl || Client.defaultBaseUrl;
89
89
  }
90
90
  request(options) {
91
- return (0, rest_client_utils_1.request)(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.1.12', baseUrl: this.baseUrl, preCallStack: new Error().stack, extraHeaders: Object.assign(Object.assign(Object.assign({}, (this.config.extraHeaders || {})), (this.config.environment
91
+ return (0, rest_client_utils_1.request)(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.1.13', baseUrl: this.baseUrl, preCallStack: new Error().stack, extraHeaders: Object.assign(Object.assign(Object.assign({}, (this.config.extraHeaders || {})), (this.config.environment
92
92
  ? { 'X-Environment': this.config.environment }
93
93
  : {})), { 'X-API-Version': '3' }), fetchJobResult: (jobId) => {
94
94
  return this.jobResultsFetcher
@@ -1 +1 @@
1
- {"version":3,"file":"buildBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/buildBlockRecord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kEAAoD;AAGpD,sDAA8C;AAK9C,SAAgB,gBAAgB,CAE9B,IAA2C;IAC3C,OAAO,KAAK,CAAC,oBAAoB,CAE9B,IAAI,EAAE;QACP,IAAI,EAAE,gBAAI,CAAC,IAAI;QACf,UAAU,EAAE,GAAG;QACf,aAAa,EAAE,CAAC,WAAW,CAAC;KAC7B,CAAC,CAAC,IAAI,CAAC;AACV,CAAC;AAVD,4CAUC"}
1
+ {"version":3,"file":"buildBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/buildBlockRecord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kEAAoD;AAGpD,sDAA8C;AAmB9C,SAAgB,gBAAgB,CAG9B,IAAiD;IAEjD,OAAO,KAAK,CAAC,oBAAoB,CAE9B,IAAI,EAAE;QACP,IAAI,EAAE,gBAAI,CAAC,IAAI;QACf,UAAU,EAAE,GAAG;QACf,aAAa,EAAE,CAAC,WAAW,CAAC;KAC7B,CAAC,CAAC,IAAI,CAAC;AACV,CAAC;AAZD,4CAYC"}
@@ -24,9 +24,10 @@ exports.duplicateBlockRecord = void 0;
24
24
  const recursiveBlocks_1 = require("./recursiveBlocks");
25
25
  function duplicateBlockRecord(existingBlock, schemaRepository) {
26
26
  return __awaiter(this, void 0, void 0, function* () {
27
- const { type, attributes, relationships } = existingBlock;
27
+ const { __itemTypeId, type, attributes, relationships } = existingBlock;
28
28
  const itemType = yield schemaRepository.getRawItemTypeById(existingBlock.relationships.item_type.data.id);
29
29
  const newBlock = {
30
+ __itemTypeId,
30
31
  type,
31
32
  relationships,
32
33
  attributes,
@@ -1 +1 @@
1
- {"version":3,"file":"duplicateBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/duplicateBlockRecord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAKA,uDAAsE;AAKtE,SAAsB,oBAAoB,CAGxC,aAAoD,EACpD,gBAAkC;;QAElC,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,aAAa,CAAC;QAE1D,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,kBAAkB,CACxD,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAC9C,CAAC;QAEF,MAAM,QAAQ,GAAG;YACf,IAAI;YACJ,aAAa;YACb,UAAU;SACU,CAAC;QAEvB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAErE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;YAC1B,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;gBAC3C,MAAM,IAAA,mDAAiC,EACrC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAC7C,KAAK,CAAC,UAAU,CAAC,UAAU,EAC3B,gBAAgB,EAChB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;oBACd,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;wBAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,6BAA6B,KAAK,2BAA2B,CACzI,CAAC;qBACH;oBAED,MAAM,EAAE,EAAE,EAAE,IAAI,KAA+B,KAAK,EAA/B,qBAAqB,UAAK,KAAK,EAA9C,cAAsC,CAAQ,CAAC;oBAErD,OAAO,qBAA0C,CAAC;gBACpD,CAAC,CACF,CAAC;SACL;QAED,OAAO,QAAyC,CAAC;IACnD,CAAC;CAAA;AAzCD,oDAyCC"}
1
+ {"version":3,"file":"duplicateBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/duplicateBlockRecord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAKA,uDAAsE;AAKtE,SAAsB,oBAAoB,CAGxC,aAAoD,EACpD,gBAAkC;;QAElC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,GAAG,aAAa,CAAC;QAExE,MAAM,QAAQ,GAAG,MAAM,gBAAgB,CAAC,kBAAkB,CACxD,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAC9C,CAAC;QAEF,MAAM,QAAQ,GAAG;YACf,YAAY;YACZ,IAAI;YACJ,aAAa;YACb,UAAU;SACU,CAAC;QAEvB,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAErE,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE;YAC1B,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC;gBAC3C,MAAM,IAAA,mDAAiC,EACrC,QAAQ,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,EAC7C,KAAK,CAAC,UAAU,CAAC,UAAU,EAC3B,gBAAgB,EAChB,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE;oBACd,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;wBAC7B,MAAM,IAAI,KAAK,CACb,6DAA6D,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,6BAA6B,KAAK,2BAA2B,CACzI,CAAC;qBACH;oBAED,MAAM,EAAE,EAAE,EAAE,IAAI,KAA+B,KAAK,EAA/B,qBAAqB,UAAK,KAAK,EAA9C,cAAsC,CAAQ,CAAC;oBAErD,OAAO,qBAA0C,CAAC;gBACpD,CAAC,CACF,CAAC;SACL;QAED,OAAO,QAAyC,CAAC;IACnD,CAAC;CAAA;AA1CD,oDA0CC"}
@@ -20,7 +20,7 @@ type NonLocalizedFieldAttributesForFieldType<SourceType, FieldType extends Field
20
20
  type LocalizedFieldAttributesForFieldType<SourceType, FieldType extends FieldAttributesStableShell['field_type'], FieldValue, FieldValidators, FieldAppearance> = Omit<SourceType, 'field_type' | 'default_value' | 'validators' | 'appearance' | 'localized'> & {
21
21
  field_type: FieldType;
22
22
  localized: true;
23
- default_value: FieldValue | Record<string, FieldValue>;
23
+ default_value: Record<string, FieldValue>;
24
24
  validators: FieldValidators;
25
25
  appearance: FieldAppearanceConfig<FieldAppearance>;
26
26
  };
@@ -52,7 +52,7 @@ export type UpdatedBlockInRequest<D extends ItemTypeDefinition = ItemTypeDefinit
52
52
  __itemTypeId?: D['itemTypeId'];
53
53
  type: RawApiTypes.ItemType1;
54
54
  id: RawApiTypes.ItemIdentity;
55
- relationships?: RawApiTypes.ItemRelationships<D>;
55
+ relationships: RawApiTypes.ItemRelationships<D>;
56
56
  meta?: RawApiTypes.ItemMeta;
57
57
  attributes: ToItemAttributesInRequest<D>;
58
58
  };