PackageTrack
Sign in Get early access

koolbase_flutter

Flutter SDK for Koolbase — feature flags, remote config, version enforcement, authentication, storage, database, realtime, OTA updates, and code push for mobile apps.

11.2.1 2.5K downloads/mo #4965 most downloaded on pub.dev kennedyowusu/koolbase_flutter

What this package is like to depend on

Last release 4 days ago

19 Aug 2026

Ships fairly regularly

a new release about every 1 weeks

Most releases are documented

notes for 56 of 76 stable releases

Nothing withdrawn

no release was ever pulled

5 months old

76 releases · first in 2026

76 releases in the last 12 months

see the full history below

Release timeline

76 releases · Mar 2026 to Aug 2026
Release Pre-release

Releases

latest 60 of 76
  1. 11.2.1 19 Aug 2026
    Release notes
    • Analytics events now carry the signed-in user automatically. identify() existed, but nothing errored when an app never called it — so every event landed anonymous, and retention, funnels and any per-user analysis were quietly worthless. Found by looking at a real project: 53 events, 8 registered users, zero events carrying a user id. The SDK already knows who is signed in; it should say so.
    • identify() still wins where an app has its own identity system, and the existing reset() releases that override — without it, events keep carrying the previous user after they sign out.
    Open source →
  2. 11.2.0 19 Aug 2026
    Release notes
    • Koolbase.fiscal — authority-grade sales recording. submit() records a transaction and drives fiscalization; status() follows it and returns the certification the tax authority granted (in Ghana: the GRA signature, receipt number and verification QR a compliant receipt must carry). Live for Ghana's GRA E-VAT; the reference adapter runs the same machine — gapless numbering, sealed immutable documents, full evidence — anywhere an authority integration doesn't exist yet.
    • The clientRef you pass is idempotent: resubmitting the same reference always returns the same intent, never a second fiscal number. A timed-out submit may still have fiscalized, so retrying or polling both converge on the truth — the exception message says so rather than leaving you guessing.
    • Fiscal deliberately does NOT use the offline write queue. A register needs a real answer or an explicit "not yet"; silently queueing a fiscalization would let a cashier believe a receipt is legal when the authority has never seen it. Offline-capable point of sale should record the commercial sale locally and submit fiscally on reconnect — the idempotent clientRef makes that replay a single call.
    • FiscalIntentResult exposes status, numbers, blockedReason, certification, isFiscalized and isPending. A blocked result means nothing was consumed — no fiscal number was spent — so fixing the cause and resubmitting the same reference resumes that exact transaction. A fiscalized result with a null certification is valid for document kinds the authority acknowledges without certifying (purchase records); it is never an error.
    Open source →
  3. 11.1.1 16 Aug 2026
    Release notes

    fix: offline writes refuse signed-out — never enqueue under a null owner

    A ticket parked on-device while the SDK session was dead was enqueued
    with userId null. Every per-user surface then did its job correctly —
    pendingWrites() throws signed-out, reads and replay filter by owner — so
    the null-owner row matched nothing, forever: physically present,
    invisible, unreplayable. The write neither failed nor succeeded; it
    vanished into a bucket nobody owns.

    All three offline enqueue sites (insert fallback, queued update, queued
    delete) now throw KoolbaseUnauthenticatedException signed-out. Signed-in
    behavior byte-for-byte unchanged. Mutation-pinned: removing the insert
    guard fails 'writes to NO bucket'. Mirrors the RN SDK's Aug 4 fix of the
    same bug family. v11.1.1

    Open source →
    Release notes
    • Offline writes now refuse with KoolbaseUnauthenticatedException when no user is signed in, instead of enqueueing under a null owner. A null-owner queue row is invisible to every per-user read and replay — the write neither fails nor succeeds; it vanishes. Found on device as a parked ticket that never reached the server. Signed-in offline behavior is unchanged. Mirrors the React Native SDK's fix of the same bug.
    Open source →
  4. 11.1.0 16 Aug 2026
    Release notes

    feat: get(fresh: true) — cache-skipping network read

    SWR cannot express read-after-write: a cached answer is the state before
    your write, and awaiting the background-refresh stream proved racy
    on-device (a local projection tracked the server exactly one sale
    behind). get(fresh: true) skips the cache and returns the network's
    answer; the read still updates the cache, so SWR callers benefit.
    Plain get() unchanged. Fake queries in tests updated to the new
    signature. v11.1.0

    Open source →
    Release notes
    • KoolbaseQuery.get() gains fresh: true — skips the cache and returns the network's answer directly. Required for read-after-write (verifying the effect of a write you just made), reconciliation, and local projections that must only ingest server-provenance data. A fresh read still updates the cache, so SWR callers benefit from it. Plain get() behavior is unchanged.
    Open source →
  5. 11.0.0 14 Aug 2026
    Release notes

    feat(auth)!: SignUpResult + ContactNotVerifiedException (11.0.0)

    BREAKING: signUp returns SignUpResult, not KoolbaseUser.

    The server can now withhold a session at registration when a project requires
    a verified contact channel. The old return type could not express 'account
    created, not signed in' — the session-less 201 reached AuthSession.fromJson
    and threw 'type Null is not a subtype of type String' on the absent
    access_token. Observed on device before this fix.

    SignUpResult carries the user in both cases and a verificationRequired flag,
    so consumers must branch. Deliberately not a nullable user or nullable
    session on the public surface: that would push the same null-check onto every
    caller and reproduce the crash one layer up.

    The session is persisted only when one was issued. Calling _setSession with
    null would leave the SDK half-authenticated — reporting a signed-in user with
    no token.

    signUp no longer routes through _parseSession. That parser assumes tokens
    exist, which is correct for login and refresh and wrong for registration
    under this policy; loosening it would have weakened login's contract for no
    reason.

    ContactNotVerifiedException maps the server's contact_not_verified code on
    login. Credentials were correct and the policy refused, so it is distinct
    from InvalidCredentialsException — apps route to resend-verification rather
    than telling the user to re-check a password that was right.

    Added only to _checkError, not to the Apple/Google parsers: OAuth satisfies
    the requirement by definition (a provider attestation IS a verified contact),
    so the server never emits this code on those paths.

    Enforcement is off for every project that existed before the server-side
    release, so verificationRequired is false and behaviour is unchanged unless a
    customer opts in.

    Open source →
  6. 10.5.0 11 Aug 2026
    Release notes

    feat: KoolbaseCollectionGrid (10.5.0)

    The same collection laid out as a grid. Deliberately thin: it shares
    KoolbaseCollectionController with KoolbaseCollectionList, so
    stale-while-revalidate, pull-to-refresh and the loading/empty/error
    slots behave identically — the two differ only in layout, and sharing
    the controller is what keeps them from drifting on the hard parts.

    Fixed crossAxisCount rather than responsive reflow: a caller who needs
    reflow can vary it from a LayoutBuilder, and building it in would have
    meant guessing at tile sizing for everyone else.

    Tests are narrow on purpose — the controller's properties are already
    covered by the list's tests, so re-testing them here would test the
    same code twice. The query fake moves to test/support so two copies
    can't drift.

    README's 'for grids, drive the controller directly' is no longer true
    and now documents the widget instead.

    Open source →
  7. 10.4.0 07 Aug 2026
    Release notes

    10.4.0: streams fetch on listen, and writes refresh them

    Two gaps that both surfaced as "the UI just does not update" — nothing
    errored, nothing logged, the data was simply absent. Both were found by
    building an app against the SDK rather than by reading it.

    .stream was a bare relay off a broadcast controller: get() performed the
    fetch and pushed refreshes into it, so a stream-only listener waited
    forever on a collection nothing else had read. It now fetches on first
    listen, cache-first exactly as get() is.

    Every write invalidated the collection cache and stopped, which only
    affects the NEXT query. A listener already watching sat unchanged until
    something happened to re-fetch — a message sent into a chat thread did
    not appear in that thread. insert, upsert, deleteWhere, batch, and
    conflict resolution now refresh open queries on the collection.

    Each query re-runs ITSELF, so a stream only receives records matching its
    own filters. The refresh is a registered closure per stream rather than
    one rebuilt from the stream key: a key carries collection, filters, and
    user but not ordering, limit, or populated fields, so a reconstructed
    query would push the wrong records into a stream that never asked.

    Mutation-verified: dropping the collection filter refreshes every query
    in the process, failing three tests.

    README gains a Live queries section — .stream was undocumented — and its
    where() example is corrected to the real named-argument signature.

    Open source →
  8. 10.3.0 05 Aug 2026
    Release notes

    KoolbaseAuthGate, KoolbaseAuthScope, KoolbaseCollectionList, and
    KoolbaseCollectionController ship as the first behavioral widgets: the
    SDK now encodes auth branching and the stale-while-revalidate list
    contract as composable components rather than patterns every app
    hand-writes. Query refresh streams are now keyed by query identity
    rather than collection name, matching their documented contract — see
    the changelog behavior note. README gains a Widgets section and catches
    up two versions of version-string drift (was still ^10.1.2).

    Open source →
  9. 10.2.0 04 Aug 2026
    Release notes

    database: insert-conflicts are real, and resolvable (10.2.0)

    The Flutter twin of RN 94d8a21, closing the cross-SDK batch. Unique
    constraints made insert-conflicts a genuine third kind: a queued insert
    refused as a duplicate is held like any terminal refusal — but the client
    coerced its operation to update (ConflictOperation admitted only two members),
    and resolving one issued a PATCH against a record id that exists nowhere.
    Storage never lied; only the mapper did.

    ConflictOperation gains insert. Resolving a rejected insert IS the insert,
    retried: resolveWithMerge carries amended data (the fix-the-colliding-title
    path), unconditional — no record, no revision to be conditional against — with
    the conflict's id as the idempotency key, so a resolution whose response is
    lost returns the original on retry rather than duplicating. Wire-proven on the
    exact route. resolveWithServer means the colliding row stands: clears with
    zero requests, asserted by request count.

    Seeded through the production path (enqueue → moveToRejected). Mutation-
    verified: deleting the insert branch resurfaces the pre-fix wrong-verb PATCH,
    caught by name by a scripted client that refuses unknown routes loudly.

    README documents the insert-conflict resolution semantics in the same change.

    Open source →
  10. 10.1.2 03 Aug 2026
    Release notes

    database: a refused resolution teaches the stored conflict (10.1.2)

    The Flutter twin of RN fb4480d, live in a published SDK until now. Resolution
    was conditional on the revision the ORIGINAL refusal reported; when the record
    moved again mid-decision, the 409 — carrying current_revision and the record —
    was correctly refused and entirely discarded by _resolveWrite. Every retry
    replayed the stale condition; abandon was the only exit. Device-proven on RN
    (three identical refusals against an unchanged server).

    Flutter's factory already parsed the 409 fully into
    KoolbaseRevisionMismatchException — the information died one method later. The
    fix is one catch: refreshConflict absorbs currentRevision and currentRecord
    into the Drift row (honoring serverState's own documented contract — 'as
    returned with the refusal, so resolving does not need a fetch' — which the
    CREATING refusal honored and the resolution refusal violated), then rethrows
    with review-and-retry.

    Proven by the revision sequence [8, 9]: the second attempt is conditional
    against the LEARNED revision and succeeds without the server moving again.
    Seeded through the production path (enqueue → moveToConflict). Mutation-
    verified: removing the refreshConflict call fails the storage assertion.

    The resolution HTTP path gained an injectable client (httpClient param) —
    an unmockable resolution path is why no test ever caught this.

    Open source →
  11. 10.1.1 02 Aug 2026

    Nothing published for this version

  12. 10.1.0 02 Aug 2026

    Nothing published for this version

  13. 10.0.0 01 Aug 2026

    Nothing published for this version

  14. 9.9.0 01 Aug 2026

    Nothing published for this version

  15. 9.8.0 01 Aug 2026

    Nothing published for this version

  16. 9.7.0 29 Jul 2026

    Nothing published for this version

  17. 9.6.0 26 Jul 2026

    Nothing published for this version

  18. 9.5.0 25 Jul 2026
    Release notes

    Breaking: Koolbase.messaging.send() removed. Sending push notifications is server-initiated only — it requires a secret kb_live_ key and must run on your backend or in a Koolbase Function, never in the app. The publishable key the SDK holds ships inside your app binary; allowing it to send would let anyone who extracts it push to your users. The API already rejects publishable-key sends with 401. Device registration (Koolbase.messaging.registerToken) is unchanged. See docs: /sdk/messaging.

    Fixed: in-app functions.deploy() now uses the auto-refreshing session token. It previously read a manually-set static token that expired after 15 minutes while invoke() (which already auto-refreshed) kept working — so a long-lived app could see deploys fail while invocations succeeded. deploy() now shares invoke()'s token path. The removed setAuthToken() method is no longer needed; the SDK manages the session token itself.

    Open source →
  19. 9.4.1 22 Jul 2026
    Release notes

    Fix: package failed to compile on stock Flutter (all platforms). 9.4.0 unconditionally imported dart:_internal (VM code-push bindings that resolve only against the Koolbase-patched engine). The stock Dart frontend rejects platform-private imports at kernel compile, so every build failed with "Can't access platform private library" — analyzer-clean, caught only at build time. The bindings are now a stock-safe stub: on a stock engine, code push reports "engine not present" through existing failure paths (koolbaseBuildId() returns '', applyKoolbasePatch returns sentinel -990). No API changes; upgrading from 9.4.0 requires no code changes.

    Open source →
  20. 9.4.0 12 Jul 2026
    Release notes
    • Code Push (VM-level, iOS): flash-free boot apply. Koolbase.initialize now completes the iOS boot-time patch apply (local disk only, ~5ms measured on device) before returning, so the app's first frame already runs the patched code — the brief v1→v2 flash on cold launch is gone, with zero configuration. The network check/download remains fully asynchronous and can never block startup.
    • Code Push (VM-level): device outcome events. The client reports patch_downloaded (on successful stage), patch_activated (on the boot that promotes a new patch, with patch_number), and patch_failed (on rejection, with the rejection code and whether the artifact was newly staged or the durable copy) to /v1/code-push/patch-events. Dashboards and rollout decisions can now count real device activations instead of inferring installs from patch-check serves. Fire-and-forget: event reporting never delays boot and failures are silent.
    • Code Push (VM-level, iOS): correct patch bookkeeping after rejections. The boot apply now records what actually happened (new patch applied / durable re-applied / clean base boot) and reconciliation consumes that record. Previously, a rejected download that fell back to the existing patch could mark the rejected patch as current — the device then reported a patch it wasn't running, suppressing future update offers. A clean base boot (e.g. after an app-store update invalidates a persisted patch) now also resets the reported patch to 0.
    • Code Push (VM-level, iOS): rejected patches are quarantined, not retried. A persisted patch that fails verification (for example, stale after an app update) is moved aside on first rejection instead of being re-read and re-rejected on every subsequent launch. Quarantined artifacts are removed once a healthy boot completes.
    Open source →
  21. 9.3.1 09 Jul 2026

    Nothing published for this version

  22. 9.3.0 26 Jun 2026
    Release notes
    • Code Push (VM-level): the client now reports flutter_version on patch-check so the resolver can refuse a patch built on a different Flutter engine version.
      • Reads the CLI-stamped assets/koolbase_flutter_version asset (written by koolbase build / koolbase release) and sends it alongside build_id / release_version.
      • Pairs with the server-side resolver guard that constrains matching on flutter_version, closing two cross-engine mis-serve cases (colliding build_id across engine versions; release_version matching on app version alone).
      • Fully backward-compatible: an app built without the asset sends no flutter_version and the server falls back to legacy matching — no change for apps already in the field.
    Open source →
  23. 9.2.1 21 Jun 2026
    Release notes
    • Widen package_info_plus to >=8.0.0 <10.0.0 and flutter_secure_storage to >=9.0.0 <11.0.0. The SDK only uses the stable surface of both (PackageInfo version/buildNumber; SecureStorage read/write/delete with default AndroidOptions and standard KeychainAccessibility), so the previous latest-major pins needlessly blocked — and for secure_storage risked force-migrating — host apps on the prior major.
    Open source →
  24. 9.2.0 20 Jun 2026
    Release notes
    • Code Push (bundle): recall/rollback now actually reverts a recalled bundle on device.
      • The runtime resolver persists a pending-revert marker when the server issues a rollback and consumes it at the start of the next cold launch, before re-applying any stored bundle. Previously the rollback was logged but never persisted, so a recalled bundle kept re-applying on every launch.
      • Pairs with the server-side resolver fix returning rollback/revert_to:0 when a device runs a bundle that has been recalled with no published replacement.
      • Affects iOS and Android bundle recall.
    Open source →
  25. 9.1.0 20 Jun 2026
    Release notes
    • Code Push (VM-level): KoolbaseVmPatchClient — over-the-air Dart code updates for Android.
      • Self-contained: no MainActivity or platform-channel wiring required.
      • Checks in with the Koolbase resolver, downloads and stages patches; the Koolbase engine applies them on next launch with signature + build_id verification and automatic crash-revert.
      • Per-ABI build_id resolution for multi-ABI app bundles (arm64-v8a / armeabi-v7a).
      • Reports the running build's build_id and current patch number on check-in.
    Open source →
  26. 9.0.0 08 Jun 2026
    Release notes

    Breaking changes

    • None. mode and minSimilarity are both optional; existing searchSemantic callers continue to work unchanged. Major bump reflects the conceptual expansion of the search contract (three retrieval modes instead of one), not API-breaking removals.
    Open source →
  27. 8.0.0 07 Jun 2026

    Nothing published for this version

  28. 7.0.0 06 Jun 2026

    Nothing published for this version

  29. 6.5.0 05 Jun 2026
    Release notes

    Object versioning support — full read + write surface against versioned buckets. None of this changes existing behavior on non-versioned buckets.

    New

    • KoolbaseObjectVersion model — one entry in a path's version timeline. Carries versionId, size, metadata, isDeleteMarker, isCurrent, createdAt and the rest of the version-row shape.
    • KoolbaseStorageClient.listVersions({bucket, path}) — returns the full timeline newest-first, current + history mixed.
    • KoolbaseStorageClient.getVersion({bucket, path, versionId}) — metadata for one specific version.
    • KoolbaseStorageClient.restoreVersion({bucket, path, versionId}) — brings a history version back to current; the previously-current row is snapshotted to history first, so the restore is itself a versioned event.
    • KoolbaseStorageClient.purgeVersion({bucket, path, versionId}) — hard removes a single history version (row + R2 bytes).

    Extended

    • KoolbaseStorageClient.getDownloadUrl(...) accepts an optional versionId — when present, the returned URL points to that specific version's bytes from .versions/.
    • KoolbaseStorageClient.delete(...) accepts an optional forcePurgetrue wipes the entire timeline for the path (all history rows, all .versions/ R2 keys, canonical, and the current row).
    Open source →
  30. 6.4.0 05 Jun 2026
    Release notes
    • feat(storage): edge image transforms (Gap #8).
      • New KoolbaseImageTransform value class — width, height, format, quality, fit, dpr, gravity. Pair with the new KoolbaseImageFormat, KoolbaseImageFit, and KoolbaseImageGravity enums for type-safe option construction. Out-of-range numeric values clamp silently to Cloudflare's valid ranges (width/height 1–2000, quality 1–100, dpr 1–3).
      • KoolbaseStorageClient.publicUrl({transform}) and KoolbaseObject.publicUrl(bucket, {transform}) accept an optional transform; the resulting URL hits Cloudflare's image pipeline at cdn.koolbase.com/cdn-cgi/image/<opts>/... and serves a resized, re-encoded copy of the source. Original URL behavior unchanged when transform is omitted.
      • KoolbaseStorageClient.publicUrlWithPreset({projectId, presetName, bucket, path}) and KoolbaseObject.publicUrlWithPreset(bucket, presetName) resolve a named preset stored server-side (managed via the dashboard or REST API) at cdn.koolbase.com/p/{project_id}/ {preset_name}/{bucket}/{path}. Edit the preset once on the server and every URL using it updates as the edge cache rolls over.
    • Cloudflare bills unique transformations per calendar month; every Koolbase account includes 5,000 free. Transformed responses are edge-cached for 4 hours.
    • No breaking changes. All new APIs are additive; existing publicUrl calls without transform produce the exact same URL they did in 6.3.0.
    Open source →
  31. 6.3.0 02 Jun 2026
    Release notes
    • feat(storage): public bucket CDN URLs (Gap #2 SDK polish).
      • KoolbaseObject gains an r2Bucket: String field identifying which physical R2 bucket holds the object's bytes. Always populated. 'koolbase-storage-public' means the object has a stable CDN URL; anything else (typically 'koolbase-storage') means it's in private storage and reads go through a presigned URL via getDownloadUrl.
      • KoolbaseObject.publicUrl(String bucketName) returns the stable https://cdn.koolbase.com/... URL for the object when it lives in the public R2 bucket, null otherwise. Use this when you have an object instance and want a safe URL — returns null rather than a URL that 404s for private or legacy public-bucket files.
      • KoolbaseStorageClient.publicUrl({projectId, bucket, path}) — static helper that builds the CDN URL pattern unconditionally. Use for build-time URL generation where you have the inputs but don't need (or want) a check that the file is actually in a public bucket.
    • No breaking changes. getDownloadUrl already returns the CDN URL for objects in public buckets since the server-side Gap #2 deploy on Jun 2 2026 — this release just makes that URL constructible without a network round-trip.
    Open source →
  32. 6.2.0 02 Jun 2026
    Release notes
    • feat(storage): custom object metadata. Attach arbitrary key/value pairs to stored objects at upload time, mutate via merge semantics post-upload, read alongside any KoolbaseObject.
      • KoolbaseStorageClient.upload() gains an optional metadata: Map<String, String> named param. Set at confirm time; REPLACES prior metadata on the overwrite: true path (matches GCS semantics — a new upload at a path produces a new object, not a patch of the old).
      • New KoolbaseStorageClient.updateMetadata() method with merge semantics: keys with a non-null value are set/updated, keys with null are deleted, keys absent from the payload are untouched. One call handles add, update, and delete atomically.
      • KoolbaseObject gains a metadata: Map<String, String> field. Always non-null — {} when empty, never null — so callers can treat it as a guaranteed map without nil checks.
      • New KoolbaseStorageMetadataInvalidException (extends KoolbaseStorageException) thrown for server-side validation failures. Its detail field names the failing key and rule (e.g. key "bad key": must match [a-z0-9_]+, exceeds 50 keys (got 53)) so callers can surface actionable errors without guessing what shape rule was violated.
    • Validation rules (server-side, recreated for SDK doc convenience): ≤50 keys, ≤8KB total, keys 1–64 chars [a-z0-9_]+, values ≤1024 chars, leading underscore reserved for system keys.
    Open source →
  33. 6.1.1 01 Jun 2026
    Release notes

    Fixed

    • Storage error mapper switches on lowercase wire codes (path_conflict, quota_exceeded, file_too_large, mime_not_allowed) after the server normalized storage codes to lowercase snake_case. Without this patch, v6.1.0 customers see generic KoolbaseStorageException instead of the typed subclass for storage limit errors. No semantic changes beyond the case match.
    Open source →
  34. 6.1.0 01 Jun 2026
    Release notes
    • feat(storage): three new typed exceptions for bucket-limit failures introduced server-side in Storage #2. All extend KoolbaseStorageException so existing catch-all blocks continue to work; catch the specifics to branch on the kind of limit hit.
      • KoolbaseStorageQuotaExceededException — 409 + QUOTA_EXCEEDED, thrown when an upload would push the bucket past its max_size_bytes cap.
      • KoolbaseStorageFileTooLargeException — 413 + FILE_TOO_LARGE, thrown when a single file exceeds the bucket's max_file_size_bytes cap.
      • KoolbaseStorageMimeTypeException — 415 + MIME_NOT_ALLOWED, thrown when an upload's content-type isn't in the bucket's allowed_mime_types allowlist (supports type/* wildcards).
    • Mapper (koolbaseStorageError / koolbaseStorageErrorFromResponse) recognizes the new codes and the new HTTP statuses (413, 415).
    • Backwards-compatible: existing callers using on KoolbaseStorageException keep working; the new types let callers surface clearer messages or prompt the user to delete files / pick a smaller file / pick a different file type.
    Open source →
  35. 6.0.0 01 Jun 2026
    Release notes

    Breaking — realtime

    • Koolbase.realtime.on / onRecordCreated / onRecordUpdated / onRecordDeleted no longer take a projectId — the project is derived from your session token, matching the React Native SDK. Migrate on(projectId: ..., collection: 'x') to on(collection: 'x').

    Breaking — storage

    • KoolbaseStorageClient.upload() is now safe-by-default. Uploads to a path where an object already exists are rejected with a new KoolbaseStorageConflictException instead of silently overwriting the existing object. Pass overwrite: true to opt into the previous replacing behavior.
    • Storage operations now throw typed KoolbaseStorageException subtypes instead of generic Exception — catching Exception still works but catching the specific subtypes (or the KoolbaseStorageException base) gives you cleaner branching.

    Added

    • KoolbaseStorageException — base class for all storage failures, mirroring the KoolbaseDataException pattern from the database layer.
    • KoolbaseStorageConflictException (code: PATH_CONFLICT) — thrown when an upload would replace an existing object and overwrite: false. Exposes the colliding path from the server response.
    • KoolbaseStorageNotFoundException, KoolbaseStorageValidationException, KoolbaseStoragePermissionException — typed exceptions for the other storage error classes (404, 400, 403). Storage operations now throw these instead of a generic Exception.
    • koolbaseStorageError(statusCode, body) and koolbaseStorageErrorFromResponse(res) — code-first response-to-exception mappers, matching the database layer's pattern.

    Migration — storage uploads

    If your app uploads to deterministic paths (e.g. avatars/{user_id}.png) and relied on the upload silently replacing the previous file:

    // Before — silent overwrite
    await Koolbase.storage.upload(
      bucket: 'avatars',
      path: 'me.png',
      file: file,
    );
    
    // After — explicit overwrite
    await Koolbase.storage.upload(
      bucket: 'avatars',
      path: 'me.png',
      file: file,
      overwrite: true,
    );
    

    If you want a conflict prompt (recommended for user-supplied filenames):

    try {
      await Koolbase.storage.upload(
        bucket: 'documents',
        path: filename,
        file: file,
      );
    } on KoolbaseStorageConflictException catch (e) {
      final ok = await showConfirm('${e.path} already exists. Overwrite?');
      if (ok) {
        await Koolbase.storage.upload(
          bucket: 'documents',
          path: filename,
          file: file,
          overwrite: true,
        );
      }
    }
    

    If you catch generic exceptions from storage operations, consider catching KoolbaseStorageException (or specific subtypes) for cleaner error handling:

    try {
      await Koolbase.storage.upload(...);
    } on KoolbaseStorageConflictException {
      // Path already exists — prompt user
    } on KoolbaseStorageNotFoundException {
      // Bucket missing or deleted
    } on KoolbaseStoragePermissionException {
      // Caller not authorized
    } on KoolbaseStorageException catch (e) {
      // Any other storage error
      showError(e.message);
    }
    

    Server requirements

    • Requires a Koolbase server build with PATH_CONFLICT 409 support (shipped alongside this release).

    5.1.0

    Fixed

    • Realtime now connects. The client was protocol-correct but was never handed an access token (the push-based setToken was never wired), so it never connected. Switched to the same token-provider model as the other clients; it now authenticates with the user session and streams created/updated/deleted events.

    Removed

    • KoolbaseRealtimeClient.setToken — dead push-model plumbing that was never wired. The token now flows from the SDK automatically.

    5.0.0

    BREAKING — security

    • Data-plane requests (database, storage, functions, offline sync) authenticate with the signed-in user's access token (Authorization: Bearer) instead of the x-user-id header. The header is no longer sent or trusted. Requires the matching Koolbase server build.
    • KoolbaseStorageClient.upload() no longer accepts a userId parameter — identity comes from the active session automatically.
    • End-user identity now flows automatically from Koolbase.auth; manual Koolbase.db.setUserId(...) is no longer needed for auth (it remains only for tagging offline-cached records).

    Added

    • KoolbaseAuthClient.validAccessToken() — returns a currently-valid token, refreshing (single-flight) near expiry; data-plane clients pull from it per request so identity follows the live session.
    Open source →
  36. 5.1.0 28 May 2026

    Nothing published for this version

  37. 5.0.0 26 May 2026

    Nothing published for this version

  38. 4.1.0 25 May 2026
    Release notes
    • Code Push — mandatory bundles. The SDK now honors a bundle's mandatory flag (set from the dashboard or via PATCH /mandatory). When a mandatory bundle is staged for the next launch:
      • Koolbase.codePush.hasMandatoryUpdate returns true — poll it on resume to gate your UI.
      • The optional onMandatoryUpdate callback on KoolbaseConfig fires immediately with MandatoryUpdateInfo(version, bundleId), so you can prompt the user to restart and apply the required update.
    • No breaking changes.
    Open source →
  39. 4.0.0 25 May 2026
    Release notes

    Breaking

    • Removed the Koolbase.ota client (KoolbaseOtaClient) and its models (OtaCheckResult, OtaProgress, OtaDownloadState). Use Koolbase.codePush for config/flag/directive overrides, or Koolbase Storage for shipping and reading raw files. This consolidates onto a single bundle client — matching the React Native SDK and the server, which already use code push exclusively.
    • Dropped the sign_in_with_apple dependency — it was only used by the removed KoolbaseAppleAuth. The current signInWithApple({identityToken}) is library-agnostic, so the SDK no longer pulls it. If your app uses Apple Sign-In, declare sign_in_with_apple in your own pubspec.yaml.

    3.3.0

    • Auth exceptions are now selected from the server's stable error code (with status/message fallback for older servers), retiring brittle message string-matching.
    • New typed data-layer exceptions — KoolbaseNotFoundException, KoolbaseValidationException, KoolbasePermissionException, KoolbaseRateLimitException — plus a shared KoolbaseDataException base. Database operations now throw these (code-first) instead of a generic Exception.
    • KoolbaseConflictException now exposes the collided field when the server reports it.
    • Fix: insert no longer queues a server-rejected write (e.g. a unique conflict) as an offline write — 4xx rejections surface immediately; only genuine network failures are queued.
    Open source →
  40. 3.3.0 24 May 2026

    Nothing published for this version

  41. 3.2.0 24 May 2026
    Release notes
    • Added KoolbaseConflictException, thrown by insert, update, and upsert when a write violates a collection's unique constraint (HTTP 409). Catch it to handle duplicates.
    Open source →
  42. 3.1.1 23 May 2026
    Release notes
    • Docs: document upsert and deleteWhere in the README (no code changes).
    Open source →
  43. 3.1.0 23 May 2026
    Release notes
    • Added Koolbase.db.upsert(collection:, match:, data:) — insert-or-update by a match filter; returns KoolbaseUpsertResult { record, created }. Online-only.
    • Added Koolbase.db.deleteWhere(collection:, filters:) — bulk delete by filter; returns the number of records deleted. Online-only.
    Open source →
  44. 3.0.0 22 May 2026
    Release notes

    Breaking

    • Flat record shape. KoolbaseRecord no longer wraps your fields under a data envelope. Your fields are now top-level, with system metadata in a reserved $-prefixed namespace: $id, $createdAt, $updatedAt, $collection, and $createdBy (when set).
    • Removed KoolbaseRecord.projectId and KoolbaseRecord.collectionId — internal identifiers are no longer exposed on records.
    • Requires a Koolbase server on the flat record contract (shipped alongside this release). Older servers return the legacy envelope and will not parse.

    Added

    • record['field'] — direct field access, shorthand for record.data['field'].
    • record.collection — the record's collection name.

    Changed

    • Populated/related records (via populate()) and realtime payloads now use the same flat $-shape as direct reads.
    • Offline cache (Drift) bumped to schema v2: stale read caches are cleared on upgrade so they refetch in the new shape; pending offline writes are preserved.

    Migration

    • Remove any record.projectId / record.collectionId usage — those fields are gone.
    • record.data['field'] still works; record['field'] is the new shorthand.
    Open source →
  45. 2.11.0 19 May 2026
    Release notes

    Added

    • Sign in with Google — production-ready end-user OAuth via Koolbase.auth.signInWithGoogle(idToken: ..., nonce: ...). Routes to the server endpoint at /v1/sdk/auth/oauth/google with RS256-only JWKS verification against Google's certs endpoint, multi-audience support (iOS / Android / web client IDs configured per environment), 15-minute replay defense, and optional nonce check.
    • Three new typed exceptions in auth_exceptions.dart: GoogleSignInNotConfiguredException, InvalidGoogleTokenException, GoogleEmailRequiredException. Reuses existing OAuthEmailConflictException and UserDisabledException.

    Example with the google_sign_in package

    import 'package:google_sign_in/google_sign_in.dart';
    
    final googleUser = await GoogleSignIn().signIn();
    final googleAuth = await googleUser?.authentication;
    
    final user = await Koolbase.auth.signInWithGoogle(
      idToken: googleAuth!.idToken!,
    );
    

    Auto-link policy

    Same as Apple Sign-In (v2.10.0). A new Google identity attaches to an existing user only when BOTH the Google email AND the existing user's email are verified, AND emails match (case-insensitive). Otherwise sign-in either creates a new user (no email collision) or surfaces OAuthEmailConflictException.

    Configuration required

    Before users can sign in with Google, configure the provider for your environment. Run this against your Koolbase project's project_oauth_configs (dashboard UI for OAuth config lands in a later release):

    UPDATE project_oauth_configs
       SET google_client_ids = ARRAY[
             '<your-ios-client-id>.apps.googleusercontent.com',
             '<your-android-client-id>.apps.googleusercontent.com',
             '<your-web-client-id>.apps.googleusercontent.com'
           ],
           enabled = true
     WHERE environment_id = '<your-env-id>'
       AND provider = 'google';
    

    Get the client IDs from Google Cloud Console under Credentials → OAuth 2.0 Client IDs. You'll need one per platform (iOS, Android, web).

    Coming next

    • React Native SDK v1.11.0 — same surface
    • Dashboard UI for OAuth config — replaces the SQL workflow

    Documentation

    • README rewritten to accurately reflect the v2.10.0 SDK surface. No SDK code changes; this release exists to refresh the README rendered on the pub.dev package page.
    • Removed fictional Koolbase.auth.signInWithGoogle reference. Google Sign-In is planned for v2.11.0 — noted explicitly in the OAuth section.
    • Replaced the deprecated KoolbaseAppleAuth.signIn() example with the new Koolbase.auth.signInWithApple(identityToken: ..., nonce: ..., fullName: ...) v2.10.0 API using the sign_in_with_apple package.
    • Added Koolbase.auth.authStateChanges.listen() example.
    • Replaced the Firebase/Supabase comparison table with a Koolbase-only feature inventory.
    • Bumped install snippet from ^2.8.0 to ^2.10.0.

    2.10.0

    Open source →
  46. 2.10.1 19 May 2026

    Nothing published for this version

  47. 2.10.0 19 May 2026

    Nothing published for this version

  48. 2.9.1 18 May 2026

    Nothing published for this version

  49. 2.9.0 18 May 2026

    Nothing published for this version

  50. 2.8.0 12 May 2026

    Nothing published for this version

  51. 2.7.0 09 May 2026
    Release notes

    Phone + OTP authentication

    Sign users in with their phone number — for emerging markets and apps where email isn't the primary identifier.

    New methods on Koolbase.auth:

    • sendOtp({required String phoneNumber}) — sends a 6-digit OTP to an E.164 phone number, returns the expiry timestamp.
    • verifyOtp({required String phoneNumber, required String code}) — verifies the code and signs the user in (creates the account if new). Returns PhoneVerifyResult with an isNewUser flag for routing first-time users to onboarding.
    • linkPhone({required String phoneNumber, required String code}) — links a phone number to an already-authenticated user.

    New types: OtpSendResult, PhoneVerifyResult.

    KoolbaseUser now exposes phoneNumber and phoneVerified fields.

    New exceptions: InvalidPhoneNumberException, OtpExpiredException, OtpInvalidException, OtpMaxAttemptsException, OtpRateLimitException, PhoneAlreadyLinkedException, SmsConfigMissingException.

    Phone numbers must be in E.164 format (e.g. +233244000000). Configure your SMS provider (Twilio, Africa's Talking, or Hubtel) in the Koolbase dashboard before using.

    Open source →
  52. 2.6.4 11 Apr 2026
    Release notes
    • README update — full feature documentation
    Open source →
  53. 2.6.3 09 Apr 2026
    Release notes
    • Updated drift to ^2.31.0
    • Updated drift_flutter to ^0.2.8
    Open source →
  54. 2.6.2 09 Apr 2026
    Release notes
    • Updated dependencies to latest versions
    • Fixed static analysis warnings
    • Removed deprecated encryptedSharedPreferences parameter
    Open source →
  55. 2.6.1 09 Apr 2026
    Release notes
    • README update — Logic Engine v2 operators
    Open source →
  56. 2.6.0 09 Apr 2026
    Release notes

    Logic Engine v2 — Richer conditions

    New operators:

    • gte — greater than or equals
    • lte — less than or equals
    • contains — string or list contains value
    • starts_with — string starts with
    • ends_with — string ends with
    • in_list — value is in a list
    • not_in_list — value is not in a list
    • between — numeric value in range [min, max]
    • is_true — value is boolean true
    • is_false — value is boolean false
    • not_exists — value is null or missing

    All operators work with AND/OR condition groups.

    Example

    {
      "op": "and",
      "conditions": [
        { "op": "gte", "left": { "from": "context.usage" }, "right": 5 },
        { "op": "in_list", "left": { "from": "context.plan" }, "right": ["free", "trial"] }
      ]
    }
    
    Open source →
  57. 2.5.1 09 Apr 2026
    Release notes
    • README update — added Sign in with Apple section
    Open source →
  58. 2.5.0 09 Apr 2026
    Release notes

    Sign in with Apple

    • Added KoolbaseAppleAuth.signIn() — Sign in with Apple for Flutter
    • Added KoolbaseAuthClient.oauthLogin() — unified OAuth login method
    • Added AuthApi.oauthLogin() — server-side Apple identity token verification
    • Apple identity token verified server-side using Apple's JWKS endpoint
    • Supports email relay addresses from Apple private email relay

    Usage

    import 'package:koolbase_flutter/koolbase_flutter.dart';
    
    final session = await KoolbaseAppleAuth.signIn();
    if (session != null) {
      print('Signed in: \${session['user']['email']}');
    }
    

    Setup required

    Add sign_in_with_apple to your pubspec.yaml and configure your App ID in the Apple Developer portal.

    Open source →
  59. 2.4.0 05 Apr 2026
    Release notes

    Koolbase Cloud Messaging

    • Added KoolbaseMessaging — push notification delivery via FCM
    • Added Koolbase.messaging.registerToken(token, platform) — register FCM device token with Koolbase
    • Added Koolbase.messaging.send(to, title, body, data) — send push notification to a specific device
    • KoolbaseConfig extended with messagingEnabled parameter (default: true)
    • Device ID automatically attached to token registration

    Usage

    // After obtaining FCM token from firebase_messaging
    final fcmToken = await FirebaseMessaging.instance.getToken();
    await Koolbase.messaging.registerToken(
      token: fcmToken!,
      platform: 'android', // or 'ios'
    );
    
    // Send to a specific device
    await Koolbase.messaging.send(
      to: deviceToken,
      title: 'Your order is ready',
      body: 'Pick up at counter 3',
      data: {'order_id': '123'},
    );
    

    Setup required

    Add your FCM server key as a project secret named FCM_SERVER_KEY in the Koolbase dashboard.

    Open source →
  60. 2.3.1 04 Apr 2026
    Release notes
    • Updated README — added Code Push, Analytics, Logic Engine sections, comparison table, clearer get started guide
    Open source →

Every package, every release, already written down.

The archive is open and free. Watching your own project is what we are building next.

Browse the archive