import { MonitoringClient } from '@wix/monitoring-types'; import { PlatformShowError } from '@wix/error-handler-types/v2'; export { ErrorCodesMap, ErrorHandlerPublicAPI as ErrorHandler, ResolvedError, ShowErrorMapFunction, ShowErrorProps, StatusCodeMap } from '@wix/error-handler-types/v2'; import { ConditionalExcept, EmptyObject, Simplify, Paths, SetNonNullableDeep, SetRequiredDeep, JsonObject } from 'type-fest'; export { ErrorHandlerInternalAPI as WixClientErrorHandler } from '@wix/error-handler-types'; type HostModule = { __type: 'host'; create(host: H): T; }; type HostModuleAPI> = T extends HostModule ? U : never; type Host = { channel?: { observeState(callback: (props: unknown, environment: Environment) => unknown): { disconnect: () => void; } | Promise<{ disconnect: () => void; }>; }; environment?: Environment; /** * Optional name of the environment, use for logging */ name?: string; /** * Optional bast url to use for API requests, for example `www.wixapis.com` */ apiBaseUrl?: string; /** * Optional function to get a monitoring client */ getMonitoringClient?: () => MonitoringClient; /** * Optional function to display an error notification to the user. * Can be used to show a toast, modal, or any other UI element * that informs the user about an error that occurred. */ showError?: PlatformShowError; /** * Possible data to be provided by every host, for cross cutting concerns * like internationalization, billing, etc. */ essentials?: { /** * The language of the currently viewed session */ language?: string; /** * The locale of the currently viewed session */ locale?: string; /** * The timezone of the currently viewed session */ timezone?: string; /** * Any headers that should be passed through to the API requests */ passThroughHeaders?: Record; }; translations?: () => { [language: string]: { [namespace: string]: { [key: string]: string; }; }; } | undefined; }; type HTTPMethod = 'POST' | 'GET' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS'; type RESTFunctionDescriptor any = (...args: any[]) => any> = (httpClient: HttpClient, options?: { validateRequestSchema?: boolean; }) => T; interface HttpClient { request(req: RequestOptionsFactory): Promise>; fetchWithAuth: typeof fetch; wixAPIFetch: (relativeUrl: string, options: RequestInit) => Promise; /** Returns the current access token synchronously, if available. */ getActiveToken?: () => string | undefined; /** Returns auth headers (may trigger token refresh). Prefer this over getActiveToken when making authenticated requests. */ getAuthHeaders?: () => Promise<{ headers: Record; }>; } type RequestOptionsFactory = (context: any) => RequestOptions; type HttpResponse = { data: T; status: number; statusText: string; headers: any; request?: any; }; type ResponseTransformer$1 = (data: any) => any; type RequestOptions<_TResponse = any, Data = any> = { method: HTTPMethod; url: string; data?: Data; params?: URLSearchParams; fallback?: RequestOptions[]; /** * The array option is for interoperability, defacto only the first function is used * if an array is provided */ transformResponse?: ResponseTransformer$1 | ResponseTransformer$1[]; } & APIMetadata; type APIMetadata = { methodFqn?: string; entityFqdn?: string; packageName?: string; migrationOptions?: MigrationOptions; }; type MigrationOptions = { optInTransformResponse?: boolean; }; type BuildRESTFunction = T extends RESTFunctionDescriptor ? U : never; type RestModuleMeta = { getUrl(context: { host: string; }): string; httpMethod: TMethod; pathParams: TPathParams; path: string; __requestType: RequestType; __originalRequestType: TOriginalRequestType; __responseType: ResponseType; __originalResponseType: OriginalResponseType; }; type AuthenticationStrategy = { getAuthHeaders: (host: Host) => Promise<{ headers: Record; }> | { headers: Record; }; decodeJWT?: (token: string, verifyCallerClaims?: boolean) => Promise<{ decoded: { data: unknown; }; valid: boolean; }>; /** * This function is used to get the token that is currently active in the context of the strategy. * This is useful when direct access to the access token is needed * (such as getTokenInfo that requires the token in the body of the request). * @returns the token that is currently active in the context of the strategy */ getActiveToken?: () => string | undefined; shouldUseCDN?: boolean; }; type BoundAuthenticationStrategy = { getAuthHeaders: () => Promise<{ headers: Record; }> | { headers: Record; }; }; interface Token { value: string; } interface AccessToken extends Token { expiresAt: number; } interface RefreshToken extends Token { role: string; } interface Tokens { accessToken: AccessToken; refreshToken: RefreshToken; } interface TokenStorage { getTokens(): Tokens; setTokens(tokens: Tokens): void; } type EventIdentity = { identityType: 'ANONYMOUS_VISITOR' | 'MEMBER' | 'WIX_USER' | 'APP'; anonymousVisitorId: string; memberId: string; wixUserId: string; appId: string; }; type AccountInfo = { accountId: string; parentAccountId?: string; siteId?: string; }; type BaseEventMetadata = { instanceId: string; identity?: EventIdentity; accountInfo?: AccountInfo; }; type EventDefinition = { __type: 'event-definition'; type: Type; isDomainEvent?: boolean; transformations?: (envelope: unknown) => Payload; __payload: Payload; }; declare function EventDefinition(type: Type, isDomainEvent?: boolean, transformations?: (envelope: any) => unknown): () => EventDefinition; type EventHandler = (payload: T['__payload']) => void | Promise; type BuildEventDefinition> = (handler: EventHandler) => void; type ServicePluginMethodInput = { request: any; metadata: any; }; type ServicePluginContract = Record unknown | Promise>; type ServicePluginMethodMetadata = { name: string; primaryHttpMappingPath: string; transformations: { fromREST: (...args: unknown[]) => ServicePluginMethodInput; toREST: (...args: unknown[]) => unknown; }; }; type ServicePluginDefinition = { __type: 'service-plugin-definition'; componentType: string; methods: ServicePluginMethodMetadata[]; __contract: Contract; }; declare function ServicePluginDefinition(componentType: string, methods: ServicePluginMethodMetadata[]): ServicePluginDefinition; type BuildServicePluginDefinition> = (implementation: T['__contract']) => void; declare const SERVICE_PLUGIN_ERROR_TYPE = "wix_spi_error"; type RequestContext = { isSSR: boolean; host: string; protocol?: string; }; type ResponseTransformer = (data: any, headers?: any) => any; /** * Ambassador request options types are copied mostly from AxiosRequestConfig. * They are copied and not imported to reduce the amount of dependencies (to reduce install time). * https://github.com/axios/axios/blob/3f53eb6960f05a1f88409c4b731a40de595cb825/index.d.ts#L307-L315 */ type Method = 'get' | 'GET' | 'delete' | 'DELETE' | 'head' | 'HEAD' | 'options' | 'OPTIONS' | 'post' | 'POST' | 'put' | 'PUT' | 'patch' | 'PATCH' | 'purge' | 'PURGE' | 'link' | 'LINK' | 'unlink' | 'UNLINK'; type AmbassadorRequestOptions = { _?: T; url?: string; method?: Method; params?: any; data?: any; transformResponse?: ResponseTransformer | ResponseTransformer[]; }; type AmbassadorFactory = (payload: Request) => ((context: RequestContext) => AmbassadorRequestOptions) & { __isAmbassador: boolean; }; type AmbassadorFunctionDescriptor = AmbassadorFactory; type BuildAmbassadorFunction = T extends AmbassadorFunctionDescriptor ? (req: Request) => Promise : never; /** * Descriptors are objects that describe the API of a module, and the module * can either be a REST module or a host module. * This type is recursive, so it can describe nested modules. */ type Descriptors = RESTFunctionDescriptor | AmbassadorFunctionDescriptor | HostModule | EventDefinition | ServicePluginDefinition | { [key: string]: Descriptors | PublicMetadata | any; }; /** * This type takes in a descriptors object of a certain Host (including an `unknown` host) * and returns an object with the same structure, but with all descriptors replaced with their API. * Any non-descriptor properties are removed from the returned object, including descriptors that * do not match the given host (as they will not work with the given host). */ type BuildDescriptors | undefined, Depth extends number = 5> = { done: T; recurse: T extends { __type: typeof SERVICE_PLUGIN_ERROR_TYPE; } ? never : T extends AmbassadorFunctionDescriptor ? BuildAmbassadorFunction : T extends RESTFunctionDescriptor ? BuildRESTFunction : T extends EventDefinition ? BuildEventDefinition : T extends ServicePluginDefinition ? BuildServicePluginDefinition : T extends HostModule ? HostModuleAPI : ConditionalExcept<{ [Key in keyof T]: T[Key] extends Descriptors ? BuildDescriptors : never; }, EmptyObject>; }[Depth extends -1 ? 'done' : 'recurse']; type PublicMetadata = { PACKAGE_NAME?: string; }; declare global { interface ContextualClient { } } /** * A type used to create concerete types from SDK descriptors in * case a contextual client is available. */ type MaybeContext = globalThis.ContextualClient extends { host: Host; } ? BuildDescriptors : T; /** * Expose fields based on the current exposure toggle. * @param T - The type to expose fields from. * @param FieldsScope - A map of fields to their exposure scope, missing fields are considered public. * @example Exposure toggle not set: * ```ts * type MyType = { * publicField: string; * alphaField: string; * }; * * type ExposedType = ExposeFieldsBasedOnToggle; * // ExposedType = { publicField: string; } * ``` * @example Exposure toggle set to alpha: * ```ts * declare global { * interface SDKExposureToggle { * alpha: true; * } * } * * type MyType = { * publicField: string; * alphaField: string; * }; * * type ExposedType = ExposeFieldsBasedOnToggle; * // ExposedType = { publicField: string; alphaField: string; } */ type ExposeFieldsBasedOnToggle, FieldsScope extends Partial>> = Simplify<{ [K in keyof T as IsExposed]: T[K]; }>; declare global { /** * A global interface to set the exposure toggle for the SDK. * @example * ```ts * declare global { * interface SDKExposureToggle { * alpha: true; * } * } */ interface SDKExposureToggle { } } type Exposure = 'alpha' | 'public'; type IsExposed = Scope extends 'public' ? T : globalThis.SDKExposureToggle extends { alpha: true; } ? T : never; declare global { /** * A global interface to set the type mode for the SDK. * @example * ```ts * declare global { * interface SDKTypeMode { * strict: true; * } * } */ interface SDKTypeMode { } } type NonNullablePaths, MaxDepth extends number = 11> = globalThis.SDKTypeMode extends { strict: true; } ? SetNonNullableDeep, K & Paths>> : T; /** * Constant used to indicate all applicable operators for a field type */ declare const ALL_APPLICABLE_OPERATORS: "*"; /** * Operators available for string fields */ type StringOperators = '$eq' | '$ne' | '$gt' | '$lt' | '$gte' | '$lte' | '$isEmpty' | '$exists' | '$in' | '$nin' | '$startsWith'; /** * Operators available for number fields */ type NumberOperators = '$eq' | '$ne' | '$gt' | '$lt' | '$gte' | '$lte' | '$exists' | '$in' | '$nin'; /** * Operators available for boolean fields */ type BooleanOperators = '$eq' | '$ne' | '$exists' | '$in' | '$nin'; /** * Operators available for enum fields */ type EnumOperators = '$eq' | '$ne' | '$in' | '$nin' | '$exists'; /** * Operators available for date fields */ type DateOperators = '$eq' | '$ne' | '$gt' | '$lt' | '$gte' | '$lte' | '$exists' | '$in' | '$nin'; /** * Operators available for object fields */ type ObjectOperators = '$exists'; /** * Base operators available for all array types */ type ArrayBaseOperators = '$isEmpty' | '$exists'; /** * Operators available for arrays of primitive values */ type ArrayOfPrimitivesOperators = '$hasAll' | '$hasSome' | ArrayBaseOperators; /** * Operators available for arrays of objects */ type ArrayOfObjectsOperators = ArrayBaseOperators | '$matchItems'; type OperatorsWithBooleanValues = '$isEmpty' | '$exists'; type OperatorsWithArrayValues = '$in' | '$nin' | '$hasAll' | '$hasSome'; type OperatorForArrayFiltering = '$matchItems'; /** * Sort direction type for requests */ type SortOrder = 'ASC' | 'DESC'; /** * Sort capability type for defining field sort options in SearchSpec */ type SortCapability = SortOrder | 'BOTH' | 'NONE'; /** * Constants for sort directions */ declare const SORT_DIRECTIONS: { readonly ASC: "ASC"; readonly DESC: "DESC"; }; /** * Constants for sort capabilities */ declare const SORT_CAPABILITIES: { readonly BOTH: "BOTH"; readonly NONE: "NONE"; readonly ASC: "ASC"; readonly DESC: "DESC"; }; /** * Helper type to get the fields from a WQL group * @template WQLGroup The WQL group type */ type WQLFields = WQLGroup extends { fields: readonly string[]; } ? WQLGroup['fields'][number] : never; /** * Sorting configuration for search/query results * @template Spec The WQL specification type */ type Sorting = Spec['wql'] extends { length: 0; } | [] ? { fieldName?: string; order?: SortOrder; selectItemsBy?: Record[] | null; } : { [WQLGroupIndex in keyof Spec['wql']]: Spec['wql'][WQLGroupIndex] extends { fields: readonly string[]; sort: infer GroupSortCapability; } ? GroupSortCapability extends typeof SORT_DIRECTIONS.ASC ? { fieldName: WQLFields; order: typeof SORT_DIRECTIONS.ASC; selectItemsBy?: Record[] | null; } : GroupSortCapability extends typeof SORT_DIRECTIONS.DESC ? { fieldName: WQLFields; order: typeof SORT_DIRECTIONS.DESC; selectItemsBy?: Record[] | null; } : GroupSortCapability extends typeof SORT_CAPABILITIES.BOTH ? { fieldName: WQLFields; order: SortOrder; selectItemsBy?: Record[] | null; } : GroupSortCapability extends typeof SORT_CAPABILITIES.NONE ? { fieldName?: never; order?: never; selectItemsBy?: Record[] | null; } : never : never; }[keyof Spec['wql']]; /** * Defines a group of fields that share the same operator and sorting capabilities * This is part of the Wix Query Language (WQL) specification * @example * const wql: WQL = { * operators: ['$eq', '$ne', '$startsWith'], * fields: ['name', 'description'], * sort: 'BOTH' * }; */ interface WQL { /** * List of operators that can be used with these fields * If not specified, uses ALL_APPLICABLE_OPERATORS */ operators?: typeof ALL_APPLICABLE_OPERATORS | readonly string[]; /** * List of fields that share these operator capabilities * These fields can be used in filters and sorting */ fields: readonly string[]; /** * Sort capabilities for fields in this group * If omitted, sorting is not allowed for these fields */ sort?: SortCapability; } /** * Base specification interface for APIs that support WQL (Wix Query Language) */ interface WQLSpec { /** * Groups of fields with shared operator and sorting capabilities * Each group defines what operations can be performed on its fields */ wql: readonly WQL[]; } /** * Gets the type of a field at a nested path */ type GetNestedType = Path extends keyof Entity ? Entity[Path] extends (infer ArrayElement)[] | null | undefined ? ArrayElement : Exclude : Path extends `${infer FirstPathPart}.${infer RemainingPath}` ? FirstPathPart extends keyof Entity ? Entity[FirstPathPart] extends (infer ArrayElement)[] | null | undefined ? GetNestedType, RemainingPath> : Entity[FirstPathPart] extends object | null | undefined ? GetNestedType, RemainingPath> : never : never : never; /** * Extracts all filterable field paths from a spec * @template Spec The WQL specification type * // Results in a union type of all field paths that can be filtered */ type FilterableFields = Spec['wql'][number]['fields'][number]; /** * Helper type to detect if a type is an enum-like union of string literals * This checks if the type is a union of specific string literals (not a generic string) * It handles both simple enums and complex enum + literal unions like EnumWithTypeAlias */ type IsEnumLike = T extends string | null | undefined ? string extends NonNullable ? false : NonNullable extends string ? true : false : false; /** * Determines operators applicable to a field based on its type * @template Entity The entity type * @template Path The field path to check */ type ApplicableOperators = Path extends keyof Entity ? Entity[Path] extends string | null | undefined ? IsEnumLike extends true ? EnumOperators : StringOperators : Entity[Path] extends number | null | undefined ? NumberOperators : Entity[Path] extends boolean | null | undefined ? BooleanOperators : Entity[Path] extends Date | null | undefined ? DateOperators : Entity[Path] extends (infer E)[] | null | undefined ? E extends object ? ArrayOfObjectsOperators : ArrayOfPrimitivesOperators : Entity[Path] extends object | null | undefined ? ObjectOperators : never : Path extends `${infer K}.${infer R}` ? K extends keyof Entity ? Entity[K] extends (infer U)[] | null | undefined ? ApplicableOperators, R> : Entity[K] extends object | null | undefined ? ApplicableOperators, R> : never : never : never; /** * Determines allowed operators for a field based on the spec * @template Entity The entity type * @template Spec The WQL specification type * @template Field The field to check */ type AllowedOperators> = Spec['wql'][number] extends infer WQLGroup ? WQLGroup extends WQL ? Field extends WQLGroup['fields'][number] ? WQLGroup['operators'] extends typeof ALL_APPLICABLE_OPERATORS ? ApplicableOperators : WQLGroup['operators'] extends readonly string[] ? WQLGroup['operators'][number] : never : never : never : never; /** * Filter operations type for individual field conditions * @template Entity The entity type * @template Spec The WQL specification type * @template Field The field to filter on */ type FilterOps> = Simplify<{ [Op in AllowedOperators]?: Op extends OperatorsWithBooleanValues ? boolean : Op extends OperatorForArrayFiltering ? JsonObject[] : Op extends OperatorsWithArrayValues ? GetNestedType[] : GetNestedType; }>; /** * Filter type for building type-safe query filters * @template Entity The entity type * @template Spec The WQL specification type * @example * // Simple filter * const filter: Filter = { * name: { $eq: 'iPhone' }, * price: { $gte: 100 } * }; * * // Complex filter with logical operators * const filter: Filter = { * $and: [ * { name: { $startsWith: 'i' } }, * { $or: [ * { price: { $lt: 1000 } }, * { onSale: { $eq: true } } * ]} * ] * }; */ type Filter = Simplify<{ [Field in FilterableFields]?: AllowedOperators extends infer AllowedOps ? AllowedOps extends '$eq' ? GetNestedType | FilterOps : FilterOps : never; } | { $and?: Filter[]; $or?: Filter[]; $not?: Filter; }>; /** * Cursor-based paging configuration */ interface CursorPaging$1 { /** Maximum number of items to return in the results. */ limit?: number | null; /** * Pointer to the next or previous page in the list of results. * * Pass the relevant cursor token from the `pagingMetadata` object in the previous call's response. * Not relevant for the first request. */ cursor?: string | null; } /** * Offset-based paging configuration */ interface OffsetPaging$1 { /** Number of items to load */ limit?: number | null; /** Number of items to skip in the current sort order */ offset?: number | null; } /** * Supported paging types for search APIs */ type PagingType = 'cursor' | 'offset'; /** * Paging type based on the SearchSpec's paging type */ type Paging = Spec['paging'] extends 'cursor' ? { cursorPaging: CursorPaging$1; } : Spec['paging'] extends 'offset' ? { paging: OffsetPaging$1; } : {}; /** * Specification for a search API * Defines what fields can be filtered, sorted, searched, and aggregated * @example * interface MySearchSpec extends SearchSpec { * wql: [{ * operators: ['$eq', '$ne'], // or 'typeof ALL_APPLICABLE_OPERATORS' for all operators that can be used based on the field type * fields: ['id', 'title'], * sort: 'BOTH' // or 'ASC' / 'DESC' for specific sorting * }], * paging: 'offset', // or 'cursor' for cursor-based pagination * searchable: ['title', 'description'], * aggregatable: ['category', 'price'] * }; */ interface SearchSpec extends WQLSpec { /** * Supported paging type for this search API * - 'cursor': Uses cursor-based pagination * - 'offset': Uses offset-based pagination */ paging: PagingType; /** * Fields that can be used for full-text search * If not specified, all fields are searchable */ searchable?: readonly string[]; /** * Fields that can be used for aggregations * These fields must be searchable and not contain PII */ aggregatable?: readonly string[]; } /** * Type of scalar aggregation to perform */ type ScalarType = 'COUNT_DISTINCT' | 'MIN' | 'MAX' | 'SUM' | 'AVG'; /** * Sort type for value aggregations */ type ValueSortType = 'COUNT' | 'VALUE'; /** * Sort direction for value aggregations */ type ValueSortDirection = 'DESC' | 'ASC'; /** * Missing values handling for value aggregations */ type MissingValues = 'EXCLUDE' | 'INCLUDE'; /** * Date histogram interval */ type DateHistogramInterval = 'YEAR' | 'MONTH' | 'WEEK' | 'DAY' | 'HOUR' | 'MINUTE' | 'SECOND'; /** * Range bucket for range aggregations */ interface RangeBucket { from?: number | null; to?: number | null; } /** * Value aggregation configuration */ interface ValueAggregation { sortType?: ValueSortType; sortDirection?: ValueSortDirection; limit?: number | null; missingValues?: MissingValues; includeOptions?: { addToBucket?: string; }; } /** * Range aggregation configuration */ interface RangeAggregation { buckets?: RangeBucket[]; } /** * Group by aggregation configuration. */ interface GroupByAggregation { name?: string | null; fieldPath?: string | null; value?: ValueAggregation; } /** * Scalar aggregation configuration */ interface ScalarAggregation { type?: ScalarType; } /** * Date histogram aggregation configuration */ interface DateHistogramAggregation { interval?: DateHistogramInterval; } /** * Nested aggregation item */ type NestedAggregationItem = BaseAggregationWithoutType & { type?: NonNestedAggregationType; }; /** * Nested aggregation configuration */ interface NestedAggregation { nestedAggregations?: NestedAggregationItem[]; } /** * Extracts all aggregatable field paths from a search spec * @template Spec The search specification type */ type AggregatableFields = Spec extends { aggregatable: readonly string[]; } ? Spec['aggregatable'][number] : string; /** * Base aggregation type that can be used for both top-level and nested aggregations */ type NonNestedAggregationType = 'DATE_HISTOGRAM' | 'RANGE' | 'SCALAR' | 'VALUE'; type AggregationTypeWithNested = 'NESTED' | NonNestedAggregationType; type BaseAggregationWithoutType = { name?: string | null; fieldPath?: AggregatableFields; dateHistogram?: DateHistogramAggregation; range?: RangeAggregation; scalar?: ScalarAggregation; value?: ValueAggregation; groupBy?: GroupByAggregation; }; /** * Base aggregation interface * @template Spec The search specification type */ type Aggregation = BaseAggregationWithoutType & { type?: AggregationTypeWithNested; nested?: NestedAggregation; }; /** * Extracts all searchable field paths from a search spec * @template Spec The search specification type * // Results in a union type of all field paths that can be searched */ type SearchableFields = Spec extends { searchable: readonly string[]; } ? Spec['searchable'][number] : string; /** * Configuration for full-text search functionality * @template Spec The search specification type * @example * const search: SearchDetails = { * expression: 'urgent task', * mode: 'AND', * fields: ['title', 'description'], * fuzzy: true * }; */ interface SearchDetails { /** * Search term or expression. */ expression?: string | null; /** * How to combine multiple search terms * - 'AND': All terms must match * - 'OR': Any term can match */ mode?: 'AND' | 'OR'; /** Fields to search in. If empty - will search in all searchable fields. Use dot notation to specify json path. */ fields?: SearchableFields[]; /** * Whether to enable fuzzy matching * Fuzzy matching allows for approximate matches */ fuzzy?: boolean; } /** * Base search request without paging * @template Entity The entity type being searched * @template Spec The search specification type */ type BaseSearch = { /** * Filter object. * Learn more about the [filter section](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#the-filter-section). */ filter?: Filter; /** * List of sort objects. * Learn more about the [sort section](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#the-sort-section). */ sort?: Sorting[]; /** * Free text to match in searchable fields. */ search?: SearchDetails; /** * Aggregations are a way to explore large amounts of data by displaying summaries about various partitions of the data and later allowing to narrow the navigation to a specific partition. */ aggregations?: Aggregation[]; /** * UTC offset or IANA time zone. Valid values are * ISO 8601 UTC offsets, such as +02:00 or -06:00, * and IANA time zone IDs, such as Europe/Rome * * Affects all filters and aggregations returned values. * You may override this behavior in a specific filter by providing * timestamps including time zone. e.g. `"2023-12-20T10:52:34.795Z"` */ timeZone?: string | null; }; /** * Complete search request for an entity type * @template Entity The entity type being searched * @template Spec The search specification type * @example * // Define a search type for products * type SearchProducts = Search; * * // Create a search request * const search: SearchProducts = { * filter: { price: { $gte: 10 } }, * sort: [{ fieldName: 'price', order: 'ASC' }], * search: { expression: 'shirt', mode: 'AND' }, * * // For offset paging: * paging: { limit: 20, offset: 0 } * * // For cursor paging: * cursorPaging: { limit: 20, cursor: "..." } * }; */ type Search = BaseSearch & Partial>; interface PagingSpec { paging: PagingType; } interface CursorPaging { limit: number; cursor?: string; } interface OffsetPaging { limit: number; offset?: number; } type PagingFor = S['paging'] extends 'cursor' ? CursorPaging : OffsetPaging; /** * Represents a filter expression that can be combined with other filters */ interface FilterExpression { readonly filter: Filter; } /** * Represents a sort expression */ interface SortExpression { readonly sort: Sorting; } /** * Extract fields that support a specific operator from the spec */ type FieldsWithOperator = S['wql'][number] extends infer Group ? Group extends WQL ? Group['operators'] extends readonly string[] ? Op extends Group['operators'][number] ? Group['fields'][number] : never : Group['fields'][number] : never : never; /** * Check if a specific field supports a specific operator */ type HasOperator = Field extends FieldsWithOperator ? true : false; /** * Extract sortable fields from the spec */ type SortableFields = S['wql'][number] extends infer Group ? Group extends { fields: readonly string[]; sort: 'ASC' | 'DESC' | 'BOTH'; } ? Group['fields'][number] : never : never; /** * Chainable field filter - extends FilterExpression so it can be used directly, * but also allows chaining multiple operators on the same field. * @example * // Single operator - returns ChainableFieldFilter which is also FilterExpression * Filter('price').gt(50) * * // Chained operators - combines into single field filter * Filter('price').gt(50).lt(100) * // Produces: { price: { $gt: 50, $lt: 100 } } */ type ChainableFieldFilter> = FilterExpression & (HasOperator extends true ? { eq(value: GetNestedType): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { ne(value: GetNestedType): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { gt(value: GetNestedType): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { gte(value: GetNestedType): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { lt(value: GetNestedType): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { lte(value: GetNestedType): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { startsWith(value: string): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { endsWith(value: string): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { contains(value: string): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { in(values: GetNestedType[]): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { nin(values: GetNestedType[]): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { hasSome(values: GetNestedType[]): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { hasAll(values: GetNestedType[]): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { exists(value?: boolean): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { isEmpty(value?: boolean): ChainableFieldFilter; } : {}) & (HasOperator extends true ? { isNotEmpty(): ChainableFieldFilter; } : {}); /** * Filter methods for a specific field (alias for ChainableFieldFilter) * Only shows methods for operators that the field supports */ type FieldFilter> = ChainableFieldFilter; /** * Sort methods for a specific field */ interface FieldSort { asc(): SortExpression; desc(): SortExpression; } /** * Filter factory interface - creates filter expressions * @example * Filter('price').gt(50) * Filter.and(Filter('title').eq('Product'), Filter('price').gt(50)) */ interface FilterFactory { /** Create a field-specific filter */ >(field: Field): FieldFilter; /** Combine filters with AND logic */ and(...filters: FilterExpression[]): FilterExpression; /** Combine filters with OR logic */ or(...filters: FilterExpression[]): FilterExpression; /** Negate a filter */ not(filter: FilterExpression): FilterExpression; } /** * Sort factory - creates sort expressions * @example * Sort('price').desc() */ type SortFactory = >(field: Field) => FieldSort; /** * The output type from SearchBuilder.build() * This is a plain object ready to be sent to an API */ interface SearchRequest { /** Filter object */ filter?: Filter; /** List of sort objects */ sort?: Sorting[]; /** Full-text search parameters */ search?: SearchDetails; /** Aggregations to compute */ aggregations?: Aggregation[]; /** Paging configuration */ paging?: PagingFor; /** Time zone for date operations */ timeZone?: string; } /** * Represents a search expression that can be used in SearchBuilder */ interface SearchExpression { readonly search: SearchDetails; } /** * Represents an aggregation expression that can be used in SearchBuilder */ interface AggregationExpression { readonly aggregation: Aggregation; } /** * Builder for constructing search parameters * @example * SearchParams('dark shoes') * .mode('AND') * .fields(['productName', 'description']) * .fuzzy(true) */ interface SearchParamsBuilder extends SearchExpression { /** Set the search expression/query string */ expression(expr: string): SearchParamsBuilder; /** Set the search mode (how to combine multiple terms) */ mode(mode: 'AND' | 'OR'): SearchParamsBuilder; /** Set the fields to search in */ fields(fields: SearchableFields[]): SearchParamsBuilder; /** Enable or disable fuzzy matching */ fuzzy(enabled?: boolean): SearchParamsBuilder; } /** * Factory function for creating SearchParamsBuilder * @param expression - Optional search expression to initialize with */ type SearchParamsFactory = (expression?: string) => SearchParamsBuilder; /** * Sort configuration for value aggregations */ interface ValueAggregationSort { sortBy(type: 'COUNT' | 'VALUE', direction: 'ASC' | 'DESC'): this; } /** * Builder for VALUE type aggregations */ interface ValueAggregationBuilder extends AggregationExpression, ValueAggregationSort { /** Set maximum number of buckets to return */ limit(count: number): ValueAggregationBuilder; /** Exclude documents with missing values */ excludeMissingValues(): ValueAggregationBuilder; /** Include documents with missing values */ includeMissingValues(): ValueAggregationBuilder; /** Include specific values in their own bucket */ includeValues(addToBucket: string): ValueAggregationBuilder; } /** * Builder for RANGE type aggregations */ interface RangeAggregationBuilder extends AggregationExpression { /** Set the range buckets */ withBuckets(...buckets: { from?: number | null; to?: number | null; }[]): RangeAggregationBuilder; } /** * Builder for DATE_HISTOGRAM type aggregations */ interface DateHistogramAggregationBuilder extends AggregationExpression { /** Set the interval for date histogram buckets */ interval(interval: 'YEAR' | 'MONTH' | 'WEEK' | 'DAY' | 'HOUR' | 'MINUTE' | 'SECOND'): DateHistogramAggregationBuilder; } /** * Builder for SCALAR type aggregations */ interface ScalarAggregationBuilder extends AggregationExpression { /** Set the scalar aggregation type */ type(scalarType: 'COUNT_DISTINCT' | 'MIN' | 'MAX' | 'SUM' | 'AVG'): ScalarAggregationBuilder; } /** * Builder for NESTED type aggregations */ interface NestedAggregationBuilder extends AggregationExpression { /** Add a nested aggregation */ addNestedAggregation(aggregation: AggregationExpression): NestedAggregationBuilder; } /** * Aggregation type configuration */ type AggregationType = 'VALUE' | 'RANGE' | 'DATE_HISTOGRAM' | 'SCALAR' | 'NESTED'; /** * Builder for constructing aggregations * @example * Aggregation('status_count') * .ofType('VALUE') * .onField('status') * .asValueAggregation() * .sortBy('COUNT', 'DESC') * .limit(10) */ interface AggregationBuilder extends AggregationExpression { /** Set the aggregation type */ ofType(type: AggregationType): AggregationBuilder; /** Set the field to aggregate on */ onField(field: AggregatableFields): AggregationBuilder; /** Configure as a value aggregation */ asValueAggregation(): ValueAggregationBuilder; /** Configure as a range aggregation */ asRangeAggregation(): RangeAggregationBuilder; /** Configure as a date histogram aggregation */ asDateHistogramAggregation(): DateHistogramAggregationBuilder; /** Configure as a scalar aggregation */ asScalarAggregation(): ScalarAggregationBuilder; /** Configure as a nested aggregation */ asNestedAggregation(): NestedAggregationBuilder; } /** * Factory function for creating AggregationBuilder */ type AggregationFactory = (name: string) => AggregationBuilder; /** * Search builder interface for constructing search requests * @template T - Entity type * @template S - Search spec defining filterable/sortable/searchable/aggregatable fields * @template R - Output type from build() (defaults to SearchRequest) * @example * SearchBuilder() * .withFilter(Filter.and( * Filter('title').eq('Product'), * Filter('price').gt(50) * )) * .withSearchClause(SearchParams('shoes').fuzzy(true)) * .withAggregation(Aggregation('status_count').ofType('VALUE').onField('status')) * .withSorting(Sort('price').desc()) * .withPaging({ limit: 20 }) * .build() */ interface SearchBuilder> { /** Add a filter to the search */ withFilter(filter: FilterExpression): SearchBuilder; /** Add a search clause for full-text search */ withSearchClause(search: SearchExpression): SearchBuilder; /** Add sorting to the search */ withSorting(...sorts: SortExpression[]): SearchBuilder; /** Add aggregations to the search */ withAggregation(...aggregations: AggregationExpression[]): SearchBuilder; /** Add paging to the search */ withPaging(paging: PagingFor): SearchBuilder; /** Set the time zone for date operations */ withTimeZone(timeZone: string): SearchBuilder; /** Build the final search request object */ build(): R; } /** * Complete set of search helpers for an entity * This is what gets spread into module namespaces * @template T - Entity type * @template S - Search spec defining filterable/sortable/searchable/aggregatable fields * @template R - Output type from SearchBuilder.build() (defaults to SearchRequest) */ interface SearchHelpers> { /** SearchBuilder factory */ SearchBuilder: () => SearchBuilder; /** Filter factory - creates filter expressions (reused from query) */ Filter: FilterFactory; /** Sort factory - creates sort expressions (reused from query) */ Sort: SortFactory; /** Search params factory - creates search expressions */ SearchParams: SearchParamsFactory; /** Aggregation factory - creates aggregation expressions */ Aggregation: AggregationFactory; } /** * Specification for a query API * Defines what fields can be filtered and sorted * @example * interface MyQuerySpec extends QuerySpec { * wql: [{ * operators: ['$eq', '$ne'], * fields: ['id', 'title'], * sort: 'BOTH' * }], * paging: 'offset', // or 'cursor' for cursor-based pagination * }; */ interface QuerySpec extends WQLSpec { /** * Supported paging type for this query API * - 'cursor': Uses cursor-based pagination * - 'offset': Uses offset-based pagination */ paging: PagingType; } /** * Complete query request for an entity type * @template Entity The entity type being queried * @template Spec The query specification type * @example * // Define a query type for products * type QueryProducts = Query; * * // Create a query request with offset paging * const query: QueryProducts = { * filter: { price: { $gte: 10 } }, * sort: [{ fieldName: 'price', order: 'ASC' }], * paging: { limit: 20, offset: 0 } * }; * * // Or with cursor paging (if spec.paging = 'cursor') * const query: QueryProducts = { * filter: { price: { $gte: 10 } }, * sort: [{ fieldName: 'price', order: 'ASC' }], * cursorPaging: { limit: 20, cursor: "..." } * }; */ type Query = { /** * Filter object. * Learn more about the [filter section](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#the-filter-section). */ filter?: Filter; /** * List of sort objects. * Learn more about the [sort section](https://dev.wix.com/docs/rest/articles/getting-started/api-query-language#the-sort-section). */ sort?: Sorting[]; } & Partial>; /** * The output type from QueryBuilder.build() * This is a plain object ready to be sent to an API */ interface QueryRequest { filter?: Filter; sort?: Sorting[]; paging?: PagingFor; /** Field projection - return only specified fields */ fields?: string[]; } /** * Query builder interface * @template T - Entity type * @template S - Query spec defining filterable/sortable fields * @template R - Output type from build() (defaults to QueryRequest) * @example * QueryBuilder() * .withFilter(Filter.and( * Filter('title').eq('Product'), * Filter('price').gt(50) * )) * .withFields('title', 'price') * .withSorting(Sort('price').desc()) * .withPaging({ limit: 20, offset: 0 }) * .build() */ interface QueryBuilder> { /** Add a filter to the query */ withFilter(filter: FilterExpression): QueryBuilder; /** Add field projection - return only specified fields */ withFields(...fields: (keyof T & string)[]): QueryBuilder; /** Add sorting to the query */ withSorting(...sorts: SortExpression[]): QueryBuilder; /** Add paging to the query */ withPaging(paging: PagingFor): QueryBuilder; /** Build the final query request object */ build(): R; } /** * Complete set of query helpers for an entity * This is what gets spread into module namespaces * @template T - Entity type * @template S - Query spec defining filterable/sortable fields * @template R - Output type from QueryBuilder.build() (defaults to QueryRequest) */ interface QueryHelpers> { /** QueryBuilder factory */ QueryBuilder: () => QueryBuilder; /** Filter factory - creates filter expressions */ Filter: FilterFactory; /** Sort factory - creates sort expressions */ Sort: SortFactory; } export { type APIMetadata, type AccessToken, type AccountInfo, type AggregatableFields, type Aggregation, type AggregationBuilder, type AggregationExpression, type AggregationFactory, type AggregationType, type AmbassadorFactory, type AmbassadorFunctionDescriptor, type AmbassadorRequestOptions, type AuthenticationStrategy, type BaseEventMetadata, type BoundAuthenticationStrategy, type BuildAmbassadorFunction, type BuildDescriptors, type BuildEventDefinition, type BuildRESTFunction, type BuildServicePluginDefinition, type CursorPaging, type DateHistogramAggregationBuilder, type Descriptors, EventDefinition, type EventHandler, type EventIdentity, type ExposeFieldsBasedOnToggle, type FieldFilter, type FieldSort, type Filter, type FilterExpression, type FilterFactory, type FilterableFields, type GetNestedType, type HTTPMethod, type Host, type HostModule, type HostModuleAPI, type HttpClient, type HttpResponse, type MaybeContext, type Method, type MigrationOptions, type NestedAggregationBuilder, type NonNullablePaths, type OffsetPaging, type PagingFor, type PublicMetadata, type Query, type QueryBuilder, type QueryHelpers, type QueryRequest, type QuerySpec, type RESTFunctionDescriptor, type RangeAggregationBuilder, type RefreshToken, type RequestContext, type RequestOptions, type RequestOptionsFactory, type RestModuleMeta, SERVICE_PLUGIN_ERROR_TYPE, SORT_CAPABILITIES, SORT_DIRECTIONS, type ScalarAggregationBuilder, type Search, type SearchBuilder, type SearchDetails, type SearchExpression, type SearchHelpers, type SearchParamsBuilder, type SearchParamsFactory, type SearchRequest, type SearchSpec, type SearchableFields, type ServicePluginContract, ServicePluginDefinition, type ServicePluginMethodInput, type ServicePluginMethodMetadata, type SortCapability, type SortExpression, type SortFactory, type SortOrder, type Sorting, type Token, type TokenStorage, type Tokens, type ValueAggregationBuilder, type ValueAggregationSort, type WQL, type WQLSpec };