packages feed

firebase-hs-0.3.0.0: CHANGELOG.md

# Changelog

## 0.3.0.0

### Fixed
- Percent-encode every caller-supplied URL component. Project IDs, collection
  paths, document IDs, and `updateMask` field paths were interpolated raw, so
  a value containing `?`, `#`, `%`, `&`, a space, or any non-ASCII character
  produced a malformed request or injected query parameters. Subcollection
  `/` separators are preserved; the segments between them are encoded.
- `FirestoreValue` covers every type Firestore stores. `bytesValue`,
  `referenceValue`, and `geoPointValue` had no representation, so a document
  containing any of them failed to decode outright and `getDocument` returned
  `InvalidResponse` for data Firestore considers perfectly valid.
- Non-finite doubles travel in proto3 JSON's string spellings. `DoubleValue`
  holding NaN or an infinity previously encoded as `null` or `"+inf"`, which
  Firestore rejects, and a stored `"NaN"`, `"Infinity"`, or `"-Infinity"`
  failed to decode, making any document that held one unreadable.
- `runQuery` posts to the queried collection's parent resource, so a
  subcollection path (`users/abc/posts`) now queries that subcollection.
  The full path used to be sent as the `from` collection ID, which
  Firestore rejects; only top-level collections were queryable.
- A query result whose document fails to decode is reported as
  `InvalidResponse` instead of being silently dropped, which misreported
  what the query matched.
- `integerValue` strings outside the `Int64` range are rejected. The digits
  were read straight into `Int64`, so an out-of-range value silently
  wrapped instead of failing.
- `{"doubleValue": null}` is rejected. The null previously fell through to
  aeson's `Double` parser, which reads JSON null as NaN.
- A cache refresh no longer overwrites a newer key set installed by a
  concurrent verification.
- `runQuery` and `runQueryInTransaction` classify their error responses.
  Firestore's streaming endpoints frame an error as a single-element JSON
  array, which the parser did not read, so a query that failed with an
  error response surfaced as `NetworkError "HTTP <status>"` instead of
  `DocumentNotFound`, `PermissionDenied`, `TransactionAborted`, or a
  specific API error.
- A query stream that fails after emitting some results reports the error
  instead of returning the partial page as a success. The trailing error
  entry was dropped, so a truncated result set looked complete.
- `TimestampValue` encodes at most nanosecond precision. A `UTCTime`
  carrying sub-nanosecond digits formatted to more than the nine fractional
  digits Firestore accepts, which it rejects on write.

### Breaking Changes
- Firestore operations take a single `Firestore` handle in place of the
  `Manager -> AccessToken -> ProjectId` prefix every one of them repeated.
  Build it with `newFirestore`, and refresh an expiring token with
  `withToken` rather than rebuilding the connection pool.
- `FirebaseUser` gained fields, so positional construction no longer
  compiles. Pattern matches on `fuUid`, `fuEmail`, and `fuName` are
  unaffected.
- `commitTransaction` and the `runTransaction` callback take the new opaque
  `Write` type in place of raw `Aeson.Value`, with `mkUpdateWrite` and
  `mkDeleteWrite` constructing it. Hand-assembled write JSON no longer
  typechecks.
- `Firebase.Firestore.Internal.queryUrl` is replaced by `runQueryUrl`, which
  takes the queried collection so it can address the parent resource.
- `KeyCache` is now backed by `IORef` rather than `TVar`, and `Firebase.Auth`
  re-exports it as an abstract type. Construct it with `newKeyCache` or
  `newTlsKeyCache`.
- Dropped the `stm` dependency: the cache is a single reference with no
  composed transactions, which `atomicModifyIORef'` covers.
- Dropped the `mtl` dependency from the `servant` flag. `Firebase.Servant`
  now builds its 401 on the `Handler` newtype and `transformers`, which does
  not depend on which `MonadError` re-export a given servant version ships.
- `Firebase.Servant` no longer exports `extractBearerToken` or
  `authErrorToBody`. Both were duplicates of the `Firebase.Auth.WAI`
  versions; use `Firebase.Auth.Internal.bearerToken` and
  `Firebase.Auth.authErrorMessage`.
- A response body that is JSON but not shaped like a Firestore error now
  reports `NetworkError "HTTP <status>"` instead of
  `FirestoreApiError status "" "unknown error"`.

### Added
- `getDocumentInTransaction` and `runQueryInTransaction` read inside a
  transaction. The reads see the transaction's snapshot and Firestore
  verifies at commit that nothing they read has changed, which is what makes
  `runTransaction` a transaction rather than an atomic batch write; reads
  without the transaction ID never did either.
- Token claims are no longer discarded. `FirebaseUser` now carries
  `fuEmailVerified`, `fuPicture`, `fuAuthTime`, `fuSignInProvider`, and
  `fuCustomClaims`, with `hasClaim` and `lookupClaim` to read them. Custom
  claims are how Firebase expresses roles, so without them a verified token
  could establish identity but not authorize anything.
- 401 responses from the WAI middleware and the Servant handler carry the
  `WWW-Authenticate: Bearer` challenge RFC 6750 requires.
- `listDocuments` lists a collection. `collectionUrl` had described itself as
  "used for listing" since the first release with nothing to use it.
- `BytesValue`, `ReferenceValue`, `GeoPointValue`, and the `GeoPoint` type.
- `mkUpdateWrite` and `mkDeleteWrite` build the writes `commitTransaction`
  and `runTransaction` expect. `mkUpdateWrite` was referenced by the README
  and Haddock but never existed, leaving no supported way to construct a
  write.
- `Firebase.Auth.Internal`: base64url padding and bearer-token extraction,
  shared by the verifier and both web integrations.
- `authErrorMessage` renders an `AuthError` as a client-safe body.
- `documentResourceName`, the percent-encoding helpers,
  `splitCollectionPath`, `documentInTransactionUrl`, and the pure response
  decoders (`decodeBody`, `decodeDocumentList`, `decodeQueryResults`,
  `decodeTransactionId`) are exported from `Firebase.Firestore.Internal`.

### Changed
- Bearer scheme names are matched case-insensitively, as RFC 7235 requires.
- Network calls catch only `HttpException`. Anything else, asynchronous
  cancellation in particular, propagates instead of surfacing as a
  `KeyFetchError` or `NetworkError` result.
- Widened bounds: `http-client-tls < 0.5` (resolves the Stackage report in
  issue #1), `containers < 0.9`, `aeson < 2.4`, `time < 1.17`,
  `crypton < 2`. Lowered `base` to `>= 4.18`, admitting GHC 9.6.
- `http-client >= 0.7.13`, the first release whose `Show Request` redacts
  the `Authorization` header. An `HttpException` rendered into
  `NetworkError` text therefore never carries the access token.
- CI builds the `wai` and `servant` modules, which no job previously
  compiled, and adds a GHC compatibility matrix, an sdist build, and an
  ASCII-only source check.

## 0.2.0.0

### Breaking Changes
- Replaced `jose` JWT backend with direct `crypton` RS256 verification
- Dropped `jose`, `lens`, `memory` dependencies for a significantly lighter dependency tree
- `JWKSet` (from jose) replaced with internal `JwkSet`/`JwkKey` types in `Firebase.Auth.Types`
- License changed from MIT to BSD-3-Clause

### Added
- `JwkSet` and `JwkKey` types for Google's public key representation
- Manual JWT parsing with `base64-bytestring` (no jose overhead)
- RS256 signature verification via `crypton` (`Crypto.PubKey.RSA.PKCS15`)

### Changed
- Bumped GHC to 9.8.4, `base >= 4.19`
- Widened `stm` bounds to `< 2.7`
- Widened `text` bounds to `>= 1.2 && < 2.2`
- Compatible with modern Haskell crypto stack (`crypton`)

### Removed
- `jose` dependency (source of `memory`/`ram` incompatibility)
- `lens` dependency (only used for jose's API)
- `FirebaseClaims`, `HasClaimsSet` internal types (replaced with direct JSON parsing)

### Unchanged
- Public API for `verifyIdToken`, `verifyIdTokenCached`, `newKeyCache`, `newTlsKeyCache`
- `FirebaseConfig`, `FirebaseUser`, `AuthError`, `KeyCache` types
- WAI middleware (`Firebase.Auth.WAI`)
- Servant combinator (`Firebase.Servant`)
- Firestore client (all modules unchanged)
- All 46 tests pass

## 0.1.1.0

### Fixed
- Import `throwError` from `Control.Monad.Except` (mtl) instead of `Servant.Server` re-export for compatibility with newer servant versions
- Add explicit `mtl` dependency under `servant` flag

## 0.1.0.0

Initial release.

### Auth
- Firebase ID token (JWT) verification against Google's public keys
- RS256 signature validation via jose
- JWK-based key fetching with `Cache-Control: max-age` caching
- STM-backed `KeyCache` for thread-safe concurrent verification
- Full claims validation: issuer, audience, expiry, issued-at, subject
- Configurable clock skew (default 300s)

### Firestore REST API Client
- CRUD operations: `getDocument`, `createDocument`, `updateDocument`, `deleteDocument`
- Structured query DSL with composable builder pattern
- Composite filters for complex query conditions
- `FirestoreValue` ADT with custom JSON instances matching Firestore's tagged wire format

### Atomic Transactions
- `beginTransaction`, `commitTransaction`, `rollbackTransaction` for manual control
- `runTransaction` for automatic begin/commit/rollback with callback
- `TransactionMode` sum type: `ReadWrite`, `RetryWith`, `ReadOnly`

### WAI Auth Middleware (optional, `wai` flag)
- `requireAuth`, `firebaseAuth`, `lookupFirebaseUser`

### Servant Auth Combinator (optional, `servant` flag)
- `firebaseAuthHandler`, `extractBearerToken`, `authErrorToBody`

### Internal
- Pure URL builders and error parsers in `Firebase.Firestore.Internal`
- 41 pure tests