@beignet/core
Version:
Core framework primitives for Beignet
126 lines • 7.15 kB
TypeScript
/** Behavior when a query collection is empty. */
export type QueryEmptyBehavior = "omit" | "preserve";
/** Scalar query parameter transport supported by OpenAPI form encoding. */
export type QueryScalarTransport = {
readonly kind: "string";
} | {
readonly kind: "number";
} | {
readonly kind: "integer";
} | {
readonly kind: "boolean";
} | {
readonly kind: "date-time";
} | {
readonly kind: "date";
};
/** Repeated scalar query parameter transport. */
export type QueryArrayTransport<TItem extends QueryScalarTransport = QueryScalarTransport> = {
readonly kind: "array";
readonly item: TItem;
readonly empty: QueryEmptyBehavior;
};
/** Fields supported inside one flat OpenAPI deepObject parameter. */
export type QueryDeepObjectFields = Readonly<Record<string, QueryScalarTransport>>;
/** Flat OpenAPI deepObject query parameter transport. */
export type QueryDeepObjectTransport<TFields extends QueryDeepObjectFields = QueryDeepObjectFields> = {
readonly kind: "deep-object";
readonly fields: TFields;
readonly empty: QueryEmptyBehavior;
};
/** Transport for one top-level query parameter. */
export type QueryFieldTransport = QueryScalarTransport | QueryArrayTransport | QueryDeepObjectTransport;
/** Query field declarations keyed by their HTTP parameter names. */
export type QueryTransportFields = Readonly<Record<string, QueryFieldTransport>>;
/**
* Deterministic HTTP transport for a contract query schema.
*
* The same declaration drives server decoding, typed-client encoding, and
* OpenAPI parameter serialization.
*/
export type QueryTransport<TFields extends QueryTransportFields = QueryTransportFields> = {
readonly kind: "query-transport";
readonly fields: TFields;
};
/** One deterministic query transport failure. */
export type QueryTransportIssue = {
readonly message: string;
readonly path: readonly (string | number)[];
};
/** Raised when an HTTP query cannot be encoded or decoded as declared. */
export declare class QueryTransportError extends Error {
readonly issues: readonly QueryTransportIssue[];
constructor(issue: QueryTransportIssue);
}
/** Logical value encoded by one query field transport. */
export type QueryFieldTransportInput<TField extends QueryFieldTransport> = TField extends {
readonly kind: "string" | "date-time";
} ? string : TField extends {
readonly kind: "number" | "integer";
} ? number : TField extends {
readonly kind: "boolean";
} ? boolean : TField extends {
readonly kind: "date";
} ? Date : TField extends QueryArrayTransport<infer TItem> ? readonly QueryFieldTransportInput<TItem>[] : TField extends QueryDeepObjectTransport<infer TFields> ? {
[K in keyof TFields]?: QueryFieldTransportInput<TFields[K]>;
} : never;
/** Logical values encoded by a query transport declaration. */
export type QueryTransportInput<TTransport extends QueryTransport> = {
[K in keyof TTransport["fields"]]?: QueryFieldTransportInput<TTransport["fields"][K]>;
};
type QueryKeys<T> = Extract<keyof T, string>;
type DeclaredQueryTransportFields<TTransport extends QueryTransport> = TTransport extends QueryTransport<infer TFields> ? TFields : never;
type QueryFieldMatches<TInput, TField extends QueryFieldTransport> = TField extends QueryArrayTransport<infer TItem> ? Exclude<TInput, undefined> extends readonly (infer TEntry)[] ? QueryFieldMatches<TEntry, TItem> : false : TField extends QueryDeepObjectTransport<infer TFields> ? Exclude<TInput, undefined> extends object ? Exclude<QueryKeys<Exclude<TInput, undefined>>, keyof TFields> extends never ? Exclude<keyof TFields, QueryKeys<Exclude<TInput, undefined>>> extends never ? false extends {
[K in keyof TFields]: K extends keyof Exclude<TInput, undefined> ? QueryFieldMatches<Exclude<TInput, undefined>[K], TFields[K]> : false;
}[keyof TFields] ? false : true : false : false : false : Exclude<TInput, undefined> extends QueryFieldTransportInput<TField> ? true : false;
type QueryTransportMatchesInput<TInput, TTransport extends QueryTransport> = unknown extends TInput ? true : TInput extends object ? keyof DeclaredQueryTransportFields<TTransport> extends never ? QueryKeys<TInput> extends never ? true : TInput[QueryKeys<TInput>] extends never ? true : false : Exclude<QueryKeys<TInput>, keyof DeclaredQueryTransportFields<TTransport>> extends never ? Exclude<keyof DeclaredQueryTransportFields<TTransport>, QueryKeys<TInput>> extends never ? false extends {
[K in keyof DeclaredQueryTransportFields<TTransport>]: K extends keyof TInput ? QueryFieldMatches<TInput[K], DeclaredQueryTransportFields<TTransport>[K]> : false;
}[keyof DeclaredQueryTransportFields<TTransport>] ? false : true : false : false : false;
/**
* Type-level contract used by `.query(...)` to keep schema input fields and
* transport declarations aligned.
*/
export type QueryTransportCompatibility<TInput, TTransport extends QueryTransport> = QueryTransportMatchesInput<TInput, TTransport> extends true ? unknown : {
readonly __beignetQueryTransportMismatch: "Query transport fields and value kinds must match the Standard Schema input type.";
};
type EmptyOptions = {
/**
* Empty collections are omitted by default because standard OpenAPI query
* serialization cannot distinguish them from absent parameters. `preserve`
* opts into Beignet's versioned typed-client extension.
*/
empty?: QueryEmptyBehavior;
};
/** Built-in, OpenAPI-inspectable query parameter transports. */
export declare const query: {
readonly string: () => QueryScalarTransport & {
readonly kind: "string";
};
readonly number: () => QueryScalarTransport & {
readonly kind: "number";
};
readonly integer: () => QueryScalarTransport & {
readonly kind: "integer";
};
readonly boolean: () => QueryScalarTransport & {
readonly kind: "boolean";
};
readonly dateTime: () => QueryScalarTransport & {
readonly kind: "date-time";
};
readonly date: () => QueryScalarTransport & {
readonly kind: "date";
};
readonly array: <const TItem extends QueryScalarTransport>(item: TItem, options?: EmptyOptions) => QueryArrayTransport<TItem>;
readonly deepObject: <const TFields extends QueryDeepObjectFields>(fields: TFields, options?: EmptyOptions) => QueryDeepObjectTransport<TFields>;
};
/** Define a reusable deterministic query transport. */
export declare function defineQueryTransport<const TFields extends QueryTransportFields>(fields: TFields): QueryTransport<TFields>;
/** Decode URL query values exactly once according to a contract transport. */
export declare function decodeQueryTransport(transport: QueryTransport, searchParams: URLSearchParams): Record<string, unknown>;
/** Encode typed query input according to the same contract transport. */
export declare function encodeQueryTransport(transport: QueryTransport, value: unknown): URLSearchParams;
/** OpenAPI schema keywords implied by a query field transport. */
export declare function queryTransportSchema(field: QueryFieldTransport): Record<string, unknown>;
export {};
//# sourceMappingURL=query-transport.d.ts.map