@datocms/cma-client 5.4.3 → 5.4.4
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 +55 -0
- package/dist/cjs/generated/Client.js +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/utilities/buildBlockRecord.js +6 -1
- package/dist/cjs/utilities/buildBlockRecord.js.map +1 -1
- package/dist/cjs/utilities/isBlockOfType.js +52 -0
- package/dist/cjs/utilities/isBlockOfType.js.map +1 -0
- package/dist/esm/generated/Client.js +1 -1
- package/dist/esm/generated/RawApiTypes.d.ts +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/utilities/buildBlockRecord.js +6 -1
- package/dist/esm/utilities/buildBlockRecord.js.map +1 -1
- package/dist/esm/utilities/isBlockOfType.d.ts +52 -0
- package/dist/esm/utilities/isBlockOfType.js +48 -0
- package/dist/esm/utilities/isBlockOfType.js.map +1 -0
- package/dist/types/generated/RawApiTypes.d.ts +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/utilities/isBlockOfType.d.ts +52 -0
- package/package.json +2 -2
- package/src/generated/Client.ts +1 -1
- package/src/generated/RawApiTypes.ts +1 -1
- package/src/index.ts +1 -0
- package/src/utilities/buildBlockRecord.ts +10 -1
- package/src/utilities/isBlockOfType.ts +61 -0
package/README.md
CHANGED
|
@@ -296,6 +296,61 @@ async function duplicateBlockRecord<D extends ItemTypeDefinition>(
|
|
|
296
296
|
**Returns:** New block record without IDs, ready to be created
|
|
297
297
|
</details>
|
|
298
298
|
|
|
299
|
+
### Narrowing Block Types
|
|
300
|
+
|
|
301
|
+
#### isBlockOfType()
|
|
302
|
+
|
|
303
|
+
Builds a type guard that narrows a union of block shapes to the one matching a given model. Meant for `Array#filter` / `Array#find` over block-bearing fields — either nested-response arrays (from `client.items.find(..., { nested: true })`) or request-payload arrays you're inspecting before sending.
|
|
304
|
+
|
|
305
|
+
TypeScript doesn't auto-narrow on discriminators buried in nested properties, so the natural-looking check `block.relationships.item_type.data.id === SOME_ID` won't narrow the block's type. This guard does the walk and returns a proper type-guard predicate.
|
|
306
|
+
|
|
307
|
+
<details>
|
|
308
|
+
<summary>View details</summary>
|
|
309
|
+
|
|
310
|
+
**TypeScript Signature:**
|
|
311
|
+
```typescript
|
|
312
|
+
function isBlockOfType<Id extends string>(
|
|
313
|
+
itemTypeId: Id,
|
|
314
|
+
): <T>(block: T) => block is NarrowBlockByItemType<T, Id>
|
|
315
|
+
|
|
316
|
+
type NarrowBlockByItemType<T, Id extends string> = Extract<
|
|
317
|
+
T,
|
|
318
|
+
{ relationships: { item_type: { data: { type: 'item_type'; id: Id } } } }
|
|
319
|
+
>
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
**Parameters:**
|
|
323
|
+
- `itemTypeId`: The item-type ID literal. For narrowing to work, the argument must be typed as a literal — use `as const` on pre-set ID constants. No `ItemTypeDefinition` type parameter is needed: `Extract` walks the input union using just the ID.
|
|
324
|
+
|
|
325
|
+
**Returns:** A predicate `(block) => block is D-typed-block` that:
|
|
326
|
+
- Narrows blocks carrying `relationships.item_type.data.id` — that covers `BlockInNestedResponse<D>` and the object variants of `BlockInRequest<D>` (`UpdatedBlockInRequest`, `NewBlockInRequest`).
|
|
327
|
+
- Returns `false` for plain string IDs (unchanged-reference form in request payloads) and for any non-block input.
|
|
328
|
+
|
|
329
|
+
The default (non-nested) response shape, where block fields are arrays of plain string IDs, is deliberately not supported — there's no way to recover the type from an ID alone.
|
|
330
|
+
|
|
331
|
+
**Usage Example:**
|
|
332
|
+
```typescript
|
|
333
|
+
import { isBlockOfType } from '@datocms/cma-client';
|
|
334
|
+
|
|
335
|
+
// ID of the ImageBlock model, one of several allowed inside Article `content`
|
|
336
|
+
const IMAGE_BLOCK_ID = 'FJM79jjKRMSVg-fR6k6X2A' as const;
|
|
337
|
+
|
|
338
|
+
const article = await client.items.find<Schema.Article>(articleId, { nested: true });
|
|
339
|
+
|
|
340
|
+
// Before: inline === check does not narrow
|
|
341
|
+
const images = article.content.filter(
|
|
342
|
+
(b) => b.relationships.item_type.data.id === IMAGE_BLOCK_ID,
|
|
343
|
+
);
|
|
344
|
+
images[0].attributes.upload_id; // ❌ property does not exist on union
|
|
345
|
+
|
|
346
|
+
// After: guard narrows the filter result
|
|
347
|
+
const images = article.content.filter(isBlockOfType(IMAGE_BLOCK_ID));
|
|
348
|
+
images[0].attributes.upload_id; // ✅ narrowed
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Use the `__itemTypeId` discriminator for inline `if` / `switch` narrowing on a single value — that's simpler and doesn't need a helper. Reach for `isBlockOfType` when you need a predicate for `.filter` / `.find`.
|
|
352
|
+
</details>
|
|
353
|
+
|
|
299
354
|
### Recursive Block Operations
|
|
300
355
|
|
|
301
356
|
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.
|
|
@@ -90,7 +90,7 @@ class Client {
|
|
|
90
90
|
return this.config.baseUrl || Client.defaultBaseUrl;
|
|
91
91
|
}
|
|
92
92
|
request(options) {
|
|
93
|
-
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.4.
|
|
93
|
+
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.4.4', baseUrl: this.baseUrl, preCallStack: new Error().stack, extraHeaders: Object.assign(Object.assign(Object.assign({}, (this.config.extraHeaders || {})), (this.config.environment
|
|
94
94
|
? { 'X-Environment': this.config.environment }
|
|
95
95
|
: {})), { 'X-API-Version': '3' }), fetchJobResult: (jobId) => {
|
|
96
96
|
return this.jobResultsFetcher
|
package/dist/cjs/index.js
CHANGED
|
@@ -41,6 +41,7 @@ __exportStar(require("./utilities/duplicateBlockRecord"), exports);
|
|
|
41
41
|
__exportStar(require("./utilities/fieldsContainingReferences"), exports);
|
|
42
42
|
__exportStar(require("./utilities/id"), exports);
|
|
43
43
|
__exportStar(require("./utilities/inspectItem"), exports);
|
|
44
|
+
__exportStar(require("./utilities/isBlockOfType"), exports);
|
|
44
45
|
__exportStar(require("./utilities/itemDefinition"), exports);
|
|
45
46
|
__exportStar(require("./utilities/normalizedFieldValues"), exports);
|
|
46
47
|
__exportStar(require("./utilities/recursiveBlocks"), exports);
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gEAA8E;AAArE,6GAAA,QAAQ,OAAA;AAAE,6GAAA,QAAQ,OAAA;AAAE,iHAAA,YAAY,OAAA;AACzC,gDAA8B;AAC9B,+CAA6B;AAC7B,6CAA4C;AAAnC,gGAAA,MAAM,OAAA;AAEf,mEAAmD;AACnD,+DAA6C;AAC7C,mEAAiD;AACjD,yEAAuD;AACvD,iDAA+B;AAC/B,0DAAwC;AACxC,6DAA2C;AAC3C,oEAAkD;AAClD,8DAA4C;AAC5C,+DAA6C"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,gEAA8E;AAArE,6GAAA,QAAQ,OAAA;AAAE,6GAAA,QAAQ,OAAA;AAAE,iHAAA,YAAY,OAAA;AACzC,gDAA8B;AAC9B,+CAA6B;AAC7B,6CAA4C;AAAnC,gGAAA,MAAM,OAAA;AAEf,mEAAmD;AACnD,+DAA6C;AAC7C,mEAAiD;AACjD,yEAAuD;AACvD,iDAA+B;AAC/B,0DAAwC;AACxC,4DAA0C;AAC1C,6DAA2C;AAC3C,oEAAkD;AAClD,8DAA4C;AAC5C,+DAA6C"}
|
|
@@ -27,11 +27,16 @@ exports.buildBlockRecord = void 0;
|
|
|
27
27
|
const Utils = __importStar(require("@datocms/rest-client-utils"));
|
|
28
28
|
const resources_1 = require("../generated/resources");
|
|
29
29
|
function buildBlockRecord(body) {
|
|
30
|
-
|
|
30
|
+
const data = Utils.serializeRequestBody(body, {
|
|
31
31
|
type: resources_1.Item.TYPE,
|
|
32
32
|
attributes: '*',
|
|
33
33
|
relationships: ['item_type'],
|
|
34
34
|
}).data;
|
|
35
|
+
// Mirror the deserializer: expose `item_type.data.id` as a top-level
|
|
36
|
+
// `__itemTypeId` so locally-built blocks support the same TS narrowing
|
|
37
|
+
// pattern as blocks read from API responses. The field is TS-only and is
|
|
38
|
+
// stripped again by the serializer when the outer request is sent.
|
|
39
|
+
return Object.assign(Object.assign({}, data), { __itemTypeId: data.relationships.item_type.data.id });
|
|
35
40
|
}
|
|
36
41
|
exports.buildBlockRecord = buildBlockRecord;
|
|
37
42
|
//# sourceMappingURL=buildBlockRecord.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/buildBlockRecord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kEAAoD;AAGpD,sDAA8C;AA6B9C,SAAgB,gBAAgB,CAG9B,IAEuC;IAEvC,
|
|
1
|
+
{"version":3,"file":"buildBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/buildBlockRecord.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,kEAAoD;AAGpD,sDAA8C;AA6B9C,SAAgB,gBAAgB,CAG9B,IAEuC;IAEvC,MAAM,IAAI,GAAG,KAAK,CAAC,oBAAoB,CAEpC,IAAI,EAAE;QACP,IAAI,EAAE,gBAAI,CAAC,IAAI;QACf,UAAU,EAAE,GAAG;QACf,aAAa,EAAE,CAAC,WAAW,CAAC;KAC7B,CAAC,CAAC,IAAI,CAAC;IAER,qEAAqE;IACrE,uEAAuE;IACvE,yEAAyE;IACzE,mEAAmE;IACnE,OAAO,gCACF,IAAI,KACP,YAAY,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,GAClB,CAAC;AACrC,CAAC;AAvBD,4CAuBC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isBlockOfType = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Builds a type guard that narrows a block to a specific model.
|
|
6
|
+
*
|
|
7
|
+
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
8
|
+
* from the argument, so no explicit type parameter is needed. The returned
|
|
9
|
+
* predicate is generic: given any input type `T`, it narrows to
|
|
10
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
11
|
+
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
12
|
+
* in any of these contexts:
|
|
13
|
+
*
|
|
14
|
+
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
15
|
+
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
16
|
+
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
17
|
+
* them without an external lookup)
|
|
18
|
+
*
|
|
19
|
+
* The default (non-nested) response shape, where block fields are arrays of
|
|
20
|
+
* plain string IDs, is deliberately not supported — the type information is
|
|
21
|
+
* not recoverable from an ID alone.
|
|
22
|
+
*
|
|
23
|
+
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
24
|
+
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
29
|
+
*
|
|
30
|
+
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
31
|
+
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
32
|
+
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
function isBlockOfType(itemTypeId) {
|
|
36
|
+
return (block) => {
|
|
37
|
+
if (typeof block !== 'object' || block === null)
|
|
38
|
+
return false;
|
|
39
|
+
const relationships = block.relationships;
|
|
40
|
+
if (typeof relationships !== 'object' || relationships === null)
|
|
41
|
+
return false;
|
|
42
|
+
const itemType = relationships.item_type;
|
|
43
|
+
if (typeof itemType !== 'object' || itemType === null)
|
|
44
|
+
return false;
|
|
45
|
+
const data = itemType.data;
|
|
46
|
+
if (typeof data !== 'object' || data === null)
|
|
47
|
+
return false;
|
|
48
|
+
return data.id === itemTypeId;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
exports.isBlockOfType = isBlockOfType;
|
|
52
|
+
//# sourceMappingURL=isBlockOfType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isBlockOfType.js","sourceRoot":"","sources":["../../../src/utilities/isBlockOfType.ts"],"names":[],"mappings":";;;AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,SAAgB,aAAa,CAC3B,UAAc;IAEd,OAAO,CAAI,KAAQ,EAAyC,EAAE;QAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC9D,MAAM,aAAa,GAAI,KAAqC,CAAC,aAAa,CAAC;QAC3E,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;YAC7D,OAAO,KAAK,CAAC;QACf,MAAM,QAAQ,GAAI,aAAyC,CAAC,SAAS,CAAC;QACtE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACpE,MAAM,IAAI,GAAI,QAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC5D,OAAQ,IAAyB,CAAC,EAAE,KAAK,UAAU,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC;AAdD,sCAcC"}
|
|
@@ -64,7 +64,7 @@ export class Client {
|
|
|
64
64
|
return this.config.baseUrl || Client.defaultBaseUrl;
|
|
65
65
|
}
|
|
66
66
|
request(options) {
|
|
67
|
-
return request(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.4.
|
|
67
|
+
return request(Object.assign(Object.assign(Object.assign({}, this.config), options), { logFn: this.config.logFn || console.log, userAgent: '@datocms/cma-client v5.4.4', baseUrl: this.baseUrl, preCallStack: new Error().stack, extraHeaders: Object.assign(Object.assign(Object.assign({}, (this.config.extraHeaders || {})), (this.config.environment
|
|
68
68
|
? { 'X-Environment': this.config.environment }
|
|
69
69
|
: {})), { 'X-API-Version': '3' }), fetchJobResult: (jobId) => {
|
|
70
70
|
return this.jobResultsFetcher
|
|
@@ -6041,7 +6041,7 @@ export type FieldUpdateSchemaStableShell = {
|
|
|
6041
6041
|
data: {
|
|
6042
6042
|
type: FieldType;
|
|
6043
6043
|
id: FieldIdentity;
|
|
6044
|
-
attributes
|
|
6044
|
+
attributes?: {
|
|
6045
6045
|
/**
|
|
6046
6046
|
* Default value for Field. When field is localized accepts an object of default values with site locales as keys
|
|
6047
6047
|
*/
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './utilities/duplicateBlockRecord';
|
|
|
9
9
|
export * from './utilities/fieldsContainingReferences';
|
|
10
10
|
export * from './utilities/id';
|
|
11
11
|
export * from './utilities/inspectItem';
|
|
12
|
+
export * from './utilities/isBlockOfType';
|
|
12
13
|
export * from './utilities/itemDefinition';
|
|
13
14
|
export * from './utilities/normalizedFieldValues';
|
|
14
15
|
export * from './utilities/recursiveBlocks';
|
package/dist/esm/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export * from './utilities/duplicateBlockRecord';
|
|
|
8
8
|
export * from './utilities/fieldsContainingReferences';
|
|
9
9
|
export * from './utilities/id';
|
|
10
10
|
export * from './utilities/inspectItem';
|
|
11
|
+
export * from './utilities/isBlockOfType';
|
|
11
12
|
export * from './utilities/itemDefinition';
|
|
12
13
|
export * from './utilities/normalizedFieldValues';
|
|
13
14
|
export * from './utilities/recursiveBlocks';
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC9E,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAC;AACnD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,wCAAwC,CAAC;AACvD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC9E,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,KAAK,SAAS,MAAM,uBAAuB,CAAC;AACnD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,kCAAkC,CAAC;AACjD,cAAc,wCAAwC,CAAC;AACvD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,mCAAmC,CAAC;AAClD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,8BAA8B,CAAC"}
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import * as Utils from '@datocms/rest-client-utils';
|
|
2
2
|
import { Item } from '../generated/resources';
|
|
3
3
|
export function buildBlockRecord(body) {
|
|
4
|
-
|
|
4
|
+
const data = Utils.serializeRequestBody(body, {
|
|
5
5
|
type: Item.TYPE,
|
|
6
6
|
attributes: '*',
|
|
7
7
|
relationships: ['item_type'],
|
|
8
8
|
}).data;
|
|
9
|
+
// Mirror the deserializer: expose `item_type.data.id` as a top-level
|
|
10
|
+
// `__itemTypeId` so locally-built blocks support the same TS narrowing
|
|
11
|
+
// pattern as blocks read from API responses. The field is TS-only and is
|
|
12
|
+
// stripped again by the serializer when the outer request is sent.
|
|
13
|
+
return Object.assign(Object.assign({}, data), { __itemTypeId: data.relationships.item_type.data.id });
|
|
9
14
|
}
|
|
10
15
|
//# sourceMappingURL=buildBlockRecord.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buildBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/buildBlockRecord.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,4BAA4B,CAAC;AAGpD,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA6B9C,MAAM,UAAU,gBAAgB,CAG9B,IAEuC;IAEvC,
|
|
1
|
+
{"version":3,"file":"buildBlockRecord.js","sourceRoot":"","sources":["../../../src/utilities/buildBlockRecord.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,4BAA4B,CAAC;AAGpD,OAAO,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA6B9C,MAAM,UAAU,gBAAgB,CAG9B,IAEuC;IAEvC,MAAM,IAAI,GAAG,KAAK,CAAC,oBAAoB,CAEpC,IAAI,EAAE;QACP,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,UAAU,EAAE,GAAG;QACf,aAAa,EAAE,CAAC,WAAW,CAAC;KAC7B,CAAC,CAAC,IAAI,CAAC;IAER,qEAAqE;IACrE,uEAAuE;IACvE,yEAAyE;IACzE,mEAAmE;IACnE,OAAO,gCACF,IAAI,KACP,YAAY,EAAE,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,GAClB,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrows a union of block shapes to the member whose model (`item_type`)
|
|
3
|
+
* matches `Id`.
|
|
4
|
+
*
|
|
5
|
+
* Any object carrying `relationships.item_type.data.id` is narrowable —
|
|
6
|
+
* that covers blocks returned from `nested: true` responses as well as the
|
|
7
|
+
* object variants of request payloads (updated / newly-created blocks). The
|
|
8
|
+
* bare string IDs that may appear inside request payloads (to reference
|
|
9
|
+
* existing, unchanged blocks) are filtered out of the result.
|
|
10
|
+
*/
|
|
11
|
+
export type NarrowBlockByItemType<T, Id extends string> = Extract<T, {
|
|
12
|
+
relationships: {
|
|
13
|
+
item_type: {
|
|
14
|
+
data: {
|
|
15
|
+
type: 'item_type';
|
|
16
|
+
id: Id;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Builds a type guard that narrows a block to a specific model.
|
|
23
|
+
*
|
|
24
|
+
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
25
|
+
* from the argument, so no explicit type parameter is needed. The returned
|
|
26
|
+
* predicate is generic: given any input type `T`, it narrows to
|
|
27
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
28
|
+
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
29
|
+
* in any of these contexts:
|
|
30
|
+
*
|
|
31
|
+
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
32
|
+
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
33
|
+
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
34
|
+
* them without an external lookup)
|
|
35
|
+
*
|
|
36
|
+
* The default (non-nested) response shape, where block fields are arrays of
|
|
37
|
+
* plain string IDs, is deliberately not supported — the type information is
|
|
38
|
+
* not recoverable from an ID alone.
|
|
39
|
+
*
|
|
40
|
+
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
41
|
+
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
46
|
+
*
|
|
47
|
+
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
48
|
+
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
49
|
+
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function isBlockOfType<Id extends string>(itemTypeId: Id): <T>(block: T) => block is NarrowBlockByItemType<T, Id>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Builds a type guard that narrows a block to a specific model.
|
|
3
|
+
*
|
|
4
|
+
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
5
|
+
* from the argument, so no explicit type parameter is needed. The returned
|
|
6
|
+
* predicate is generic: given any input type `T`, it narrows to
|
|
7
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
8
|
+
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
9
|
+
* in any of these contexts:
|
|
10
|
+
*
|
|
11
|
+
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
12
|
+
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
13
|
+
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
14
|
+
* them without an external lookup)
|
|
15
|
+
*
|
|
16
|
+
* The default (non-nested) response shape, where block fields are arrays of
|
|
17
|
+
* plain string IDs, is deliberately not supported — the type information is
|
|
18
|
+
* not recoverable from an ID alone.
|
|
19
|
+
*
|
|
20
|
+
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
21
|
+
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
26
|
+
*
|
|
27
|
+
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
28
|
+
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
29
|
+
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function isBlockOfType(itemTypeId) {
|
|
33
|
+
return (block) => {
|
|
34
|
+
if (typeof block !== 'object' || block === null)
|
|
35
|
+
return false;
|
|
36
|
+
const relationships = block.relationships;
|
|
37
|
+
if (typeof relationships !== 'object' || relationships === null)
|
|
38
|
+
return false;
|
|
39
|
+
const itemType = relationships.item_type;
|
|
40
|
+
if (typeof itemType !== 'object' || itemType === null)
|
|
41
|
+
return false;
|
|
42
|
+
const data = itemType.data;
|
|
43
|
+
if (typeof data !== 'object' || data === null)
|
|
44
|
+
return false;
|
|
45
|
+
return data.id === itemTypeId;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=isBlockOfType.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"isBlockOfType.js","sourceRoot":"","sources":["../../../src/utilities/isBlockOfType.ts"],"names":[],"mappings":"AAeA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,aAAa,CAC3B,UAAc;IAEd,OAAO,CAAI,KAAQ,EAAyC,EAAE;QAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC9D,MAAM,aAAa,GAAI,KAAqC,CAAC,aAAa,CAAC;QAC3E,IAAI,OAAO,aAAa,KAAK,QAAQ,IAAI,aAAa,KAAK,IAAI;YAC7D,OAAO,KAAK,CAAC;QACf,MAAM,QAAQ,GAAI,aAAyC,CAAC,SAAS,CAAC;QACtE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACpE,MAAM,IAAI,GAAI,QAA+B,CAAC,IAAI,CAAC;QACnD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC5D,OAAQ,IAAyB,CAAC,EAAE,KAAK,UAAU,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -6041,7 +6041,7 @@ export type FieldUpdateSchemaStableShell = {
|
|
|
6041
6041
|
data: {
|
|
6042
6042
|
type: FieldType;
|
|
6043
6043
|
id: FieldIdentity;
|
|
6044
|
-
attributes
|
|
6044
|
+
attributes?: {
|
|
6045
6045
|
/**
|
|
6046
6046
|
* Default value for Field. When field is localized accepts an object of default values with site locales as keys
|
|
6047
6047
|
*/
|
package/dist/types/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './utilities/duplicateBlockRecord';
|
|
|
9
9
|
export * from './utilities/fieldsContainingReferences';
|
|
10
10
|
export * from './utilities/id';
|
|
11
11
|
export * from './utilities/inspectItem';
|
|
12
|
+
export * from './utilities/isBlockOfType';
|
|
12
13
|
export * from './utilities/itemDefinition';
|
|
13
14
|
export * from './utilities/normalizedFieldValues';
|
|
14
15
|
export * from './utilities/recursiveBlocks';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrows a union of block shapes to the member whose model (`item_type`)
|
|
3
|
+
* matches `Id`.
|
|
4
|
+
*
|
|
5
|
+
* Any object carrying `relationships.item_type.data.id` is narrowable —
|
|
6
|
+
* that covers blocks returned from `nested: true` responses as well as the
|
|
7
|
+
* object variants of request payloads (updated / newly-created blocks). The
|
|
8
|
+
* bare string IDs that may appear inside request payloads (to reference
|
|
9
|
+
* existing, unchanged blocks) are filtered out of the result.
|
|
10
|
+
*/
|
|
11
|
+
export type NarrowBlockByItemType<T, Id extends string> = Extract<T, {
|
|
12
|
+
relationships: {
|
|
13
|
+
item_type: {
|
|
14
|
+
data: {
|
|
15
|
+
type: 'item_type';
|
|
16
|
+
id: Id;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Builds a type guard that narrows a block to a specific model.
|
|
23
|
+
*
|
|
24
|
+
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
25
|
+
* from the argument, so no explicit type parameter is needed. The returned
|
|
26
|
+
* predicate is generic: given any input type `T`, it narrows to
|
|
27
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
28
|
+
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
29
|
+
* in any of these contexts:
|
|
30
|
+
*
|
|
31
|
+
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
32
|
+
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
33
|
+
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
34
|
+
* them without an external lookup)
|
|
35
|
+
*
|
|
36
|
+
* The default (non-nested) response shape, where block fields are arrays of
|
|
37
|
+
* plain string IDs, is deliberately not supported — the type information is
|
|
38
|
+
* not recoverable from an ID alone.
|
|
39
|
+
*
|
|
40
|
+
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
41
|
+
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```ts
|
|
45
|
+
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
46
|
+
*
|
|
47
|
+
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
48
|
+
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
49
|
+
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function isBlockOfType<Id extends string>(itemTypeId: Id): <T>(block: T) => block is NarrowBlockByItemType<T, Id>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datocms/cma-client",
|
|
3
|
-
"version": "5.4.
|
|
3
|
+
"version": "5.4.4",
|
|
4
4
|
"description": "JS client for DatoCMS REST Content Management API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"datocms",
|
|
@@ -45,5 +45,5 @@
|
|
|
45
45
|
"@datocms/dashboard-client": "^5.4.3",
|
|
46
46
|
"@types/uuid": "^9.0.7"
|
|
47
47
|
},
|
|
48
|
-
"gitHead": "
|
|
48
|
+
"gitHead": "9bfdb472db5e4c48543fb9a2c3a64b95722c8d78"
|
|
49
49
|
}
|
package/src/generated/Client.ts
CHANGED
|
@@ -151,7 +151,7 @@ export class Client {
|
|
|
151
151
|
...this.config,
|
|
152
152
|
...options,
|
|
153
153
|
logFn: this.config.logFn || console.log,
|
|
154
|
-
userAgent: '@datocms/cma-client v5.4.
|
|
154
|
+
userAgent: '@datocms/cma-client v5.4.4',
|
|
155
155
|
baseUrl: this.baseUrl,
|
|
156
156
|
preCallStack: new Error().stack,
|
|
157
157
|
extraHeaders: {
|
|
@@ -6365,7 +6365,7 @@ export type FieldUpdateSchemaStableShell = {
|
|
|
6365
6365
|
data: {
|
|
6366
6366
|
type: FieldType;
|
|
6367
6367
|
id: FieldIdentity;
|
|
6368
|
-
attributes
|
|
6368
|
+
attributes?: {
|
|
6369
6369
|
/**
|
|
6370
6370
|
* Default value for Field. When field is localized accepts an object of default values with site locales as keys
|
|
6371
6371
|
*/
|
package/src/index.ts
CHANGED
|
@@ -9,6 +9,7 @@ export * from './utilities/duplicateBlockRecord';
|
|
|
9
9
|
export * from './utilities/fieldsContainingReferences';
|
|
10
10
|
export * from './utilities/id';
|
|
11
11
|
export * from './utilities/inspectItem';
|
|
12
|
+
export * from './utilities/isBlockOfType';
|
|
12
13
|
export * from './utilities/itemDefinition';
|
|
13
14
|
export * from './utilities/normalizedFieldValues';
|
|
14
15
|
export * from './utilities/recursiveBlocks';
|
|
@@ -37,11 +37,20 @@ export function buildBlockRecord<
|
|
|
37
37
|
| CreateBlockRecordSchema<NoInfer<D>>
|
|
38
38
|
| UpdateBlockRecordSchema<NoInfer<D>>,
|
|
39
39
|
): NewBlockInRequest<NoInfer<D>> {
|
|
40
|
-
|
|
40
|
+
const data = Utils.serializeRequestBody<{
|
|
41
41
|
data: NewBlockInRequest<NoInfer<D>>;
|
|
42
42
|
}>(body, {
|
|
43
43
|
type: Item.TYPE,
|
|
44
44
|
attributes: '*',
|
|
45
45
|
relationships: ['item_type'],
|
|
46
46
|
}).data;
|
|
47
|
+
|
|
48
|
+
// Mirror the deserializer: expose `item_type.data.id` as a top-level
|
|
49
|
+
// `__itemTypeId` so locally-built blocks support the same TS narrowing
|
|
50
|
+
// pattern as blocks read from API responses. The field is TS-only and is
|
|
51
|
+
// stripped again by the serializer when the outer request is sent.
|
|
52
|
+
return {
|
|
53
|
+
...data,
|
|
54
|
+
__itemTypeId: data.relationships.item_type.data.id,
|
|
55
|
+
} as NewBlockInRequest<NoInfer<D>>;
|
|
47
56
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrows a union of block shapes to the member whose model (`item_type`)
|
|
3
|
+
* matches `Id`.
|
|
4
|
+
*
|
|
5
|
+
* Any object carrying `relationships.item_type.data.id` is narrowable —
|
|
6
|
+
* that covers blocks returned from `nested: true` responses as well as the
|
|
7
|
+
* object variants of request payloads (updated / newly-created blocks). The
|
|
8
|
+
* bare string IDs that may appear inside request payloads (to reference
|
|
9
|
+
* existing, unchanged blocks) are filtered out of the result.
|
|
10
|
+
*/
|
|
11
|
+
export type NarrowBlockByItemType<T, Id extends string> = Extract<
|
|
12
|
+
T,
|
|
13
|
+
{ relationships: { item_type: { data: { type: 'item_type'; id: Id } } } }
|
|
14
|
+
>;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Builds a type guard that narrows a block to a specific model.
|
|
18
|
+
*
|
|
19
|
+
* Call it with the block's `itemTypeId` literal — the ID generic is inferred
|
|
20
|
+
* from the argument, so no explicit type parameter is needed. The returned
|
|
21
|
+
* predicate is generic: given any input type `T`, it narrows to
|
|
22
|
+
* `Extract<T, { relationships: { item_type: { data: { id: Id } } } }>`. It's
|
|
23
|
+
* meant to plug into `Array#filter` / `Array#find` over block-bearing fields
|
|
24
|
+
* in any of these contexts:
|
|
25
|
+
*
|
|
26
|
+
* - `ItemInNestedResponse<D>` (responses with `nested: true`)
|
|
27
|
+
* - `ItemCreateSchema<D>` / `ItemUpdateSchema<D>` (request payloads, object
|
|
28
|
+
* variants; plain string IDs are filtered out — there's no way to narrow
|
|
29
|
+
* them without an external lookup)
|
|
30
|
+
*
|
|
31
|
+
* The default (non-nested) response shape, where block fields are arrays of
|
|
32
|
+
* plain string IDs, is deliberately not supported — the type information is
|
|
33
|
+
* not recoverable from an ID alone.
|
|
34
|
+
*
|
|
35
|
+
* For the literal `Id` to be preserved (and narrowing to work), the argument
|
|
36
|
+
* must be typed as a literal — use `as const` on pre-set ID constants.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const SESSION_BLOCK_ID = 'abc123' as const;
|
|
41
|
+
*
|
|
42
|
+
* const record = await client.items.find<Schema.ConferenceDay>(id, { nested: true });
|
|
43
|
+
* const sessions = record.agenda.filter(isBlockOfType(SESSION_BLOCK_ID));
|
|
44
|
+
* sessions[0].attributes.signup_url; // OK — narrowed
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export function isBlockOfType<Id extends string>(
|
|
48
|
+
itemTypeId: Id,
|
|
49
|
+
): <T>(block: T) => block is NarrowBlockByItemType<T, Id> {
|
|
50
|
+
return <T>(block: T): block is NarrowBlockByItemType<T, Id> => {
|
|
51
|
+
if (typeof block !== 'object' || block === null) return false;
|
|
52
|
+
const relationships = (block as { relationships?: unknown }).relationships;
|
|
53
|
+
if (typeof relationships !== 'object' || relationships === null)
|
|
54
|
+
return false;
|
|
55
|
+
const itemType = (relationships as { item_type?: unknown }).item_type;
|
|
56
|
+
if (typeof itemType !== 'object' || itemType === null) return false;
|
|
57
|
+
const data = (itemType as { data?: unknown }).data;
|
|
58
|
+
if (typeof data !== 'object' || data === null) return false;
|
|
59
|
+
return (data as { id?: unknown }).id === itemTypeId;
|
|
60
|
+
};
|
|
61
|
+
}
|