/** * Flagsmith REST API client — Phase-1 config snapshot. * * Flagsmith has no bulk-export endpoint, so the fetcher stitches per-resource * calls: project → environments → features → per-env featurestates → segments * → feature-segments (priority) → edge identities → edge identity overrides * → tags. * * Auth is `Authorization: Api-Key ` — note the `Api-Key` prefix (not * `Bearer`, and not bare-token like LaunchDarkly). Rate-limiting headers are * unpublished; we program against the response: back off on 429 using * `Retry-After` (standard) or `X-RateLimit-Reset` (Flagsmith's variant), and * step the inter-request throttle up briefly when we hit one (mirrors the * Phase-2 generator's empirical backoff loop). On any non-429 error we throw * immediately — only rate limiting is retried. * * Pagination is standard Django REST `{count, next, previous, results}` with * absolute `next` URLs. Edge-identities listing is the one exception: it uses * `{results, last_evaluated_key}` cursor pagination via a query-string param. */ import type { FlagsmithEdgeIdentity, FlagsmithEdgeIdentityOverride, FlagsmithEnvironment, FlagsmithFeature, FlagsmithFeatureSegment, FlagsmithFeatureState, FlagsmithProject, FlagsmithSegment, FlagsmithSnapshot, FlagsmithTag } from './types.js'; export declare function setFlagsmithBaseUrl(url: string): void; export declare function selectFlagsmithBaseUrl(): string; export declare function applyFlagsmithBaseUrl(): void; export declare function __setSleepForTests(fn: (ms: number) => Promise): void; export declare function __resetSleepForTests(): void; export declare class FlagsmithApiError extends Error { readonly status: number; constructor(status: number, statusText: string, url: string, body: string); } /** * Single GET with `Api-Key` auth, 429 backoff against `Retry-After` / * `X-RateLimit-Reset`, and an exponential fallback. Non-429 errors throw * immediately — only rate limiting is retried. */ export declare function apiFetch(path: string, apiKey: string): Promise; /** `GET /projects/{id}/` — used as the cheap auth probe AND as a source of `use_edge_identities`. */ export declare function fetchProject(apiKey: string, projectId: number | string): Promise; /** `GET /environments/?project={id}` — paginated env list. */ export declare function fetchEnvironments(apiKey: string, projectId: number | string): Promise; /** * `GET /projects/{pk}/features/` — paginated feature list. Each result * includes inline `multivariate_options[]` which we sort ASC by id (API6) so * downstream code sees variations in definition order, not the reverse order * the API returns. */ export declare function fetchFeatures(apiKey: string, projectId: number | string): Promise; /** * `GET /features/featurestates/?environment={env_id}` — per-env featurestates. * * This is the unified listing that returns BOTH env-default rows * (`feature_segment == null && identity == null`) AND segment-override rows * (`feature_segment != null`). The plan §4.1 suggests * `/environments/{api_key}/featurestates/`, but empirically on v2-versioned * envs that endpoint silently omits segment-override rows. The * `/features/featurestates/?environment=` path is the only read endpoint that * returns both on a v2 env, so we use it uniformly across v1 and v2 envs. * * Identity overrides are NOT in this listing on edge-enabled projects — see * `fetchEdgeIdentityOverrides`. */ export declare function fetchEnvFeatureStates(apiKey: string, envId: number): Promise; /** `GET /projects/{pk}/segments/` — project-scoped segment pool. */ export declare function fetchSegments(apiKey: string, projectId: number | string): Promise; /** * `GET /features/feature-segments/?environment={env_id}&feature={feature_id}` — * the per-env, per-feature segment priority list. Required by the converter * to order the segment-override rules (Quonfig is a strict first-match list). * * The endpoint REJECTS calls without `feature` (`{feature: ["This field is * required."]}`), so we have to walk every feature × env combo. This is N×E * calls in the worst case — acceptable for the corpus (~110 features × 2 envs * = ~220 calls) and roughly the same order as fetchEnvFeatureStates. */ export declare function fetchFeatureSegments(apiKey: string, envId: number, featureId: number): Promise; /** * `GET /environments/{api_key}/edge-identities/` — paginated edge-identity * listing. Pagination here is CURSOR-based (`last_evaluated_key`) not page * numbers — the Flagsmith dynamo-backed edge store can't offset-paginate. * * The fetcher uses this only to surface identifiers for the report; the * actual identity-override featurestates come from * `fetchEdgeIdentityOverrides`, which is a one-call-per-env shortcut. */ export declare function fetchEdgeIdentities(apiKey: string, envApiKey: string): Promise; /** * `GET /environments/{api_key}/edge-identity-overrides` — every identity * override in the env, flat. Each row is `{identifier, identity_uuid, * feature_state}` so we can index by feature without walking N identities. * * Note: the path has NO trailing slash (unlike most Flagsmith paths). This * endpoint does not paginate in the verified shape — it returns * `{results: [...]}` directly. */ export declare function fetchEdgeIdentityOverrides(apiKey: string, envApiKey: string): Promise; /** `GET /projects/{pk}/tags/` — project-scoped tag pool. */ export declare function fetchTags(apiKey: string, projectId: number | string): Promise; /** * Stitch the whole Phase-1 snapshot: project → environments → features → * per-env featurestates (split into env-default + segment-overrides) → segments * → feature-segments (per env, per feature with segment overrides) → edge * identity overrides → tags. * * Walk count grows as 1 (project) + 1 (envs) + 1 (segments) + 1 (tags) + E × * (1 featurestates + 1 edge-id-overrides + S features-with-segov × * feature-segments). For the 110-feature, 2-env, 5 features-with-segov live * corpus: ~1 + 1 + 1 + 1 + 2 × (1 + 1 + 5) = ~17 calls. The featurestates * endpoint is paginated under 100/page so larger projects multiply that * featurestates leg. * * `sinceEpochMs` is currently unused — decision D2 says Phase 1 is always a * full re-snapshot. It survives in the signature so reporting (Epic 5) can * compute "what's new since last run" against the same snapshot. */ export declare function fetchSnapshot(apiKey: string, projectId: number | string): Promise;