@datocms/cma-client 5.1.11 → 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.
Files changed (118) hide show
  1. package/README.md +313 -178
  2. package/dist/cjs/fieldTypes/file.js +6 -6
  3. package/dist/cjs/fieldTypes/gallery.js +7 -7
  4. package/dist/cjs/fieldTypes/rich_text.js +14 -12
  5. package/dist/cjs/fieldTypes/rich_text.js.map +1 -1
  6. package/dist/cjs/fieldTypes/schema.js +3 -0
  7. package/dist/cjs/fieldTypes/schema.js.map +1 -0
  8. package/dist/cjs/fieldTypes/single_block.js +13 -12
  9. package/dist/cjs/fieldTypes/single_block.js.map +1 -1
  10. package/dist/cjs/fieldTypes/structured_text.js +13 -12
  11. package/dist/cjs/fieldTypes/structured_text.js.map +1 -1
  12. package/dist/cjs/generated/Client.js +1 -1
  13. package/dist/cjs/generated/resources/Item.js.map +1 -1
  14. package/dist/cjs/generated/resources/ScheduledPublication.js.map +1 -1
  15. package/dist/cjs/generated/resources/ScheduledUnpublishing.js.map +1 -1
  16. package/dist/cjs/generated/resources/Upload.js.map +1 -1
  17. package/dist/cjs/index.js +1 -0
  18. package/dist/cjs/index.js.map +1 -1
  19. package/dist/cjs/utilities/buildBlockRecord.js +1 -46
  20. package/dist/cjs/utilities/buildBlockRecord.js.map +1 -1
  21. package/dist/cjs/utilities/duplicateBlockRecord.js +50 -0
  22. package/dist/cjs/utilities/duplicateBlockRecord.js.map +1 -0
  23. package/dist/cjs/utilities/inspectItem.js +50 -20
  24. package/dist/cjs/utilities/inspectItem.js.map +1 -1
  25. package/dist/cjs/utilities/nonRecursiveBlocks.js +1 -170
  26. package/dist/cjs/utilities/nonRecursiveBlocks.js.map +1 -1
  27. package/dist/cjs/utilities/recursiveBlocks.js +52 -112
  28. package/dist/cjs/utilities/recursiveBlocks.js.map +1 -1
  29. package/dist/esm/fieldTypes/file.d.ts +3 -3
  30. package/dist/esm/fieldTypes/file.js +3 -3
  31. package/dist/esm/fieldTypes/gallery.d.ts +5 -5
  32. package/dist/esm/fieldTypes/gallery.js +5 -5
  33. package/dist/esm/fieldTypes/rich_text.d.ts +8 -9
  34. package/dist/esm/fieldTypes/rich_text.js +9 -7
  35. package/dist/esm/fieldTypes/rich_text.js.map +1 -1
  36. package/dist/esm/fieldTypes/schema.d.ts +59 -0
  37. package/dist/esm/fieldTypes/schema.js +2 -0
  38. package/dist/esm/fieldTypes/schema.js.map +1 -0
  39. package/dist/esm/fieldTypes/single_block.d.ts +30 -15
  40. package/dist/esm/fieldTypes/single_block.js +8 -7
  41. package/dist/esm/fieldTypes/single_block.js.map +1 -1
  42. package/dist/esm/fieldTypes/structured_text.d.ts +14 -15
  43. package/dist/esm/fieldTypes/structured_text.js +8 -7
  44. package/dist/esm/fieldTypes/structured_text.js.map +1 -1
  45. package/dist/esm/generated/ApiTypes.d.ts +94 -980
  46. package/dist/esm/generated/Client.js +1 -1
  47. package/dist/esm/generated/RawApiTypes.d.ts +160 -999
  48. package/dist/esm/generated/resources/Field.d.ts +300 -300
  49. package/dist/esm/generated/resources/Item.d.ts +34 -34
  50. package/dist/esm/generated/resources/Item.js.map +1 -1
  51. package/dist/esm/generated/resources/ItemVersion.d.ts +3 -1
  52. package/dist/esm/generated/resources/ScheduledPublication.d.ts +3 -3
  53. package/dist/esm/generated/resources/ScheduledPublication.js.map +1 -1
  54. package/dist/esm/generated/resources/ScheduledUnpublishing.d.ts +3 -3
  55. package/dist/esm/generated/resources/ScheduledUnpublishing.js.map +1 -1
  56. package/dist/esm/generated/resources/Upload.d.ts +6 -6
  57. package/dist/esm/generated/resources/Upload.js.map +1 -1
  58. package/dist/esm/index.d.ts +1 -0
  59. package/dist/esm/index.js +1 -0
  60. package/dist/esm/index.js.map +1 -1
  61. package/dist/esm/utilities/buildBlockRecord.d.ts +11 -5
  62. package/dist/esm/utilities/buildBlockRecord.js +0 -44
  63. package/dist/esm/utilities/buildBlockRecord.js.map +1 -1
  64. package/dist/esm/utilities/duplicateBlockRecord.d.ts +6 -0
  65. package/dist/esm/utilities/duplicateBlockRecord.js +46 -0
  66. package/dist/esm/utilities/duplicateBlockRecord.js.map +1 -0
  67. package/dist/esm/utilities/inspectItem.d.ts +3 -3
  68. package/dist/esm/utilities/inspectItem.js +28 -21
  69. package/dist/esm/utilities/inspectItem.js.map +1 -1
  70. package/dist/esm/utilities/itemDefinition.d.ts +25 -27
  71. package/dist/esm/utilities/nonRecursiveBlocks.d.ts +10 -75
  72. package/dist/esm/utilities/nonRecursiveBlocks.js +1 -164
  73. package/dist/esm/utilities/nonRecursiveBlocks.js.map +1 -1
  74. package/dist/esm/utilities/recursiveBlocks.d.ts +53 -23
  75. package/dist/esm/utilities/recursiveBlocks.js +52 -112
  76. package/dist/esm/utilities/recursiveBlocks.js.map +1 -1
  77. package/dist/types/fieldTypes/file.d.ts +3 -3
  78. package/dist/types/fieldTypes/gallery.d.ts +5 -5
  79. package/dist/types/fieldTypes/rich_text.d.ts +8 -9
  80. package/dist/types/fieldTypes/schema.d.ts +59 -0
  81. package/dist/types/fieldTypes/single_block.d.ts +30 -15
  82. package/dist/types/fieldTypes/structured_text.d.ts +14 -15
  83. package/dist/types/generated/ApiTypes.d.ts +94 -980
  84. package/dist/types/generated/RawApiTypes.d.ts +160 -999
  85. package/dist/types/generated/resources/Field.d.ts +300 -300
  86. package/dist/types/generated/resources/Item.d.ts +34 -34
  87. package/dist/types/generated/resources/ItemVersion.d.ts +3 -1
  88. package/dist/types/generated/resources/ScheduledPublication.d.ts +3 -3
  89. package/dist/types/generated/resources/ScheduledUnpublishing.d.ts +3 -3
  90. package/dist/types/generated/resources/Upload.d.ts +6 -6
  91. package/dist/types/index.d.ts +1 -0
  92. package/dist/types/utilities/buildBlockRecord.d.ts +11 -5
  93. package/dist/types/utilities/duplicateBlockRecord.d.ts +6 -0
  94. package/dist/types/utilities/inspectItem.d.ts +3 -3
  95. package/dist/types/utilities/itemDefinition.d.ts +25 -27
  96. package/dist/types/utilities/nonRecursiveBlocks.d.ts +10 -75
  97. package/dist/types/utilities/recursiveBlocks.d.ts +53 -23
  98. package/package.json +4 -4
  99. package/src/fieldTypes/file.ts +6 -6
  100. package/src/fieldTypes/gallery.ts +10 -10
  101. package/src/fieldTypes/rich_text.ts +26 -24
  102. package/src/fieldTypes/schema.ts +657 -0
  103. package/src/fieldTypes/single_block.ts +61 -38
  104. package/src/fieldTypes/structured_text.ts +57 -51
  105. package/src/generated/ApiTypes.ts +221 -1880
  106. package/src/generated/Client.ts +1 -1
  107. package/src/generated/RawApiTypes.ts +276 -2113
  108. package/src/generated/resources/Item.ts +93 -187
  109. package/src/generated/resources/ScheduledPublication.ts +4 -15
  110. package/src/generated/resources/ScheduledUnpublishing.ts +4 -15
  111. package/src/generated/resources/Upload.ts +9 -32
  112. package/src/index.ts +1 -0
  113. package/src/utilities/buildBlockRecord.ts +16 -56
  114. package/src/utilities/duplicateBlockRecord.ts +53 -0
  115. package/src/utilities/inspectItem.ts +64 -52
  116. package/src/utilities/itemDefinition.ts +109 -98
  117. package/src/utilities/nonRecursiveBlocks.ts +25 -279
  118. package/src/utilities/recursiveBlocks.ts +337 -72
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
63
238
 
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.
239
+ <details>
240
+ <summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
65
241
 
66
- #### Recursive Block Operations
242
+ Converts a block data object into the proper format for API requests.
67
243
 
68
- These functions traverse blocks recursively, processing nested blocks within blocks. They require a `SchemaRepository` instance to look up field definitions for nested blocks.
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
273
+
274
+ **Returns:** New block record without IDs, ready to be created
275
+ </details>
276
+
277
+ ### Recursive Block Operations
278
+
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>
@@ -75,21 +286,18 @@ Visit every block in a non-localized field value recursively, including blocks n
75
286
  **TypeScript Signature:**
76
287
  ```typescript
77
288
  async function visitBlocksInNonLocalizedFieldValue(
78
- schemaRepository: SchemaRepository,
79
- fieldType: string,
80
289
  nonLocalizedFieldValue: unknown,
81
- visitor: (item: BlockItemInARequest, path: TreePath) => void | Promise<void>,
82
- path?: TreePath
290
+ fieldType: string,
291
+ schemaRepository: SchemaRepository,
292
+ visitor: (item: BlockInRequest, path: TreePath) => void | Promise<void>,
83
293
  ): Promise<void>
84
294
  ```
85
295
 
86
296
  **Parameters:**
87
- - `schemaRepository`: Repository for caching schema lookups
88
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
89
297
  - `nonLocalizedFieldValue`: The non-localized field value
298
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
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>
@@ -100,20 +308,18 @@ Transform all blocks in a non-localized field value recursively, including neste
100
308
  **TypeScript Signature:**
101
309
  ```typescript
102
310
  async function mapBlocksInNonLocalizedFieldValue(
103
- schemaRepository: SchemaRepository,
104
- fieldType: string,
105
311
  nonLocalizedFieldValue: unknown,
106
- mapper: (item: BlockItemInARequest, path: TreePath) => BlockItemInARequest | Promise<BlockItemInARequest>,
107
- path?: TreePath
312
+ fieldType: string,
313
+ schemaRepository: SchemaRepository,
314
+ mapper: (item: BlockInRequest, path: TreePath) => BlockInRequest | Promise<BlockInRequest>,
108
315
  ): Promise<unknown>
109
316
  ```
110
317
 
111
318
  **Parameters:**
112
- - `schemaRepository`: Repository for caching schema lookups
113
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
114
319
  - `nonLocalizedFieldValue`: The non-localized field value
320
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
321
+ - `schemaRepository`: Repository for caching schema lookups
115
322
  - `mapper`: Function that transforms each block
116
- - `path`: Optional base path
117
323
 
118
324
  **Returns:** New field value
119
325
  </details>
@@ -126,20 +332,18 @@ Filter blocks recursively, removing blocks at any nesting level that don't match
126
332
  **TypeScript Signature:**
127
333
  ```typescript
128
334
  async function filterBlocksInNonLocalizedFieldValue(
129
- schemaRepository: SchemaRepository,
130
- fieldType: string,
131
335
  nonLocalizedFieldValue: unknown,
132
- predicate: (item: BlockItemInARequest, path: TreePath) => boolean | Promise<boolean>,
133
- path?: TreePath
336
+ fieldType: string,
337
+ schemaRepository: SchemaRepository,
338
+ predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
134
339
  ): Promise<unknown>
135
340
  ```
136
341
 
137
342
  **Parameters:**
138
- - `schemaRepository`: Repository for caching schema lookups
139
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
140
343
  - `nonLocalizedFieldValue`: The non-localized field value to filter
344
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
345
+ - `schemaRepository`: Repository for caching schema lookups
141
346
  - `predicate`: Function that tests each block
142
- - `path`: Optional base path
143
347
 
144
348
  **Returns:** New field value with filtered blocks
145
349
 
@@ -163,20 +367,18 @@ Find all blocks that match the predicate, searching recursively through nested b
163
367
  **TypeScript Signature:**
164
368
  ```typescript
165
369
  async function findAllBlocksInNonLocalizedFieldValue(
166
- schemaRepository: SchemaRepository,
167
- fieldType: string,
168
370
  nonLocalizedFieldValue: unknown,
169
- predicate: (item: BlockItemInARequest, path: TreePath) => boolean | Promise<boolean>,
170
- path?: TreePath
171
- ): Promise<Array<{ item: BlockItemInARequest; path: TreePath }>>
371
+ fieldType: string,
372
+ schemaRepository: SchemaRepository,
373
+ predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
374
+ ): Promise<Array<{ item: BlockInRequest; path: TreePath }>>
172
375
  ```
173
376
 
174
377
  **Parameters:**
175
- - `schemaRepository`: Repository for caching schema lookups
176
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
177
378
  - `nonLocalizedFieldValue`: The non-localized field value to search
379
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
380
+ - `schemaRepository`: Repository for caching schema lookups
178
381
  - `predicate`: Function that tests each block
179
- - `path`: Optional base path
180
382
 
181
383
  **Returns:** Array of all matching blocks with their paths
182
384
  </details>
@@ -189,25 +391,22 @@ Reduce all blocks recursively to a single value.
189
391
  **TypeScript Signature:**
190
392
  ```typescript
191
393
  async function reduceBlocksInNonLocalizedFieldValue<R>(
192
- schemaRepository: SchemaRepository,
193
- fieldType: string,
194
394
  nonLocalizedFieldValue: unknown,
195
- reducer: (accumulator: R, item: BlockItemInARequest, path: TreePath) => R | Promise<R>,
395
+ fieldType: string,
396
+ schemaRepository: SchemaRepository,
397
+ reducer: (accumulator: R, item: BlockInRequest, path: TreePath) => R | Promise<R>,
196
398
  initialValue: R,
197
- path?: TreePath
198
399
  ): Promise<R>
199
400
  ```
200
401
 
201
402
  **Parameters:**
202
- - `schemaRepository`: Repository for caching schema lookups
203
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
204
403
  - `nonLocalizedFieldValue`: The non-localized field value to reduce
404
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
405
+ - `schemaRepository`: Repository for caching schema lookups
205
406
  - `reducer`: Function that processes each block
206
407
  - `initialValue`: Initial accumulator value
207
- - `path`: Optional base path
208
408
 
209
409
  **Returns:** The final accumulated value
210
- ```
211
410
  </details>
212
411
 
213
412
  <details>
@@ -218,23 +417,20 @@ Check if any block (including nested) matches the predicate.
218
417
  **TypeScript Signature:**
219
418
  ```typescript
220
419
  async function someBlocksInNonLocalizedFieldValue(
221
- schemaRepository: SchemaRepository,
222
- fieldType: string,
223
420
  nonLocalizedFieldValue: unknown,
224
- predicate: (item: BlockItemInARequest, path: TreePath) => boolean | Promise<boolean>,
225
- path?: TreePath
421
+ fieldType: string,
422
+ schemaRepository: SchemaRepository,
423
+ predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
226
424
  ): Promise<boolean>
227
425
  ```
228
426
 
229
427
  **Parameters:**
230
- - `schemaRepository`: Repository for caching schema lookups
231
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
232
428
  - `nonLocalizedFieldValue`: The non-localized field value to test
429
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
430
+ - `schemaRepository`: Repository for caching schema lookups
233
431
  - `predicate`: Function that tests each block
234
- - `path`: Optional base path
235
432
 
236
433
  **Returns:** True if any block matches
237
- ```
238
434
  </details>
239
435
 
240
436
  <details>
@@ -245,84 +441,26 @@ Check if every block (including nested) matches the predicate.
245
441
  **TypeScript Signature:**
246
442
  ```typescript
247
443
  async function everyBlockInNonLocalizedFieldValue(
248
- schemaRepository: SchemaRepository,
249
- fieldType: string,
250
444
  nonLocalizedFieldValue: unknown,
251
- predicate: (item: BlockItemInARequest, path: TreePath) => boolean | Promise<boolean>,
252
- path?: TreePath
445
+ fieldType: string,
446
+ schemaRepository: SchemaRepository,
447
+ predicate: (item: BlockInRequest, path: TreePath) => boolean | Promise<boolean>,
253
448
  ): Promise<boolean>
254
449
  ```
255
450
 
256
451
  **Parameters:**
257
- - `schemaRepository`: Repository for caching schema lookups
258
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
259
452
  - `nonLocalizedFieldValue`: The non-localized field value to test
453
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
454
+ - `schemaRepository`: Repository for caching schema lookups
260
455
  - `predicate`: Function that tests each block
261
- - `path`: Optional base path
262
456
 
263
457
  **Returns:** True if all blocks match
264
458
  </details>
265
459
 
266
- #### Block Record Management
267
-
268
- <details>
269
- <summary><strong>buildBlockRecord()</strong> - Create block records from data</summary>
270
-
271
- Converts a block data object into the proper format for API requests.
272
-
273
- **TypeScript Signature:**
274
- ```typescript
275
- function buildBlockRecord<D extends ItemTypeDefinition>(
276
- body: ItemUpdateSchema<ToItemDefinitionAsRequest<D>>
277
- ): NewBlockInARequest<ToItemDefinitionAsRequest<D>>
278
- ```
279
-
280
- **Parameters:**
281
- - `body`: Block data in update schema format
282
-
283
- **Returns:** Formatted block record ready for API requests
284
- </details>
285
-
286
- <details>
287
- <summary><strong>duplicateBlockRecord()</strong> - Deep clone blocks with nested content</summary>
288
-
289
- Creates a deep copy of a block record, including all nested blocks, removing IDs to create new instances.
290
-
291
- **TypeScript Signature:**
292
- ```typescript
293
- async function duplicateBlockRecord<D extends ItemTypeDefinition>(
294
- existingBlock: ItemWithOptionalIdAndMeta<ToItemDefinitionWithNestedBlocks<D>>,
295
- schemaRepository: SchemaRepository
296
- ): Promise<NewBlockInARequest<ToItemDefinitionAsRequest<D>>>
297
- ```
298
-
299
- **Parameters:**
300
- - `existingBlock`: The block to duplicate
301
- - `schemaRepository`: Repository for schema lookups
302
-
303
- **Returns:** New block record without IDs, ready to be created
304
- </details>
305
-
306
- ### 3. Localization-Aware Field Utilities
460
+ ## Unified Field Processing (Localized & Non-Localized)
307
461
 
308
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.
309
463
 
310
- <details>
311
- <summary><strong>isLocalized()</strong> - Check if a field is localized</summary>
312
-
313
- Determines whether a DatoCMS field is configured for localization.
314
-
315
- **TypeScript Signature:**
316
- ```typescript
317
- function isLocalized(field: Field): boolean
318
- ```
319
-
320
- **Parameters:**
321
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
322
-
323
- **Returns:** True if the field is localized, false otherwise
324
- </details>
325
-
326
464
  <details>
327
465
  <summary><strong>mapNormalizedFieldValues() / mapNormalizedFieldValuesAsync()</strong> - Transform field values</summary>
328
466
 
@@ -344,7 +482,7 @@ async function mapNormalizedFieldValuesAsync<TInput, TOutput>(
344
482
  ```
345
483
 
346
484
  **Parameters:**
347
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
485
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
348
486
  - `nonLocalizedFieldValue`: The non-localized field value (localized or non-localized)
349
487
  - `mapFn`: Function to transform each value (receives locale for localized fields, undefined for non-localized)
350
488
 
@@ -372,7 +510,7 @@ async function filterNormalizedFieldValuesAsync<T>(
372
510
  ```
373
511
 
374
512
  **Parameters:**
375
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
513
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
376
514
  - `nonLocalizedFieldValue`: The non-localized field value to filter
377
515
  - `filterFn`: Predicate function for filtering
378
516
 
@@ -400,7 +538,7 @@ async function visitNormalizedFieldValuesAsync<T>(
400
538
  ```
401
539
 
402
540
  **Parameters:**
403
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
541
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
404
542
  - `nonLocalizedFieldValue`: The non-localized field value to visit
405
543
  - `visitFn`: Function called for each value
406
544
  </details>
@@ -426,7 +564,7 @@ async function someNormalizedFieldValuesAsync<T>(
426
564
  ```
427
565
 
428
566
  **Parameters:**
429
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
567
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
430
568
  - `nonLocalizedFieldValue`: The non-localized field value to test
431
569
  - `testFn`: Predicate function
432
570
 
@@ -454,7 +592,7 @@ async function everyNormalizedFieldValueAsync<T>(
454
592
  ```
455
593
 
456
594
  **Parameters:**
457
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
595
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
458
596
  - `nonLocalizedFieldValue`: The non-localized field value to test
459
597
  - `testFn`: Predicate function
460
598
 
@@ -485,7 +623,7 @@ type NormalizedFieldValueEntry<T> = {
485
623
  ```
486
624
 
487
625
  **Parameters:**
488
- - `fieldType`: The typeo of DatoCMS field (ie. `string`, `rich_text`, etc.)
626
+ - `fieldType`: The type of DatoCMS field (ie. `string`, `rich_text`, etc.)
489
627
  - `nonLocalizedFieldValue`/`entries non-localized`: Value to convert from/to
490
628
 
491
629
  **Returns:** Normalized entries array or reconstructed field value
@@ -503,25 +641,57 @@ const processed = entries.map(({ locale, value }) => ({
503
641
 
504
642
  // Convert back to field value format
505
643
  const result = fromNormalizedFieldValueEntries(field, processed);
506
- ```
507
644
  </details>
508
645
 
509
- ### 4. Schema Repository
646
+ ### 4. SchemaRepository
510
647
 
511
- 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.
512
649
 
513
- <details>
514
- <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**
515
681
 
516
- Repository for DatoCMS schema entities including item types, fields, fieldsets, and plugins. Provides caching and efficient lookup functionality for schema-related operations.
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
517
686
 
518
- **Key Features:**
519
- - Automatic caching of schema entities after first fetch
520
- - Efficient lookups by ID, API key, or package name
521
- - Essential for recursive block operations
522
- - Dramatically reduces API calls during complex traversals
687
+ **When Not to Use**
688
+
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>
523
694
 
524
- **TypeScript Class:**
525
695
  ```typescript
526
696
  class SchemaRepository {
527
697
  constructor(client: GenericClient)
@@ -548,41 +718,6 @@ class SchemaRepository {
548
718
  // ... and more raw variants
549
719
  }
550
720
  ```
551
-
552
- **When to Use:**
553
- - Complex traversal operations that repeatedly lookup schema
554
- - Bulk operations processing multiple records
555
- - Scripts that need efficient access to schema information
556
- - Working with recursive block utilities
557
-
558
- **When NOT to Use:**
559
- - Scripts that modify schema (models, fields, etc.)
560
- - Long-running applications (no cache expiration)
561
- - When schema might change during execution
562
-
563
- **Usage Example:**
564
- ```typescript
565
- const schemaRepository = new SchemaRepository(client);
566
-
567
- // First call fetches from API and caches
568
- const blogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
569
- const fields = await schemaRepository.getItemTypeFields(blogPost);
570
-
571
- // Subsequent calls use cached data (no API calls)
572
- const sameBlogPost = await schemaRepository.getItemTypeByApiKey('blog_post');
573
- const sameFields = await schemaRepository.getItemTypeFields(blogPost);
574
-
575
- // Use with recursive utilities for optimal performance
576
- await mapBlocksInNonLocalizedFieldValue(
577
- schemaRepository, // Pass repository for efficient lookups
578
- field,
579
- fieldValue,
580
- async (block) => { /* transform */ }
581
- );
582
- ```
583
-
584
- **Performance Impact:**
585
- 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.
586
721
  </details>
587
722
 
588
723
  ## Contributing