/**
 * Field-schema introspection for the `GET /api/cms/collections` discovery
 * endpoint (roadmap WS-B4).
 *
 * Reduces a collection's field map to a compact, **recursive** summary an
 * agent can plan a create/update against — including `array` element
 * subfields and `blocks` variant subfields — WITHOUT shipping the full
 * runtime validators, hooks, or access functions (those can carry closure
 * state and must never reach the unauthenticated discovery surface).
 *
 * The shape is intentionally additive over the flat `{ name, type, required }`
 * summary: relationship targets, select options, and nested subfield schemas
 * appear only when present, so existing consumers keep working.
 */
/**
 * Defensive recursion cap. Configs are static and authored by the developer,
 * so cycles are not expected, but a malformed/self-referential config must
 * never be able to blow the stack or balloon the response. Five levels is far
 * deeper than any realistic page/array/blocks nesting.
 */
const MAX_DEPTH = 5;
function isFieldMap(value) {
    return !!value && typeof value === 'object' && !Array.isArray(value);
}
/**
 * Summarize a collection's `fields` map into the recursive {@link FieldSummary}
 * array used by the discovery endpoint. Safe on any input — a non-object map
 * (or a missing one) yields `[]`.
 */
export function summarizeCollectionFields(fields, depth = 0) {
    if (!isFieldMap(fields))
        return [];
    return Object.entries(fields).map(([name, fieldDef]) => summarizeField(name, fieldDef, depth));
}
function summarizeField(name, fieldDef, depth) {
    const summary = {
        name,
        type: typeof fieldDef?.type === 'string' ? fieldDef.type : 'unknown',
        required: fieldDef?.required === true,
    };
    // Relationship target collection(s) — the agent needs this to resolve a
    // slug→id for a relationship field.
    if (typeof fieldDef?.relationTo === 'string' || Array.isArray(fieldDef?.relationTo)) {
        summary.relationTo = fieldDef.relationTo;
    }
    if (fieldDef?.hasMany === true || fieldDef?.multiple === true)
        summary.hasMany = true;
    // Select options (label/value pairs or bare strings) so the agent can fill enums.
    if (Array.isArray(fieldDef?.options))
        summary.options = fieldDef.options;
    // Stop recursing past the cap, but still emit the field's own metadata.
    if (depth >= MAX_DEPTH)
        return summary;
    // `array`: recurse into the element subfields so an agent knows the shape of
    // each row it must author.
    if (summary.type === 'array' && isFieldMap(fieldDef?.fields)) {
        summary.fields = summarizeCollectionFields(fieldDef.fields, depth + 1);
        if (typeof fieldDef.minRows === 'number')
            summary.minRows = fieldDef.minRows;
        if (typeof fieldDef.maxRows === 'number')
            summary.maxRows = fieldDef.maxRows;
    }
    // `blocks`: recurse into each block variant's subfields, keyed by the block
    // slug (the discriminator the agent writes as `blockType`).
    if (summary.type === 'blocks' && Array.isArray(fieldDef?.blocks)) {
        summary.blocks = fieldDef.blocks
            .filter((b) => !!b && typeof b === 'object')
            .map((b) => {
            const slug = typeof b.slug === 'string' ? b.slug : 'unknown';
            const labels = b.labels;
            const block = {
                slug,
                fields: summarizeCollectionFields(b.fields, depth + 1),
            };
            if (typeof labels?.singular === 'string')
                block.label = labels.singular;
            return block;
        });
    }
    return summary;
}
//# sourceMappingURL=collection-introspection.js.map