kitty_sdk 0.11.0 copy "kitty_sdk: ^0.11.0" to clipboard
kitty_sdk: ^0.11.0 copied to clipboard

unlisted

Kitty Flutter SDK — unified package for device fingerprint attribution (Flare) and authentication, user management, licenses & subscriptions (Account) against the Kitty Launch platform APIs.

0.11.0 #

  • New: Google Play client purchase — KittyAccount.loginWithPlayStore() and KittyAccount.claimPlayStoreSubscriptions(). The Play analog of the App Store pair, for apps whose Android purchases must land on the Kitty account layer. Android hands the client an opaque purchase token rather than a signed transaction, so both take {packageName, purchaseToken} and authenticity comes from server-side verification against the Google Play Developer API — loginWithPlayStore returns null when no account matches the purchase, and throws when the server could not verify it (409 not-entitling, 503 verification unavailable) so a purchase can never read as "logged in" on an unconfirmed token. claimPlayStoreSubscriptions binds a verified purchase to the signed-in account and transfers the licence off the virtual txn_*@googleplay.internal user. New public models PlayStoreLoginResult, ClaimPlayStoreResult, ClaimPlayStoreDetail. Additive: no host changes required, and no behaviour changes for apps that do not call them.
  • New: KittyAccount.getFirebaseToken() — mints a Firebase custom token via the new authenticated GET /api/account/vault/firebase-login (factory /account/vault/firebase-login wire parity: {accessToken}), so the Firestore-backed legacy media gallery keeps working when an app runs on the Kitty account backend. Token-only by design: the SDK carries no firebase_auth dependency — the app performs FirebaseAuth.signInWithCustomToken itself. The bearer is attached and refreshed by AuthorizedHttpClient; x-project-id selects the per-project Firebase credentials server-side.
  • Added example/ — a rehearsal host that exercises the legacy auth bridge end to end against a local stack.
  • Legacy auth bridge: users are no longer logged out at backend cutover. An app updated onto the Kitty backend is holding an access/refresh pair that Kitty never issued and cannot validate, so the first authenticated call after cutover returns 401 and the user lands on a login screen. The SDK can now exchange that pair for a real Kitty session. New KittyAccount.adoptLegacySession({accessToken, refreshToken}): call it once at startup with the pair read from the app's own pre-Kitty storage, and the SDK stores it as TokenOrigin.legacy, exchanges it at POST /account/vault/login-legacy on the first 401, retries the original request, and returns the restored account. It returns null when the exchange is refused — show the ordinary login screen then. Calling it while a Kitty session already exists is a no-op, so it is safe to call unconditionally at startup.
  • A failed exchange is always recoverable. The legacy pair is never cleared on failure — not on a 401, not on a 5xx, not on a malformed response — so a refusal is retried on the next launch rather than stranding the user permanently. This also required a fix in AccountRepository.refreshAccountInfo: its ReauthRequiredException handler cleared all stored tokens, which would have destroyed the legacy pair on the very first failed exchange, including on the initialize() launch path. It now keeps a legacy pair while still dropping the cached account, so the app shows login and the next launch can retry. An explicit logout() still clears everything.
  • The exchange runs at most once per launch, never in a loop. The attempt is recorded before the first await, so concurrent 401s coalesce into a single request and every later caller sees that attempt's outcome — including its failure — rather than triggering another.
  • Ships dark. No behaviour changes for any app that does not call adoptLegacySession: without it nothing is ever tagged TokenOrigin.legacy, the new branch is unreachable, and no bridge request is made. The exchange is additionally inert unless the account config supplies a project id, and x-project-id is sent on the exchange only — deliberately not added to defaultHeaders, which would put it on every authenticated request.
  • Fix — a failed token refresh was reported to concurrent callers as a success. AuthorizedHttpClient completed its refresh waiters with a hardcoded true in a finally block, while the refresh itself returned false on all three failure paths (no refresh token, non-2xx, exception). Waiters were told the refresh had succeeded and retried with the still-stale token, hitting 401 again and re-entering refresh — roughly tripling the calls reaching the endpoint on a day when refreshes fail. Waiters now receive the real outcome. (The same defect exists in the pre-Kitty client this SDK forked from.)
  • New public API: TokenOrigin (kitty / legacy) on AuthTokens, plus TokenStorage.origin and TokenStorage.hasLegacyPair. TokenOrigin.legacy is reachable only through adoptLegacySessionAuthTokens.fromJson always yields kitty, so no server response can put the SDK into legacy mode. Origin is local bookkeeping and is not serialized by toJson. An install that predates this change has no stored origin and reads as kitty, so no migration is needed.
  • Additive and backward-compatible: no host changes are required, and the refresh-coalescing fix applies to every app on a version bump alone. 44 new tests under test/account/ (75 total).
  • New pre-login checks + password-reset facade surface (for the mobile-nidrana account-layer swap). VaultApiClient gains userExist (GET /account/vault/users/exist — the pre-login existence check the mobile login/signup UX branches on) and canLoginWithPassword (GET /account/vault/can-login-with-password; note it returns false for both "no such user" and "user exists but passwordless", so pair it with userExist where that distinction matters). Both are exposed on AccountRepository (isUserExist / canLoginWithPassword, deliberately silent in analytics — they run on every login-screen step) and on KittyAccount, which additionally now surfaces the existing repository methods sendResetPasswordCode, validateResetPasswordCode and resetPassword (resetPassword also logs the user in — the server mints a session, matching the legacy flow). 5 new client tests.

0.10.19 #

  • Account: v2 /users/current client + per-license token support. New UsersApiClient.getCurrentUserV2() calls GET /api/account/v2/users/current — same contract as v1, plus every license carries tokensPerCycle (renewable allowance per billing cycle) and supportsTokens (plan-level flag, tokensPerCycle > 0). License gains both fields with safe defaults (0 / false), so v1 responses and previously cached accounts keep parsing unchanged; toJson roundtrips them through the SDK's account cache. Note supportsTokens: false does not mean a zero balance — one-time top-up tokens live in GET /api/account/tokens/balance. Requires a backend with the /api/account/v2/users/* routes deployed; additive and backward-compatible.

0.10.18 #

  • Auth: valid login codes are no longer rejected as "Please enter a valid code" when PostHog isn't ready. Root cause: _resolveSid() threw a StateError when analytics wasn't initialized, or produced an empty sid when PostHog wasn't actually ready (systematic on web, where initPostHogWeb silently no-ops if the posthog JS global hasn't loaded yet while the SDK still reports analytics as initialized). The empty sid went on the wire and failed the backend's verify-code validation with a 400, and the UI treated every error as a wrong code — so a correct code produced a code-blame message, sometimes without any network call at all. Fixes: (1) sid is resolved defensively — never throws, never empty; when unavailable it is omitted from verify-code/signup-password (the verify-code backend treats sid as optional attribution metadata, so login without it is fully supported); (2) after a successful code login that went out without a sid, the real distinct id is attached best-effort via attach-sid (the same pattern App Store login already used, now shared); (3) verify-code maps 400 → AccountErrorType.badRequest and 429 → tooManyAttempts (401 stays loginCodeNotValid); (4) the code screen now shows a generic "Something went wrong… contact us" message for non-code failures instead of blaming the code.
  • Behaviour change — KittyAuthCodeState.isWrongCode is narrower (exported public API). It was errorType != null && errorType != noInternet, i.e. true for any error except offline. It is now true only for a real code rejection (loginCodeNotValid / invalidCode). Two new getters accompany it: isOffline and hasGenericError (any error that is neither a code rejection nor offline). Hosts that branched on isWrongCode to mean "something failed" must switch to errorType != null.
  • Offline stays delegated to the host. hasGenericError renders inline under the code input; noInternet deliberately renders nothing inline, matching the existing login form — the auth flows already invoke the host's onNoInternet callback, and duplicating the message inline would double up with the host's own snackbar.
  • API restored — sid is back on KittyAccount.verifyLoginCode. It was removed in 0.2.2, when sid resolution moved entirely inside AccountRepository on the assumption that analytics is always available. That assumption is what broke login here, so the caller-supplied override returns: an explicit sid wins over auto-resolution, and a blank/whitespace value is normalized to "absent" rather than sent as an empty string. Additionally KittyAccount.initialize / KittySdk.initialize accept a SidResolver (sidResolver / accountSidResolver) — an async String? Function() — so hosts that already know their analytics id can supply it directly instead of depending on KittyAnalytics. Exported as SidResolver.
  • Failure-mode change for signupWithPassword without analytics. It previously threw a client-side StateError before any request. It now omits the sid and reaches the server, which still requires sid for signup-password, so the call fails with a 400 ApiException carrying a clear validation message. Hosts catching StateError around signup must widen to ApiException. Relaxing the server-side signup schema is tracked separately; only verify-code is fixed end-to-end here.
  • Attribution can never break or stall login. Sid resolution and the post-auth attach are both bounded: getDistinctId() is capped at 500 ms (a half-booted PostHog on web can leave that Future pending forever, which would hang login before any network call — the one original failure mode with no fallback), and the late attach-sid is capped at 2 s (it runs through the authorized client, whose 401 retry ladder adds 1 s + 2 s of backoff while the already-authenticated user waits). Both failures are swallowed by design — sid is attribution-only — and a regression test pins the invariant from both sides.
  • New diagnostics via the existing onAnalyticsEvent host callback (deliberately host-side, since these fire exactly when PostHog is unavailable): LoginSidAttachedAfterAuth when the late attach succeeded, and LoginSidUnavailable with a reason property distinguishing resolver_threw / analytics_uninitialized / analytics_timeout / analytics_blank — so a host whose sidResolver throws is not indistinguishable from PostHog merely not being ready.
  • Additive and backward-compatible apart from the isWrongCode narrowing and the signup failure-mode change noted above: no host changes are required to get the login fix, only a version bump. First tests for the account client, repository, auth state and code form (27 new tests under test/account/).

0.10.17 #

  • Settings: hide an untrusted billing period instead of showing a misleading "1 year". KittySubscriptionPage now derives the card's billing period via the new reliableBillingPeriod(License) helper. A web/Lago license whose duration is exactly the Account API's un-populated default (365 days) is ambiguous — a genuine yearly plan vs the old default that was never populated — so the period is treated as unknown and omitted (the card falls back to the plan name). Healed/real Lago periods (weekly / monthly / …) and all App Store / Google Play durations — including a genuine yearly 365 — are shown as before. This guarantees no user sees a wrong billing cycle while legacy web licenses back-fill their real duration on renewal. Trade-off: a genuine Lago yearly license hides its period until its duration is populated. New helpers hasReliableBillingPeriod(License) / reliableBillingPeriod(License) in license_helpers.dart (exported via kitty_sdk.dart); first unit tests added under test/account/ui/settings/helpers/.
  • Additive and backward-compatible: no API/schema change; apps get the safer display with a kitty_sdk version bump.

0.10.16 #

  • Settings: Web2Wave "manage subscription" card. KittySubscriptionPage now renders a bordered card instead of a flat list: a body header, a current-phase block (status badge + trial/plan title + price + expiry), and — for a trial that will auto-convert — a separate Upcoming block showing the post-trial charge (amount + next-charge date). Non-trial or non-renewing licenses collapse to a single block. The cancel/renew action and its analytics events (CancelSubscriptionButtonClicked / RenewSubscriptionButtonClicked) are unchanged. A legal-links footer (Privacy Policy / Terms of Use / Subscription Policy) now appears on the page whenever those URLs are configured — required for web2app funnel compliance ("manage without leaving").
  • Settings: top-level "Manage subscription" entry. KittySettingsPage now shows a Manage-subscription item directly on the Settings screen (new optional onSubscriptionTap / onSubscriptionsTap; visible when logged-in with ≥1 license — a single license opens the detail card, multiple opens the list). Previously it was reachable only via Account → Manage subscriptions. Backward-compatible: the entry is hidden when the callbacks aren't wired.
  • New reusable widget KittyLegalLinks. The three legal links are extracted from KittyLegalInfoPage into a shared widget (same labels, analytics events, and launchUrl behaviour) so they also render as the subscription-card footer.
  • New helpers (exported via kitty_sdk.dart): shouldShowUpcomingBlock(License) and trialLengthLabel(License, {suffix}). The latter derives the trial length from expiresAt - createdAt, falling back to a bare label when the dates are missing or the span is non-positive.
  • Status-fidelity badge. The current-phase badge reflects the true license status — Active / Cancelling / Suspended / Expired — rather than a binary, so a dunning (suspended) or cancelling license no longer reads as green "Active". The header ("You have 1 active subscription") is shown only for active licenses; a trial always displays its expiry (the charge, when known, lives in the Upcoming block).
  • Theme: KittySettingsCardTheme + KittySettingsBadgeTheme added to KittySettingsTheme (as card / badge). All fields are nullable with sensible fallbacks, so the card renders correctly with no host theming; override card/badge to brand the container, divider, and the Active / Upcoming / Cancelling / Suspended / Expired badge colors.
  • New KittySettingsConfig copy fields: manageSubscriptionHeader, subscriptionActiveBadgeLabel, subscriptionUpcomingBadgeLabel, subscriptionExpiredBadgeLabel, subscriptionCancellingBadgeLabel, subscriptionSuspendedBadgeLabel, trialLabel, subscriptionSuffix (all with English defaults, threaded through resolveWithSdkConfig), plus a hasLegalLinks getter. The old flat-row copy fields currentPlanPrefix, statusPrefix, pricePrefix, billingPeriodPrefix, and nextChargeAmountPrefix are no longer rendered by the card and are now @Deprecated (kept for source compatibility).
  • Additive and backward-compatible: apps get sensible defaults with no changes beyond a kitty_sdk version bump; theming the card and overriding copy are optional.

0.10.15 #

  • Settings: onAccountDeleted cleanup hook on KittySettingsConfig. New optional Future<void> Function()? onAccountDeleted. KittySettingsCubit.deleteAccount() invokes it immediately before KittyAccount.deleteAccount() — while the session/token is still valid — so host apps can wipe product-specific user data (e.g. images stored in their own backend) as part of account deletion. The call is wrapped in a guard: any error it throws is caught (tracked as AccountDataCleanupFailed) and never blocks account deletion. Additive and backward-compatible — apps that don't set the callback are unaffected.

0.10.14 #

  • Fix: the "contact us" link in login-form error messages did nothing unless KittyAuthUiConfig.onSupportEmailTap was set. The code form already fell back to opening a mailto: link with KittySdkConfig.supportEmail when the callback was not provided, but the login form wired the tap recognizer straight to the (possibly null) callback, so with only supportEmail configured the link was dead. Both forms now share one helper: onSupportEmailTap if provided, otherwise mailto: to the SDK-configured support email.

0.10.13 #

  • Fix: Apple Pay button missing on the web buy-now checkout (Flutter web). On Flutter web KittyWebBuyNowPage renders the checkout inside an iframe (flutter_inappwebview web implementation). Safari exposes ApplePaySession to cross-origin iframes only when the iframe carries allow="payment", so the embedded checkout silently hid the Apple Pay button while Google Pay and card stayed visible (the checkout's supportsApplePay() gate saw typeof ApplePaySession === 'undefined'). InAppWebViewSettings now sets iframeAllow: 'payment'. Native iOS builds are unaffected: WKWebView never exposes Apple Pay JS — the StoreKit IAP path covers native. Note: consumer apps that still ship their own pre-migration copy of this page (e.g. mobile-renovio) need the same one-line change locally.

0.10.12 #

  • Settings: Subscription Policy link on the legal info page. New subscriptionPolicyUrl on KittySdkConfig / KittySettingsConfig (+ subscriptionPolicyLabel, default "Subscription Policy"). When set, KittyLegalInfoPage renders it next to Privacy Policy and Terms of Use (tracked as SettingsSubscriptionPolicyClicked). Required for web2app funnel compliance (refund policy visibility).
  • Settings: subscription page now shows renewal info. KittySubscriptionPage renders Price (license.price + currency), Billing period (derived from license.duration) and — for active auto-renewing subscriptions only — Next charge date (subscriptionNextChargeDate, falling back to expiresAt) and Next charge amount (subscriptionNextChargeAmount, when > 0). Cancelled/cancelling plans keep showing only the expiry date. New label overrides: pricePrefix, billingPeriodPrefix, nextChargeDatePrefix, nextChargeAmountPrefix.
  • Fix: "Current plan" value was clipped on the subscription page. The default currentPlanPrefix puts the value on a second line ('Current plan:\n'), but KittySettingsMenuItem hard-capped text at one line, so the plan name never showed. The menu item now takes a maxLines parameter (default 1) and the current-plan row uses 2.
  • Added formatDate, formatLicensePrice and formatBillingPeriod helpers to license_helpers.dart (exported via kitty_sdk.dart).

0.10.11 #

  • Fix: on mobile web browsers the on-screen keyboard did not appear when tapping the login code input. The code screen appears after the async send-code call, so KittyCodeInput's autofocus grabbed focus outside a user gesture — mobile browsers focus the hidden input but keep the keyboard hidden, and a tap on the already-focused field was a focus no-op (the user had to tap elsewhere and tap the input again). Tapping the code input while it already holds focus now forces a blur → refocus cycle within the tap's own event task (web only; native platforms unchanged), so the keyboard pulls up on the first tap.

0.10.10 #

  • Fix: AccountDeleteRequested (and LogOutSuccess) never reaching PostHog. The PostHog native SDKs batch events (flush at 20 events / every 30s) and account deletion is a terminal flow — the queued event was waiting for a batch flush that never happened because the app was killed or uninstalled right after. AccountRepository.deleteAccount() and logout() now force an immediate flush of queued events before tearing down. Additionally, LogOutSuccess is now tracked before KittyAnalytics.reset() so it is attributed to the logging-out user instead of a freshly rotated anonymous distinct ID.
  • Added KittyAnalytics.flush() — flushes queued PostHog events immediately (no-op on web, where the JS SDK manages its own send cycle). Use it before any flow where the app may be killed before the next scheduled batch flush.

0.10.9 #

  • Fix (follow-up to 0.10.8): buy-now loader still spun forever on StoreKit 2 cancel with in_app_purchase_storekit 0.4.4–0.4.6. 0.10.8 only handled the case where SK2Product.purchase returns userCancelled/pending (0.4.7+). On 0.4.4 the native layer instead throws a PlatformException (storekit2_purchase_cancelled / storekit2_purchase_pending), which BuyNowHelper.buySubscription silently swallowed (its on PlatformException handler only covered storekit_duplicate_product_object), so the bloc never left PurchaseInProgressState. Now IOSSK2ExtendedProductDetails.buy() handles cancel/pending whether reported as a thrown PlatformException or a returned result, and buySubscription rethrows any other PlatformException instead of swallowing it. Fixes the loader for the whole ^0.4.0 range.

0.10.8 #

  • Fix: in-app buy-now loader spinning forever when the user cancels the native payment sheet (StoreKit 2). KittyInAppBuyNowPage kept its loading overlay up indefinitely if the user dismissed the StoreKit payment dialog. Under StoreKit 2 (the default in in_app_purchase_storekit >= 0.4) the idiomatic buyNonConsumable discards the purchase result and StoreKit emits nothing on purchaseStream for a user cancellation, so the bloc never left PurchaseInProgressState. The SK2 purchase path now reads the SK2ProductPurchaseResult directly and surfaces userCancelled / pending as a BuyNowPurchaseNotCompletedException, which the buy-now bloc handles by clearing the loader (and tracking BuySubscriptionCanceled / BuySubscriptionPending). StoreKit 2 stays enabled; StoreKit 1 and Android behaviour are unchanged (cancellation already arrives via the purchase stream there).

0.10.7 #

  • TokenBalance now exposes a per-license breakdown. GET /account/tokens/balance?projectId=... now returns an additional licenses array (one entry per license belonging to the authenticated user in the project, with licenseId, balance, subscriptionBalance and total). The top-level aggregate fields keep the same shape as before, so existing code continues to work.
  • For single-license responses (?licenseId=...) the same licenses array is returned with a single entry mirroring the top-level balance.
  • Added LicenseTokenBalance model and TokenBalance.licenses / TokenBalance.licenseBalance(licenseId) helpers (exported from kitty_sdk.dart).

0.10.6 #

  • Aggregated balance is now a single backend request. GET /account/tokens/balance accepts projectId (in addition to licenseId) and the server returns the sum of balance / subscriptionBalance / total across the user's licenses in that project. KittyTokens.getBalance() (without licenseId) makes one HTTP call instead of one per license — no more fan-out from the client.
  • Added TokensRepository.getAggregateBalanceForProject({required String projectId}) and the matching TokensApiClient method for SDK consumers that need the aggregate from a custom repository.
  • Aggregated TokenBalance.licenseId is now null (returned as such by the backend).

0.10.5 #

  • KittyTokens.getBalance() now aggregates across all of the user's licenses when called without licenseId. Pass licenseId: explicitly to get the balance for a single license.
  • TokenBalance extended: now exposes licenseId, subscriptionBalance and total (= balance + subscriptionBalance) returned by the backend. licenseId is null for aggregated balances.
  • TokensState.tokenCount now returns balance.total instead of balance.balance, so the built-in account-page UI shows the full spendable amount (top-up + subscription cycle tokens). If you relied on tokenCount to show only the top-up part, switch to state.balance?.balance.
  • Returns a zero TokenBalance (instead of throwing) when the authenticated user has no licenses.

0.10.4 #

  • Tokens module aligned with new backend contract (breaking): /account/tokens/balance and /account/tokens/operations now require a licenseId (UUID) query param instead of projectId. KittyTokens.getBalance() / getOperations() and TokensCubit.loadBalance() / loadOperations() now accept an optional licenseId: argument; when omitted the SDK picks the first usable license of the currently authenticated user.
  • Removed KittySdk.tokens.addTokens / removeTokens: those endpoints are no longer exposed to clients — they live under internal-tokens and require an internal API key or a per-project kap_ bearer token. Call them from your backend instead.
  • KittyTokens.initialize no longer takes a projectId (licenses already carry their own project association).

0.10.2 #

  • Logout cleanup: Account logout now resets PostHog and clears local auth state; KittySettingsConfig.onLogout lets host apps run custom settings-page logout handling.
  • Auto-identify control: Added enableAutoIdentify to KittySdk.initialize() so apps can disable startup fingerprint identify and prevent automatic PostHog aliasing.

0.10.0 #

  • Buy Now module migrated from mobile-renovio: full in-app and web buy-now flow with bloc state management, web purchase bridge and restore helpers.
  • Buy Now configuration: new KittyBuyNowConfig with productIds, webBuyNowUrl, pwaBuyNowUrl(Stage), domain, eulaUrl, privacyPolicyUrl, customerSupportEmail, isStaging, isAutoRestorePurchaseEnabled. Wire it through KittySdkConfig.buyNow and access globally via KittySdk.buyNow / KittyBuyNow.I.
  • Buy Now UI theming: added KittyBuyNowTheme for KittyInAppBuyNowPage and KittyWebBuyNowPage, split into logical blocks: page, navBar, mainBlock, subscription, buttons, legal, and webView. Replaces the previous InAppBuyNowTheme.
  • KittyBuyNowTheme and KittyBuyNowThemeProvider are exported from kitty_sdk.dart.

0.9.0 #

  • Account UI theming: KittyTheme now accepts a direct ThemeData override via KittyTheme(themeData: ...). The SDK merges it over the default SDK theme when provided.
  • Auth UI theming: Added KittyAuthTheme for KittyAuthFlow and KittyBindEmailFlow. It supports per-flow styling for background, AppBar, header widgets, titles, inputs, buttons, code input boxes, resend/support sections, spacings, and errors.
  • Settings UI theming: Added KittySettingsTheme for KittySettingsFlow, split into logical blocks: page, menuItem, buttons, destructive, subscription, tokens, dialog, and bindEmail.
  • KittyAuthUiConfig.icon is deprecated. Use KittyAuthTheme.loginHeaderWidget or KittyAuthTheme.codeHeaderWidget instead.
  • KittyAuthTheme and KittySettingsTheme are exported from kitty_sdk.dart.

0.8.0 #

  • Tokens module: New module for managing user token balances and operations.
  • KittyTokensConfig — configure isDebug to show/hide debug UI in settings.
  • KittySdk.tokens — static accessor for the Tokens client with getBalance(), addTokens(), removeTokens(), and getOperations(). (Note: addTokens/removeTokens were removed from the client in 0.10.3 — see above.)
  • Integrated into KittyAccountPage to automatically display the user's token balance (and debug controls if enabled) when the module is initialized.
  • Conditional initialization — Tokens module only starts when KittySdkConfig.tokens is provided and the user is authenticated.

0.6.0 #

  • KittyOtel module: New observability module for sending logs, traces, and metrics via OTEL to the Kitty Launch platform.
  • KittyOtelConfig — configure endpoint, token, batching, compression, and queue size.
  • KittySdk.otel — static accessor for the OTEL client with addLog(), addTrace(), addMetric(), and manual flush().
  • Automatic batching with configurable interval and batch size, gzip compression, and retry logic.
  • Conditional initialization — OTEL module only starts when KittySdkConfig.otel is provided.

0.5.5 #

  • Fingerprint auto-login: On SDK init, if Flare identifies a strong fingerprint match (IP_v4 / GEO_UA) with a loginCode in userData, the SDK automatically exchanges it for auth tokens — seamless web-to-mobile login.
  • onFingerprintAutoLogin callback: New optional parameter in KittySdk.initialize() — notifies the host app when fingerprint auto-login succeeds.
  • Safe userData casts: distinctId and loginCode from fingerprint userData now use ?.toString() instead of as String? to prevent runtime type errors.

0.5.4 #

  • KittySdkConfig: Added productName, privacyPolicyUrl, termsOfUseUrl, shareAppText, shareAppLink fields so all app-level config lives in one place.
  • KittySettingsFlow: Automatically resolves empty settings config fields from KittySdkConfig — no need to duplicate values between SDK init and settings config.

0.5.3 #

  • Fix: Bumped posthog_flutter minimum to ^5.15.0 — fixes PostHogFeatureFlagResult not found compile error when resolving to older 5.x versions.

0.5.2 #

  • Auto-identify on init: KittySdk.initialize() now automatically calls flare.identify() if no previous result is cached. On a match, aliases the web PostHog distinctId from the fingerprint with the current mobile session — linking web and mobile analytics.

0.5.1 #

  • PostHog per-project routing: SDK now sends x-ph-api-key and x-ph-host headers in every API request (both authenticated and unauthenticated). The backend uses these to route identify/alias calls to the correct PostHog project — no shared PostHog instance needed.
  • KittyAccountConfig.baseHeaders centralizes common headers (content-type, x-project-id, PostHog keys) to avoid duplication across API clients.

0.5.0 #

  • AccountInfo.primaryEmail: Backend now sends primaryEmail in /users/current response; SDK uses it for the email getter instead of emails[0]. Fixes email not updating after bind-email flow.
  • Bind-email UI: Title moved to AppBar for consistent design; embedded mode prevents duplicate Scaffold/AppBar.
  • Delete account: Now performs a client-side logout instead of calling the non-existent mark-for-deletion API.
  • Contact Support button: Upgraded to FilledButton.tonal for better visibility on the code page; fixed mailto: URI construction that was dropping the email domain.
  • Code page support section: Hidden on initial code entry, shown only after the user taps "Resend Code".
  • PostHog: Session replay and lifecycle events disabled by default for lightweight event-only tracking.

0.4.0 #

  • KittyTheme: New theming system with auto light/dark detection from platform brightness. All SDK forms (auth + settings) now render with a consistent minimalist design.
  • KittySdkConfig.theme accepts a KittyTheme(primaryColor: ...) to customize button, link, and accent colors across all SDK UI.
  • Redesigned code input boxes, settings menu items, and form layouts for a cleaner look.
  • Breaking: widgets now use SDK theme instead of inheriting host app theme. Override via KittySdkConfig.theme.

0.3.3 #

  • Updated auth form texts to match design: "Access Your Purchased Account" title, "Enter email..." hint, "Log In" button, "Check Your Email" code page, "RESEND CODE (XX sec)" timer.
  • Restructured code form support section with contact prompt, tappable support link, and outside hours message.
  • Added supportEmail to KittySdkConfig for global configuration — no longer needed per-form.
  • Resend timer default changed from 5 minutes to 30 seconds.

0.3.2 #

  • Fix: claimAppStoreSubscriptions now sends x-project-id header — licenses are correctly associated with the project instead of being created with project_id=null.

0.3.1 #

  • Removed sign-up mode from auth flow — login + 2FA code is a single unified flow with no login/signup distinction.
  • Removed isSignUp, toggleSignUp(), signUpTitle, dontHaveAccountText, signUpLinkText, alreadyHaveAccountText, logInLinkText, emailAlreadyInUseError, tryLoggingInText, emailTakenError, showSignUpToggle from public API.

0.3.0 #

  • Account UI — Auth flow: Configurable login and 2FA code forms (KittyAuthFlow, KittyLoginForm, KittyCodeForm) with KittyAuthUiConfig for customizing icon, support email, all text content, timer duration, and code length.
  • Account UI — Settings flow: Full settings module (KittySettingsFlow) with account management, subscription details, cancel/renew, delete/restore account, legal info, logout — all driven by KittySettingsConfig. No dependency on auto_route or external analytics/environment packages.
  • New dependencies: flutter_bloc, url_launcher, share_plus.

0.2.3 #

  • KittyAnalytics.initialize() now calls posthog.init() via JS interop on web, so PostHog API key is only configured in Dart — no need to hardcode it in index.html.

0.2.2 #

  • AccountRepository now auto-resolves sid from KittyAnalytics (PostHog distinctId) for verifyLoginCode and signupWithPassword.
  • Removed sid parameter from KittyAccount.verifyLoginCode() public API.
  • Removed canLoginWithPassword from AccountRepository and VaultApiClient.

0.2.1 #

  • Fix: add web platform support — guard Platform calls with kIsWeb to prevent dart:io crashes on web.
  • DeviceInfoCollector now returns browser metadata on web instead of throwing UnsupportedError.
  • FlarePurchaseObserver and AppStorePurchaseObserver gracefully no-op on web.

0.2.0 #

  • Analytics module: PostHog event tracking, user identification, feature flags, session replay.
  • KittySdkConfig.analytics parameter for configuring PostHog via unified initialization.

0.1.0 #

  • Initial release.
  • Flare module: device fingerprint identification and purchase attribution.
  • Account module: authentication, user management, licenses, subscriptions.
  • Unified KittySdk.initialize() entry point.
0
likes
80
points
332
downloads

Documentation

API reference

Publisher

verified publisherkitty-dev.org

Weekly Downloads

Kitty Flutter SDK — unified package for device fingerprint attribution (Flare) and authentication, user management, licenses & subscriptions (Account) against the Kitty Launch platform APIs.

Repository (GitHub)

License

unknown (license)

Dependencies

connectivity_plus, darq, device_info_plus, flutter, flutter_bloc, flutter_inappwebview, http, in_app_purchase, in_app_purchase_android, in_app_purchase_platform_interface, in_app_purchase_storekit, meta, package_info_plus, posthog_flutter, share_plus, shared_preferences, sign_in_with_apple, url_launcher, uuid, web

More

Packages that depend on kitty_sdk