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
45 changes: 32 additions & 13 deletions API_DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,15 +189,30 @@ fixed; the rest are deliberate, recorded decisions.
- Removed two exact duplicates: core `toResultFlow()` (≡ `asFlow()`) and realtime `statusFlow()`
(≡ the `status` property).

**Perfection pass — every enum now one casing, every remaining outlier resolved:**
- **All enum entries are now `UPPER_SNAKE`, SDK-wide.** The two PascalCase hold-outs
(`SupabaseErrorCategory` = `CONFLICT`/`NOT_FOUND`/… and `TextSearchType` = `RAW`/`PLAIN`/`PHRASE`/
`WEB_SEARCH`) were converted to match the ~38 other enums. Both were verified non-wire
(`SupabaseErrorCategory` is derived from HTTP status; `TextSearchType` carries its PostgREST token
in a constructor arg), so the change is name-only.
- `RealtimeSubscription.channel: String` → **`channelName`** — it returns a name, not a
`RealtimeChannel`; this also aligns it with the builder's existing `channelName`.
- `sync.Record` / `sync.Cursor` → **`SyncRecord`** / **`SyncCursor`** — qualified domain nouns
(matching `PendingChange`/`PullResult`), and `SyncCursor` no longer collides with the generated
`…store.db.Cursor`.
- storage `ObjectListV2Result` → **`ObjectListV2Response`** (the lone `*Result` among `*Response`
list DTOs); auth-admin `AuditLogEntry` → **`AuditLogEvent`** (the method is `listAuditLogEvents`);
auth-admin OIDC `userinfoUrl` → **`userInfoUrl`** (camelCase, siblings `authorizationUrl`/
`tokenUrl`; `@SerialName` keeps the `userinfo_url` wire field); client config `logLevel` →
**`httpLogLevel`** (disambiguates the wire-verbosity `HttpLogLevel` from logger-severity
`SupabaseLogLevel`).

**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.
the range ops are a distinct PostgREST range-operator family ("strictly right of", "doesn't
extend left") deliberately mirroring the supabase-js range tokens, so `rangeGreater` would
wrongly imply scalar-greater semantics. 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
Expand All @@ -210,10 +225,14 @@ fixed; the rest are deliberate, recorded decisions.
- **`*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.
**Still deliberately kept (renaming would not be an improvement):**
- **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** — 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.
26 changes: 22 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,26 @@ each call site.
- 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
(`authorizationUrl` / `tokenUrl` / `userInfoUrl`); the `jwks_uri` wire field is
unchanged (via `@SerialName`).
- **Final naming pass, part 2 — every enum entry is now `UPPER_SNAKE` and every remaining
outlier is resolved:**
- **`SupabaseErrorCategory`** entries `Conflict`/`NotFound`/`Unauthorized`/`RateLimited`/
`Validation`/`Internal`/`Network`/`Unknown` → **`CONFLICT`/`NOT_FOUND`/`UNAUTHORIZED`/
`RATE_LIMITED`/`VALIDATION`/`INTERNAL`/`NETWORK`/`UNKNOWN`**, and **`TextSearchType`**
`Raw`/`Plain`/`Phrase`/`Websearch` → **`RAW`/`PLAIN`/`PHRASE`/`WEB_SEARCH`** — the last two
PascalCase enums now match the ~38 others. Both are name-only (the wire values live in HTTP
status mapping / a constructor arg, not the entry name).
- Realtime `RealtimeSubscription.channel` → **`channelName`** — it returns a name, not a
`RealtimeChannel` (and it now matches the builder's `channelName`).
- Sync `Record` / `Cursor` → **`SyncRecord`** / **`SyncCursor`** — qualified domain nouns;
`SyncCursor` no longer collides with the generated SQLDelight `Cursor`.
- Storage `ObjectListV2Result` → **`ObjectListV2Response`** (the lone `*Result` among the
`*Response` list DTOs); auth-admin `AuditLogEntry` → **`AuditLogEvent`** (the method is
`listAuditLogEvents`); auth-admin OIDC `userinfoUrl` → **`userInfoUrl`** (camelCase;
`userinfo_url` wire field unchanged).
- Client config `logLevel` → **`httpLogLevel`** — disambiguates wire-verbosity `HttpLogLevel`
from logger-severity `SupabaseLogLevel` at the call site.

### Removed (breaking)

Expand Down Expand Up @@ -588,7 +606,7 @@ change is additive — no breaking changes.
`captchaToken` and a defaulted `skip_http_redirect=true` on SSO so the URL call
returns JSON instead of a 303 redirect; `webauthn` verification on `mfaVerify`
(new `MfaWebauthnVerification` model).
- **Auth Admin** — `auditLogEvents(page, perPage)` returning `AuditLogEntry`;
- **Auth Admin** — `auditLogEvents(page, perPage)` returning `AuditLogEvent`;
`updateFactor(userId, factorId, friendlyName)` returning the full `MfaFactor`.

### Fixed
Expand Down Expand Up @@ -652,7 +670,7 @@ change is additive — no breaking changes.
- **Auth** — `getSettings()` (`GET /auth/v1/settings`, reports which providers and
flags the project has enabled) and `getHealth()` (`GET /auth/v1/health`); both
decode tolerantly so unknown/missing keys don't break the response.
- **Postgrest** — `TextSearchType.Raw` exposes the bare `fts` operator
- **Postgrest** — `TextSearchType.RAW` exposes the bare `fts` operator
(`to_tsquery`); a standalone `offset()`; `ReturnOption.HEADERS_ONLY`
(`Prefer: return=headers-only`, an empty body that keeps headers like
`Location`); and `replace()` — `PUT`-based single-row upsert by primary key.
Expand Down Expand Up @@ -957,7 +975,7 @@ change is additive — no breaking changes.
for issuing raw, non-JSON requests through the configured client (powers the
resumable upload protocol).
- **Errors:** network-aware error handling — `SupabaseError.httpStatus` and
`retryAfterSeconds`, a `SupabaseErrorCategory.Network` category,
`retryAfterSeconds`, a `SupabaseErrorCategory.NETWORK` category,
`SupabaseErrorCategory.isRetryable`, `SupabaseError.isNetworkError()`, and an
`onNetworkError { }` result handler. Transport now classifies timeouts and
connection failures into `SupabaseErrorCodes.Client` codes so categorization
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ database.selectTyped<Todo>(table = "todos") {
}
```

Errors carry a `category` (`Conflict`, `NotFound`, `Unauthorized`, `RateLimited`, `Validation`, `Internal`, `Network`, `Unknown`) so you can branch without parsing codes — plus chainable helpers like `onUnauthorized { }`, `onRateLimited { }` and `onNetworkError { }`. See [Results & Errors](https://androidpoet.github.io/supabase-kmp/results-and-errors) for the full surface.
Errors carry a `category` (`CONFLICT`, `NOT_FOUND`, `UNAUTHORIZED`, `RATE_LIMITED`, `VALIDATION`, `Internal`, `NETWORK`, `UNKNOWN`) so you can branch without parsing codes — plus chainable helpers like `onUnauthorized { }`, `onRateLimited { }` and `onNetworkError { }`. See [Results & Errors](https://androidpoet.github.io/supabase-kmp/results-and-errors) for the full surface.

## Modules

Expand Down
24 changes: 12 additions & 12 deletions supabase-auth-admin/api/android/supabase-auth-admin.api
Original file line number Diff line number Diff line change
Expand Up @@ -106,16 +106,16 @@ public final class io/github/androidpoet/supabase/auth/admin/models/AdminUserAtt
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}

public final class io/github/androidpoet/supabase/auth/admin/models/AuditLogEntry {
public static final field Companion Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry$Companion;
public final class io/github/androidpoet/supabase/auth/admin/models/AuditLogEvent {
public static final field Companion Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent$Companion;
public fun <init> (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Ljava/lang/String;Ljava/lang/String;)V
public synthetic fun <init> (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun component1 ()Ljava/lang/String;
public final fun component2 ()Lkotlinx/serialization/json/JsonObject;
public final fun component3 ()Ljava/lang/String;
public final fun component4 ()Ljava/lang/String;
public final fun copy (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Ljava/lang/String;Ljava/lang/String;)Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry;
public static synthetic fun copy$default (Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry;
public final fun copy (Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Ljava/lang/String;Ljava/lang/String;)Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent;
public static synthetic fun copy$default (Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent;
public fun equals (Ljava/lang/Object;)Z
public final fun getCreatedAt ()Ljava/lang/String;
public final fun getId ()Ljava/lang/String;
Expand All @@ -125,18 +125,18 @@ public final class io/github/androidpoet/supabase/auth/admin/models/AuditLogEntr
public fun toString ()Ljava/lang/String;
}

public final synthetic class io/github/androidpoet/supabase/auth/admin/models/AuditLogEntry$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry$$serializer;
public final synthetic class io/github/androidpoet/supabase/auth/admin/models/AuditLogEvent$$serializer : kotlinx/serialization/internal/GeneratedSerializer {
public static final field INSTANCE Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent$$serializer;
public final fun childSerializers ()[Lkotlinx/serialization/KSerializer;
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry;
public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent;
public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object;
public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor;
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEntry;)V
public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/github/androidpoet/supabase/auth/admin/models/AuditLogEvent;)V
public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V
public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer;
}

public final class io/github/androidpoet/supabase/auth/admin/models/AuditLogEntry$Companion {
public final class io/github/androidpoet/supabase/auth/admin/models/AuditLogEvent$Companion {
public final fun serializer ()Lkotlinx/serialization/KSerializer;
}

Expand Down Expand Up @@ -190,7 +190,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getSkipNonceCheck ()Ljava/lang/Boolean;
public final fun getTokenUrl ()Ljava/lang/String;
public final fun getUpdatedAt ()Ljava/lang/String;
public final fun getUserinfoUrl ()Ljava/lang/String;
public final fun getUserInfoUrl ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down Expand Up @@ -254,7 +254,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getScopes ()Ljava/util/List;
public final fun getSkipNonceCheck ()Ljava/lang/Boolean;
public final fun getTokenUrl ()Ljava/lang/String;
public final fun getUserinfoUrl ()Ljava/lang/String;
public final fun getUserInfoUrl ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down Expand Up @@ -359,7 +359,7 @@ public final class io/github/androidpoet/supabase/auth/admin/models/CustomProvid
public final fun getScopes ()Ljava/util/List;
public final fun getSkipNonceCheck ()Ljava/lang/Boolean;
public final fun getTokenUrl ()Ljava/lang/String;
public final fun getUserinfoUrl ()Ljava/lang/String;
public final fun getUserInfoUrl ()Ljava/lang/String;
public fun hashCode ()I
public fun toString ()Ljava/lang/String;
}
Expand Down
Loading
Loading