import {z} from 'zod' export type GetApiApiPropfirmsChallengesQueryArgs = {challengeId?: string | undefined, challengeName?: string | undefined, accountSizeMin?: string | undefined, accountSizeMax?: string | undefined, steps?: string | undefined, stepsMin?: string | undefined, stepsMax?: string | undefined, priceMin?: string | undefined, priceMax?: string | undefined, profitSplitMin?: string | undefined, maxLeverageMin?: string | undefined, minTradingDaysMax?: string | undefined, dailyLossMax?: string | undefined, maxLossMax?: string | undefined, maxLossMode?: string | undefined, newsTrading?: ('true' | 'false') | undefined, copyTrading?: ('true' | 'false') | undefined, autoTrading?: ('true' | 'false') | undefined, weekendHolding?: ('true' | 'false') | undefined, overnightHolding?: ('true' | 'false') | undefined, stoplossRequired?: ('true' | 'false') | undefined, isFeeRefundable?: ('true' | 'false') | undefined, interval?: string | undefined, pageIndex?: string | undefined, pageQuantity?: string | undefined, direction?: ('asc' | 'desc') | undefined, text?: string | undefined, firmId?: string | undefined, propfirmId?: string | undefined, productTypes?: string | undefined, tradedMarketTypes?: string | undefined, tradingPlatforms?: string | undefined, isPreferredPartner?: ('true' | 'false') | undefined, availableIn?: string | undefined, include?: string | undefined, sort?: ('challengeName' | 'accountSize' | 'price' | 'steps' | 'profitSplitPercent') | undefined}; export type GetApiApiPropfirmsChallengesQueryOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const getApiApiPropfirmsChallengesQueryResponse = z.object({data: z.object({challenges: z.array(z.object({challengeId: z.string(), challengeName: z.string(), accountSize: z.number(), steps: z.number(), profitTarget: z.array(z.number()), profitTargetIsPercent: z.boolean(), minTradingDays: z.number().nullable(), dailyLoss: z.number().nullable(), maxLoss: z.number().nullable(), dailyLossType: z.string().nullable(), maxLossType: z.string().nullable(), lossIsPercent: z.boolean(), maxLeverage: z.number().nullable(), newsTrading: z.boolean().nullable(), copyTrading: z.boolean().nullable(), autoTrading: z.boolean().nullable(), weekendHolding: z.boolean().nullable(), overnightHolding: z.boolean().nullable(), stoplossRequired: z.boolean().nullable(), activationFee: z.number().nullable(), resetFee: z.number().nullable(), maxContractSize: z.object({minis: z.number().nullable(), micros: z.number().nullable()}).nullable(), profitSplitPercent: z.number().nullable(), profitSplitDetails: z.string().nullable(), payoutFrequency: z.string().nullable(), isFeeRefundable: z.boolean().nullable(), price: z.number().nullable(), interval: z.string().nullable(), maxLossMode: z.enum(["static-initial", "trailing-realized-eod", "trailing-intraday-unrealized"]).nullable().optional(), maxLossLocksAtInitial: z.boolean().nullable().optional(), maxLossLockOffset: z.number().nullable().optional(), maxLossIsPercent: z.boolean().nullable().optional(), dailyLossBasis: z.enum(["prior-day-balance", "prior-day-equity"]).nullable().optional(), dailyLossLimitBasis: z.enum(["initial-balance", "anchor"]).nullable().optional(), dailyLossIncludesOpenPnl: z.boolean().nullable().optional(), dailyLossEvaluation: z.enum(["intraday", "end-of-day"]).nullable().optional(), dailyLossIsPercent: z.boolean().nullable().optional(), consistencyMaxBestDayPct: z.number().nullable().optional(), payoutIntervalDays: z.number().nullable().optional(), payoutMinWinningDays: z.number().nullable().optional(), payoutWinningDayMinProfit: z.number().nullable().optional(), payoutMaxPct: z.number().nullable().optional(), payoutMaxAmount: z.number().nullable().optional(), payoutBufferAmount: z.number().nullable().optional(), fundedConsistencyPct: z.number().nullable().optional(), firstPayoutMinDays: z.number().nullable().optional(), feeCurrency: z.string().min(3).max(3).nullable().optional(), sourceUrl: z.string().nullable().optional(), lastVerifiedAt: z.string().nullable().optional(), firmId: z.string(), propfirmId: z.string(), propfirmName: z.string(), offers: z.array(z.object({offerId: z.string(), firmId: z.string(), propfirmId: z.string(), propfirmName: z.string(), promoCode: z.string().nullable(), affiliateLink: z.string().nullable(), discountIsPercent: z.boolean(), discountValue: z.number().nullable(), shortDescription: z.string().nullable(), fullDescription: z.string().nullable(), isActive: z.boolean(), isFeatured: z.boolean(), hasEndDate: z.boolean(), endsAt: z.string().nullable(), scope: z.union([z.object({type: z.literal("all_challenges")}), z.object({type: z.literal("specific_challenges"), challengeIds: z.array(z.string())})])})).optional()})), count: z.number()}), errors: z.unknown()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Public: search challenges across visible firms. Filter by challenge rules and parent firm; pass propfirmId to list one firm's challenges. Use include=offers to attach live offers that apply to each challenge. * * GET /api/propfirms/challenges/query */ export const getApiApiPropfirmsChallengesQuery = async (args: GetApiApiPropfirmsChallengesQueryArgs, options?: GetApiApiPropfirmsChallengesQueryOptions) => { const {baseUrl = "https://app.luxalgo.com", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json") if (args.challengeId != null) query.append("challengeId", String(args.challengeId)) if (args.challengeName != null) query.append("challengeName", String(args.challengeName)) if (args.accountSizeMin != null) query.append("accountSizeMin", String(args.accountSizeMin)) if (args.accountSizeMax != null) query.append("accountSizeMax", String(args.accountSizeMax)) if (args.steps != null) query.append("steps", String(args.steps)) if (args.stepsMin != null) query.append("stepsMin", String(args.stepsMin)) if (args.stepsMax != null) query.append("stepsMax", String(args.stepsMax)) if (args.priceMin != null) query.append("priceMin", String(args.priceMin)) if (args.priceMax != null) query.append("priceMax", String(args.priceMax)) if (args.profitSplitMin != null) query.append("profitSplitMin", String(args.profitSplitMin)) if (args.maxLeverageMin != null) query.append("maxLeverageMin", String(args.maxLeverageMin)) if (args.minTradingDaysMax != null) query.append("minTradingDaysMax", String(args.minTradingDaysMax)) if (args.dailyLossMax != null) query.append("dailyLossMax", String(args.dailyLossMax)) if (args.maxLossMax != null) query.append("maxLossMax", String(args.maxLossMax)) if (args.maxLossMode != null) query.append("maxLossMode", String(args.maxLossMode)) if (args.newsTrading != null) query.append("newsTrading", String(args.newsTrading)) if (args.copyTrading != null) query.append("copyTrading", String(args.copyTrading)) if (args.autoTrading != null) query.append("autoTrading", String(args.autoTrading)) if (args.weekendHolding != null) query.append("weekendHolding", String(args.weekendHolding)) if (args.overnightHolding != null) query.append("overnightHolding", String(args.overnightHolding)) if (args.stoplossRequired != null) query.append("stoplossRequired", String(args.stoplossRequired)) if (args.isFeeRefundable != null) query.append("isFeeRefundable", String(args.isFeeRefundable)) if (args.interval != null) query.append("interval", String(args.interval)) if (args.pageIndex != null) query.append("pageIndex", String(args.pageIndex)) if (args.pageQuantity != null) query.append("pageQuantity", String(args.pageQuantity)) if (args.direction != null) query.append("direction", String(args.direction)) if (args.text != null) query.append("text", String(args.text)) if (args.firmId != null) query.append("firmId", String(args.firmId)) if (args.propfirmId != null) query.append("propfirmId", String(args.propfirmId)) if (args.productTypes != null) query.append("productTypes", String(args.productTypes)) if (args.tradedMarketTypes != null) query.append("tradedMarketTypes", String(args.tradedMarketTypes)) if (args.tradingPlatforms != null) query.append("tradingPlatforms", String(args.tradingPlatforms)) if (args.isPreferredPartner != null) query.append("isPreferredPartner", String(args.isPreferredPartner)) if (args.availableIn != null) query.append("availableIn", String(args.availableIn)) if (args.include != null) query.append("include", String(args.include)) if (args.sort != null) query.append("sort", String(args.sort)) const url = `${baseUrl.replace(/\/+$/, '')}/api/propfirms/challenges/query${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getApiApiPropfirmsChallengesQueryResponse, await res.json()) };