From 0fed48801a8a86e278b010a4cc9e59f6d3e9246e Mon Sep 17 00:00:00 2001 From: tr00d Date: Tue, 30 Jun 2026 13:48:29 +0200 Subject: [PATCH] feat: add sdk compliance file for capabilities matrix --- sdk-compliance.yaml | 631 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 631 insertions(+) create mode 100644 sdk-compliance.yaml diff --git a/sdk-compliance.yaml b/sdk-compliance.yaml new file mode 100644 index 00000000..4cd339a3 --- /dev/null +++ b/sdk-compliance.yaml @@ -0,0 +1,631 @@ +sdk: csharp +features: + + # ── Auth ─────────────────────────────────────────────────────────────────── + + auth.sign_in.sign_up: + status: partially_implemented + note: "API mirrors signUp, but on a session-returning sign-up (confirmations off) C# does NOT adopt the session — CurrentUser/CurrentSession stay null, so 'signed up' != 'signed in' as in JS." + symbols: + - Client.SignUp + auth.sign_in.sign_in_with_password: + status: implemented + symbols: + - Client.SignInWithPassword + - Client.SignIn + auth.sign_in.sign_in_with_oauth: + status: implemented + symbols: + - Client.SignIn + - ProviderAuthState + auth.sign_in.sign_in_with_otp: + status: implemented + symbols: + - Client.SignInWithOtp + - Client.SendMagicLink + auth.sign_in.sign_in_with_sso: + status: implemented + symbols: + - Client.SignInWithSSO + auth.sign_in.sign_in_with_id_token: + status: implemented + symbols: + - Client.SignInWithIdToken + auth.sign_in.sign_in_anonymously: + status: implemented + symbols: + - Client.SignInAnonymously + auth.sign_in.verify_otp: + status: implemented + symbols: + - Client.VerifyOTP + - Client.VerifyTokenHash + auth.sign_in.reset_password: + status: implemented + symbols: + - Client.ResetPasswordForEmail + auth.sign_in.reauthenticate: + status: implemented + symbols: + - Client.Reauthenticate + auth.sign_in.exchange_code_for_session: + status: implemented + symbols: + - Client.ExchangeCodeForSession + + auth.session.get_session: + status: implemented + symbols: + - Client.RetrieveSessionAsync + - Client.CurrentSession + - Client.LoadSession + auth.session.get_user: + status: implemented + symbols: + - Client.GetUser + - Client.CurrentUser + auth.session.refresh_session: + status: implemented + symbols: + - Client.RefreshSession + - Client.RefreshToken + auth.session.set_session: + status: implemented + symbols: + - Client.SetSession + auth.session.sign_out: + status: implemented + symbols: + - Client.SignOut + auth.session.subscribe_auth_events: + status: implemented + symbols: + - Client.AddStateChangedListener + - Client.RemoveStateChangedListener + - Client.NotifyAuthStateChange + auth.session.update_user: + status: implemented + symbols: + - Client.Update + auth.session.auto_refresh: + status: partially_implemented + note: "Refreshes on an internal background timer (ClientOptions.AutoRefreshToken), but does not expose JS's explicit startAutoRefresh/stopAutoRefresh control. Implicit-only." + symbols: + - ClientOptions.AutoRefreshToken + auth.identities.link_identity: + status: implemented + symbols: + - Client.LinkIdentity + auth.identities.unlink_identity: + status: implemented + symbols: + - Client.UnlinkIdentity + auth.identities.list_identities: + status: partially_implemented + note: "No dedicated getUserIdentities method; linked identities are reachable only via the User.Identities property." + symbols: + - User.Identities + auth.mfa.enroll: + status: implemented + symbols: + - Client.Enroll + auth.mfa.challenge: + status: implemented + symbols: + - Client.Challenge + auth.mfa.verify: + status: implemented + symbols: + - Client.Verify + auth.mfa.unenroll: + status: implemented + symbols: + - Client.Unenroll + auth.mfa.challenge_and_verify: + status: implemented + symbols: + - Client.ChallengeAndVerify + auth.mfa.list_factors: + status: implemented + symbols: + - Client.ListFactors + auth.mfa.get_authenticator_assurance_level: + status: implemented + symbols: + - Client.GetAuthenticatorAssuranceLevel + auth.admin.create_user: + status: implemented + symbols: + - AdminClient.CreateUser + auth.admin.delete_user: + status: partially_implemented + note: "Hard-delete only; no shouldSoftDelete flag (JS deleteUser(id, shouldSoftDelete))." + symbols: + - AdminClient.DeleteUser + auth.admin.update_user: + status: implemented + symbols: + - AdminClient.UpdateUserById + auth.admin.get_user: + status: implemented + symbols: + - AdminClient.GetUserById + auth.admin.list_users: + status: implemented + symbols: + - AdminClient.ListUsers + auth.admin.invite_user: + status: implemented + symbols: + - AdminClient.InviteUserByEmail + auth.admin.generate_link: + status: implemented + symbols: + - AdminClient.GenerateLink + auth.admin.list_mfa_factors: + status: implemented + symbols: + - AdminClient.ListFactors + auth.admin.delete_mfa_factor: + status: implemented + symbols: + - AdminClient.DeleteFactor + + # ── Client ───────────────────────────────────────────────────────────────── + + client.authentication_integration.cross_client_token_sync: + status: implemented + note: "Umbrella Client listens to auth state changes and injects the current JWT into every sub-client via a shared GetAuthHeaders callback." + symbols: + - Client.GetAuthHeaders + client.authentication_integration.oauth_flow_type: + status: partially_implemented + note: "Flow type (PKCE/Implicit) is chosen per sign-in via SignInOptions.FlowType, not as a single construction-time client setting." + symbols: + - SignInOptions.FlowType + - Constants.OAuthFlowType + client.session_management.custom_storage: + status: implemented + symbols: + - SupabaseOptions.SessionHandler + - Client.SetPersistence + client.session_management.persist_session: + status: partially_implemented + note: "No boolean persist toggle; in-memory-only behavior is achievable only by supplying a no-op IGotrueSessionPersistence handler." + symbols: + - SupabaseOptions.SessionHandler + client.request_configuration.global_headers: + status: implemented + symbols: + - SupabaseOptions.Headers + + + # ── Database ─────────────────────────────────────────────────────────────── + + database.query.from_table: + status: implemented + symbols: + - Client.Table + - Client.From + database.query.select: + status: implemented + symbols: + - Table.Select + database.query.schema_selection: + status: partially_implemented + note: "Schema is set once at construction (ClientOptions.Schema); no per-query schema switch like JS client.schema(name)." + symbols: + - ClientOptions.Schema + database.query.rpc: + status: partially_implemented + note: "Invocation works (typed + untyped) but Rpc is terminal — no post-filtering/transform chaining on the result like JS rpc()." + symbols: + - Client.Rpc + database.mutate.insert: + status: implemented + symbols: + - Table.Insert + database.mutate.update: + status: implemented + symbols: + - Table.Update + - Table.Set + database.mutate.upsert: + status: implemented + symbols: + - Table.Upsert + - Table.OnConflict + database.mutate.delete: + status: implemented + symbols: + - Table.Delete + database.mutate.select_after_mutation: + status: implemented + note: "Mutations return the affected rows by default (QueryOptions.Returning = Representation)." + symbols: + - QueryOptions.Returning + database.using_filters.eq: + status: implemented + symbols: + - Table.Filter + - Table.Where + - Constants.Operator.Equals + database.using_filters.neq: + status: implemented + symbols: + - Constants.Operator.NotEqual + database.using_filters.gt: + status: implemented + symbols: + - Constants.Operator.GreaterThan + database.using_filters.gte: + status: implemented + symbols: + - Constants.Operator.GreaterThanOrEqual + database.using_filters.lt: + status: implemented + symbols: + - Constants.Operator.LessThan + database.using_filters.lte: + status: implemented + symbols: + - Constants.Operator.LessThanOrEqual + database.using_filters.like: + status: implemented + symbols: + - Constants.Operator.Like + database.using_filters.ilike: + status: implemented + symbols: + - Constants.Operator.ILike + database.using_filters.is: + status: implemented + symbols: + - Constants.Operator.Is + database.using_filters.in: + status: implemented + symbols: + - Constants.Operator.In + database.using_filters.contains: + status: implemented + symbols: + - Constants.Operator.Contains + database.using_filters.contained_by: + status: implemented + symbols: + - Constants.Operator.ContainedIn + database.using_filters.range_gt: + status: implemented + symbols: + - Constants.Operator.StrictlyRight + database.using_filters.range_gte: + status: implemented + symbols: + - Constants.Operator.NotLeftOf + database.using_filters.range_lt: + status: implemented + symbols: + - Constants.Operator.StrictlyLeft + database.using_filters.range_lte: + status: implemented + symbols: + - Constants.Operator.NotRightOf + database.using_filters.range_adjacent: + status: implemented + symbols: + - Constants.Operator.Adjacent + database.using_filters.overlaps: + status: implemented + symbols: + - Constants.Operator.Overlap + database.using_filters.text_search: + status: implemented + note: "FTS family: fts/plfts/phfts/wfts." + symbols: + - Constants.Operator.FTS + - Constants.Operator.PLFTS + - Constants.Operator.PHFTS + - Constants.Operator.WFTS + database.using_filters.match: + status: implemented + symbols: + - Table.Match + database.using_filters.not: + status: implemented + symbols: + - Table.Not + - Constants.Operator.Not + database.using_filters.or: + status: implemented + symbols: + - Table.Or + - Constants.Operator.Or + database.using_filters.not_in: + status: implemented + note: "Composed via the Not(column, Operator.In, list) overload." + symbols: + - Table.Not + database.using_modifiers.order: + status: implemented + note: "Capability at parity, but the primary Order(\"col\", ...) form is stringly-typed (breaks silently on a property rename)." + symbols: + - Table.Order + database.using_modifiers.limit: + status: implemented + symbols: + - Table.Limit + - Table.Offset + database.using_modifiers.range: + status: implemented + symbols: + - Table.Range + database.using_modifiers.single_row: + status: implemented + symbols: + - Table.Single + database.using_modifiers.request_cancellation: + status: implemented + note: "Every terminal (Get/Insert/Update/Delete/Single/Count) accepts a CancellationToken." + symbols: + - Table.Get + database.using_modifiers.relationship_embed: + status: partially_implemented + note: "Embeds expressible via PostgREST string syntax in Select(); no typed relationship builder (LINQ embed mapping is weak)." + symbols: + - Table.Select + + # ── Functions ────────────────────────────────────────────────────────────── + + functions.invocation.invoke: + status: implemented + note: "Three return shapes — string, deserialized T, and raw HttpContent." + symbols: + - Client.Invoke + - Client.RawInvoke + functions.invocation.set_auth_token: + status: partially_implemented + note: "No stateful SetAuth; bearer token is supplied per invocation or via a GetHeaders provider hook, not stored for all subsequent calls." + symbols: + - Client.GetHeaders + functions.invocation.method_override: + status: implemented + note: "InvokeFunctionOptions.HttpMethod is wired into the request (default POST). [feature-parity.md called this POST-only; the source disagrees as of 2026-06-29.]" + symbols: + - InvokeFunctionOptions.HttpMethod + functions.invocation.streaming_response: + status: partially_implemented + note: "RawInvoke returns raw HttpContent, but the request uses the default buffered completion (no incremental text/event-stream streaming)." + symbols: + - Client.RawInvoke + functions.invocation.region_selection: + status: implemented + note: "Full AWS region list; per-call override or client default; emits x-region." + symbols: + - InvokeFunctionOptions.FunctionRegion + - FunctionRegion + functions.invocation.timeout: + status: partially_implemented + note: "Per-invoke HttpTimeout exists, but it is not composable with a caller-supplied cancellation signal (Invoke accepts no CancellationToken)." + symbols: + - InvokeFunctionOptions.HttpTimeout + + # ── Realtime ─────────────────────────────────────────────────────────────── + + realtime.client.connect: + status: implemented + symbols: + - RealtimeClient.Connect + - RealtimeClient.ConnectAsync + realtime.client.disconnect: + status: implemented + symbols: + - RealtimeClient.Disconnect + realtime.client.channel: + status: implemented + note: "Plain-topic form plus a typed convenience overload Channel(db, schema, table, col, value)." + symbols: + - RealtimeClient.Channel + realtime.client.connection_state: + status: partially_implemented + note: "Socket state delivered via SocketStateEventHandler events; no synchronous connection-state getter on the client." + symbols: + - RealtimeClient.AddStateChangedHandler + realtime.client.get_channels: + status: partially_implemented + note: "Active channels exposed as a Subscriptions dictionary; no getChannels() method." + symbols: + - RealtimeClient.Subscriptions + realtime.client.remove_channel: + status: implemented + symbols: + - RealtimeClient.Remove + realtime.client.set_auth_token: + status: implemented + symbols: + - RealtimeClient.SetAuth + + realtime.channel.subscribe: + status: implemented + symbols: + - RealtimeChannel.Subscribe + realtime.channel.unsubscribe: + status: implemented + symbols: + - RealtimeChannel.Unsubscribe + realtime.channel.send: + status: implemented + symbols: + - RealtimeChannel.Send + - RealtimeChannel.Push + realtime.subscriptions.broadcast: + status: implemented + note: "Typed broadcast payloads via generics; better-typed than JS on('broadcast', ...)." + symbols: + - RealtimeChannel.Register + - RealtimeChannel.Broadcast + - RealtimeBroadcast + realtime.subscriptions.postgres_changes: + status: implemented + note: "Model-typed path via SupabaseTable.On (blessed) plus the low-level Channel().Register(PostgresChangesOptions)." + symbols: + - SupabaseTable.On + - RealtimeChannel.Register + - RealtimeChannel.AddPostgresChangeHandler + realtime.subscriptions.subscribe_presence: + status: partially_implemented + note: "Join/leave/sync handlers exist, but the presence sync diverges from JS (see realtime.presence.presence_state)." + symbols: + - RealtimePresence + realtime.subscriptions.postgres_changes_filter: + status: implemented + note: "Filter is a hand-built PostgREST string (e.g. 'user_id=eq.{id}'), untied to the model." + symbols: + - PostgresChangesOptions.Filter + realtime.subscriptions.broadcast_self: + status: implemented + symbols: + - BroadcastOptions.BroadcastSelf + realtime.subscriptions.broadcast_ack: + status: implemented + symbols: + - BroadcastOptions.BroadcastAck + realtime.presence.track: + status: implemented + symbols: + - RealtimePresence.Track + realtime.presence.untrack: + status: implemented + symbols: + - RealtimePresence.Untrack + realtime.presence.presence_state: + status: partially_implemented + note: "Typed CurrentState/LastState exist, but the initial presence snapshot is dropped, so any client that joins after others undercounts everyone — a behavioral gap, not just a shape gap." + symbols: + - RealtimePresence.CurrentState + - RealtimePresence.LastState + realtime.presence.presence_key: + status: implemented + note: "Set via Channel.Register(presenceKey)." + symbols: + - RealtimeChannel.Register + realtime.configuration.reconnect_backoff: + status: implemented + symbols: + - ClientOptions.ReconnectAfterInterval + realtime.configuration.heartbeat_interval: + status: implemented + symbols: + - ClientOptions.HeartbeatInterval + realtime.configuration.custom_logger: + status: partially_implemented + note: "Diagnostics routed through a debug handler hook; no custom logging function with a log-level filter." + symbols: + - RealtimeClient.AddDebugHandler + + # ── Storage ──────────────────────────────────────────────────────────────── + + storage.file_buckets.create_file_bucket: + status: implemented + symbols: + - StorageBucketApi.CreateBucket + storage.file_buckets.get_bucket: + status: implemented + symbols: + - StorageBucketApi.GetBucket + storage.file_buckets.list_file_buckets: + status: implemented + symbols: + - StorageBucketApi.ListBuckets + storage.file_buckets.update_bucket: + status: implemented + symbols: + - StorageBucketApi.UpdateBucket + storage.file_buckets.delete_file_bucket: + status: implemented + symbols: + - StorageBucketApi.DeleteBucket + storage.file_buckets.empty_bucket: + status: implemented + symbols: + - StorageBucketApi.EmptyBucket + storage.file_buckets.access_bucket: + status: implemented + symbols: + - StorageClient.From + storage.file_buckets.upload: + status: implemented + note: "File-path and byte[] overloads; onProgress + FileOptions (content-type, cache-control, upsert)." + symbols: + - StorageFileApi.Upload + - StorageFileApi.UploadOrResume + storage.file_buckets.download: + status: implemented + symbols: + - StorageFileApi.Download + - StorageFileApi.DownloadPublicFile + storage.file_buckets.list_files: + status: implemented + symbols: + - StorageFileApi.List + storage.file_buckets.move: + status: implemented + symbols: + - StorageFileApi.Move + storage.file_buckets.copy: + status: implemented + symbols: + - StorageFileApi.Copy + storage.file_buckets.remove: + status: implemented + symbols: + - StorageFileApi.Remove + storage.file_buckets.get_public_url: + status: implemented + note: "Transform + download options present. Footgun: passing an empty TransformOptions() routes to the image-render endpoint instead of the plain object URL." + symbols: + - StorageFileApi.GetPublicUrl + storage.file_buckets.create_signed_url: + status: implemented + symbols: + - StorageFileApi.CreateSignedUrl + storage.file_buckets.create_signed_urls: + status: implemented + symbols: + - StorageFileApi.CreateSignedUrls + storage.file_buckets.create_signed_upload_url: + status: implemented + symbols: + - StorageFileApi.CreateUploadSignedUrl + storage.file_buckets.upload_with_signed_url: + status: implemented + symbols: + - StorageFileApi.UploadToSignedUrl + storage.file_buckets.update_file: + status: implemented + symbols: + - StorageFileApi.Update + storage.file_buckets.file_info: + status: implemented + symbols: + - StorageFileApi.Info + storage.file_buckets.download_with_transform: + status: implemented + note: "Image transforms applied inline via the TransformOptions argument on Download/DownloadPublicFile." + symbols: + - StorageFileApi.Download + storage.file_buckets.copy_cross_bucket: + status: implemented + symbols: + - StorageFileApi.Copy + - DestinationOptions.DestinationBucket + storage.file_buckets.move_cross_bucket: + status: implemented + symbols: + - StorageFileApi.Move + - DestinationOptions.DestinationBucket + storage.file_buckets.upload_with_metadata: + status: implemented + symbols: + - FileOptions.Metadata + - FileOptions.CacheControl + - FileOptions.ContentType \ No newline at end of file