import {z} from 'zod' export type FilteringCondition1 = {field?: string | undefined, operator?: ('EQUAL' | 'NOT_EQUAL' | 'LESS' | 'GREATER' | 'LESS_OR_EQUAL' | 'GREATER_OR_EQUAL' | 'LIKE' | 'NOT_LIKE' | 'BETWEEN' | 'IN' | 'NOT_IN' | 'NOT' | 'IS_NULL' | 'IS_NOT_NULL' | 'IS_TRUE' | 'IS_FALSE' | 'IS_EMPTY' | 'IS_NOT_EMPTY' | 'CONTAINS') | undefined, parameters?: Array> | undefined}; export type FilterParameters = {conditionalOperator?: ('AND' | 'OR') | undefined, expressions?: (Array) | undefined}; export type SortParameter = {direction?: ('ASC' | 'DESC') | undefined, field?: string | undefined}; export type RequestParametersV1 = {filter?: FilterParameters | undefined, page?: number | undefined, perPage?: number | undefined, sort?: Array | undefined}; export type CreateApiFeatureFlagsSearchArgs = {optionalFields?: Array | undefined, body: RequestParametersV1}; export type CreateApiFeatureFlagsSearchOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const bucketingKeyCustomDataDto = z.object({bucketingKeyType: z.enum(["VISITOR_CODE", "CUSTOM_DATA"]).optional(), customDataId: z.number().int().optional()}); export const bucketingKeyVisitorCodeDto = z.object({bucketingKeyType: z.enum(["VISITOR_CODE", "CUSTOM_DATA"]).optional()}); export const featureFlagIntegrations: z.ZodType = z.object({deliveryRules: z.array(z.lazy(() => featureFlagIntegrations)).optional(), experimentRules: z.array(z.lazy(() => featureFlagIntegrations)).optional()}); export const featureFlagRelease = z.object({releaseFrom: z.string().optional(), releaseTo: z.string().optional(), timeZone: z.string().optional()}); export const featureRollbackCondition = z.object({comparisonOperator: z.enum(["GREATER_THAN", "LESS_THAN"]).optional(), criteria: z.enum(["UPLIFT", "DOWNLIFT", "CONVERSION_RATE"]).optional(), goalId: z.number().int().optional(), id: z.number().int().optional(), matchValue: z.number().gte(0.0001).lte(100).optional(), recipients: z.array(z.string()).optional(), target: z.enum(["RULE", "ENVIRONMENT"]).optional(), visitors: z.number().int().gte(1).optional()}); export const featureTrafficAllocation = z.object({exposition: z.number().optional(), variationId: z.number().int().optional(), variationKey: z.string().optional()}); export const experimentationRuleResponse = z.object({experimentId: z.number().int().optional(), id: z.number().int().optional(), name: z.string().optional(), release: featureFlagRelease.optional(), rollbackConditions: z.array(featureRollbackCondition).optional(), segmentId: z.number().int().optional(), status: z.enum(["ACTIVE", "PAUSED", "PLANNED"]).optional(), trafficAllocations: z.array(featureTrafficAllocation).optional(), type: z.enum(["TARGETED_DELIVERY", "PROGRESSIVE_DELIVERY", "EXPERIMENTATION"]), controlVariationKey: z.string().optional(), exposition: z.number().int().gte(0).lte(100).optional(), multiArmedBandit: z.boolean().optional(), trafficAllocationMethod: z.enum(["CONTEXTUAL_BANDIT", "MANUAL", "MULTI_ARMED_BANDIT"]).optional()}); export const featureRolloutTargetedRule = z.object({experimentId: z.number().int().optional(), id: z.number().int().optional(), name: z.string().optional(), release: featureFlagRelease.optional(), rollbackConditions: z.array(featureRollbackCondition).optional(), segmentId: z.number().int().optional(), status: z.enum(["ACTIVE", "PAUSED", "PLANNED"]).optional(), trafficAllocations: z.array(featureTrafficAllocation).optional(), type: z.enum(["TARGETED_DELIVERY", "PROGRESSIVE_DELIVERY", "EXPERIMENTATION"]), exposition: z.number().int().gte(0).lte(100).optional(), variationKey: z.string().optional()}); export const rolloutStep = z.object({dateTime: z.string().optional(), exposure: z.number().optional()}); export const customRampUpRollout = z.object({type: z.enum(["PROGRESSIVE_EXPOSURE", "CUSTOM_RAMP_UP"]), steps: z.array(rolloutStep)}); export const rolloutFrequency = z.object({unit: z.enum(["Nanos", "Micros", "Millis", "Seconds", "Minutes", "Hours", "HalfDays", "Days", "Weeks", "Months", "Years", "Decades", "Centuries", "Millennia", "Eras", "Forever"]), value: z.number().int().gte(1)}); export const rolloutPercentageRange = z.object({start: z.number().int().gte(0).lte(100), stop: z.number().int().gte(0).lte(100)}); export const progressiveExposure = z.object({type: z.enum(["PROGRESSIVE_EXPOSURE", "CUSTOM_RAMP_UP"]), frequency: rolloutFrequency.optional(), increaseBy: z.number().int().gte(1).lte(100), percentageRange: rolloutPercentageRange, releaseDateTime: z.string().optional()}); export const progressiveRuleResponse = z.object({experimentId: z.number().int().optional(), id: z.number().int().optional(), name: z.string().optional(), release: featureFlagRelease.optional(), rollbackConditions: z.array(featureRollbackCondition).optional(), segmentId: z.number().int().optional(), status: z.enum(["ACTIVE", "PAUSED", "PLANNED"]).optional(), trafficAllocations: z.array(featureTrafficAllocation).optional(), type: z.enum(["TARGETED_DELIVERY", "PROGRESSIVE_DELIVERY", "EXPERIMENTATION"]), currentExposition: z.number().int().optional(), rolloutConfiguration: z.union([customRampUpRollout, progressiveExposure]).optional(), variationKey: z.string().optional()}); export const environmentResponse = z.object({dateModified: z.string().optional(), defaultVariationKey: z.string().optional(), environmentKey: z.string().optional(), featureEnabled: z.boolean().optional(), integrations: featureFlagIntegrations.optional(), rolloutRules: z.array(z.union([experimentationRuleResponse, featureRolloutTargetedRule, progressiveRuleResponse])).optional()}); export const variableResponse = z.object({allowedValues: z.array(z.string().nullable()).nullable().optional(), key: z.string(), type: z.enum(["BOOLEAN", "NUMBER", "STRING", "JSON", "JS", "CSS", "ENUM"]), value: z.string()}); export const variationVariableResponse = z.object({key: z.string(), type: z.enum(["BOOLEAN", "NUMBER", "STRING", "JSON", "JS", "CSS", "ENUM"]), value: z.string()}); export const variationResponse = z.object({key: z.string(), name: z.string(), variables: z.array(variationVariableResponse).optional()}); export const featureFlagConfiguration = z.object({archived: z.boolean().optional(), attributionWindow: z.number().int().optional(), bucketingKey: z.union([bucketingKeyCustomDataDto, bucketingKeyVisitorCodeDto]).optional(), createdById: z.number().int().optional(), dateContentModified: z.string().optional(), dateCreated: z.string().optional(), dateModified: z.string().optional(), description: z.string().max(5000).optional(), environmentConfigurations: z.array(environmentResponse).optional(), featureKey: z.string().min(1).max(255), health: z.enum(["PERMANENT", "HEALTHY", "STALE", "SMELLY"]).optional(), id: z.number().int(), isArchived: z.boolean().optional(), name: z.string().min(1).max(100), primaryGoalId: z.number().int().optional(), secondaryGoalIds: z.array(z.number().int()).optional(), siteCode: z.string().min(1).max(10), tags: z.array(z.string()).optional(), teamId: z.number().int().optional(), variables: z.array(variableResponse).optional(), variations: z.array(variationResponse).optional()}); export const createApiFeatureFlagsSearchResponse = z.array(featureFlagConfiguration); 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 }; /** * Search feature flags * * POST /feature-flags/search */ export const createApiFeatureFlagsSearch = async (args: CreateApiFeatureFlagsSearchArgs, options?: CreateApiFeatureFlagsSearchOptions) => { const {baseUrl = "https://api.kameleoon.com", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") for (const item of args.optionalFields ?? []) query.append("optionalFields", String(item)) const url = `${baseUrl.replace(/\/+$/, '')}/feature-flags/search${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(createApiFeatureFlagsSearchResponse, await res.json()) };