import { GroupInfo } from './table.js';
/**
 * Manifest entry shape, matching `extensions[]` in the deployed app record
 * and in local `./swell.json`. Mirrors the schema at
 * schema-api-server/api/admin/models/apps.json:429-491.
 */
export interface ManifestEntry {
    id: string;
    type: 'payment' | 'tax' | 'shipping';
    name?: string;
    description?: string;
    setting?: string;
    subscriptions?: boolean;
    method?: string;
    gateway?: string;
    method_logo_src?: string;
    method_icon_src?: string;
    gateway_logo_src?: string;
    gateway_icon_src?: string;
    carrier?: string;
    carrier_logo_src?: string;
    carrier_icon_src?: string;
    [key: string]: unknown;
}
/** CLI-resolved type. Diverges from raw manifest `type` for payment (card vs alt). */
export type ExtensionType = 'card' | 'alt' | 'shipping' | 'tax';
export type ExtensionStatus = 'not deployed' | 'not activated' | 'app id mismatch' | 'id mismatch' | 'not selected' | 'gateway missing' | 'not enabled' | 'no handler' | 'handler mismatch' | 'activated';
export type ActionOwner = 'dev' | 'merchant' | null;
export interface FunctionRecord {
    id?: string;
    name?: string;
    enabled?: boolean;
    app_id?: string;
    extension?: string;
    model?: {
        events?: string[];
    };
}
export interface ComponentRecord {
    id?: string;
    name?: string;
    file_path?: string;
    values?: {
        [key: string]: unknown;
        extension?: string;
    };
    [key: string]: unknown;
}
export interface PaymentMethodRecord {
    id?: string;
    name?: string;
    gateway?: string;
    extension_app_id?: string;
    extension_config_id?: string;
    enabled?: boolean;
    activated?: boolean;
    [key: string]: unknown;
}
export interface PaymentGatewayRecord {
    id?: string;
    name?: string;
    extension_app_id?: string;
    extension_config_id?: string;
    [key: string]: unknown;
}
export interface ShippingCarrierRecord {
    id?: string;
    name?: string;
    enabled?: boolean;
    extension_app_id?: string;
    extension_config_id?: string;
    [key: string]: unknown;
}
export interface TaxSettingsRecord {
    extension_app_id?: string;
    extension_config_id?: string;
    [key: string]: unknown;
}
export interface PaymentSettings {
    methods?: PaymentMethodRecord[];
    gateways?: PaymentGatewayRecord[];
    [key: string]: unknown;
}
export interface ShippingSettings {
    carriers?: ShippingCarrierRecord[];
    [key: string]: unknown;
}
export interface NativeBinding {
    path: string;
    record: unknown;
    field_checks: Record<string, boolean>;
}
export interface BoundFunction {
    id?: string;
    name?: string;
    extension?: string;
    enabled?: boolean;
    model?: {
        events?: string[];
    };
}
export interface BoundComponent {
    id?: string;
    name?: string;
    extension?: string;
    file_path?: string;
}
export interface LocalDiff {
    changed_fields: string[];
    local: ManifestEntry;
    deployed: ManifestEntry;
}
export interface ExtensionDetail {
    status: ExtensionStatus;
    action_owner: ActionOwner;
    action: string | null;
    type: ExtensionType | null;
    manifest: ManifestEntry | null;
    native_bindings: NativeBinding[];
    bound: {
        components: BoundComponent[];
        functions: BoundFunction[];
    };
    required_events: string[];
    missing_required_events: string[];
    local_diff: LocalDiff | null;
}
/** Parsed identifier for `swell inspect extensions <id>`. */
export type ParsedExtensionKey = {
    appPart: string;
    extId: string;
    kind: 'slug';
} | {
    kind: 'name';
    name: string;
} | {
    input: string;
    kind: 'invalid';
};
/**
 * Parse a `swell inspect extensions` identifier.
 *
 * Accepts:
 *   - `app.<slug>.<extId>`  → kind 'slug'
 *   - bare `<extId>`        → kind 'name' (requires --app= scope at the call site)
 *
 * 24-char hex is intentionally NOT a valid form — the synthesized resource has
 * no canonical 24-char id. Callers should reject hex shapes upstream so the
 * error message can be clear about the cause.
 */
export declare function parseExtensionKey(input: string): ParsedExtensionKey;
/** Build the column-1 paste-back key for a row. */
export declare function formatExtensionKey(slug: string, extId: string): string;
/**
 * Resolve a manifest entry to the CLI's type taxonomy. Payment splits on
 * `method`: when `method === 'card'` the extension provides a card gateway;
 * otherwise it's an alt method. The platform formula at
 * schema-api-server/api/admin/models/apps.json:457-458 defaults `method` to
 * `id` when unset, so a payment extension whose `id` happens to be `card`
 * resolves to `card` even with no explicit `method`.
 */
export declare function resolveExtensionType(entry: Pick<ManifestEntry, 'type' | 'method' | 'id'>): ExtensionType;
/** Apply the platform's `if(method, method, id)` formula. */
export declare function paymentMethodIdFor(entry: Pick<ManifestEntry, 'method' | 'id'>): string;
/** Shipping records use `app_<appId>_<extId>` as both the row id and the carrier id. */
export declare function shippingBindId(appId: string, extId: string): string;
/** Card-gateway records use the same id form as shipping rows. */
export declare function gatewayBindId(appId: string, extId: string): string;
/**
 * Required events per extension type, in the `<model>/<event>` form that
 * function records actually store.
 *
 * Verified against:
 *   schema-api-server/server/vault.js:1818,1894          (payment.create_intent)
 *   schema-api-server/api/com/features/payments/index.js:701-757
 *                                                        (payment.charge, payment.refund, dispatcher gate)
 *   schema-api-server/server/vault.js:2304-2322          (card-gateway intent path)
 *   schema-api-server/api/com/features/orders/shipping.js:411-417,424-431,452-458
 *                                                        (shipping dispatch + enabled gate)
 *   schema-api-server/api/com/features/orders/taxes.js:123-176
 *                                                        (tax dispatch)
 *   schema-api-server/api/com/features/orders/extensions.test.js:85,95,179,271,290,303,671,704
 *                                                        (event-name format fixtures)
 */
export declare function requiredEventsFor(type: ExtensionType): string[];
/**
 * Strip `before:` / `after:` hook-type prefix from an event identifier.
 *
 * Both prefixes are platform-supported on function records; bare events
 * default to `after`. For required-event coverage we treat any prefix as
 * equivalent so that a function declaring `before:payment.charge` covers a
 * required `payments/payment.charge`. Cite:
 * schema-api-server/api/com/features/orders/extensions.test.js:95.
 */
export declare function stripHookPrefix(event: string): string;
/**
 * Compute the set of bare event identifiers covered by a function record's
 * `model.events` list. The function event format is `<model>/<event>` with
 * an optional `before:`/`after:` prefix on the bare event part. Returns the
 * full `<model>/<event>` string with hook prefixes stripped from the event.
 */
export declare function eventsCoveredByFunctions(functions: Pick<FunctionRecord, 'model'>[]): Set<string>;
/** Required events not covered by any of the bound functions. */
export declare function missingRequiredEvents(type: ExtensionType, functions: Pick<FunctionRecord, 'model'>[]): string[];
/** Lift a component record into the synthesized `BoundComponent` shape. */
export declare function liftBoundComponent(record: ComponentRecord): BoundComponent;
/** Lift a function record into the synthesized `BoundFunction` shape. */
export declare function liftBoundFunction(record: FunctionRecord): BoundFunction;
/**
 * Compare a local manifest entry against the deployed entry. Uses deep
 * equality for change detection and reports differing top-level keys. When
 * the entries are equal, returns `null`.
 */
export declare function diffManifestEntries(local: ManifestEntry, deployed: ManifestEntry): LocalDiff | null;
export interface BuildDetailInput {
    appId: string;
    appSlug: string;
    extId: string;
    manifest: ManifestEntry | null;
    /** True when the local manifest has the entry but the deployed app record doesn't. */
    notDeployed?: boolean;
    payments?: PaymentSettings | null;
    shipments?: ShippingSettings | null;
    taxes?: TaxSettingsRecord | null;
    /** Functions in the same app whose top-level `extension` matches this extId. */
    functions: FunctionRecord[];
    /** Components in the same app whose `values.extension` matches this extId. */
    components: ComponentRecord[];
    localDiff?: LocalDiff | null;
}
export interface BuildOrphanInput {
    appId: string;
    appSlug: string;
    /** The unresolved extension value taken from the function/component. */
    unresolvedId: string;
    functions: FunctionRecord[];
    components: ComponentRecord[];
}
/** Build the synthesized envelope for a regular (non-orphan) extension row. */
export declare function buildExtensionDetail(input: BuildDetailInput): ExtensionDetail;
/** Build the synthesized envelope for an orphan row. */
export declare function buildOrphanDetail(input: BuildOrphanInput): ExtensionDetail;
/**
 * List-mode meta string for one row. Returns `undefined` when the row has
 * nothing surface-worthy beyond the type tag (which is always present).
 */
export declare function listMetaFor(detail: ExtensionDetail): string;
/**
 * List-mode meta string for an orphan row. The type tag is replaced with
 * the status word since there's no manifest to derive type from.
 */
export declare function orphanListMeta(fnCount: number, compCount: number): string;
/**
 * `Next steps:` lines per status. Runnable shell commands come first,
 * merchant-UI lines come second prefixed with `(merchant)` so an agent can
 * filter. Empty array when there are no actionable next steps.
 */
export declare function nextStepLines(detail: ExtensionDetail): string[];
/**
 * Section ordering for the list view. Apps render alphabetically; orphan
 * rows land in a single trailing `<orphans>` group.
 */
export declare function listGroupForApp(slug: string): GroupInfo;
export declare function listGroupForOrphans(): GroupInfo;
/** True when a function/component "belongs to" an extension by direct match. */
export declare function functionMatchesExtension(fn: FunctionRecord, extId: string): boolean;
export declare function componentMatchesExtension(comp: ComponentRecord, extId: string): boolean;
