# 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