import * as S from 'effect/Schema';
import { Schema } from 'effect/Schema';
import { Json, ErrorMessage, JsonObject, Simplify, FileRouterInputConfig, RouteOptions, UploadThingError, MaybePromise } from '@uploadthing/shared';
import * as Standard from '@standard-schema/spec';

type ParseFn<TType> = (input: unknown) => Promise<TType>;
type ParserZodEsque<TInput extends Json, TParsedInput> = {
    _input: TInput;
    _output: TParsedInput;
    parseAsync: ParseFn<TParsedInput>;
};
type JsonParser<In extends Json, Out = In> = ParserZodEsque<In, Out> | Standard.v1.StandardSchema<In, Out> | S.Schema<Out, In>;

declare const FileUploadData_base: S.Class<FileUploadData, {
    name: typeof S.String;
    size: typeof S.Number;
    type: typeof S.String;
    lastModified: S.optional<typeof S.Number>;
}, S.Struct.Encoded<{
    name: typeof S.String;
    size: typeof S.Number;
    type: typeof S.String;
    lastModified: S.optional<typeof S.Number>;
}>, never, {
    readonly name: string;
} & {
    readonly size: number;
} & {
    readonly type: string;
} & {
    readonly lastModified?: number | undefined;
}, {}, {}>;
/**
 * =============================================================================
 * ======================== File Type Hierarchy ===============================
 * =============================================================================
 */
/**
 * Properties from the web File object, this is what the client sends when initiating an upload
 */
declare class FileUploadData extends FileUploadData_base {
}
declare const FileUploadDataWithCustomId_base: S.Class<FileUploadDataWithCustomId, {
    name: typeof S.String;
    size: typeof S.Number;
    type: typeof S.String;
    lastModified: S.optional<typeof S.Number>;
} & {
    customId: S.NullOr<typeof S.String>;
}, {
    readonly name: string;
    readonly size: number;
    readonly type: string;
} & {
    readonly lastModified?: number | undefined;
} & {
    readonly customId: string | null;
} & {}, never, {
    readonly name: string;
} & {
    readonly size: number;
} & {
    readonly type: string;
} & {
    readonly lastModified?: number | undefined;
} & {
    readonly customId: string | null;
}, FileUploadData, {}>;
/**
 * `.middleware()` can add a customId to the incoming file data
 */
declare class FileUploadDataWithCustomId extends FileUploadDataWithCustomId_base {
}
declare const UploadedFileData_base: S.Class<UploadedFileData, {
    name: typeof S.String;
    size: typeof S.Number;
    type: typeof S.String;
    lastModified: S.optional<typeof S.Number>;
} & {
    customId: S.NullOr<typeof S.String>;
} & {
    key: typeof S.String;
    url: typeof S.String;
    appUrl: typeof S.String;
    fileHash: typeof S.String;
}, {
    readonly name: string;
    readonly size: number;
    readonly type: string;
} & {
    readonly lastModified?: number | undefined;
} & {
    readonly customId: string | null;
} & {} & {
    readonly key: string;
    readonly url: string;
    readonly appUrl: string;
    readonly fileHash: string;
} & {}, never, {
    readonly name: string;
} & {
    readonly size: number;
} & {
    readonly type: string;
} & {
    readonly lastModified?: number | undefined;
} & {
    readonly customId: string | null;
} & {
    readonly key: string;
} & {
    readonly url: string;
} & {
    readonly appUrl: string;
} & {
    readonly fileHash: string;
}, FileUploadDataWithCustomId, {}>;
/**
 * When files are uploaded, we get back
 * - a key
 * - a direct URL for the file
 * - an app-specific URL for the file (useful for scoping eg. for optimization allowed origins)
 * - the hash (md5-hex) of the uploaded file's contents
 */
declare class UploadedFileData extends UploadedFileData_base {
}
declare const NewPresignedUrl_base: S.Class<NewPresignedUrl, {
    url: typeof S.String;
    key: typeof S.String;
    customId: S.NullOr<typeof S.String>;
    name: typeof S.String;
}, S.Struct.Encoded<{
    url: typeof S.String;
    key: typeof S.String;
    customId: S.NullOr<typeof S.String>;
    name: typeof S.String;
}>, never, {
    readonly name: string;
} & {
    readonly customId: string | null;
} & {
    readonly key: string;
} & {
    readonly url: string;
}, {}, {}>;
/**
 * =============================================================================
 * ======================== Server Response Schemas ============================
 * =============================================================================
 */
declare class NewPresignedUrl extends NewPresignedUrl_base {
}
declare const UploadActionPayload_base: S.Class<UploadActionPayload, {
    files: S.Array$<typeof FileUploadData>;
    input: S.Schema<Json>;
}, S.Struct.Encoded<{
    files: S.Array$<typeof FileUploadData>;
    input: S.Schema<Json>;
}>, never, {
    readonly files: readonly FileUploadData[];
} & {
    readonly input: Json;
}, {}, {}>;
/**
 * =============================================================================
 * ======================== Client Action Payloads ============================
 * =============================================================================
 */
declare class UploadActionPayload extends UploadActionPayload_base {
}

/**
 * Marker used to append a `customId` to the incoming file data in `.middleware()`
 * @example
 * ```ts
 * .middleware((opts) => {
 *   return {
 *     [UTFiles]: opts.files.map((file) => ({
 *       ...file,
 *       customId: generateId(),
 *     }))
 *   };
 * })
 * ```
 */
declare const UTFiles: unique symbol;
declare const unsetMarker: "unsetMarker" & {
    __brand: "unsetMarker";
};
type UnsetMarker = typeof unsetMarker;
type ValidMiddlewareObject = {
    [UTFiles]?: Partial<FileUploadDataWithCustomId>[];
    [key: string]: unknown;
};
/**
 * Different frameworks have different request and response types
 */
type AdapterFnArgs<TRequest, TResponse, TEvent> = {
    req: TRequest;
    res: TResponse;
    event: TEvent;
};
interface AnyParams {
    _routeOptions: any;
    _input: {
        in: any;
        out: any;
    };
    _metadata: any;
    _adapterFnArgs: AdapterFnArgs<any, any, any>;
    _errorShape: any;
    _errorFn: any;
    _output: any;
}
type MiddlewareFn<TInput extends Json | UnsetMarker, TOutput extends ValidMiddlewareObject, TArgs extends AdapterFnArgs<any, any, any>> = (opts: TArgs & {
    files: Schema.Type<typeof UploadActionPayload>["files"];
    input: TInput extends UnsetMarker ? undefined : TInput;
}) => MaybePromise<TOutput>;
type UploadCompleteFn<TMetadata, TOutput extends JsonObject | void, TArgs extends AdapterFnArgs<any, any, any>> = (opts: TArgs & {
    metadata: TMetadata;
    file: UploadedFileData;
}) => MaybePromise<TOutput>;
type UploadErrorFn<TArgs extends AdapterFnArgs<any, any, any>> = (input: TArgs & {
    error: UploadThingError;
    fileKey: string;
}) => MaybePromise<void>;
interface UploadBuilder<TParams extends AnyParams> {
    input: <TIn extends Json, TOut>(parser: TParams["_input"]["in"] extends UnsetMarker ? JsonParser<TIn, TOut> : ErrorMessage<"input is already set">) => UploadBuilder<{
        _routeOptions: TParams["_routeOptions"];
        _input: {
            in: TIn;
            out: TOut;
        };
        _metadata: TParams["_metadata"];
        _adapterFnArgs: TParams["_adapterFnArgs"];
        _errorShape: TParams["_errorShape"];
        _errorFn: TParams["_errorFn"];
        _output: UnsetMarker;
    }>;
    middleware: <TOutput extends ValidMiddlewareObject>(fn: TParams["_metadata"] extends UnsetMarker ? MiddlewareFn<TParams["_input"]["out"], TOutput, TParams["_adapterFnArgs"]> : ErrorMessage<"middleware is already set">) => UploadBuilder<{
        _routeOptions: TParams["_routeOptions"];
        _input: TParams["_input"];
        _metadata: TOutput;
        _adapterFnArgs: TParams["_adapterFnArgs"];
        _errorShape: TParams["_errorShape"];
        _errorFn: TParams["_errorFn"];
        _output: UnsetMarker;
    }>;
    onUploadError: (fn: TParams["_errorFn"] extends UnsetMarker ? UploadErrorFn<TParams["_adapterFnArgs"]> : ErrorMessage<"onUploadError is already set">) => UploadBuilder<{
        _routeOptions: TParams["_routeOptions"];
        _input: TParams["_input"];
        _metadata: TParams["_metadata"];
        _adapterFnArgs: TParams["_adapterFnArgs"];
        _errorShape: TParams["_errorShape"];
        _errorFn: UploadErrorFn<TParams["_adapterFnArgs"]>;
        _output: UnsetMarker;
    }>;
    onUploadComplete: <TOutput extends JsonObject | void>(fn: UploadCompleteFn<Simplify<TParams["_metadata"] extends UnsetMarker ? undefined : Omit<TParams["_metadata"], typeof UTFiles>>, TOutput, TParams["_adapterFnArgs"]>) => FileRoute<{
        input: TParams["_input"]["in"] extends UnsetMarker ? undefined : TParams["_input"]["in"];
        output: TParams["_routeOptions"]["awaitServerData"] extends false ? null : TOutput extends void | undefined ? null : TOutput;
        errorShape: TParams["_errorShape"];
    }>;
}
type AnyBuiltUploaderTypes = {
    input: any;
    output: any;
    errorShape: any;
};
interface FileRoute<TTypes extends AnyBuiltUploaderTypes> {
    $types: TTypes;
    routerConfig: FileRouterInputConfig;
    routeOptions: RouteOptions;
    inputParser: JsonParser<any>;
    middleware: MiddlewareFn<any, ValidMiddlewareObject, any>;
    onUploadError: UploadErrorFn<any>;
    errorFormatter: (err: UploadThingError) => any;
    onUploadComplete: UploadCompleteFn<any, any, any>;
}
type AnyFileRoute = FileRoute<AnyBuiltUploaderTypes>;
/**
 * Map actionType to the required payload for that action
 * @todo Look into using @effect/rpc :thinking:
 */
type UTEvents = {
    upload: {
        in: UploadActionPayload;
        out: ReadonlyArray<NewPresignedUrl>;
    };
};
/**
 * Result from the PUT request to the UploadThing Ingest server
 */
type UploadPutResult<TServerOutput = unknown> = {
    url: string;
    appUrl: string;
    fileHash: string;
    serverData: TServerOutput;
};

export { type AdapterFnArgs, type AnyBuiltUploaderTypes, type AnyFileRoute, type AnyParams, type FileRoute, type UTEvents, UTFiles, type UnsetMarker, type UploadBuilder, type UploadPutResult, type ValidMiddlewareObject };
