Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 51 additions & 1 deletion API_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ handled in source.
- `ErrorResponse` (wire-only) → `internal`; deleted unused typed-id value classes (dead public API).
- `SupabaseConfig` → plain `class` (function-typed fields; no meaningful `copy`/`equals`).
- `MAX_PULL_PAGES` / `DEFAULT_PAGE_SIZE` no longer leak as public static fields.
- `asFlow()` relabeled hot (was mislabeled "Cold"); `streamLines` / `invokeSSE` defaults defer
- `asFlow()` relabeled hot (was mislabeled "Cold"); `streamLines` / `invokeSse` defaults defer
their throw into the cold `flow { }` instead of throwing eagerly.
- **Database query response shape unified into `ResponseFormat`** — `select` / `rpc` / `rpcGet` /
`selectRange` took 4 mutually-exclusive `head`/`single`/`csv`/`geojson` booleans (illegal combos
Expand Down Expand Up @@ -167,3 +167,53 @@ handled in source.
upload/download isn't forced through an in-memory `ByteArray`. A bytes-returning functions
response accessor (`invokeForBytes`) is the same shape of additive gap — both are purely new
surface, safe to land post-1.0.

## Final naming audit (last pass before the freeze)

A second, naming-only sweep across **every** module's `.klib.api` (7 parallel auditors +
a cross-module acronym/factory-verb/enum-casing analysis), judged against the Kotlin/JetBrains
API guidelines. Verdict: the surface was already in good shape — all auditors reported "no
blockers." A handful of genuine, contained violations of the SDK's **own** conventions were
fixed; the rest are deliberate, recorded decisions.

**Fixed (the SDK's own convention was violated, and the change was contained):**
- `invokeSSE`→`invokeSse` — acronyms are word-cased in every other identifier (`Url`, `Otp`,
`Jwt`, `Csv`, `GeoJson`); this was the single all-caps outlier in the whole SDK.
- `Paginator.endReached`→`isEndReached` — booleans read as assertions; its sibling is `isLoading`.
- `selectWithCount`→`selectWithCountTyped` — it decodes into `T`, so it joins the `*Typed` family.
- `RealtimeChannelBuilder.setPrivate`→`configurePrivate` — matches the builder's `configure*` group.
- storage `createUploadSignedUrl(WithPath)`→`createSignedUploadUrl(WithPath)` — `Signed`+direction
order, matching `createSignedUrl` / `getSignedDownloadUrl`.
- `VectorDistanceMetric.DOTPRODUCT`→`DOT_PRODUCT`; auth-admin OIDC `jwksUri`→`jwksUrl`
(both keep their wire value via `@SerialName`).
- Removed two exact duplicates: core `toResultFlow()` (≡ `asFlow()`) and realtime `statusFlow()`
(≡ the `status` property).

**Deliberate — kept by design (recorded so they aren't "fixed" later):**
- **Enum-entry casing is intentionally mixed.** Wire-mapped / option / SQL-keyword enums use
`UPPER_SNAKE` (`Order.ASC`, `ResponseFormat.GEOJSON`, every `@SerialName`-backed enum); the two
pure-domain category sets — `SupabaseErrorCategory` and `TextSearchType` — use `PascalCase`
because they read as a closed set of named conditions at a `when`/`onFailureCategory` call site.
Both styles are sanctioned by the Kotlin style guide; the split is by role, not by accident.
- **Filter-operator vocabulary** (`eq`/`neq` abbreviated, `greater`/`greaterEq` spelled, range
ops `rangeGt`/`rangeGte`) is kept — the query DSL was reviewed and blessed in the main audit;
the equality/ordering shorthands match what query-DSL users reach for. Not reopened.
- **Factory verbs differ by what they return**, on purpose: `Supabase.create` (root builder),
`createXClient` (feature clients), `googleAuthProvider`/`appleAuthProvider` (return a provider
*descriptor* you hand to config, not a client), `openOfflineSyncStore` (opens a DB-backed
resource).
- **`rpcTyped`=single vs `selectTyped`=list** is intentional: an RPC returns one value by nature,
a `select` returns rows. `rpcListTyped` / `rpcSingleTyped` make the other cardinalities explicit.
- **Pseudo-namespaced auth methods** (`mfa*`/`oauth*`/`passkey*`) read noun-first by design — a
flattened stand-in for sub-clients; admin stays verb-first CRUD. `getUserById`/`updateUserById`
keep `ById` because the non-admin `getUser` already means "by access token."
- **`*OrThrow` / `*WithResult` / `*WithAck` suffixes** are the deliberate explicit-exception /
await-confirmation escape hatches on top of the Result-first defaults — kept, not collapsed.

**Deferred (real but not worth pre-freeze churn; the sync surface isn't published in 1.0):**
- `sync-core` `Record`/`Cursor` → `SyncRecord`/`SyncCursor` (collide with `java.lang.Record`) —
~285 references across the sync tree; the sync modules' publishing is deferred, so this can ride
the same train as their first publish.
- `RealtimeSubscription.channel: String` → `channelName` (a name-trap, but `.channel` is too
ambiguous to rename mechanically without risk) and storage `ObjectListV2Result`→`*Response`
(suffix polish, 69 references) — both additive-safe to revisit.
28 changes: 24 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,23 @@ each call site.
your own `SqlDriver` (or `openOfflineSyncStore`). The generated `…sync.store.db` package
(including a `Cursor` that collided with the public `sync.Cursor`) is no longer part of
the published API.
- **Final naming pass (cross-module consistency).** A last convention sweep before the
freeze, so one rule holds across every module:
- `FunctionsClient.invokeSSE` → **`invokeSse`** — acronyms are word-cased everywhere
else in the SDK (`Url`, `Otp`, `Jwt`, `Csv`, `GeoJson`); this was the lone exception.
- `Paginator.endReached` → **`isEndReached`** — a boolean reads as an assertion, matching
its sibling `isLoading`.
- Database `selectWithCount` → **`selectWithCountTyped`** — it decodes into your type, so
it joins the `*Typed` family (`selectTyped` / `selectSingleTyped` / …).
- Realtime `RealtimeChannelBuilder.setPrivate(…)` → **`configurePrivate(…)`** — matches
the builder's own `configureBroadcast` / `configurePresence` prefix.
- Storage `createUploadSignedUrl` / `…WithPath` → **`createSignedUploadUrl`** / `…WithPath`
— `Signed`+direction word order, matching `createSignedUrl` / `getSignedDownloadUrl`.
- Storage `VectorDistanceMetric.DOTPRODUCT` → **`DOT_PRODUCT`** — legible entry next to
`COSINE` / `EUCLIDEAN`; the `dotproduct` wire value is unchanged (via `@SerialName`).
- Auth-admin OIDC `jwksUri` → **`jwksUrl`** — its siblings are all `*Url`
(`authorizationUrl` / `tokenUrl` / `userinfoUrl`); the `jwks_uri` wire field is
unchanged (via `@SerialName`).

### Removed (breaking)

Expand All @@ -127,6 +144,9 @@ each call site.
fire-and-forget.
- **Realtime `removeChannel(subscription)`** — the deprecated duplicate of
`removeSubscription(subscription)`.
- **Duplicate `Flow` bridges** — core `SupabaseResult.toResultFlow()` (byte-for-byte the
same single-emit as `asFlow()`) and realtime `RealtimeSubscription.statusFlow()`
(identical to the `status` property) were removed; use `asFlow()` and `.status`.
- **~46 wire-only request/response DTOs** in `supabase-auth` and `supabase-storage` are now
`internal` (they were never meant to be constructed by callers).

Expand Down Expand Up @@ -402,7 +422,7 @@ each call site.
`order=` params — so `order("a"); order("b")` sorted by only one column. Successive `order`
calls now accumulate into one parameter (per referenced table), matching PostgREST.
- **Edge Function SSE streaming: the last-event-id now persists across events.** The
`invokeSSE` parser reset the id on every event, so a streamed event that omitted `id:`
`invokeSse` parser reset the id on every event, so a streamed event that omitted `id:`
reported `null` instead of inheriting the most recent id (the browser
`EventSource.lastEventId` behaviour). The id is now carried forward until the server sends
a new one. As part of the same fix, a block carrying only a (now-persistent) id no longer
Expand Down Expand Up @@ -536,7 +556,7 @@ each call site.
### Added

- **Pagination** — a demand-driven `Paginator<T>` in `supabase-core` (exposes
`items`/`isLoading`/`endReached`/`error` as `StateFlow`s, with `loadNext()` and
`items`/`isLoading`/`isEndReached`/`error` as `StateFlow`s, with `loadNext()` and
`refresh()`), plus in-module factories: `DatabaseClient.paginator()`,
`StorageClient.listPaginator()` and `AuthAdminClient.usersPaginator()`. No new
dependencies; works on all targets. See the new **Pagination** docs page
Expand Down Expand Up @@ -755,13 +775,13 @@ change is additive — no breaking changes.
corrupting images/PDFs. Also: extension→MIME inference when `contentType` is
left at the octet-stream default, and a `withCacheNonce` URL cache-buster.
- **Postgrest count** — `selectCount` (HTTP `HEAD`), `selectRange`, and typed
`selectWithCount<T>` parse the `Content-Range` header into a `PostgrestPage`/
`selectWithCountTyped<T>` parse the `Content-Range` header into a `PostgrestPage`/
`PostgrestRange` (handles `0-9/27`, `*/27`, `*/*`), so the requested count is
finally surfaced. Added the geojson+`stripNulls` mutual-exclusion guard.
- **Realtime** — HTTP `broadcast(...)` without a subscription (`/realtime/v1/api/broadcast`);
presence `metas` are unwrapped to user state; `postgres_changes` route by the
server-assigned binding `ids`; reconnect backoff gains optional jitter.
- **Edge Functions SSE** — `invokeSSE(...): Flow<FunctionServerSentEvent>` with
- **Edge Functions SSE** — `invokeSse(...): Flow<FunctionServerSentEvent>` with
per-event `decodeAs<T>()`, over a new `streamLines` transport primitive.
- **Auth** — single-flight, TTL-cached JWKS (`resolveSigningKey`); `getClaims`
validates `exp`/`nbf` (with clock-skew leeway) and, opt-in, `iss`/`aud`;
Expand Down
8 changes: 4 additions & 4 deletions supabase-auth-admin/api/android/supabase-auth-admin.api
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getId ()Ljava/lang/String;
public final fun getIdentifier ()Ljava/lang/String;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPkceEnabled ()Ljava/lang/Boolean;
public final fun getProviderType ()Lio/github/androidpoet/supabase/auth/admin/models/CustomProviderType;
Expand Down Expand Up @@ -247,7 +247,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getEnabled ()Ljava/lang/Boolean;
public final fun getIdentifier ()Ljava/lang/String;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPkceEnabled ()Ljava/lang/Boolean;
public final fun getProviderType ()Lio/github/androidpoet/supabase/auth/admin/models/CustomProviderType;
Expand Down Expand Up @@ -353,7 +353,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getEmailOptional ()Ljava/lang/Boolean;
public final fun getEnabled ()Ljava/lang/Boolean;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPkceEnabled ()Ljava/lang/Boolean;
public final fun getScopes ()Ljava/util/List;
Expand Down Expand Up @@ -816,7 +816,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/OidcDiscover
public fun equals (Ljava/lang/Object;)Z
public final fun getAuthorizationEndpoint ()Ljava/lang/String;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getRevocationEndpoint ()Ljava/lang/String;
public final fun getSupportedIdTokenSigningAlgs ()Ljava/util/List;
public final fun getSupportedResponseTypes ()Ljava/util/List;
Expand Down
8 changes: 4 additions & 4 deletions supabase-auth-admin/api/jvm/supabase-auth-admin.api
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getId ()Ljava/lang/String;
public final fun getIdentifier ()Ljava/lang/String;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPkceEnabled ()Ljava/lang/Boolean;
public final fun getProviderType ()Lio/github/androidpoet/supabase/auth/admin/models/CustomProviderType;
Expand Down Expand Up @@ -247,7 +247,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getEnabled ()Ljava/lang/Boolean;
public final fun getIdentifier ()Ljava/lang/String;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPkceEnabled ()Ljava/lang/Boolean;
public final fun getProviderType ()Lio/github/androidpoet/supabase/auth/admin/models/CustomProviderType;
Expand Down Expand Up @@ -353,7 +353,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getEmailOptional ()Ljava/lang/Boolean;
public final fun getEnabled ()Ljava/lang/Boolean;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getName ()Ljava/lang/String;
public final fun getPkceEnabled ()Ljava/lang/Boolean;
public final fun getScopes ()Ljava/util/List;
Expand Down Expand Up @@ -816,7 +816,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/OidcDiscover
public fun equals (Ljava/lang/Object;)Z
public final fun getAuthorizationEndpoint ()Ljava/lang/String;
public final fun getIssuer ()Ljava/lang/String;
public final fun getJwksUri ()Ljava/lang/String;
public final fun getJwksUrl ()Ljava/lang/String;
public final fun getRevocationEndpoint ()Ljava/lang/String;
public final fun getSupportedIdTokenSigningAlgs ()Ljava/util/List;
public final fun getSupportedResponseTypes ()Ljava/util/List;
Expand Down
Loading
Loading