import { importShared } from './__federation_fn_import-C3oBjoRC.js';

/**
 * Creates a plugin spec with init and use phases.
 *
 * @example
 * ```typescript
 * const mySpec = createPluginSpec('core/my-spec', {
 *   initializer: () => {
 *     const items = new Map<string, Item>();
 *     return {
 *       init: {
 *         register: (item: Item) => items.set(item.name, item),
 *       },
 *       use: () => ({
 *         get: (name: string) => items.get(name),
 *         getAll: () => [...items.values()],
 *       }),
 *     };
 *   },
 * });
 * ```
 *
 * @param name - Unique identifier for the spec (e.g., 'core/my-spec')
 * @param options - Options including the initializer function
 * @returns A plugin spec that can be used with SpecStore
 */
function createPluginSpec(name, options) {
    const { initializer } = options;
    return {
        type: 'plugin-spec',
        name,
        initializer,
    };
}

function compareValues(a, b, order) {
    if (a < b) {
        return order === 'asc' ? -1 : 1;
    }
    if (a > b) {
        return order === 'asc' ? 1 : -1;
    }
    return 0;
}

function orderBy(arr, criteria, orders) {
    return arr.slice().sort((a, b) => {
        const ordersLength = orders.length;
        for (let i = 0; i < criteria.length; i++) {
            const order = ordersLength > i ? orders[i] : orders[ordersLength - 1];
            const criterion = criteria[i];
            const criterionIsFunction = typeof criterion === 'function';
            const valueA = criterionIsFunction ? criterion(a) : a[criterion];
            const valueB = criterionIsFunction ? criterion(b) : b[criterion];
            const result = compareValues(valueA, valueB, order);
            if (result !== 0) {
                return result;
            }
        }
        return 0;
    });
}

function sortBy(arr, criteria) {
    return orderBy(arr, criteria, ['asc']);
}

function noop() { }

function getSymbols(object) {
    return Object.getOwnPropertySymbols(object).filter(symbol => Object.prototype.propertyIsEnumerable.call(object, symbol));
}

function getTag(value) {
    if (value == null) {
        return value === undefined ? '[object Undefined]' : '[object Null]';
    }
    return Object.prototype.toString.call(value);
}

const regexpTag = '[object RegExp]';
const stringTag = '[object String]';
const numberTag = '[object Number]';
const booleanTag = '[object Boolean]';
const argumentsTag = '[object Arguments]';
const symbolTag = '[object Symbol]';
const dateTag = '[object Date]';
const mapTag = '[object Map]';
const setTag = '[object Set]';
const arrayTag = '[object Array]';
const functionTag = '[object Function]';
const arrayBufferTag = '[object ArrayBuffer]';
const objectTag = '[object Object]';
const errorTag = '[object Error]';
const dataViewTag = '[object DataView]';
const uint8ArrayTag = '[object Uint8Array]';
const uint8ClampedArrayTag = '[object Uint8ClampedArray]';
const uint16ArrayTag = '[object Uint16Array]';
const uint32ArrayTag = '[object Uint32Array]';
const bigUint64ArrayTag = '[object BigUint64Array]';
const int8ArrayTag = '[object Int8Array]';
const int16ArrayTag = '[object Int16Array]';
const int32ArrayTag = '[object Int32Array]';
const bigInt64ArrayTag = '[object BigInt64Array]';
const float32ArrayTag = '[object Float32Array]';
const float64ArrayTag = '[object Float64Array]';

function isPlainObject(value) {
    if (!value || typeof value !== 'object') {
        return false;
    }
    const proto = Object.getPrototypeOf(value);
    const hasObjectPrototype = proto === null ||
        proto === Object.prototype ||
        Object.getPrototypeOf(proto) === null;
    if (!hasObjectPrototype) {
        return false;
    }
    return Object.prototype.toString.call(value) === '[object Object]';
}

function isEqualsSameValueZero(value, other) {
    return value === other || (Number.isNaN(value) && Number.isNaN(other));
}

function isEqualWith(a, b, areValuesEqual) {
    return isEqualWithImpl(a, b, undefined, undefined, undefined, undefined, areValuesEqual);
}
function isEqualWithImpl(a, b, property, aParent, bParent, stack, areValuesEqual) {
    const result = areValuesEqual(a, b, property, aParent, bParent, stack);
    if (result !== undefined) {
        return result;
    }
    if (typeof a === typeof b) {
        switch (typeof a) {
            case 'bigint':
            case 'string':
            case 'boolean':
            case 'symbol':
            case 'undefined': {
                return a === b;
            }
            case 'number': {
                return a === b || Object.is(a, b);
            }
            case 'function': {
                return a === b;
            }
            case 'object': {
                return areObjectsEqual(a, b, stack, areValuesEqual);
            }
        }
    }
    return areObjectsEqual(a, b, stack, areValuesEqual);
}
function areObjectsEqual(a, b, stack, areValuesEqual) {
    if (Object.is(a, b)) {
        return true;
    }
    let aTag = getTag(a);
    let bTag = getTag(b);
    if (aTag === argumentsTag) {
        aTag = objectTag;
    }
    if (bTag === argumentsTag) {
        bTag = objectTag;
    }
    if (aTag !== bTag) {
        return false;
    }
    switch (aTag) {
        case stringTag:
            return a.toString() === b.toString();
        case numberTag: {
            const x = a.valueOf();
            const y = b.valueOf();
            return isEqualsSameValueZero(x, y);
        }
        case booleanTag:
        case dateTag:
        case symbolTag:
            return Object.is(a.valueOf(), b.valueOf());
        case regexpTag: {
            return a.source === b.source && a.flags === b.flags;
        }
        case functionTag: {
            return a === b;
        }
    }
    stack = stack ?? new Map();
    const aStack = stack.get(a);
    const bStack = stack.get(b);
    if (aStack != null && bStack != null) {
        return aStack === b;
    }
    stack.set(a, b);
    stack.set(b, a);
    try {
        switch (aTag) {
            case mapTag: {
                if (a.size !== b.size) {
                    return false;
                }
                for (const [key, value] of a.entries()) {
                    if (!b.has(key) || !isEqualWithImpl(value, b.get(key), key, a, b, stack, areValuesEqual)) {
                        return false;
                    }
                }
                return true;
            }
            case setTag: {
                if (a.size !== b.size) {
                    return false;
                }
                const aValues = Array.from(a.values());
                const bValues = Array.from(b.values());
                for (let i = 0; i < aValues.length; i++) {
                    const aValue = aValues[i];
                    const index = bValues.findIndex(bValue => {
                        return isEqualWithImpl(aValue, bValue, undefined, a, b, stack, areValuesEqual);
                    });
                    if (index === -1) {
                        return false;
                    }
                    bValues.splice(index, 1);
                }
                return true;
            }
            case arrayTag:
            case uint8ArrayTag:
            case uint8ClampedArrayTag:
            case uint16ArrayTag:
            case uint32ArrayTag:
            case bigUint64ArrayTag:
            case int8ArrayTag:
            case int16ArrayTag:
            case int32ArrayTag:
            case bigInt64ArrayTag:
            case float32ArrayTag:
            case float64ArrayTag: {
                if (typeof Buffer !== 'undefined' && Buffer.isBuffer(a) !== Buffer.isBuffer(b)) {
                    return false;
                }
                if (a.length !== b.length) {
                    return false;
                }
                for (let i = 0; i < a.length; i++) {
                    if (!isEqualWithImpl(a[i], b[i], i, a, b, stack, areValuesEqual)) {
                        return false;
                    }
                }
                return true;
            }
            case arrayBufferTag: {
                if (a.byteLength !== b.byteLength) {
                    return false;
                }
                return areObjectsEqual(new Uint8Array(a), new Uint8Array(b), stack, areValuesEqual);
            }
            case dataViewTag: {
                if (a.byteLength !== b.byteLength || a.byteOffset !== b.byteOffset) {
                    return false;
                }
                return areObjectsEqual(new Uint8Array(a), new Uint8Array(b), stack, areValuesEqual);
            }
            case errorTag: {
                return a.name === b.name && a.message === b.message;
            }
            case objectTag: {
                const areEqualInstances = areObjectsEqual(a.constructor, b.constructor, stack, areValuesEqual) ||
                    (isPlainObject(a) && isPlainObject(b));
                if (!areEqualInstances) {
                    return false;
                }
                const aKeys = [...Object.keys(a), ...getSymbols(a)];
                const bKeys = [...Object.keys(b), ...getSymbols(b)];
                if (aKeys.length !== bKeys.length) {
                    return false;
                }
                for (let i = 0; i < aKeys.length; i++) {
                    const propKey = aKeys[i];
                    const aProp = a[propKey];
                    if (!Object.hasOwn(b, propKey)) {
                        return false;
                    }
                    const bProp = b[propKey];
                    if (!isEqualWithImpl(aProp, bProp, propKey, a, b, stack, areValuesEqual)) {
                        return false;
                    }
                }
                return true;
            }
            default: {
                return false;
            }
        }
    }
    finally {
        stack.delete(a);
        stack.delete(b);
    }
}

function isEqual(a, b) {
    return isEqualWith(a, b, noop);
}

/**
 * Field container for a single value that cannot be overridden once set
 */
class ScalarContainer {
    _value;
    defaultValue;
    isSet = false;
    setBySource;
    getDynamicSource;
    constructor(defaultValue, options) {
        this.defaultValue = defaultValue;
        this.getDynamicSource = options?.getDynamicSource;
    }
    getValue() {
        return this._value === undefined ? this.defaultValue : this._value;
    }
    set(value, source) {
        const setBySource = source ?? this.getDynamicSource?.() ?? 'unknown';
        if (this.isSet) {
            // oxlint-disable-next-line unicorn/prefer-type-error -- false positive
            throw new Error(`Value has already been set by ${this.setBySource} and cannot be overwritten by ${setBySource}`);
        }
        this._value = value;
        this.isSet = true;
        this.setBySource = setBySource;
    }
}
// Array field container
class ArrayContainer {
    _stripDuplicates;
    _value;
    constructor(initialValue, options) {
        this._stripDuplicates = options?.stripDuplicates ?? false;
        this._value = initialValue ?? [];
    }
    push(...items) {
        let currentValue = this._value;
        if (this._stripDuplicates) {
            // Add items without duplicates
            const set = new Set([...currentValue, ...items]);
            currentValue = [...set];
        }
        else {
            // Add all items
            currentValue = [...currentValue, ...items];
        }
        this._value = currentValue;
    }
    getValue() {
        return this._value;
    }
}
class ObjectContainer {
    map;
    getDynamicSource;
    constructor(initialValue, options) {
        this.getDynamicSource = options?.getDynamicSource;
        this.map = new Map(Object.entries(initialValue).map(([key, value]) => [
            key,
            { value, setBySource: this.getDynamicSource?.() },
        ]));
    }
    set(key, value, source) {
        const existingValue = this.map.get(key);
        const setBySource = source ?? this.getDynamicSource?.() ?? 'unknown';
        if (existingValue?.setBySource) {
            throw new Error(`Value for key ${key} has already been set by ${existingValue.setBySource} and cannot be overwritten by ${setBySource}`);
        }
        this.map.set(key, {
            value,
            setBySource,
        });
    }
    merge(value, source) {
        const mergeSource = source ?? this.getDynamicSource?.();
        for (const [key, val] of Object.entries(value)) {
            this.set(key, val, mergeSource);
        }
    }
    getValue() {
        return Object.fromEntries([...this.map.entries()].map(([key, value]) => [key, value.value]));
    }
}
// Map field container
class MapContainer {
    _value;
    getDynamicSource;
    constructor(initialValue, options) {
        this.getDynamicSource = options?.getDynamicSource;
        const initialMap = initialValue ?? new Map();
        this._value = new Map([...initialMap.entries()].map(([key, value]) => [
            key,
            { value, setBySource: this.getDynamicSource?.() },
        ]));
    }
    set(key, value, source) {
        const existingValue = this._value.get(key);
        const setBySource = source ?? this.getDynamicSource?.() ?? 'unknown';
        if (existingValue?.setBySource) {
            throw new Error(`Value for key ${key} has already been set by ${existingValue.setBySource} and cannot be overwritten by ${setBySource}`);
        }
        this._value.set(key, {
            value,
            setBySource,
        });
    }
    merge(value, source) {
        const mergeSource = source ?? this.getDynamicSource?.();
        for (const [key, val] of value.entries()) {
            this.set(key, val, mergeSource);
        }
    }
    mergeObj(value, source) {
        const mergeSource = source ?? this.getDynamicSource?.();
        for (const [key, val] of Object.entries(value)) {
            this.set(key, val, mergeSource);
        }
    }
    getValue() {
        return new Map([...this._value.entries()].map(([key, value]) => [key, value.value]));
    }
}
/**
 * Named field container
 *
 * This container stores objects that contains a name field that can be used for
 * detecting duplicate names.
 */
class NamedArrayFieldContainer {
    _value;
    getDynamicSource;
    constructor(initialValue, options) {
        this.getDynamicSource = options?.getDynamicSource;
        const value = initialValue ?? [];
        this._value = new Map(value.map((val) => [
            val.name,
            { value: val, setBySource: this.getDynamicSource?.() },
        ]));
    }
    add(value, source) {
        const existingValue = this._value.get(value.name);
        const setBySource = source ?? this.getDynamicSource?.() ?? 'unknown';
        if (existingValue?.setBySource) {
            throw new Error(`Value for name ${value.name} has already been set by ${existingValue.setBySource} and cannot be overwritten by ${setBySource}`);
        }
        this._value.set(value.name, {
            value,
            setBySource,
        });
    }
    addMany(values, source) {
        for (const value of values) {
            this.add(value, source);
        }
    }
    getValue() {
        return sortBy([...this._value.values()].map((value) => value.value), [(v) => v.name]);
    }
}
/**
 * Named array field container that returns a map of names to values
 */
class NamedArrayToMapFieldContainer {
    _namedFieldContainer;
    constructor(initialValue, options) {
        this._namedFieldContainer = new NamedArrayFieldContainer(initialValue, options);
    }
    add(value, source) {
        this._namedFieldContainer.add(value, source);
    }
    addMany(values, source) {
        this._namedFieldContainer.addMany(values, source);
    }
    getValue() {
        return new Map(this._namedFieldContainer.getValue().map((value) => [value.name, value]));
    }
}
// Map of maps field container
class MapOfMapsContainer {
    _value;
    getDynamicSource;
    constructor(initialValue, options) {
        this.getDynamicSource = options?.getDynamicSource;
        const initialMap = initialValue ?? new Map();
        this._value = new Map([...initialMap.entries()].map(([key1, innerMap]) => [
            key1,
            {
                value: new Map([...innerMap.entries()].map(([key2, value]) => [
                    key2,
                    { value, setBySource: this.getDynamicSource?.() },
                ])),
                setBySource: this.getDynamicSource?.(),
            },
        ]));
    }
    set(key1, key2, value, source) {
        const existingOuterValue = this._value.get(key1);
        const setBySource = source ?? this.getDynamicSource?.() ?? 'unknown';
        // If the outer key doesn't exist yet, create a new map for it
        if (!existingOuterValue) {
            const newInnerMap = new Map([[key2, { value, setBySource }]]);
            this._value.set(key1, {
                value: newInnerMap,
                setBySource,
            });
            return;
        }
        // Check if this specific key1+key2 combination has already been set
        const existingInnerValue = existingOuterValue.value.get(key2);
        if (existingInnerValue?.setBySource) {
            throw new Error(`Value for keys ${key1}+${key2} has already been set by ${existingInnerValue.setBySource} and cannot be overwritten by ${setBySource}`);
        }
        // Add the new value to the existing inner map
        existingOuterValue.value.set(key2, {
            value,
            setBySource,
        });
    }
    merge(key1, value, source) {
        const mergeSource = source ?? this.getDynamicSource?.() ?? 'unknown';
        for (const [key2, val] of value.entries()) {
            this.set(key1, key2, val, mergeSource);
        }
    }
    mergeObj(key1, value, source) {
        const mergeSource = source ?? this.getDynamicSource?.() ?? 'unknown';
        for (const [key2, val] of Object.entries(value)) {
            this.set(key1, key2, val, mergeSource);
        }
    }
    getValue() {
        return new Map([...this._value.entries()].map(([key1, outerValue]) => [
            key1,
            new Map([...outerValue.value.entries()].map(([key2, innerValue]) => [
                key2,
                innerValue.value,
            ])),
        ]));
    }
}
// Schema builder class
class FieldMapSchemaBuilder {
    options;
    constructor(options) {
        this.options = options;
    }
    scalar(defaultValue) {
        return new ScalarContainer(defaultValue, this.options);
    }
    string(defaultValue) {
        return new ScalarContainer(defaultValue, this.options);
    }
    number(defaultValue) {
        return new ScalarContainer(defaultValue, this.options);
    }
    boolean(defaultValue) {
        return new ScalarContainer(defaultValue, this.options);
    }
    array(initialValue, options) {
        return new ArrayContainer(initialValue, options);
    }
    object(defaultValue) {
        return new ObjectContainer(defaultValue, this.options);
    }
    map(initialValue) {
        return new MapContainer(initialValue ?? new Map(), this.options);
    }
    mapFromObj(initialValue) {
        return new MapContainer(new Map(Object.entries(initialValue ?? {})), this.options);
    }
    namedArray(initialValue) {
        return new NamedArrayFieldContainer(initialValue, this.options);
    }
    namedArrayToMap(initialValue) {
        return new NamedArrayToMapFieldContainer(initialValue, this.options);
    }
    mapOfMaps(initialValue) {
        return new MapOfMapsContainer(initialValue ?? new Map(), this.options);
    }
    mapOfMapsFromObj(initialValue) {
        const map = new Map();
        if (initialValue) {
            for (const [key1, innerObj] of Object.entries(initialValue)) {
                map.set(key1, new Map(Object.entries(innerObj)));
            }
        }
        return new MapOfMapsContainer(map, this.options);
    }
}
/**
 * Creates a field map with type-safe field definitions
 */
function createFieldMap(schemaBuilder, options) {
    const schema = schemaBuilder(new FieldMapSchemaBuilder(options));
    // Add getValues method
    return {
        ...schema,
        getValues: () => {
            const values = {};
            for (const key of Object.keys(schema)) {
                const container = schema[key];
                values[key] = container.getValue();
            }
            return values;
        },
    };
}

let random = bytes => crypto.getRandomValues(new Uint8Array(bytes));
let customRandom = (alphabet, defaultSize, getRandom) => {
  let mask = (2 << Math.log2(alphabet.length - 1)) - 1;
  let step = -~((1.6 * mask * defaultSize) / alphabet.length);
  return (size = defaultSize) => {
    let id = '';
    while (true) {
      let bytes = getRandom(step);
      let j = step | 0;
      while (j--) {
        id += alphabet[bytes[j] & mask] || '';
        if (id.length >= size) return id
      }
    }
  }
};
let customAlphabet = (alphabet, size = 21) =>
  customRandom(alphabet, size | 0, random);

const NUMBERS = '0123456789';
const LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
const UPPERCASE = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
/**
 * Use custom ID generator for characters that be easily selected
 */
const customNanoid = customAlphabet(`${NUMBERS}${LOWERCASE}${UPPERCASE}_`, 12);
/**
 * Generate a random key string made up of numbers, lowercase, and uppercase letters
 * @returns A random key string
 */
function randomKey(length = 12) {
    return customNanoid(length);
}

const {z: z$3} = await importShared('zod');

/**
 * Registry that stores human-readable validation hints on Zod schema instances.
 *
 * Used by `buildTsDescriptionRegistry` to annotate TypeScript type output with
 * validation constraints (e.g., "camelCase", "CONSTANT_CASE") as JSDoc comments.
 *
 * Validators register hints at module load time. The registry is consumed
 * during schema-to-TypeScript conversion to produce annotated output.
 */
const validationHintRegistry = z$3.registry();

const {z: z$2} = await importShared('zod');
/**
 * Regex for validating kebab case, e.g. "my-project".
 */
const KEBAB_CASE_REGEX = /^[a-z0-9-]+$/;
/**
 * Regex for validating pascal case, e.g. "MyProject".
 */
const PASCAL_CASE_REGEX = /^[A-Z][a-zA-Z0-9]*$/;
/**
 * Regex for validating camel case, e.g. "myProject".
 */
const CAMEL_CASE_REGEX = /^[a-z][a-zA-Z0-9]*$/;
/**
 * Regex for validating constant case, e.g. "MY_PROJECT".
 */
const CONSTANT_CASE_REGEX = /^[A-Z][A-Z0-9_]*$/;
const CASE_VALIDATORS = {
    /**
     * Zod validator for validating kebab case, e.g. "my-project".
     */
    KEBAB_CASE: z$2
        .string()
        .regex(KEBAB_CASE_REGEX, {
        message: 'Must be kebab case (e.g. "my-project")',
    })
        .register(validationHintRegistry, {
        description: 'kebab-case (e.g. "my-project")',
    }),
    /**
     * Zod validator for validating pascal case, e.g. "MyProject".
     */
    PASCAL_CASE: z$2
        .string()
        .regex(PASCAL_CASE_REGEX, {
        message: 'Must be pascal case (e.g. "MyProject")',
    })
        .register(validationHintRegistry, {
        description: 'PascalCase (e.g. "MyProject")',
    }),
    /**
     * Zod validator for validating camel case, e.g. "myProject".
     */
    CAMEL_CASE: z$2
        .string()
        .regex(CAMEL_CASE_REGEX, {
        message: 'Must be camel case (e.g. "myProject")',
    })
        .register(validationHintRegistry, {
        description: 'camelCase (e.g. "myProject")',
    }),
    /**
     * Zod validator for validating constant case, e.g. "MY_PROJECT".
     */
    CONSTANT_CASE: z$2
        .string()
        .regex(CONSTANT_CASE_REGEX, {
        message: 'Must be constant case (e.g. "MY_PROJECT")',
    })
        .register(validationHintRegistry, {
        description: 'CONSTANT_CASE (e.g. "MY_PROJECT")',
    }),
};

/**
 * Plugin context module for tracking the current plugin being initialized.
 *
 * Uses a simple synchronous context that works on both Node and browser platforms.
 * This is safe because plugin initialization is synchronous and single-threaded.
 */
// Simple synchronous context - works on both Node and browser
// Safe because plugin initialization is synchronous and single-threaded
let currentPluginContext;
/**
 * Runs a function within a plugin context.
 *
 * This sets the current plugin context for the duration of the function execution,
 * allowing nested functions to access the plugin key via `getPluginContext()`.
 *
 * @param context - The plugin context to set
 * @param fn - The function to run within the context
 * @returns The result of the function
 */
function runInPluginContext(context, fn) {
    const prev = currentPluginContext;
    currentPluginContext = context;
    try {
        return fn();
    }
    finally {
        currentPluginContext = prev;
    }
}
/**
 * Gets the current plugin context if one exists.
 *
 * @returns The current plugin context, or undefined if not in a plugin context
 */
function getPluginContext() {
    return currentPluginContext;
}

/**
 * Creates a field map that automatically tracks which plugin registered each value.
 *
 * Similar to `createConfigFieldMap` in the sync package, this utility uses the
 * current plugin context to track the source of registrations. This enables
 * clear error messages when registration conflicts occur.
 *
 * @example
 * ```typescript
 * const fieldMap = createPluginFieldMap((t) => ({
 *   transformers: t.map<string, Transformer>(),
 * }));
 *
 * // When a plugin tries to overwrite a value:
 * // Error: Value for key 'myTransformer' has already been set by plugin-auth
 * //        and cannot be overwritten by plugin-storage
 * ```
 *
 * @param schemaBuilder - A function that builds the field map schema
 * @returns A field map with automatic source tracking
 */
function createPluginFieldMap(schemaBuilder) {
    return createFieldMap(schemaBuilder, {
        getDynamicSource: () => getPluginContext()?.pluginKey,
    });
}

/**
 * Creates a plugin spec backed by a FieldMap for automatic source tracking.
 *
 * @param name - Unique identifier for the spec
 * @param schemaBuilder - Function that builds the field map schema
 * @param options - Optional configuration including custom use interface
 */
function createFieldMapSpec(name, schemaBuilder, options) {
    return createPluginSpec(name, {
        initializer: () => {
            const fieldMap = createPluginFieldMap(schemaBuilder);
            return {
                init: fieldMap,
                use: () => {
                    const values = fieldMap.getValues();
                    if (options?.use) {
                        return options.use(values);
                    }
                    return values;
                },
            };
        },
    });
}

/**
 * Global registry that stores Baseplate metadata on Zod schema instances.
 *
 * Uses a plain WeakMap to avoid Zod's `$replace<Meta, S>` type substitution
 * which causes "type instantiation excessively deep" errors with complex unions.
 *
 * Stores an array of metadata per schema to support schemas that carry multiple
 * annotations (e.g. a schema that is both an `entity` and a `ref-context`).
 *
 * Used by `withEnt`, `withRef`, `withExpression`, and `refContext` to attach
 * metadata to schema nodes. The parallel schema+data walker reads this registry
 * to extract entity/reference/expression information after validation.
 */
const definitionRefRegistry = (() => {
    const map = new WeakMap();
    return {
        add(schema, meta) {
            const existing = map.get(schema);
            if (existing) {
                if ((meta.kind === 'entity' || meta.kind === 'reference') &&
                    existing.some((e) => e.kind === meta.kind && e.type === meta.type)) {
                    throw new Error(`Duplicate definition ref metadata kind "${meta.kind}" for type "${meta.type.name}" on the same schema instance. ` +
                        `This usually means a shared/module-level schema was passed to withEnt/withRef multiple times. ` +
                        `Create a fresh schema instance instead.`);
                }
                existing.push(meta);
            }
            else {
                map.set(schema, [meta]);
            }
        },
        getAll(schema) {
            return map.get(schema) ?? [];
        },
        has(schema) {
            return map.has(schema);
        },
    };
})();

/**
 * Plugin spec for registering expression parsers.
 *
 * Expression parsers handle parsing, validation, and rename detection
 * for expression fields in the project definition (e.g., authorizer
 * role expressions).
 *
 * Built-in parsers (authorizer expressions) are registered by core modules.
 * Plugins can register additional parsers during initialization.
 *
 * @example
 * ```typescript
 * createPluginModule({
 *   dependencies: { expressionParsers: expressionParserSpec },
 *   initialize: ({ expressionParsers }) => {
 *     expressionParsers.parsers.set('my-expression', myParser);
 *   },
 * });
 * ```
 */
const expressionParserSpec = createFieldMapSpec('core/expression-parsers', (t) => ({
    parsers: t.map(),
}), {
    use: (values) => ({
        getParser: (name) => values.parsers.get(name),
    }),
});

/**
 * A pluggable parser for ref expressions.
 *
 * The parser is format-agnostic - the core references system
 * doesn't know or care what format the expressions are in. The parser
 * handles all parsing, validation, and rename handling.
 *
 * Parsers can declare required slots via the TRequiredSlots generic parameter.
 * When a parser requires slots, TypeScript enforces that they are provided
 * when calling `withExpression()`.
 *
 * @typeParam TValue - The type of the raw expression value (e.g., string for TS expressions)
 * @typeParam TParseResult - The type of the parsed result (e.g., AST for TS expressions)
 * @typeParam TRequiredSlots - Record of required slot names to entity types
 *
 * @example
 * ```typescript
 * // A simple parser with no required slots
 * class StubParser extends RefExpressionParser<string, undefined> {
 *   readonly name = 'stub';
 *   parse(): undefined { return undefined; }
 *   getWarnings(): [] { return []; }
 *   getReferencedEntities(): [] { return []; }
 * }
 *
 * // A parser that requires a model slot
 * class AuthorizerParser extends RefExpressionParser<
 *   string,
 *   TsAst,
 *   { model: typeof modelEntityType }
 * > {
 *   readonly name = 'authorizer';
 *   // TypeScript enforces slot requirement in withExpression()
 * }
 * ```
 */
class RefExpressionParser {
    /**
     * Convenience method that combines parse() and getWarnings() into a single call.
     * Parses the expression and returns all validation warnings (including parse errors).
     *
     * @param value - The raw expression value
     * @param projectDef - The project definition for context
     * @param context - Validation context with project definition and plugin store
     * @param resolvedSlots - The resolved slot paths for this expression
     * @returns Array of warnings (empty if valid)
     */
    validate(value, projectDef, context, resolvedSlots) {
        const parseResult = this.parse(value, projectDef);
        if (!parseResult.success) {
            return [{ message: parseResult.error }];
        }
        return this.getWarnings(parseResult.value, context, resolvedSlots);
    }
    /**
     * Phantom property for TRequiredSlots type inference.
     * This is never actually used at runtime.
     * @internal
     */
    _requiredSlots;
}

/**
 * Creates a new ref context slot for the given entity type.
 * Each call creates a unique slot, even for the same entity type.
 *
 * @param name - A descriptive name for debugging (shows in Symbol description)
 * @param entityType - The entity type this slot will be associated with
 * @returns A new unique RefContextSlot instance
 *
 * @example
 * ```typescript
 * const modelSlot = createRefContextSlot('modelSlot', modelEntityType);
 * const anotherModelSlot = createRefContextSlot('anotherModelSlot', modelEntityType);
 *
 * // These are different slots despite same entity type
 * modelSlot.id !== anotherModelSlot.id
 * // modelSlot.id.toString() === 'Symbol(modelSlot)'
 * ```
 */
function createRefContextSlot(name, entityType) {
    return {
        entityType,
        id: Symbol(name),
    };
}
/**
 * Creates a RefContextSlotMap from a slot definition.
 * Used internally by ctx.refContext().
 *
 * @param slotDefinition - Map of slot names to entity types
 * @returns Map of slot names to RefContextSlot instances
 */
function createRefContextSlotMap(slotDefinition) {
    return Object.fromEntries(Object.entries(slotDefinition).map(([key, entityType]) => [
        key,
        createRefContextSlot(key, entityType),
    ]));
}

const {z: z$1} = await importShared('zod');
/**
 * Creates a string schema annotated as a reference to another entity.
 *
 * Can be used standalone:
 * ```typescript
 * withRef({ type: modelEnumEntityType, onDelete: 'RESTRICT' })
 * ```
 *
 * Or on the parser context:
 * ```typescript
 * ctx.withRef({ type: modelEnumEntityType, onDelete: 'RESTRICT' })
 * ```
 */
function withRef(reference) {
    const schema = z$1.string().min(1);
    definitionRefRegistry.add(schema, {
        kind: 'reference',
        type: reference.type,
        onDelete: reference.onDelete,
        parentSlot: reference.parentSlot,
        provides: reference.provides,
    });
    return schema;
}
/**
 * Creates a schema decorator that marks a schema as defining an entity.
 *
 * Can be used with `.apply()`:
 * ```typescript
 * schema.apply(withEnt({ type: modelEntityType, provides: modelSlot }))
 * ```
 *
 * Or via the parser context (2-arg legacy form):
 * ```typescript
 * ctx.withEnt(schema, { type: modelEntityType, provides: modelSlot })
 * ```
 *
 * @param entity - The entity definition input
 * @returns A function that decorates a schema with entity metadata
 */
function withEnt(entity) {
    return (schema) => {
        const idPath = entity.idPath ?? ['id'];
        definitionRefRegistry.add(schema, {
            kind: 'entity',
            type: entity.type,
            idPath,
            getNameResolver: entity.getNameResolver,
            parentSlot: entity.parentSlot,
            provides: entity.provides,
            sortByName: entity.sortByName,
        });
        return schema;
    };
}
/**
 * Creates ref context slots for use within a schema definition.
 * Slots provide type-safe context for parent-child entity relationships.
 *
 * @example
 * ```typescript
 * ctx.refContext(
 *   { modelSlot: modelEntityType },
 *   ({ modelSlot }) =>
 *     ctx.withEnt(schema, {
 *       type: modelEntityType,
 *       provides: modelSlot,
 *     }),
 * );
 * ```
 */
function refContext(slotDefinition, schemaBuilder) {
    const slots = createRefContextSlotMap(slotDefinition);
    const schema = schemaBuilder(slots);
    definitionRefRegistry.add(schema, {
        kind: 'ref-context',
        slots: Object.values(slots),
    });
    return schema;
}
/**
 * Wraps a value with a ref expression parser for deferred validation.
 * The parser handles all parsing, validation, and rename handling.
 *
 * If the parser declares required slots (via TRequiredSlots), they must be
 * provided as the second argument. TypeScript enforces this at compile time.
 *
 * The parser's `createSchema()` method is called to get a fresh schema
 * instance per call site, allowing per-call metadata to be registered
 * independently in the Baseplate registry.
 *
 * @example
 * ```typescript
 * // Parser without required slots
 * const expressionSchema = ctx.withExpression(simpleParser);
 *
 * // Parser with required slots (TypeScript enforces the second argument)
 * ctx.refContext(
 *   { modelSlot: modelEntityType },
 *   ({ modelSlot }) =>
 *     z.object({
 *       condition: ctx.withExpression(authorizerParser, { model: modelSlot }),
 *     })
 * );
 * ```
 */
/**
 * Creates a `withExpression` function that resolves parser refs eagerly
 * from the plugin spec store at schema construction time.
 */
function createWithExpression(plugins) {
    // Implementation
    function withExpression(parserOrRef, 
    // oxlint-disable-next-line typescript/no-explicit-any
    slots) {
        // oxlint-disable-next-line typescript/no-explicit-any
        let parser;
        if (parserOrRef instanceof RefExpressionParser) {
            parser = parserOrRef;
        }
        else {
            // Resolve parser ref from plugin spec store
            if (!plugins) {
                throw new Error(`PluginSpecStore is required to resolve expression parser ref "${parserOrRef.name}". ` +
                    `Ensure plugins are provided to createDefinitionSchemaParserContext.`);
            }
            const specUse = plugins.use(expressionParserSpec);
            const resolved = specUse.getParser(parserOrRef.name);
            if (!resolved) {
                throw new Error(`Expression parser "${parserOrRef.name}" not found in expressionParserSpec. ` +
                    `Ensure it is registered via a core module or plugin.`);
            }
            parser = resolved;
        }
        const schema = parser.createSchema();
        definitionRefRegistry.add(schema, {
            kind: 'expression',
            parser,
            slots,
        });
        return schema;
    }
    return withExpression;
}
function extendParserContextWithRefs(plugins) {
    return {
        withRef,
        // Legacy 2-arg API that delegates to the standalone withEnt decorator.
        // Uses a cast because the standalone accepts DefinitionEntityInput<unknown, ...>
        // while this 2-arg form infers the full z.output<TType> for type-safe idPath.
        withEnt(schema, entity) {
            return schema.apply(withEnt(entity));
        },
        refContext,
        withExpression: createWithExpression(plugins),
    };
}

/**
 * Registry that stores default-value metadata on Zod schema instances.
 *
 * Uses a WeakMap to avoid interfering with Zod's type system.
 * Annotated by `withDefault()`; read by `cleanDefaultValues()`.
 */
const definitionDefaultRegistry = (() => {
    const map = new WeakMap();
    return {
        set(schema, meta) {
            map.set(schema, meta);
        },
        get(schema) {
            return map.get(schema);
        },
    };
})();

/**
 * Creates a schema decorator that applies a default value.
 *
 * Uses `prefault` to ensure defaults are populated during Zod parse, and
 * registers the default value in the registry so `cleanDefaultValues()` can
 * strip matching values during serialization.
 *
 * Can be used standalone with `.apply()`:
 * ```typescript
 * z.boolean().apply(withDefault(false))
 * ```
 *
 * @param defaultValue - The default value to apply
 * @returns A function that decorates a schema with the default value
 */
function withDefault(defaultValue) {
    return (schema) => {
        const result = schema.prefault(defaultValue);
        definitionDefaultRegistry.set(result, { defaultValue });
        return result;
    };
}
/**
 * Extends the parser context with default value handling functionality.
 *
 * @returns An object containing the withDefault method
 */
function extendParserContextWithDefaults() {
    return {
        withDefault: (schema, defaultValue) => withDefault(defaultValue)(schema),
    };
}

const contextCache = new WeakMap();
function createDefinitionSchemaParserContext(options) {
    const cached = contextCache.get(options.plugins);
    if (cached)
        return cached;
    const context = {
        ...options,
        ...extendParserContextWithRefs(options.plugins),
        ...extendParserContextWithDefaults(),
    };
    contextCache.set(options.plugins, context);
    return context;
}
function definitionSchema(creator) {
    const cache = new WeakMap();
    return (context) => {
        const cached = cache.get(context);
        if (cached)
            return cached;
        const result = creator(context);
        cache.set(context, result);
        return result;
    };
}
/**
 * Creates a schema that requires slots to be passed from parent schemas.
 * Used when a schema needs to reference entities from a parent context.
 *
 * @example
 * ```typescript
 * // Child schema requiring modelSlot from parent
 * export const createModelScalarFieldSchema = definitionSchemaWithSlots(
 *   { modelSlot: modelEntityType },
 *   (ctx, { modelSlot }) =>
 *     ctx.withEnt(schema, {
 *       type: modelScalarFieldEntityType,
 *       parentSlot: modelSlot,
 *     }),
 * );
 *
 * // Called from parent:
 * createModelScalarFieldSchema(ctx, { modelSlot: parentModelSlot })
 * ```
 */
function definitionSchemaWithSlots(slotDefinition, creator) {
    const creatorWithSlots = (context, slots) => creator(context, slots);
    creatorWithSlots.slotDefinition = slotDefinition;
    return creatorWithSlots;
}
/**
 * Wraps a schema creator that requires slots with placeholder slots,
 * producing a simple schema creator that can be used for validation-only
 * contexts (e.g., React Hook Form).
 *
 * The placeholder slots allow the schema to parse without actual parent context,
 * which is useful when you only need schema validation without ref extraction.
 *
 * @example
 * ```typescript
 * // Schema that normally requires modelSlot from parent
 * const createModelScalarFieldSchema = definitionSchemaWithSlots(
 *   { modelSlot: modelEntityType },
 *   (ctx, { modelSlot }) => ctx.withEnt(schema, { parentSlot: modelSlot }),
 * );
 *
 * // For React Hook Form validation, wrap with placeholder slots
 * const fieldSchema = withPlaceholderSlots(createModelScalarFieldSchema);
 * const zodSchema = fieldSchema(ctx); // No slots needed
 * ```
 */
function withPlaceholderSlots(schemaCreator) {
    return (ctx) => {
        const placeholderSlots = createRefContextSlotMap(schemaCreator.slotDefinition);
        return schemaCreator(ctx, placeholderSlots);
    };
}

/**
 * Definition of an entity type.
 */
class DefinitionEntityType {
    prefix;
    name;
    parentType;
    /**
     * Creates a new entity type.
     *
     * @param name - The name of the entity type.
     * @param prefix - The prefix of the entity type to use in the ID, defaults to the name.
     * @param parentType - The type of the parent entity if any
     */
    constructor(name, prefix, parentType) {
        this.name = name;
        this.parentType = parentType;
        this.prefix = prefix ?? name.split('/').pop() ?? name;
    }
    /**
     * Generates a new ID for the entity type.
     *
     * @returns The new ID.
     */
    generateNewId() {
        return `${this.prefix}:${randomKey()}`;
    }
    idFromKey(key) {
        if (!key) {
            return undefined;
        }
        return `${this.prefix}:${key}`;
    }
    keyFromId(id) {
        return id.split(':')[1];
    }
    isId(id) {
        return id.startsWith(`${this.prefix}:`);
    }
}
function createEntityType(name, options) {
    const { parentType, prefix } = options ?? {};
    return new DefinitionEntityType(name, prefix, parentType);
}

const {z} = await importShared('zod');
const featureEntityType = createEntityType('feature');
const featureNameSchema = CASE_VALIDATORS.KEBAB_CASE;
const createFeatureSchema = definitionSchema((ctx) => ctx.withEnt(z.object({
    id: z.string(),
    name: z
        .string()
        .min(1)
        .refine((name) => name
        .split('/')
        .every((part) => featureNameSchema.safeParse(part).success), {
        message: 'Feature name must be lowercase and contain only letters, numbers, and dashes',
    }),
    parentRef: ctx
        .withRef({
        type: featureEntityType,
        onDelete: 'DELETE_PARENT',
    })
        .optional(),
}), { type: featureEntityType, sortByName: true }));
const createFeaturesSchema = definitionSchema((ctx) => z.array(createFeatureSchema(ctx)).default([]));

function getRootFeatures(projectDefinition) {
    return projectDefinition.features.filter((f) => !f.parentRef);
}
function getFeatureById(projectDefinition, featureId) {
    return projectDefinition.features.find((f) => f.id === featureId);
}
function getFeatureByIdOrThrow(projectDefinition, featureId) {
    const feature = getFeatureById(projectDefinition, featureId);
    if (!feature) {
        throw new Error(`Could not find feature with ID ${featureId}`);
    }
    return feature;
}
function getFeatureChildren(projectDefinition, featureId) {
    return projectDefinition.features.filter((f) => f.parentRef === featureId);
}
function getFeatureName(featureConfig) {
    return featureConfig.name.split('/').pop() ?? '';
}
function getFeatureNameById(projectDefinition, featureId) {
    const feature = getFeatureByIdOrThrow(projectDefinition, featureId);
    return getFeatureName(feature);
}
function getFeaturePathByIdOrThrow(projectDefinition, featureId) {
    const feature = getFeatureByIdOrThrow(projectDefinition, featureId);
    return feature.name;
}
function validateFeatureName(name) {
    const nameParts = name.split('/');
    return nameParts.every((part) => featureNameSchema.safeParse(part).success);
}
function ensureFeatureByNameRecursively(projectDefinition, nameOrId) {
    if (featureEntityType.isId(nameOrId)) {
        return nameOrId;
    }
    const nameParts = nameOrId.split('/');
    let lastName = '';
    let parentRef = undefined;
    for (const part of nameParts) {
        const feature = projectDefinition.features.find((f) => f.name === part && f.parentRef === parentRef);
        const name = [lastName, part].filter(Boolean).join('/');
        if (feature) {
            parentRef = feature.id;
        }
        else {
            const newFeature = {
                id: featureEntityType.generateNewId(),
                name,
                parentRef,
            };
            projectDefinition.features.push(newFeature);
            parentRef = newFeature.id;
        }
        lastName = name;
    }
    if (!parentRef) {
        throw new Error('Failed to create feature');
    }
    return parentRef;
}
function createPartialFeatures(nameOrPath) {
    if (!nameOrPath)
        return [];
    const parts = nameOrPath.split('/');
    return parts.map((_, i) => {
        const name = parts.slice(0, i + 1).join('/');
        const parentRef = i > 0 ? parts.slice(0, i).join('/') : undefined;
        return { name, parentRef };
    });
}
function getFeatureByName(projectDefinition, name) {
    return projectDefinition.features.find((f) => f.name === name);
}
function getFeatureIdByNameOrThrow(projectDefinition, name) {
    const feature = getFeatureByName(projectDefinition, name);
    if (!feature) {
        throw new Error(`Could not find feature with name ${name}`);
    }
    return feature.id;
}
function getFeatureIdByNameOrDefault(projectDefinition, name) {
    return getFeatureByName(projectDefinition, name)?.id ?? name;
}
function resolveFeatureName(projectDefinition, featureRef) {
    if (!featureRef)
        return '';
    if (featureEntityType.isId(featureRef)) {
        return getFeaturePathByIdOrThrow(projectDefinition, featureRef);
    }
    return featureRef;
}
const FeatureUtils = {
    getRootFeatures,
    getFeatureById,
    getFeatureByIdOrThrow,
    getFeatureChildren,
    getFeatureName,
    getFeatureNameById,
    getFeaturePathByIdOrThrow,
    validateFeatureName,
    ensureFeatureByNameRecursively,
    createPartialFeatures,
    getFeatureByName,
    getFeatureIdByNameOrThrow,
    getFeatureIdByNameOrDefault,
    resolveFeatureName,
};

function byId(projectDefinition, id) {
    return projectDefinition.models.find((m) => m.id === id);
}
function byIdOrThrow(projectDefinition, id) {
    const model = byId(projectDefinition, id);
    if (!model) {
        throw new Error(`Could not find model with ID ${id}`);
    }
    return model;
}
function byName(projectDefinition, name) {
    return projectDefinition.models.find((m) => m.name === name);
}
function byNameOrThrow(projectDefinition, name) {
    const model = byName(projectDefinition, name);
    if (!model) {
        throw new Error(`Could not find model with name ${name}`);
    }
    return model;
}
function getScalarFieldById(model, id) {
    const field = model.model.fields.find((f) => f.id === id);
    if (!field) {
        throw new Error(`Could not find field with ID ${id}`);
    }
    return field;
}
function getRelationsToModel(projectDefinition, modelId) {
    return projectDefinition.models.flatMap((m) => m.model.relations
        .filter((r) => r.modelRef === modelId)
        .map((r) => ({ model: m, relation: r })));
}
function getModelsForFeature(projectDefinition, featureId) {
    return projectDefinition.models.filter((m) => m.featureRef === featureId);
}
function getModelIdFields(model) {
    return model.model.primaryKeyFieldRefs;
}
function hasService(model) {
    return (model.service.create.enabled ||
        model.service.update.enabled ||
        model.service.delete.enabled ||
        model.service.transformers.length > 0);
}
function validateModelName(name) {
    return PASCAL_CASE_REGEX.test(name);
}
/**
 * Returns the ID of a model by name, or the name if no model is found.
 * @param projectDefinition - The project definition.
 * @param name - The name of the model.
 * @returns The ID of the model, or the name if no model is found.
 */
function getModelIdByNameOrDefault(projectDefinition, name) {
    return projectDefinition.models.find((m) => m.name === name)?.id ?? name;
}
function getPrimaryKeyFields(model) {
    const primaryKeyFields = model.model.primaryKeyFieldRefs;
    return primaryKeyFields.map((id) => getScalarFieldById(model, id));
}
const ModelUtils = {
    byId,
    byIdOrThrow,
    byName,
    byNameOrThrow,
    getScalarFieldById,
    getRelationsToModel,
    getModelsForFeature,
    getModelIdFields,
    hasService,
    validateModelName,
    getModelIdByNameOrDefault,
    getPrimaryKeyFields,
};

export { withEnt as $, createFieldMapSpec as A, createEntityType as B, CASE_VALIDATORS as C, definitionSchemaWithSlots as D, validationHintRegistry as E, isEqualsSameValueZero as F, definitionRefRegistry as G, sortBy as H, definitionDefaultRegistry as I, definitionSchema as J, featureEntityType as K, withDefault as L, runInPluginContext as M, createFeaturesSchema as N, ModelUtils as O, createDefinitionSchemaParserContext as P, expressionParserSpec as Q, RefExpressionParser as R, DefinitionEntityType as S, FeatureUtils as T, createFeatureSchema as U, createPluginFieldMap as V, createPluginSpec as W, createRefContextSlot as X, createRefContextSlotMap as Y, featureNameSchema as Z, getPluginContext as _, getTag as a, withPlaceholderSlots as a0, withRef as a1, uint16ArrayTag as b, uint8ClampedArrayTag as c, uint8ArrayTag as d, stringTag as e, setTag as f, getSymbols as g, int16ArrayTag as h, int32ArrayTag as i, int8ArrayTag as j, float64ArrayTag as k, float32ArrayTag as l, mapTag as m, numberTag as n, objectTag as o, dateTag as p, booleanTag as q, regexpTag as r, symbolTag as s, dataViewTag as t, uint32ArrayTag as u, arrayBufferTag as v, arrayTag as w, argumentsTag as x, isPlainObject as y, isEqual as z };
//# sourceMappingURL=model-utils-PSRun-7E.js.map
