chore: wire up SDK compliance checking#1518
Conversation
Adds the three files needed to integrate with the cross-SDK capability matrix (https://github.com/supabase/sdk): - sdk-compliance.yaml — declares implementation status for every feature in the canonical registry, with symbol names mapped to Python class methods so the parser can cross-reference them - sdk-parse-ignore — tells the Python API-surface parser to skip test directories and conftest files - .github/workflows/validate-capabilities.yml — calls the reusable validate-sdk-compliance workflow from supabase/sdk on every push to main and every PR The compliance file covers auth, database (postgrest), storage, realtime, functions, and client configuration. Notable gaps flagged as not_implemented: passkeys, OAuth server/admin APIs, several newer realtime features, and storage vector/analytics buckets. Part of SDK-991.
Use sdk-ref + the branch ref in `uses:` so the validate workflow picks up Python/griffe support from the in-flight supabase/sdk PR. Revert both to @main once SDK PR #36 is merged. Also rename sdk-parse-ignore → .sdk-parse-ignore to match the rename that landed in supabase/sdk#37.
Audit every implemented feature against the supabase-js reference to check behavioral parity, not just method existence. Corrections (wrong not_implemented status): - functions.invocation.region_selection: implemented via region key in invoke_options (FunctionRegion enum → x-region header) - client.authentication_integration.cross_client_token_sync: sub-clients lazily recreated with updated Authorization header on auth events; realtime.set_auth() called directly - realtime.subscriptions.private_channel: private config passed to server - realtime.subscriptions.broadcast_self: broadcast.self config passed to server - realtime.presence.presence_key: presence.key config passed to server Corrections (partial — config passes but behavior diverges from JS): - realtime.subscriptions.broadcast_ack: ack config sent to server but send_broadcast() does not await acknowledgment (JS does) - realtime.configuration.reconnect_backoff: fixed params only; JS accepts a custom reconnect function Symbol fix: - realtime.channel.send: renamed to send_broadcast in Python SDK Note improvements: - auth.session.auto_refresh: mention missing startAutoRefresh/stopAutoRefresh - database.mutate.select_after_mutation: clarify .select() chaining works for column selection after mutations, not just returning='representation'
Supabase no longer auto-grants public schema access to the anon and authenticated roles. Explicit GRANT statements are now required for tables and sequences to be reachable via the REST Data API. Mirrors the fix applied to supabase-swift in supabase/supabase-swift@8372c18. Ref: https://github.com/orgs/supabase/discussions/45329
All storage3 vector bucket and analytics features are fully implemented: - AsyncStorageVectorsClient/SyncStorageVectorsClient: create/list/delete bucket, from_() - AsyncVectorBucketScope/SyncVectorBucketScope: create/get/list/delete index, index() - AsyncVectorIndexScope/SyncVectorIndexScope: put/get/list/query/delete vectors; list() supports segment_count/segment_index for parallel scan - AsyncStorageAnalyticsClient/SyncStorageAnalyticsClient: create/list/delete bucket; catalog() returns pyiceberg RestCatalog covering iceberg_namespace and iceberg_table
- auth.admin.list_mfa_factors / delete_mfa_factor: real HTTP implementations are wired to admin.mfa.list_factors / delete_factor at construction time - auth.oauth_admin.*: all six operations (create/delete/get/list/regenerate_secret/update) are wired to admin.oauth.* at construction time and make real HTTP calls to admin/oauth/clients endpoints Passkeys, oauth_server, and provider admin features remain not_implemented (no code found in the codebase).
- auth.session.auto_refresh: implemented (no startAutoRefresh/stopAutoRefresh needed) - database filters not_in, like_all, like_any, ilike_all, ilike_any: all implemented - database max_affected_rows, request_cancellation, request_timeout: implemented - functions request_cancellation, timeout: implemented via asyncio - realtime broadcast_replay: implemented via broadcast config replay field - realtime custom_logger: not_applicable (Python uses stdlib logging)
| realtime.client.connection_state: | ||
| status: partially_implemented | ||
| note: "is_connected boolean property; no full connection-state enum exposed." | ||
| symbols: | ||
| - AsyncRealtimeClient.is_connected | ||
| - SyncRealtimeClient.is_connected |
There was a problem hiding this comment.
I don't think this should be a feature, as there is no explicit definition of all possible connection states, and this might be misleading to the end user.
There was a problem hiding this comment.
These should be connection states https://github.com/supabase/supabase-js/blob/master/packages/core/realtime-js/src/lib/constants.ts#L55
I do think this should be a canonical feature, the client should expose its current state.
WDYT?
There was a problem hiding this comment.
I think it only makes sense in the callback model where the client is "opaque" and control flow is hidden; in the iterator approach, it should be obvious what is the current state; ie. before running 'subscribe', its always disconnected, before leaving, its always disconnected, etc.
There was a problem hiding this comment.
It may not apply for v3 realtime, but currently it does make sense to have a way to get the connections state.
Summary
Integrates supabase-py with the cross-SDK capability matrix at supabase/sdk. On every push to
mainand every PR, CI will now:sdk-compliance.yamlagainst the canonical feature registryChanges
sdk-compliance.yaml— declares implementation status for all 195 features in the registry, with Python class/method symbols for cross-referencing (e.g.AsyncGoTrueClient.sign_up,AsyncBucketActionsMixin.upload).sdk-parse-ignore— tells the Python parser to skip test directories and conftest files.github/workflows/validate-capabilities.yml— calls the reusablevalidate-sdk-compliance.yml@mainworkflow from supabase/sdk withlanguage: pythonImplementation status highlights
admin.mfa.*admin.oauth.*select()chaining after insert/update/upsert/deletenot_invia.not_.in_(); rest viaBaseFilterRequestBuilder.cancel(); timeout viaasyncio.timeout()storage.vectors()→AsyncStorageVectorsClientstorage.analytics()→AsyncStorageAnalyticsClient+ pyicebergRestCatalogFunctionRegionenumrealtime.set_auth()send_broadcast()returns immediately without awaiting the ack (supabase-js awaits it)initial_backoff/max_retriesparams; supabase-js accepts a custom functionDepends on
Part of SDK-991.