@datocms/cma-client
Version:
JS client for DatoCMS REST Content Management API
160 lines (159 loc) • 8.63 kB
TypeScript
import type * as RawApiTypes from '../generated/RawApiTypes';
import type { ItemTypeDefinition, ToItemAttributesInRequest } from '../utilities/itemDefinition';
import { type LocalizedFieldValue } from '../utilities/normalizedFieldValues';
import type { FramedSingleBlockEditorConfiguration } from './appearance/framed_single_block';
import type { FramelessSingleBlockEditorConfiguration } from './appearance/frameless_single_block';
import type { RequiredValidator } from './validators/required';
import type { SingleBlockBlocksValidator } from './validators/single_block_blocks';
/**
* SINGLE BLOCK FIELD TYPE SYSTEM FOR DATOCMS
*
* This module defines a comprehensive type system for handling DatoCMS Single Block fields,
* which contain a single embedded content block.
*
* The challenge we're solving:
* - DatoCMS Single Block fields contain a single "block" (embedded content item)
* - By default, API responses contain blocks as string IDs (lightweight references)
* - With ?nested=true parameter, API responses contain blocks as full block objects
* (which in turn can contain other blocks)
* - For API requests, blocks can be represented as:
* 1. String IDs (referencing existing blocks)
* 2. Full block objects with IDs (for updates)
* 3. Block objects without IDs (for creation)
*
* This creates a need for different type variants for the same conceptual data structure.
*/
/**
* =============================================================================
* BASIC SINGLE BLOCK TYPE - Default API response format
* =============================================================================
*
* The standard Single Block field value containing a block reference as string ID.
* This is what you get from regular API responses without ?nested=true.
*/
/**
* Basic Single Block field value - string block ID (lightweight reference)
*/
export type SingleBlockFieldValue = string | null;
/**
* =============================================================================
* REQUEST VARIANT - Type for sending data TO the DatoCMS API
* =============================================================================
*
* When making API requests, we need flexibility in how we represent embedded blocks:
* - Use string ID to reference existing block that does not need to change
* - Include full block object for updates
* - Omit ID for new blocks being created
*/
/** Represents an existing block in a CMA request */
export type UnchangedBlockInRequest = RawApiTypes.ItemIdentity;
/** Represents a block we want to update in a CMA request */
export type UpdatedBlockInRequest<D extends ItemTypeDefinition = ItemTypeDefinition> = {
__itemTypeId?: D['itemTypeId'];
type: RawApiTypes.ItemType1;
id: RawApiTypes.ItemIdentity;
relationships: RawApiTypes.ItemRelationships<D>;
meta?: RawApiTypes.ItemMeta;
attributes: ToItemAttributesInRequest<D>;
};
/** Represents a new block to create in a CMA request */
export type NewBlockInRequest<D extends ItemTypeDefinition = ItemTypeDefinition> = {
__itemTypeId?: D['itemTypeId'];
type: RawApiTypes.ItemType1;
relationships: RawApiTypes.ItemRelationships<D>;
meta?: RawApiTypes.ItemMeta;
attributes: ToItemAttributesInRequest<D>;
};
/**
* Union type representing the different ways a block can be specified in API requests:
* - string: Just the block ID (to keep existing blocks unchanged)
* - Full block object with ID (to update an existing block)
* - Block object without ID (to create a new block)
*
* Also, 'meta' can always be omitted
*/
export type BlockInRequest<D extends ItemTypeDefinition = ItemTypeDefinition> = UnchangedBlockInRequest | UpdatedBlockInRequest<D> | NewBlockInRequest<D>;
export type BlockInNestedResponse<D extends ItemTypeDefinition = ItemTypeDefinition> = D extends unknown ? RawApiTypes.ItemInNestedResponse<D> : never;
/**
* Single Block field value for API requests - allows flexible block representations:
* - string: Just the block ID (to keep existing blocks unchanged)
* - Full block object with ID (to update an existing block)
* - Block object without ID (to create a new block)
*/
export type SingleBlockFieldValueInRequest<D extends ItemTypeDefinition = ItemTypeDefinition> = BlockInRequest<D> | null;
/**
* =============================================================================
* NESTED VARIANT - Type for API responses with ?nested=true parameter
* =============================================================================
*
* When using the ?nested=true query parameter, the API returns Single Block data
* with embedded block fully populated as complete RawApiTypes.Item object instead
* of just string ID. This provides type safety for working with fully resolved data.
*/
/**
* Single Block field value with nested block - fully populated block object
*/
export type SingleBlockFieldValueInNestedResponse<D extends ItemTypeDefinition = ItemTypeDefinition> = BlockInNestedResponse<D> | null;
/**
* =============================================================================
* SHARED UTILITY FUNCTIONS
* =============================================================================
* These functions are used internally and can be imported by other modules
*/
/**
* Validates if the input is a valid item (either block or record) ID
*/
export declare function isItemId(input: unknown): input is string;
export type ItemWithOptionalIdAndMeta<D extends ItemTypeDefinition = ItemTypeDefinition> = D extends any ? OptionalFields<RawApiTypes.Item<D>, 'id' | 'meta'> : never;
/**
* Validates if the input is a RawApiTypes.Item object (with optional `id` and `meta`)
*/
export declare function isItemWithOptionalIdAndMeta<D extends ItemTypeDefinition = ItemTypeDefinition>(block: unknown): block is ItemWithOptionalIdAndMeta<D>;
export type ItemWithOptionalMeta<D extends ItemTypeDefinition = ItemTypeDefinition> = D extends any ? OptionalFields<RawApiTypes.Item<D>, 'meta'> : never;
/**
* Validates if the input is a a complete RawApiTypes.Item object with optional `meta`
*/
export declare function isItemWithOptionalMeta<D extends ItemTypeDefinition = ItemTypeDefinition>(block: unknown): block is ItemWithOptionalMeta<D>;
/**
* =============================================================================
* TYPE GUARDS - Runtime validation functions
* =============================================================================
*/
/**
* Type guard for basic Single Block field values (block as string ID only).
* Checks for string structure and ensures block is a string reference.
*/
export declare function isSingleBlockFieldValue(value: unknown): value is SingleBlockFieldValue;
export declare function isLocalizedSingleBlockFieldValue(value: unknown): value is LocalizedFieldValue<SingleBlockFieldValue>;
/**
* Type guard for Single Block field values in API request format.
* Allows block as string ID, full object with ID, or object without ID.
*/
export declare function isSingleBlockFieldValueInRequest<D extends ItemTypeDefinition = ItemTypeDefinition>(value: unknown): value is SingleBlockFieldValueInRequest<D>;
export declare function isLocalizedSingleBlockFieldValueInRequest<D extends ItemTypeDefinition = ItemTypeDefinition>(value: unknown): value is LocalizedFieldValue<SingleBlockFieldValueInRequest<D>>;
/**
* Type guard for Single Block field values with nested blocks (?nested=true format).
* Ensures block is a full RawApiTypes.Item object with complete data.
*/
export declare function isSingleBlockFieldValueInNestedResponse<D extends ItemTypeDefinition = ItemTypeDefinition>(value: unknown): value is SingleBlockFieldValueInNestedResponse<D>;
export declare function isLocalizedSingleBlockFieldValueInNestedResponse<D extends ItemTypeDefinition = ItemTypeDefinition>(value: unknown): value is LocalizedFieldValue<SingleBlockFieldValueInNestedResponse<D>>;
export type SingleBlockFieldValidators = {
/** Only accept references to block records of the specified block models */
single_block_blocks: SingleBlockBlocksValidator;
/** Value must be specified or it won't be valid */
required?: RequiredValidator;
};
export type SingleBlockFieldAppearance = {
editor: 'framed_single_block';
parameters: FramedSingleBlockEditorConfiguration;
} | {
editor: 'frameless_single_block';
parameters: FramelessSingleBlockEditorConfiguration;
} | {
/** Plugin ID */
editor: string;
/** Plugin configuration */
parameters: Record<string, unknown>;
};
type OptionalFields<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
export {};