better-supabase 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +187 -46
- package/dist/access-sql-B0dF-SoF.js +181 -0
- package/dist/{actor-DaJjqD5R.d.ts → actor-CQTlc1Hh.d.ts} +1 -1
- package/dist/adapter-Bc1o3zyy.js +1106 -0
- package/dist/agents-CVHGd7It.d.ts +94 -0
- package/dist/ai-cache-CBWs1W0k.js +80 -0
- package/dist/ai-cache-DaDu_G5L.d.ts +64 -0
- package/dist/ai-chat-7amvXjmQ.d.ts +590 -0
- package/dist/ai-chat-B24UI962.js +743 -0
- package/dist/ai-files-CSPNswUY.js +319 -0
- package/dist/ai-sdk/agents/index.d.ts +74 -0
- package/dist/ai-sdk/agents/index.js +159 -0
- package/dist/ai-sdk/batches/index.d.ts +74 -0
- package/dist/ai-sdk/batches/index.js +180 -0
- package/dist/ai-sdk/cache/index.d.ts +38 -0
- package/dist/ai-sdk/cache/index.js +127 -0
- package/dist/ai-sdk/chat/index.d.ts +2 -0
- package/dist/ai-sdk/chat/index.js +246 -0
- package/dist/ai-sdk/embeddings/index.d.ts +3 -0
- package/dist/ai-sdk/embeddings/index.js +2 -0
- package/dist/ai-sdk/files/index.d.ts +61 -0
- package/dist/ai-sdk/files/index.js +111 -0
- package/dist/ai-sdk/index.d.ts +145 -0
- package/dist/ai-sdk/index.js +174 -0
- package/dist/ai-sdk/mcp/index.d.ts +102 -0
- package/dist/ai-sdk/mcp/index.js +362 -0
- package/dist/ai-sdk/memory/index.d.ts +67 -0
- package/dist/ai-sdk/memory/index.js +175 -0
- package/dist/ai-sdk/react/index.d.ts +2 -0
- package/dist/ai-sdk/react/index.js +3 -0
- package/dist/ai-sdk/react/server.d.ts +6 -0
- package/dist/ai-sdk/react/server.js +7 -0
- package/dist/ai-sdk/workflow/index.d.ts +249 -0
- package/dist/ai-sdk/workflow/index.js +575 -0
- package/dist/ai-sdk/workflow/react/index.d.ts +20 -0
- package/dist/ai-sdk/workflow/react/index.js +66 -0
- package/dist/ai-sdk/workflow/react/server.d.ts +10 -0
- package/dist/ai-sdk/workflow/react/server.js +12 -0
- package/dist/ai-tasks-Cd1HMFvB.d.ts +131 -0
- package/dist/announcements-CiyOs-xP.js +107 -0
- package/dist/announcements-ZRGnScWI.d.ts +72 -0
- package/dist/api-keys-rCGtKaZA.d.ts +156 -0
- package/dist/assistant-DwdpDH1q.d.ts +147 -0
- package/dist/astro/index.d.ts +86 -0
- package/dist/astro/index.js +93 -0
- package/dist/attributes-5dYul0u0.js +13 -0
- package/dist/auth-link-BjFPqwLz.d.ts +97 -0
- package/dist/auth-link-DrDX9KOT.js +114 -0
- package/dist/authorization-BFCqamMs.d.ts +172 -0
- package/dist/before-route-CnR0C0Jr.js +30 -0
- package/dist/bind-Bu_ZNa3W.d.ts +62 -0
- package/dist/bind-l4kAvYSv.js +97 -0
- package/dist/block-events-CrT8r7Fe.js +76 -0
- package/dist/block-fields-GFkxl4dP.js +49 -0
- package/dist/block-fields-SJ6fEf3o.d.ts +31 -0
- package/dist/block-helpers-CKtbFcRv.d.ts +37 -0
- package/dist/block-helpers-DWHxHsEQ.js +190 -0
- package/dist/block-hooks-BmjMyXTa.js +114 -0
- package/dist/block-hooks-plbZ0AbJ.d.ts +107 -0
- package/dist/{kit-transport-DJlHQUBU.js → block-transport-BLr-ZgLc.js} +11 -7
- package/dist/block-transport-DvaoPuZ9.d.ts +48 -0
- package/dist/blocks/agents/index.d.ts +3 -0
- package/dist/blocks/agents/index.js +123 -0
- package/dist/blocks/ai-cache/index.d.ts +3 -0
- package/dist/blocks/ai-cache/index.js +3 -0
- package/dist/blocks/ai-chat/index.d.ts +31 -0
- package/dist/blocks/ai-chat/index.js +5 -0
- package/dist/blocks/ai-chat/react/index.d.ts +77 -0
- package/dist/blocks/ai-chat/react/index.js +387 -0
- package/dist/blocks/ai-chat/react/server.d.ts +16 -0
- package/dist/blocks/ai-chat/react/server.js +14 -0
- package/dist/blocks/ai-files/index.d.ts +14 -0
- package/dist/blocks/ai-files/index.js +3 -0
- package/dist/blocks/ai-providers/index.d.ts +7 -0
- package/dist/blocks/ai-providers/index.js +211 -0
- package/dist/blocks/ai-tasks/index.d.ts +3 -0
- package/dist/blocks/ai-tasks/index.js +203 -0
- package/dist/blocks/announcements/index.d.ts +3 -0
- package/dist/blocks/announcements/index.js +3 -0
- package/dist/blocks/announcements/react/index.d.ts +31 -0
- package/dist/blocks/announcements/react/index.js +86 -0
- package/dist/blocks/announcements/react/server.d.ts +6 -0
- package/dist/blocks/announcements/react/server.js +7 -0
- package/dist/blocks/api-keys/index.d.ts +35 -0
- package/dist/blocks/api-keys/index.js +334 -0
- package/dist/blocks/attachments/index.d.ts +210 -0
- package/dist/blocks/attachments/index.js +222 -0
- package/dist/blocks/audit/index.d.ts +366 -0
- package/dist/blocks/audit/index.js +714 -0
- package/dist/blocks/billing/index.d.ts +265 -0
- package/dist/blocks/billing/index.js +400 -0
- package/dist/blocks/comments/index.d.ts +200 -0
- package/dist/blocks/comments/index.js +207 -0
- package/dist/blocks/connectors/index.d.ts +3 -0
- package/dist/blocks/connectors/index.js +164 -0
- package/dist/blocks/data-lifecycle/index.d.ts +251 -0
- package/dist/blocks/data-lifecycle/index.js +353 -0
- package/dist/blocks/entitlements/index.d.ts +14 -0
- package/dist/blocks/entitlements/index.js +25 -0
- package/dist/blocks/flags/index.d.ts +226 -0
- package/dist/blocks/flags/index.js +282 -0
- package/dist/blocks/inbox/index.d.ts +6 -0
- package/dist/blocks/inbox/index.js +499 -0
- package/dist/blocks/inbox/react/index.d.ts +2 -0
- package/dist/blocks/inbox/react/index.js +225 -0
- package/dist/blocks/inbox/react/server.d.ts +10 -0
- package/dist/blocks/inbox/react/server.js +12 -0
- package/dist/blocks/index.d.ts +65 -0
- package/dist/blocks/index.js +77 -0
- package/dist/blocks/jobs/index.d.ts +297 -0
- package/dist/blocks/jobs/index.js +1051 -0
- package/dist/blocks/knowledge/index.d.ts +3 -0
- package/dist/blocks/knowledge/index.js +3 -0
- package/dist/blocks/memory/index.d.ts +8 -0
- package/dist/blocks/memory/index.js +289 -0
- package/dist/blocks/notifications/index.d.ts +297 -0
- package/dist/blocks/notifications/index.js +425 -0
- package/dist/blocks/notifications/react/index.d.ts +44 -0
- package/dist/blocks/notifications/react/index.js +67 -0
- package/dist/blocks/notifications/react/server.d.ts +6 -0
- package/dist/blocks/notifications/react/server.js +7 -0
- package/dist/blocks/onboarding/index.d.ts +3 -0
- package/dist/blocks/onboarding/index.js +64 -0
- package/dist/blocks/onboarding/react/index.d.ts +28 -0
- package/dist/blocks/onboarding/react/index.js +78 -0
- package/dist/blocks/onboarding/react/server.d.ts +7 -0
- package/dist/blocks/onboarding/react/server.js +7 -0
- package/dist/blocks/organizations/index.d.ts +241 -0
- package/dist/blocks/organizations/index.js +400 -0
- package/dist/blocks/outbox/index.d.ts +3 -0
- package/dist/blocks/outbox/index.js +266 -0
- package/dist/blocks/profiles/index.d.ts +40 -0
- package/dist/blocks/profiles/index.js +28 -0
- package/dist/blocks/push/index.d.ts +185 -0
- package/dist/blocks/push/index.js +258 -0
- package/dist/blocks/settings/index.d.ts +89 -0
- package/dist/blocks/settings/index.js +104 -0
- package/dist/blocks/sso/index.d.ts +198 -0
- package/dist/blocks/sso/index.js +1297 -0
- package/dist/blocks/usage/index.d.ts +4 -0
- package/dist/blocks/usage/index.js +233 -0
- package/dist/blocks/waitlist/index.d.ts +117 -0
- package/dist/blocks/waitlist/index.js +132 -0
- package/dist/blocks/webhooks/index.d.ts +304 -0
- package/dist/{webhooks → blocks/webhooks}/index.js +468 -148
- package/dist/blocks/workflow-builder/index.d.ts +21 -0
- package/dist/blocks/workflow-builder/index.js +5 -0
- package/dist/blocks/workflow-builder/react/index.d.ts +47 -0
- package/dist/blocks/workflow-builder/react/index.js +119 -0
- package/dist/blocks/workflow-builder/react/server.d.ts +8 -0
- package/dist/blocks/workflow-builder/react/server.js +11 -0
- package/dist/blocks/workflows/index.d.ts +3 -0
- package/dist/blocks/workflows/index.js +3 -0
- package/dist/blocks/workflows/react/index.d.ts +47 -0
- package/dist/blocks/workflows/react/index.js +137 -0
- package/dist/blocks/workflows/react/server.d.ts +8 -0
- package/dist/blocks/workflows/react/server.js +11 -0
- package/dist/{index-SaTsEfGP.d.ts → bucket-Cl46E3jS.d.ts} +134 -91
- package/dist/{simplify-_0oUKqCd.js → build-BXIzE6Xv.js} +222 -124
- package/dist/{channel-FQW-CnGR.d.ts → channel-_2Mx1Oyu.d.ts} +2 -2
- package/dist/channels-CkgQ_X60.js +114 -0
- package/dist/chat-sdk/index.d.ts +303 -0
- package/dist/chat-sdk/index.js +733 -0
- package/dist/chat-sdk/react/index.d.ts +2 -0
- package/dist/chat-sdk/react/index.js +3 -0
- package/dist/chat-sdk/react/server.d.ts +3 -0
- package/dist/chat-sdk/react/server.js +2 -0
- package/dist/claims-DDBQT6BK.js +61 -0
- package/dist/{claims-BAf6c7is.js → claims-PqzCxaTD.js} +39 -2
- package/dist/cli/bin.js +1 -1
- package/dist/cli/{codemod-DqV7612m.js → codemod-Bl_tQpHn.js} +105 -2
- package/dist/cli/config-B9HkL8nF.js +2 -0
- package/dist/cli/config-DU7EJImt.js +49 -0
- package/dist/cli/config-NiPxAmUF.js +1077 -0
- package/dist/cli/{dist-xn4wlboc.js → dist-DRAVaE6w.js} +111 -1
- package/dist/cli/{doctor-C_A-KEAz.js → doctor-B4JOm_ox.js} +991 -317
- package/dist/cli/{env-DmKv_G4A.js → env-CJLbUVPB.js} +1 -1
- package/dist/cli/{env-jIFUADLY.js → env-qXgyMV6r.js} +2 -2
- package/dist/cli/fresh-import-BeYf9I3x.js +40 -0
- package/dist/cli/gen-BGLb_zou.js +3100 -0
- package/dist/cli/gen-DAH8FM2W.js +2 -0
- package/dist/cli/index.d.ts +44 -5
- package/dist/cli/index.js +7 -7
- package/dist/cli/{init-DMa6M7hV.js → init-BIIwclPg.js} +242 -27
- package/dist/cli/{introspect-BKlaIu_M.js → introspect-DNUTuNvb.js} +5 -5
- package/dist/cli/{io-k41_z-jT.js → io-DI1mTdSA.js} +12 -3
- package/dist/cli/{keys-ByKHnvP9.js → keys-BGCnnb-s.js} +8 -6
- package/dist/cli/{ohash-D7bG_EOb.js → ohash-BjQY1cBb.js} +1 -1
- package/dist/cli/{openapi-Cp5Fyta-.js → openapi-BlRJ18s3.js} +2 -2
- package/dist/cli/{project-B_GeXyHh.js → project-DZRaBaY7.js} +11 -6
- package/dist/cli/read-sets-CETOSFx4.js +223 -0
- package/dist/cli/{run-Bo_NLT5n.js → run-DNWxHynX.js} +33 -23
- package/dist/cli/{seed-CUlqWh-8.js → seed-DQzqT7LP.js} +8 -6
- package/dist/cli/{skills-LJJIhLFR.js → skills-QQs4q68J.js} +3 -2
- package/dist/cli/sql-D0GUtUPp.js +536 -0
- package/dist/cli/{config-CPVpXP5I.js → supabase-toml-B-bIukQF.js} +72 -942
- package/dist/cli/typegen-version-DeFbtzYI.js +8 -0
- package/dist/cli/{version-BCtlgDQx.js → version-hr88OZG0.js} +1 -1
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.js +11 -71
- package/dist/client/native/index.d.ts +228 -0
- package/dist/client/native/index.js +361 -0
- package/dist/client-CI0Z2zWX.js +277 -0
- package/dist/cloud-event-BnmD5fb9.js +46 -0
- package/dist/cloud-event-C1JCc1bH.d.ts +50 -0
- package/dist/{compiler-BXH_aZ7N.d.ts → compiler-DY_wkj4R.d.ts} +2 -2
- package/dist/compose-BIBNgAnq.js +53 -0
- package/dist/composite-Bt1YK3Ke.d.ts +146 -0
- package/dist/composite-DhE66P5u.js +130 -0
- package/dist/config/index.d.ts +6 -4
- package/dist/config/index.js +5 -5
- package/dist/{config-Bv7gvfzC.d.ts → config-D44Y7PAv.d.ts} +406 -214
- package/dist/{config-DreERlKo.js → config-Dn7F5k9A.js} +62 -14
- package/dist/connector-Dv8kK0MO.d.ts +107 -0
- package/dist/connectors-hkLCwyEz.d.ts +120 -0
- package/dist/context-BCrWe7ow.d.ts +237 -0
- package/dist/credentials/index.d.ts +31 -0
- package/dist/credentials/index.js +168 -0
- package/dist/cron-DVPUg5k3.js +145 -0
- package/dist/csv-CPAzEmB6.js +25 -0
- package/dist/db-exception-CnWcYPxL.js +15 -0
- package/dist/{define-cNKzqwL_.js → define-B-TVjC25.js} +784 -227
- package/dist/{define-Bp_BZa5h.d.ts → define-CJJkkr1-.d.ts} +353 -61
- package/dist/edge/index.d.ts +69 -11
- package/dist/edge/index.js +191 -75
- package/dist/elysia/index.d.ts +59 -0
- package/dist/elysia/index.js +62 -0
- package/dist/embeddings-4ZvFzjsU.js +127 -0
- package/dist/embeddings-C9KGQnXt.d.ts +68 -0
- package/dist/{refresh-CFPX0Qft.d.ts → ended-jLfvw8h-.d.ts} +20 -2
- package/dist/{entitlements-BiJZ4t49.d.ts → entitlements-DHrY2UDZ.d.ts} +16 -7
- package/dist/entitlements-DRl6ZJUm.js +24 -0
- package/dist/envelope-DqnYGRw7.js +47 -0
- package/dist/{errors-DtwXa6b8.js → errors-B11Duf73.js} +82 -13
- package/dist/errors-DLjJHPLK.js +44 -0
- package/dist/escape-like-DHfx6jRr.js +7 -0
- package/dist/escape-like-ImTK0ps_.d.ts +15 -0
- package/dist/eve/index.d.ts +220 -0
- package/dist/eve/index.js +504 -0
- package/dist/eve-gT2Fpjut.d.ts +151 -0
- package/dist/events/index.d.ts +4 -3
- package/dist/events/index.js +9 -50
- package/dist/events-DWDhx77e.d.ts +549 -0
- package/dist/executor-Bq28caBo.js +718 -0
- package/dist/executor-C-R4pucm.js +83 -0
- package/dist/executor-CaWigTyR.d.ts +148 -0
- package/dist/executor-D14tGopJ.d.ts +36 -0
- package/dist/{executor-Cghdstwu.d.ts → executor-DbvExCFC.d.ts} +7 -1
- package/dist/{sql-Coh6n4cC.js → executor-De1Of3m3.js} +210 -11
- package/dist/executor-DvsBbNBS.d.ts +261 -0
- package/dist/expo/index.d.ts +79 -0
- package/dist/expo/index.js +129 -0
- package/dist/expo-sqlite/index.d.ts +58 -0
- package/dist/expo-sqlite/index.js +104 -0
- package/dist/field-errors-BFOa7WhB.d.ts +99 -0
- package/dist/field-errors-VF1yb8yI.js +13 -0
- package/dist/framework-CONDyPYx.js +51 -0
- package/dist/framework-DuVb4Xa8.d.ts +25 -0
- package/dist/gateway-C1ssRHnf.d.ts +130 -0
- package/dist/graph-BGyLLFLX.js +265 -0
- package/dist/h3/index.d.ts +59 -0
- package/dist/h3/index.js +55 -0
- package/dist/h3/v1/index.d.ts +63 -0
- package/dist/h3/v1/index.js +49 -0
- package/dist/history-BZih6SFP.js +64 -0
- package/dist/hono/index.d.ts +56 -7
- package/dist/hono/index.js +97 -45
- package/dist/{react-C_s7kiNz.js → hooks-1BTCJsiw.js} +104 -133
- package/dist/http-Cv4T29xh.js +40 -0
- package/dist/http-DdYadv-o.js +126 -0
- package/dist/image-url-pIVlO6R1.js +41 -0
- package/dist/{impersonation-BgSHAYLf.js → impersonation-DcqaTBHx.js} +21 -6
- package/dist/inbox-i7E1ppo6.d.ts +384 -0
- package/dist/index-ACiNPN4Z.d.ts +74 -0
- package/dist/{index-DgILJRXj.d.ts → index-Bepi-Hgg.d.ts} +91 -28
- package/dist/index-BkWT_uBO.d.ts +51 -0
- package/dist/index-BpFYMsi0.d.ts +53 -0
- package/dist/{index-C7f8cOBM.d.ts → index-Bxih3l0u.d.ts} +2 -2
- package/dist/index-CaxrMD1A.d.ts +1 -0
- package/dist/index-ClmjK_o-.d.ts +55 -0
- package/dist/index-CtuakVRc.d.ts +267 -0
- package/dist/index-D48jVS-N.d.ts +246 -0
- package/dist/index-DDrYaUcq.d.ts +138 -0
- package/dist/index-DQh4VCc9.d.ts +98 -0
- package/dist/{live-D9W2M5aO.d.ts → index-DunNRdnT.d.ts} +136 -38
- package/dist/index.d.ts +65 -18
- package/dist/index.js +42 -14
- package/dist/invalidate-BBqhpxyB.d.ts +19 -0
- package/dist/json-CEnpTHlZ.js +16 -0
- package/dist/json-schema-CvER4kgT.js +502 -0
- package/dist/keys-4MnkWTTh.js +35 -0
- package/dist/kit-B5tid-q5.d.ts +60 -0
- package/dist/kit-Fm-Fv7q5.js +78 -0
- package/dist/knowledge-BXBbT0Tr.d.ts +176 -0
- package/dist/knowledge-CDmiMLew.js +255 -0
- package/dist/lint/index.d.ts +1 -1
- package/dist/lint/index.js +37 -0
- package/dist/list/index.d.ts +3 -2
- package/dist/list/index.js +1 -444
- package/dist/{index-fag8VJZ2.d.ts → list-query-BRt-zDF7.d.ts} +20 -12
- package/dist/list-query-gl808ac1.js +459 -0
- package/dist/{live-CdJBOc4f.js → live-CTAZQkwl.js} +99 -14
- package/dist/logger-DWVYUmwi.d.ts +18 -0
- package/dist/mcp/index.d.ts +38 -11
- package/dist/mcp/index.js +82 -46
- package/dist/mcp/sdk/index.d.ts +105 -0
- package/dist/mcp/sdk/index.js +126 -0
- package/dist/message-CaKlqdsX.js +219 -0
- package/dist/message-CfDoR0Y6.d.ts +94 -0
- package/dist/messages-B9-5887d.js +715 -0
- package/dist/messages-DYP0sUTe.d.ts +59 -0
- package/dist/mfa-Daak8ukG.d.ts +54 -0
- package/dist/modules-DpPwzC7E.d.ts +192 -0
- package/dist/modules-dxrVK3ID.js +228 -0
- package/dist/nestjs/index.d.ts +68 -0
- package/dist/nestjs/index.js +164 -0
- package/dist/next/client/index.d.ts +35 -0
- package/dist/next/client/index.js +36 -0
- package/dist/next/image/index.js +3 -24
- package/dist/next/index.d.ts +150 -51
- package/dist/next/index.js +261 -107
- package/dist/node/index.d.ts +4 -0
- package/dist/node/index.js +210 -0
- package/dist/node-headers-AO06VhqH.d.ts +24 -0
- package/dist/node-headers-C71zNQHe.js +55 -0
- package/dist/nuxt/index.d.ts +60 -0
- package/dist/nuxt/index.js +64 -0
- package/dist/onboarding-BZGHYJks.d.ts +62 -0
- package/dist/openapi/index.d.ts +1 -1
- package/dist/openapi/index.js +3 -3
- package/dist/orpc/index.d.ts +70 -11
- package/dist/orpc/index.js +73 -24
- package/dist/otel/index.d.ts +7 -7
- package/dist/otel/index.js +87 -57
- package/dist/outbox-Cq7pPYvl.d.ts +161 -0
- package/dist/{plugin-o144f322.d.ts → plugin-FGY8UhYm.d.ts} +30 -10
- package/dist/plugin-tfXW1-qO.js +45 -0
- package/dist/plugins/actor/index.d.ts +2 -2
- package/dist/plugins/actor/index.js +3 -3
- package/dist/plugins/rules/index.d.ts +11 -4
- package/dist/plugins/rules/index.js +40 -13
- package/dist/plugins/soft-delete/index.d.ts +5 -4
- package/dist/plugins/soft-delete/index.js +10 -5
- package/dist/plugins/tenant/index.d.ts +2 -2
- package/dist/plugins/tenant/index.js +18 -11
- package/dist/plugins/timestamps/index.d.ts +5 -3
- package/dist/plugins/timestamps/index.js +6 -4
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +10 -6
- package/dist/{pool-C9voM4Kw.d.ts → pool-CAu2nLrL.d.ts} +2 -2
- package/dist/postgres/index.d.ts +4 -4
- package/dist/postgres/index.js +1 -2
- package/dist/{postgrest-CruYKAvV.d.ts → postgrest-BLVdEnfe.d.ts} +13 -3
- package/dist/powersync/index.d.ts +43 -0
- package/dist/powersync/index.js +199 -0
- package/dist/powersync/react/index.d.ts +87 -0
- package/dist/powersync/react/index.js +108 -0
- package/dist/{problem-BW1KhzSG.js → problem-BreOl8b8.js} +14 -3
- package/dist/{problem-Blxe8S31.d.ts → problem-DD8LZFjc.d.ts} +21 -3
- package/dist/provider-BH5UWZJ6.d.ts +113 -0
- package/dist/provider-Di3sRutW.js +57 -0
- package/dist/query/index.d.ts +4 -2
- package/dist/query/index.js +4 -3
- package/dist/{query-CCbo44lG.js → query-BQ-NaZon.js} +141 -24
- package/dist/{queue-BYUCjr59.d.ts → queue-CLJurhdy.d.ts} +258 -83
- package/dist/react/index.d.ts +11 -7
- package/dist/react/index.js +7 -3
- package/dist/react/native/index.d.ts +116 -0
- package/dist/react/native/index.js +130 -0
- package/dist/react/server.d.ts +28 -10
- package/dist/react/server.js +22 -5
- package/dist/react/session.d.ts +2 -2
- package/dist/react-4ZqkP8da.js +79 -0
- package/dist/react-F80mF4-t.js +409 -0
- package/dist/react-router/index.d.ts +83 -0
- package/dist/react-router/index.js +89 -0
- package/dist/react-topic-seAWjL3_.js +38 -0
- package/dist/{read-set-DQFt1N_Y.js → read-set-DuKWC9Mj.js} +67 -25
- package/dist/realtime/index.d.ts +4 -5
- package/dist/realtime/index.js +144 -82
- package/dist/refusal-CeJWxmkH.js +61 -0
- package/dist/refusal-D1rgbzNq.d.ts +15 -0
- package/dist/replicas-CwrYp5Zj.js +94 -0
- package/dist/{view-Bn6HNKUe.js → resolve-D_IcnvFd.js} +248 -240
- package/dist/{impersonation-BmePsuxz.d.ts → resolve-KW8nCeL6.d.ts} +29 -69
- package/dist/{resource-mqfJW4YF.js → resource-BsvzCMlX.js} +4 -4
- package/dist/{resource-DNRFP7KR.d.ts → resource-D6Uc7Sk7.d.ts} +5 -5
- package/dist/respond-BUgsXNgk.js +91 -0
- package/dist/respond-DoBijysA.d.ts +93 -0
- package/dist/result-D7y2fT87.d.ts +282 -0
- package/dist/{result-BKiliPY7.js → result-DzUbqgdW.js} +27 -2
- package/dist/run-state-CPo-1X2B.d.ts +12 -0
- package/dist/run-state-CgBKzYMW.js +13 -0
- package/dist/search-CUWCRYKL.js +9 -0
- package/dist/server/index.d.ts +143 -22
- package/dist/server/index.js +46 -14
- package/dist/{respond-BR1fJWOB.d.ts → server-CeVeeXwz.d.ts} +224 -85
- package/dist/session-ChiXDZdZ.d.ts +72 -0
- package/dist/shared-CBxosKK3.js +75 -0
- package/dist/{shared-D1dRUrAg.js → shared-CxWmcyqB.js} +2 -1
- package/dist/shared-DDSjEGDR.d.ts +11 -0
- package/dist/sign-in-BCV5S2WZ.d.ts +49 -0
- package/dist/sign-in-Cb1mwv6X.js +86 -0
- package/dist/{signers-Cc6r98SW.d.ts → signers-4y62_VIi.d.ts} +13 -9
- package/dist/simplify-DDO0j0LI.js +83 -0
- package/dist/solid/index.d.ts +131 -0
- package/dist/solid/index.js +344 -0
- package/dist/solid-start/index.d.ts +75 -0
- package/dist/solid-start/index.js +58 -0
- package/dist/{spec-pins-C3oc-Tdp.js → spec-pins--j6mTok4.js} +8 -1
- package/dist/{spec-pins-CqorWDnO.d.ts → spec-pins-C89s6DyW.d.ts} +7 -0
- package/dist/sql/index.d.ts +313 -212
- package/dist/sql/index.js +34872 -6579
- package/dist/ssr/index.d.ts +6 -5
- package/dist/ssr/index.js +3 -3
- package/dist/{standard-D7r6dMUu.js → standard-BK0cqJ7y.js} +4 -3
- package/dist/{standard-J4YgMOLm.d.ts → standard-CYsm7xpT.d.ts} +1 -1
- package/dist/stats-D_AD9GGu.js +1123 -0
- package/dist/storage/index.d.ts +5 -5
- package/dist/storage/index.js +1027 -368
- package/dist/store-BdH5ruDx.js +66 -0
- package/dist/store-CGjgWu5n.d.ts +68 -0
- package/dist/streams/index.d.ts +76 -0
- package/dist/streams/index.js +77 -0
- package/dist/streams/redis/index.d.ts +52 -0
- package/dist/streams/redis/index.js +185 -0
- package/dist/stripe-BMj5LtsT.js +38 -0
- package/dist/stripe-D04h-QBT.d.ts +136 -0
- package/dist/{support-wHnK6zp-.js → support-BivNqSpK.js} +32 -11
- package/dist/{support-view-B8SlToQX.d.ts → support-view-33Oi07TT.d.ts} +1 -1
- package/dist/svelte/index.d.ts +114 -0
- package/dist/svelte/index.js +344 -0
- package/dist/sveltekit/index.d.ts +116 -0
- package/dist/sveltekit/index.js +106 -0
- package/dist/tags-B99_U9Pp.js +39 -0
- package/dist/tags-Cx-LnIQP.d.ts +30 -0
- package/dist/tanstack-db/index.d.ts +71 -0
- package/dist/tanstack-db/index.js +72 -0
- package/dist/tanstack-start/index.d.ts +75 -0
- package/dist/tanstack-start/index.js +95 -0
- package/dist/tee-CoEppCER.js +101 -0
- package/dist/{template-TxrGI5jR.js → template--jDkl3UP.js} +34 -13
- package/dist/template-CwO38Do8.d.ts +6 -0
- package/dist/temporal-BJGitm-h.js +79 -0
- package/dist/{temporal-required-CAt4Dc9Z.js → temporal-required-BVvW7SYJ.js} +3 -2
- package/dist/tenant-I1TEZ_BX.js +27 -0
- package/dist/tenant-icPeuUBN.d.ts +17 -0
- package/dist/testing/index.d.ts +315 -41
- package/dist/testing/index.js +1046 -79
- package/dist/timing-CyTQPubY.js +92 -0
- package/dist/ttl-Hr34gRu8.js +12 -0
- package/dist/{types-Dnf_wRDz.d.ts → types-6BdhkmZe.d.ts} +111 -45
- package/dist/types-BI-0Sl2v.d.ts +359 -0
- package/dist/types-C05bxW-W.d.ts +220 -0
- package/dist/types-DGs5L0VN.d.ts +192 -0
- package/dist/types-TaiEeBGA.d.ts +156 -0
- package/dist/usage-CrvrL2vw.d.ts +177 -0
- package/dist/user-change-XzvgafU4.js +130 -0
- package/dist/vault-CSO7ss5C.d.ts +50 -0
- package/dist/vercel-connect/index.d.ts +47 -0
- package/dist/vercel-connect/index.js +119 -0
- package/dist/{verify-Ce49ETPz.js → verify-DL41hbvY.js} +85 -13
- package/dist/verify-DPuWngD4.d.ts +172 -0
- package/dist/{version-DOYTYwHP.js → version-Bvv6aLjZ.js} +1 -1
- package/dist/view-BeFcRV6G.js +99 -0
- package/dist/{view-CbgObAeb.d.ts → view-DbxLNu8L.d.ts} +22 -5
- package/dist/vue/index.d.ts +141 -0
- package/dist/vue/index.js +362 -0
- package/dist/watch-DI34G86j.d.ts +60 -0
- package/dist/watch-Xuxrvxq-.js +122 -0
- package/dist/{wire-D2dT86vi.js → wire-DtZQ4sdE.js} +15 -5
- package/dist/workflow-builder-DJ1oHn8g.js +398 -0
- package/dist/workflow-sdk/builder/index.d.ts +85 -0
- package/dist/workflow-sdk/builder/index.js +250 -0
- package/dist/workflow-sdk/index.d.ts +14 -0
- package/dist/workflow-sdk/index.js +3 -0
- package/dist/workflow-sdk/world/index.d.ts +107 -0
- package/dist/workflow-sdk/world/index.js +702 -0
- package/dist/workflow-sdk-B3yLD6Br.d.ts +98 -0
- package/dist/workflow-sdk-C2WJ_G2O.js +173 -0
- package/dist/workflow-sdk-world-D-prir6O.js +1397 -0
- package/dist/workflows-B0j9WKPu.d.ts +185 -0
- package/dist/workflows-wu1WWBn7.js +216 -0
- package/package.json +461 -20
- package/schemas/ai-message-v1.json +258 -0
- package/schemas/config-v1.json +1074 -140
- package/schemas/doctor-report-v1.json +20 -1
- package/schemas/snapshot-v2.json +8 -0
- package/skills/better-supabase/SKILL.md +41 -12
- package/skills/better-supabase/references/frontend.md +96 -0
- package/skills/better-supabase/references/plugins.md +10 -6
- package/skills/better-supabase/references/troubleshooting.md +2 -1
- package/skills/better-supabase-api/SKILL.md +76 -22
- package/skills/better-supabase-api/references/adapters.md +207 -0
- package/skills/better-supabase-api/references/ai.md +125 -0
- package/skills/better-supabase-api/references/expo.md +65 -0
- package/skills/better-supabase-api/references/powersync.md +35 -0
- package/skills/better-supabase-api/references/streams-credentials.md +105 -0
- package/skills/better-supabase-auth/SKILL.md +47 -11
- package/skills/better-supabase-auth/references/authorization-providers.md +51 -0
- package/skills/better-supabase-testing/SKILL.md +3 -1
- package/dist/cli/config-dtoekM0v.js +0 -2
- package/dist/cli/gen-CIdSQZad.js +0 -2
- package/dist/cli/gen-CjElD1Vw.js +0 -2241
- package/dist/cli/read-sets-VQcPgxU9.js +0 -436
- package/dist/cli/sql-CVx-1O8G.js +0 -373
- package/dist/entitlements-CTEBm7IB.js +0 -20
- package/dist/events-aIO7vsIk.d.ts +0 -230
- package/dist/executor-BunPOO-k.d.ts +0 -402
- package/dist/executor-XycESQPH.js +0 -94
- package/dist/index-CWMDdEr4.d.ts +0 -50
- package/dist/index-DOESKG27.d.ts +0 -100
- package/dist/index-DmXSxbLi.d.ts +0 -62
- package/dist/index-Dp2VDwog.d.ts +0 -161
- package/dist/jobs/index.d.ts +0 -226
- package/dist/jobs/index.js +0 -1007
- package/dist/json-schema-m1fiwKgN.js +0 -208
- package/dist/kit-events-CTFDfSwb.js +0 -60
- package/dist/kit-transport-B82k1djG.d.ts +0 -33
- package/dist/kits-CGLLrNPd.js +0 -157
- package/dist/mfa-Cu96oJdw.d.ts +0 -30
- package/dist/notifications/index.d.ts +0 -162
- package/dist/notifications/index.js +0 -264
- package/dist/orgs/index.d.ts +0 -132
- package/dist/orgs/index.js +0 -245
- package/dist/permdock-sql-C2Inc6Xc.d.ts +0 -29
- package/dist/permdock-sql-DgOfeixi.js +0 -51
- package/dist/plugin-DwARMuQp.js +0 -59
- package/dist/server-B1mZ7CgQ.js +0 -660
- package/dist/stats-Bqob3WqT.js +0 -592
- package/dist/support-CEPwlw2G.d.ts +0 -89
- package/dist/template-mbvlysOo.d.ts +0 -6
- package/dist/temporal-CVlIV2DZ.js +0 -40
- package/dist/user-change-CHFEUro1.js +0 -49
- package/dist/webhooks/index.d.ts +0 -285
- package/skills/better-supabase-auth/references/permdock.md +0 -122
|
@@ -82,6 +82,25 @@ export const router = {
|
|
|
82
82
|
};
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
For a contract from `@orpc/contract`, use the same middleware on the
|
|
86
|
+
implementer and serve it with `OpenAPIHandler`, so errors keep their HTTP
|
|
87
|
+
status (RLS denials answer 403):
|
|
88
|
+
|
|
89
|
+
```ts title="src/server.ts"
|
|
90
|
+
const os = implement(contract)
|
|
91
|
+
.$context<OrpcRequestContext>()
|
|
92
|
+
.use(bs.middleware());
|
|
93
|
+
const router = os.router({
|
|
94
|
+
customers: {
|
|
95
|
+
get: os.customers.get.handler(({ context, input }) =>
|
|
96
|
+
bs.unwrap(context.db.customers.findById(input.id)),
|
|
97
|
+
),
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
const handle = bs.fetchHandler(new OpenAPIHandler(router), { prefix: "/api" });
|
|
101
|
+
const app = new Hono().all("/api/*", (c) => handle(c.req.raw));
|
|
102
|
+
```
|
|
103
|
+
|
|
85
104
|
## Edge Functions
|
|
86
105
|
|
|
87
106
|
```ts title="supabase/functions/api/index.ts"
|
|
@@ -96,6 +115,152 @@ Deno.serve(
|
|
|
96
115
|
);
|
|
97
116
|
```
|
|
98
117
|
|
|
118
|
+
## Middleware entries and bridges
|
|
119
|
+
|
|
120
|
+
`withBetterSupabase(server, { allow })` from `better-supabase/server` is one
|
|
121
|
+
`@supabase/middleware` entry: it resolves the caller, guards, and contributes
|
|
122
|
+
`bs`, `db`, `sql`, `jwtClaims`, `userClaims` and `authMode`. Put
|
|
123
|
+
`withPostgresClient` or `withCors` next to it, then run the array with the
|
|
124
|
+
bridge for the framework:
|
|
125
|
+
|
|
126
|
+
```ts title="src/hooks.server.ts"
|
|
127
|
+
import { createServer, withBetterSupabase } from "better-supabase/server";
|
|
128
|
+
import { toSvelteKit } from "better-supabase/sveltekit";
|
|
129
|
+
|
|
130
|
+
import { betterSupabase } from "$lib/supabase";
|
|
131
|
+
|
|
132
|
+
export const handle = toSvelteKit([
|
|
133
|
+
withBetterSupabase(createServer(betterSupabase), {
|
|
134
|
+
refresh: true,
|
|
135
|
+
allow: ["user", "anon"],
|
|
136
|
+
}),
|
|
137
|
+
]);
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
| Framework | Bridge | Where the keys land |
|
|
141
|
+
| ------------------- | -------------------------------------------------- | --------------------------------------------------- |
|
|
142
|
+
| Hono | `toHono(entries)` from `better-supabase/hono` | `c.var` |
|
|
143
|
+
| Edge, Deno, Workers | `toEdge(entries, handler)` from `/edge` | the handler's `ctx` |
|
|
144
|
+
| oRPC | `toOrpc(entries, rpcHandler)` from `/orpc` | the initial `context` |
|
|
145
|
+
| Expo API routes | `toExpo(entries, handler)` from `/expo` | the handler's `ctx` |
|
|
146
|
+
| TanStack Start | `toTanStackStart(entries)` from `/tanstack-start` | middleware `context` |
|
|
147
|
+
| SvelteKit | `toSvelteKit(entries)` from `/sveltekit` | `event.locals` |
|
|
148
|
+
| React Router | `toReactRouter(entries, key)` from `/react-router` | `context.get(key)` |
|
|
149
|
+
| H3, Nitro, Nuxt | `toH3(entries)` from `/h3` | `event.context` |
|
|
150
|
+
| Elysia | `toElysia(entries)` from `/elysia` | `.derive(({ request }) => bridge.context(request))` |
|
|
151
|
+
| Nitro 2, Nuxt | `toH3V1(entries)` from `/h3/v1` | `event.context` |
|
|
152
|
+
| Node `http` | `toNodeHandler(entries, handler)` from `/node` | the handler's `ctx` |
|
|
153
|
+
| Express | `toExpress(entries)` from `/node` | `res.locals` |
|
|
154
|
+
| Fastify | `toFastify(entries)` from `/node` | `request.locals` |
|
|
155
|
+
| Koa | `toKoa(entries)` from `/node` | `ctx.state` |
|
|
156
|
+
| NestJS | `toNestMiddleware(entries)` from `/nestjs` | `@Ctx("db")` in a controller |
|
|
157
|
+
|
|
158
|
+
Don't use the `@supabase/server/adapters/*` adapters: they are deprecated and
|
|
159
|
+
removed on 2026-12-01. Don't put `withSupabase` and `withBetterSupabase` in
|
|
160
|
+
one array; they write the same keys and the type checker rejects it. Set
|
|
161
|
+
`refresh: true` only on the bridge that runs once per request with a response
|
|
162
|
+
(request middleware, the `handle` hook), never in Server Components.
|
|
163
|
+
|
|
164
|
+
## Node, Express, Fastify and Koa
|
|
165
|
+
|
|
166
|
+
`better-supabase/node` types each framework structurally, so it adds no
|
|
167
|
+
dependency. Each bridge has a guard and an error handler that answers
|
|
168
|
+
`.orThrow()` failures with Problem Details:
|
|
169
|
+
|
|
170
|
+
```ts title="app.ts"
|
|
171
|
+
import express from "express";
|
|
172
|
+
import { guard, problemErrorHandler, toExpress } from "better-supabase/node";
|
|
173
|
+
import { withBetterSupabase } from "better-supabase/server";
|
|
174
|
+
|
|
175
|
+
import { bs } from "./lib/server";
|
|
176
|
+
|
|
177
|
+
const app = express();
|
|
178
|
+
app.use(
|
|
179
|
+
toExpress([
|
|
180
|
+
withBetterSupabase(bs, { refresh: true, allow: ["user", "anon"] }),
|
|
181
|
+
]),
|
|
182
|
+
);
|
|
183
|
+
app.get("/admin/members", guard({ roles: ["admin"] }), async (req, res) => {
|
|
184
|
+
res.json(await res.locals.db.members.findMany().orThrow());
|
|
185
|
+
});
|
|
186
|
+
app.use(problemErrorHandler());
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
| Framework | Bridge | Guard | Errors |
|
|
190
|
+
| ----------- | ----------------------------------- | --------------------------------------- | ----------------------- |
|
|
191
|
+
| `node:http` | `toNodeHandler(entries, handler)` | `allow` on `withBetterSupabase` | the handler's `Result` |
|
|
192
|
+
| Express | `toExpress(entries)` | `guard(options)` per route | `problemErrorHandler()` |
|
|
193
|
+
| Fastify | `toFastify(entries)` in `onRequest` | `fastifyGuard(options)` as `preHandler` | `problemErrorHandler()` |
|
|
194
|
+
| Koa | `toKoa(entries)` | `koaGuard(options)` | built into `toKoa` |
|
|
195
|
+
|
|
196
|
+
For Fastify, call `app.decorateRequest("locals", null)` first. Type
|
|
197
|
+
Express's `res.locals` by extending `Express.Locals` with
|
|
198
|
+
`BetterSupabaseContributions<Models, Functions, unknown>` from
|
|
199
|
+
`better-supabase/server`.
|
|
200
|
+
|
|
201
|
+
## NestJS
|
|
202
|
+
|
|
203
|
+
```ts title="src/app.module.ts"
|
|
204
|
+
consumer
|
|
205
|
+
.apply(toNestMiddleware([withBetterSupabase(bs, { allow: ["user"] })]))
|
|
206
|
+
.forRoutes("*");
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
```ts title="src/notes.controller.ts"
|
|
210
|
+
import { Controller, Get, UseFilters, UseGuards } from "@nestjs/common";
|
|
211
|
+
import { Ctx, guard, problemFilter } from "better-supabase/nestjs";
|
|
212
|
+
|
|
213
|
+
@Controller("notes")
|
|
214
|
+
@UseFilters(problemFilter())
|
|
215
|
+
export class NotesController {
|
|
216
|
+
@Get()
|
|
217
|
+
@UseGuards(guard({ roles: ["admin"] }))
|
|
218
|
+
list(@Ctx("db") db: Db) {
|
|
219
|
+
return db.notes.findMany({ select: ["id", "title"] }).orThrow();
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Astro and SolidStart
|
|
225
|
+
|
|
226
|
+
```ts title="src/lib/server.ts"
|
|
227
|
+
import { createAstro } from "better-supabase/astro";
|
|
228
|
+
|
|
229
|
+
export const bs = createAstro(betterSupabase, { signIn: "/sign-in" });
|
|
230
|
+
// src/middleware.ts: export const onRequest = bs.onRequest;
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
In a page, `const refused = await bs.guard(Astro, { roles: ["admin"] })`
|
|
234
|
+
returns the refusal to send, and `bs.locals(Astro).db` is the caller's
|
|
235
|
+
`db`. Wrap an Action's handler with `bs.action({ input, requireTenant }, fn)`.
|
|
236
|
+
`createImageService({ url })` serves Storage images through Astro's image
|
|
237
|
+
service.
|
|
238
|
+
|
|
239
|
+
```ts title="src/lib/server.ts"
|
|
240
|
+
import { createSolidStart } from "better-supabase/solid-start";
|
|
241
|
+
import { getRequestEvent } from "solid-js/web";
|
|
242
|
+
|
|
243
|
+
export const bs = createSolidStart(betterSupabase, {
|
|
244
|
+
getRequestEvent,
|
|
245
|
+
signIn: "/sign-in",
|
|
246
|
+
});
|
|
247
|
+
// src/middleware.ts: export default createMiddleware(bs.middleware);
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
In a `"use server"` query, `const { db } = await bs.require()`; for forms,
|
|
251
|
+
`bs.action({ input }, (input, { db }) => ...)`.
|
|
252
|
+
|
|
253
|
+
## Nuxt and Nitro 2
|
|
254
|
+
|
|
255
|
+
Export the entries from `server/better-supabase.ts`, register the module
|
|
256
|
+
with `modules: ["better-supabase/nuxt"]` and
|
|
257
|
+
`betterSupabase: { server: "~~/server/better-supabase" }` in
|
|
258
|
+
`nuxt.config.ts`, or run them yourself with
|
|
259
|
+
`defineEventHandler(toH3V1(entries))` from `better-supabase/h3/v1`. Guard a
|
|
260
|
+
route with `(await guard({ roles: ["admin"] })(event)) ?? ...`, and turn
|
|
261
|
+
`.orThrow()` failures into Problem Details with `problemOnError()`. On H3 2
|
|
262
|
+
and Nitro 3, use the same helpers from `better-supabase/h3`.
|
|
263
|
+
|
|
99
264
|
## MCP
|
|
100
265
|
|
|
101
266
|
```ts title="supabase/functions/mcp/index.ts"
|
|
@@ -132,3 +297,45 @@ Tools run as the calling user, so RLS applies to every tool call.
|
|
|
132
297
|
tokens that lack one, and `authorize` refuses a single call. The session comes
|
|
133
298
|
from the `Authorization` header only, never from a cookie. A
|
|
134
299
|
`delegation` that is unset means the user's own token, which no scope limits.
|
|
300
|
+
|
|
301
|
+
On Supabase Edge Functions, set `[functions.mcp] verify_jwt = false` in
|
|
302
|
+
`supabase/config.toml`; the gateway's own 401 has no OAuth challenge. The
|
|
303
|
+
server then derives its public URL from `SUPABASE_FUNCTION_SLUG` and the
|
|
304
|
+
gateway's `X-Forwarded-*` headers and serves the metadata at
|
|
305
|
+
`/functions/v1/mcp/oauth-protected-resource`, so leave `resource` unset there.
|
|
306
|
+
CORS preflights are answered by default (`cors: false` turns them off).
|
|
307
|
+
To keep a Supabase library MCP block's pipeline instead, add
|
|
308
|
+
`withBetterDb(betterSupabase)()` from `better-supabase/server` after its
|
|
309
|
+
`withSupabase` entry for `ctx.db`.
|
|
310
|
+
|
|
311
|
+
### MCP on the official SDK
|
|
312
|
+
|
|
313
|
+
```ts title="src/mcp.ts"
|
|
314
|
+
import { createMcpHandler, McpServer } from "@modelcontextprotocol/server";
|
|
315
|
+
import { createMcpAuth, withBetterSupabaseMcp } from "better-supabase/mcp/sdk";
|
|
316
|
+
|
|
317
|
+
import { betterSupabase } from "./lib/supabase/schema";
|
|
318
|
+
|
|
319
|
+
const auth = createMcpAuth(betterSupabase, {
|
|
320
|
+
resource: "https://crm.example.com/mcp",
|
|
321
|
+
advertisedScopes: ["crm.read"],
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
const handler = createMcpHandler(() => {
|
|
325
|
+
const server = withBetterSupabaseMcp(
|
|
326
|
+
new McpServer({ name: "crm", version: "0.1.0" }),
|
|
327
|
+
auth,
|
|
328
|
+
);
|
|
329
|
+
server.registerTool("count_customers", {}, async ({ db }) => {
|
|
330
|
+
const count = await db.customers.count().orThrow();
|
|
331
|
+
return { content: [{ type: "text", text: String(count) }] };
|
|
332
|
+
});
|
|
333
|
+
return server;
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
export default { fetch: auth.serve(handler) };
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`auth.serve` answers the RFC 9728 metadata and the 401 challenge, then passes
|
|
340
|
+
the verified `authInfo` to the SDK handler. `auth.verifier` plugs into the
|
|
341
|
+
SDK's own `requireBearerAuth` when you keep your own routing.
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# AI blocks, agents and SDK adapters
|
|
2
|
+
|
|
3
|
+
The AI blocks store data and never import an AI SDK. The SDK code lives in
|
|
4
|
+
the adapter subpaths (`better-supabase/ai-sdk/*`, `/chat-sdk`, `/eve`) or in
|
|
5
|
+
the app. Each block takes `transport` (calls as the user) and, where it
|
|
6
|
+
writes on the user's behalf, `service` (calls as the service role). Use
|
|
7
|
+
`rpcTransport(supabase)` over PostgREST or `sqlTransport(postgres.asUser(claims))`
|
|
8
|
+
over direct Postgres. Its docs page is
|
|
9
|
+
`https://bettersupabase.com/docs/blocks/<name>.md`.
|
|
10
|
+
|
|
11
|
+
## Knowledge and memory
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm better-supabase sql add knowledge memory # adds tenant, access and vector-search
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { embedWith } from "better-supabase/ai-sdk/embeddings";
|
|
19
|
+
import {
|
|
20
|
+
createKnowledge,
|
|
21
|
+
rpcTransport,
|
|
22
|
+
} from "better-supabase/blocks/knowledge";
|
|
23
|
+
import { createMemory } from "better-supabase/blocks/memory";
|
|
24
|
+
|
|
25
|
+
const embedder = embedWith("openai/text-embedding-3-small");
|
|
26
|
+
const knowledge = createKnowledge({
|
|
27
|
+
transport: rpcTransport(supabase),
|
|
28
|
+
service: rpcTransport(admin),
|
|
29
|
+
embedder,
|
|
30
|
+
});
|
|
31
|
+
const memory = createMemory({
|
|
32
|
+
transport: rpcTransport(supabase),
|
|
33
|
+
service: rpcTransport(admin),
|
|
34
|
+
embedder,
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
- Ingest with `knowledge.ingest.text(organizationId, { title, text, source })`
|
|
39
|
+
and search with `knowledge.search(organizationId, query, { scopes, k })`.
|
|
40
|
+
A scope is `organization`, `user`, `agent` or `chat` (with an `id`).
|
|
41
|
+
- Give the model the knowledge with `searchTool(knowledge, organizationId, { scopes, onHits })`
|
|
42
|
+
and cite with `toSourceParts(hits)`; rerank with `rerankWith(model, { topN })`.
|
|
43
|
+
`supabaseEmbed` uses Supabase's built-in model instead of a gateway model.
|
|
44
|
+
- Memory has files (`memory.run(organizationId, { command, path, ... })`),
|
|
45
|
+
archival facts (`memory.archival.save` and `.search`) and versioned
|
|
46
|
+
documents (`memory.documents.read` and `.write` with `expectedVersion`).
|
|
47
|
+
- In a chat route, from `better-supabase/ai-sdk/memory`: `withMemory(instructions, memory, organizationId)`
|
|
48
|
+
adds the core memory, `memoryTool` and `recallTool` are the tools, and
|
|
49
|
+
`anthropicMemory(anthropic.tools, memory, organizationId)` backs
|
|
50
|
+
Anthropic's built-in memory tool. Run `extractMemories({ model, memory })`
|
|
51
|
+
as a job handler with a service-role `memory`.
|
|
52
|
+
|
|
53
|
+
## Agents, connectors and scheduled tasks
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pnpm better-supabase sql add agents connectors ai-tasks
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
- `createAgents({ transport })` stores assistants: `agents.create(organizationId, { slug, name, instructions, tools, knowledgeScopes })`,
|
|
60
|
+
then `agents.publish(id, "organization")`.
|
|
61
|
+
- Run a stored agent with `createAgentRuntime({ agent, model, tools, policies, knowledge, instructions })`
|
|
62
|
+
from `better-supabase/ai-sdk/agents`, then `runtime.stream({ messages })`.
|
|
63
|
+
Wrap the model with `moderationMiddleware({ chats, organizationId, chatId, check })`
|
|
64
|
+
to check input and output; a blocked turn throws `ModerationBlockedError`.
|
|
65
|
+
- `createConnectors({ transport, service, credentials })` stores MCP servers
|
|
66
|
+
per organization. OAuth servers get one grant per user behind a
|
|
67
|
+
`credential_ref`. From `better-supabase/ai-sdk/mcp`: `authorizeConnector`
|
|
68
|
+
starts the OAuth flow, `completeConnector` finishes it on the callback
|
|
69
|
+
route, and `connectAll(servers, { connectors, userId, vault, credentials, chatKey })`
|
|
70
|
+
returns `{ tools, skipped, close }`. Call `close()` in a `finally`.
|
|
71
|
+
Review changed tool lists with `connectors.fingerprints.check`, `.approve`
|
|
72
|
+
and `.reject`.
|
|
73
|
+
- `createAiTasks({ transport, service, run })` stores scheduled prompts with
|
|
74
|
+
a `cron` and a `timezone`. `tick()` queues the due runs (handle them with
|
|
75
|
+
`runJob()` on the `ai_task_run` queue when the `jobs` module is
|
|
76
|
+
installed); without jobs, call `drain()` from a cron route.
|
|
77
|
+
|
|
78
|
+
## Files, cache and batches
|
|
79
|
+
|
|
80
|
+
- `aiFileDownload(files)` as `experimental_download` in `streamText` reads
|
|
81
|
+
Storage file parts; `saveGeneratedFiles(files, images, { organizationId, ownerId, chatId })`
|
|
82
|
+
stores generated images; `providerFile(files, fileId, provider, upload)`
|
|
83
|
+
caches a provider's file id. All from `better-supabase/ai-sdk/files`.
|
|
84
|
+
- `aiBatches({ providers })` from `better-supabase/ai-sdk/batches` starts a
|
|
85
|
+
batch per tenant with `.start({ organizationId, userId }, { requests })`,
|
|
86
|
+
polls it with the `pollJob()` handler and pages results with `.results(batchId, { after, limit })`.
|
|
87
|
+
|
|
88
|
+
## eve (Node only)
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pnpm add eve @workflow/world @workflow/world-postgres pg
|
|
92
|
+
pnpm better-supabase sql add workflow-sdk-world ai-chat memory knowledge credentials inbox
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Set `experimental.workflow.world` to `"better-supabase/workflow-sdk/world"`
|
|
96
|
+
in `defineAgent`, then use the helpers from `better-supabase/eve`:
|
|
97
|
+
|
|
98
|
+
| Helper | Where it goes | What it does |
|
|
99
|
+
| ------------------------- | -------------------------------------- | ------------------------------------------------------- |
|
|
100
|
+
| `supabaseAuth({ env })` | `eveChannel({ auth: [...] })` | signs eve routes in with the Supabase session |
|
|
101
|
+
| `credentialAuth(...)` | a connection's `auth` | resolves the connection's token from a `credential_ref` |
|
|
102
|
+
| `supabaseMemory(...)` | `defineMemoryProvider(...)` | backs eve memory with the memory and knowledge blocks |
|
|
103
|
+
| `supabaseDocumentBackend` | `fileMemory({ backend })` | stores file memory in `memory_documents` |
|
|
104
|
+
| `persistSessions(...)` | `defineHook({ events })` | copies sessions into the AI chat tables |
|
|
105
|
+
| `routeInbox(...)` | `chatSdkChannel()` over `inboxAdapter` | hands inbox conversations in bot mode to eve |
|
|
106
|
+
|
|
107
|
+
## Chat SDK bots
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pnpm add chat
|
|
111
|
+
pnpm better-supabase sql add chat-sdk-state inbox
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
From `better-supabase/chat-sdk`: `createSupabaseState(...)` is the Chat SDK
|
|
115
|
+
state adapter on Postgres, `inboxAdapter(...)` answers in the in-app widget,
|
|
116
|
+
`webhook(...)` receives platform webhooks, `inboundHandler(...).drain()`
|
|
117
|
+
replays them, `deliver(...)` sends staff replies and `maintain(...)` runs on
|
|
118
|
+
a cron. Mirror platform messages into the inbox with
|
|
119
|
+
`handler.mirror(thread, message)`. Platform adapters such as
|
|
120
|
+
`@chat-adapter/slack` are the app's own dependencies.
|
|
121
|
+
|
|
122
|
+
Docs: https://bettersupabase.com/docs/ai-sdk.md (and `agents`, `mcp`,
|
|
123
|
+
`embeddings`, `memory`, `files`, `batches` under `/docs/ai-sdk/`),
|
|
124
|
+
https://bettersupabase.com/docs/eve.md and
|
|
125
|
+
https://bettersupabase.com/docs/chat-sdk.md.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Expo and React Native
|
|
2
|
+
|
|
3
|
+
## Server (web): `better-supabase/expo`
|
|
4
|
+
|
|
5
|
+
Needs `expo-server` 55 or later and, in `app.json`, `web.output: "server"`
|
|
6
|
+
plus the `expo-router` plugin options `unstable_useServerDataLoaders` and
|
|
7
|
+
`unstable_useServerMiddleware`.
|
|
8
|
+
|
|
9
|
+
```ts title="src/lib/supabase/server.ts"
|
|
10
|
+
import { createExpo } from "better-supabase/expo";
|
|
11
|
+
import { betterSupabase } from "./index";
|
|
12
|
+
|
|
13
|
+
export const bs = createExpo(betterSupabase);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```tsx title="src/app/customers/index.tsx"
|
|
17
|
+
export const loader = bs.loader(
|
|
18
|
+
({ db }) => db.customers.findMany({ select: ["id", "name"] }).orThrow(),
|
|
19
|
+
{ allow: ["user"] },
|
|
20
|
+
);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```ts title="src/app/+middleware.ts"
|
|
24
|
+
export default bs.middleware();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- Loaders run as the caller (bearer token first, then the cookie), so RLS applies.
|
|
28
|
+
- A refused caller and a `DbException` from `.orThrow()` become a `StatusError` with the right status.
|
|
29
|
+
- Only `+middleware.ts` refreshes the session; loaders never do.
|
|
30
|
+
- Loader data is JSON: select the columns the screen needs and turn Temporal values into strings.
|
|
31
|
+
- API routes: `export const GET = bs.handler((request, { db }) => db.customers.findMany())` in `+api.ts`.
|
|
32
|
+
|
|
33
|
+
## Device: `better-supabase/client/native`
|
|
34
|
+
|
|
35
|
+
```ts title="src/lib/supabase/native.ts"
|
|
36
|
+
import { createClient } from "@supabase/supabase-js";
|
|
37
|
+
import {
|
|
38
|
+
autoRefreshOnForeground,
|
|
39
|
+
createNativeClient,
|
|
40
|
+
secureStorage,
|
|
41
|
+
} from "better-supabase/client/native";
|
|
42
|
+
import * as SecureStore from "expo-secure-store";
|
|
43
|
+
import { AppState } from "react-native";
|
|
44
|
+
|
|
45
|
+
const supabase = createClient(url, key, {
|
|
46
|
+
auth: {
|
|
47
|
+
storage: secureStorage(SecureStore),
|
|
48
|
+
persistSession: true,
|
|
49
|
+
detectSessionInUrl: false,
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
autoRefreshOnForeground(supabase, AppState);
|
|
53
|
+
export const bs = createNativeClient(betterSupabase, supabase);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- `autoRefreshOnForeground(supabase, AppState)` refreshes the session only while the app is active; supabase-js can't detect the background on React Native.
|
|
57
|
+
- Never import `better-supabase/client` on the device: it pulls in `@supabase/ssr`.
|
|
58
|
+
- Hermes has no `Temporal`: `defineSupabase(schema, { temporal: Temporal })` with `temporal-polyfill`, no global install.
|
|
59
|
+
- Put device-only code (SecureStore, PowerSync) in `.native.ts` files or modules only they import.
|
|
60
|
+
|
|
61
|
+
Done when the web export has no `expo-secure-store` or PowerSync code, a loader
|
|
62
|
+
answers 401 for a signed-out request, and a native screen reads with `bs.db`.
|
|
63
|
+
|
|
64
|
+
Docs: https://bettersupabase.com/docs/frameworks/expo.md and
|
|
65
|
+
https://bettersupabase.com/docs/frontend/react-native.md.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# PowerSync (offline reads and writes)
|
|
2
|
+
|
|
3
|
+
```ts title="src/lib/powersync/database.ts"
|
|
4
|
+
import { powersyncExecutor } from "better-supabase/powersync";
|
|
5
|
+
|
|
6
|
+
export const local = betterSupabase.connect(powersyncExecutor(powersync));
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
- `local.customers.findMany(...)` and `list.run(local, query)` run on the device's SQLite database and return the same rows (casing, Temporal values) as PostgREST.
|
|
10
|
+
- Live results: `watch(powersync, () => list.run(local, query), { tables: sqliteTables(betterSupabase, ["customers"]), onResult })`.
|
|
11
|
+
- Includes, related counts, full-text search, `db.rpc` and writes to tables without a primary key return a `DbError` of kind `unsupported`. Assert `checkSqlite(betterSupabase, list)` in a test for every list a native screen runs.
|
|
12
|
+
- `ilike` is SQLite `like` (case-insensitive for ASCII only).
|
|
13
|
+
|
|
14
|
+
## Uploading local writes
|
|
15
|
+
|
|
16
|
+
In the connector's `uploadData`, replay each `CrudEntry` through the online
|
|
17
|
+
client's repositories (`bs.db` from `better-supabase/client/native`), so RLS
|
|
18
|
+
and validation run:
|
|
19
|
+
|
|
20
|
+
| `entry.op` | Call |
|
|
21
|
+
| ---------- | ------------------------------------------- |
|
|
22
|
+
| `PUT` | `upsert({ ...entry.opData, id: entry.id })` |
|
|
23
|
+
| `PATCH` | `update(entry.id, entry.opData)` |
|
|
24
|
+
| `DELETE` | `delete(entry.id)` |
|
|
25
|
+
|
|
26
|
+
Decide by `error.kind`, with an exhaustive `switch` ending in a `never` check:
|
|
27
|
+
|
|
28
|
+
- Retry (throw, PowerSync calls again): `network`, `timeout`, `aborted`, `rate_limited`, `serialization`, `unauthorized`, `unexpected`.
|
|
29
|
+
- Conflict (complete, then show it on the row): `conflict`, `stale`, `foreign_key`.
|
|
30
|
+
- Discard (complete): every other kind; the server will never accept it.
|
|
31
|
+
|
|
32
|
+
Never throw for a kind that can't succeed: it blocks the upload queue.
|
|
33
|
+
|
|
34
|
+
Docs: https://bettersupabase.com/docs/repository/powersync.md and
|
|
35
|
+
https://bettersupabase.com/docs/guides/offline-first.md.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Streams, credentials and the Workflow World
|
|
2
|
+
|
|
3
|
+
## Resumable streams
|
|
4
|
+
|
|
5
|
+
Store long output (a chat answer, a workflow's progress) so a client that
|
|
6
|
+
reconnects reads the rest instead of starting over.
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
pnpm better-supabase sql add streams
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import {
|
|
14
|
+
postgresStreamStore,
|
|
15
|
+
resumeFromStore,
|
|
16
|
+
sqlTransport,
|
|
17
|
+
teeToStore,
|
|
18
|
+
} from "better-supabase/streams";
|
|
19
|
+
|
|
20
|
+
const streams = postgresStreamStore({
|
|
21
|
+
transport: sqlTransport(postgres.asService()),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// POST: send the output and store it at the same time.
|
|
25
|
+
const { stream, persisted } = teeToStore(streams, chatId, output, {
|
|
26
|
+
owner: userId,
|
|
27
|
+
kind: "chat",
|
|
28
|
+
onCancel: () => controller.abort(),
|
|
29
|
+
});
|
|
30
|
+
after(() => persisted);
|
|
31
|
+
|
|
32
|
+
// GET: resume from the last chunk the client has.
|
|
33
|
+
const rest = await resumeFromStore(streams, id, { fromIdx }).orThrow();
|
|
34
|
+
if (rest === undefined) return new Response(null, { status: 204 });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
For Redis, `redisStreamStore({ url: process.env.REDIS_URL })` from
|
|
38
|
+
`better-supabase/streams/redis` (add `redis`, or pass your own client). Keep
|
|
39
|
+
`persisted` alive with `after` or `waitUntil`, or the stored copy stops
|
|
40
|
+
when the response ends.
|
|
41
|
+
|
|
42
|
+
## Credentials
|
|
43
|
+
|
|
44
|
+
Third-party tokens never go in a column. A row holds a `credential_ref`
|
|
45
|
+
(`{ provider, secret, scope }`) and a `CredentialProvider` resolves it.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm better-supabase sql add credentials
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import {
|
|
53
|
+
sqlTransport,
|
|
54
|
+
subjectFor,
|
|
55
|
+
vaultCredentials,
|
|
56
|
+
} from "better-supabase/credentials";
|
|
57
|
+
|
|
58
|
+
export const bs = createServer(betterSupabase, {
|
|
59
|
+
credentials: vaultCredentials({
|
|
60
|
+
transport: sqlTransport(postgres.asService()),
|
|
61
|
+
}),
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// In a handler:
|
|
65
|
+
const subject = subjectFor(ctx);
|
|
66
|
+
if (ctx.credentials === undefined || subject === undefined)
|
|
67
|
+
return unauthorized();
|
|
68
|
+
const token = await ctx.credentials
|
|
69
|
+
.getToken(row.credential_ref, { subject })
|
|
70
|
+
.orThrow();
|
|
71
|
+
await fetch(url, { headers: token.headers });
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
- On Vercel Connect, pass `vercelConnectCredentials()` from
|
|
75
|
+
`better-supabase/vercel-connect` instead (add `@vercel/connect`).
|
|
76
|
+
- Check a custom provider with `testCredentialProvider` from
|
|
77
|
+
`better-supabase/testing`.
|
|
78
|
+
|
|
79
|
+
## The Workflow World on Supabase (Node only)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm better-supabase sql add workflow-sdk-world # adds workflows and jobs
|
|
83
|
+
pnpm add workflow @workflow/world @workflow/world-postgres pg
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
```bash title=".env"
|
|
87
|
+
WORKFLOW_TARGET_WORLD=better-supabase/workflow-sdk/world
|
|
88
|
+
SUPABASE_DB_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
The entry's default export reads its options from the environment, so
|
|
92
|
+
setting `WORKFLOW_TARGET_WORLD` is enough. To build it in code, call
|
|
93
|
+
`createSupabaseWorld({ connectionString, delivery: "pg_net" })`. The World
|
|
94
|
+
imports `pg` and Node built-ins: never import it from an edge or browser
|
|
95
|
+
entry.
|
|
96
|
+
|
|
97
|
+
From `better-supabase/workflow-sdk`, which runs anywhere: `startFor(ctx, workflow, args)`
|
|
98
|
+
starts a run members see under RLS, `authorizeHook(token, ctx)` checks a
|
|
99
|
+
caller before `resumeHook`, `protectWebHandler(handler, key, { can })` refuses callers before a workflow UI route or a run's stream and
|
|
100
|
+
`workflowStarter({ name: workflow })` hands scheduled starts from the
|
|
101
|
+
`workflows` block to the SDK.
|
|
102
|
+
|
|
103
|
+
Docs: https://bettersupabase.com/docs/blocks/streams.md,
|
|
104
|
+
https://bettersupabase.com/docs/extending/credentials.md and
|
|
105
|
+
https://bettersupabase.com/docs/blocks/workflow-sdk.md.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: better-supabase-auth
|
|
3
|
-
description: Read and check the caller in better-supabase apps, including sessions, typed claims, user profiles, OAuth clients and agents acting for a user, scopes, ended sessions and
|
|
3
|
+
description: Read and check the caller in better-supabase apps, including sessions, typed claims, user profiles, OAuth clients and agents acting for a user, scopes, ended sessions and authorization providers. Use when code reads auth, session or claims, when adding a custom access token hook, an OAuth or agent integration, sign-out, account deletion or role changes, or when better-supabase.config.ts has an authorization key.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Auth with better-supabase
|
|
@@ -50,7 +50,8 @@ path treats `invalid` as `anon`.
|
|
|
50
50
|
`betterSupabase.userMetadata(schema)` and read `session.profile`.
|
|
51
51
|
3. Read roles, memberships, the tenant and entitlements from the verified
|
|
52
52
|
claims only. Never from `user_metadata`, `session.profile`, a URL or a
|
|
53
|
-
request body.
|
|
53
|
+
request body. A tenant from the URL or input is only safe through the
|
|
54
|
+
`tenant` resolver or the `{ tenant }` option, which check membership.
|
|
54
55
|
|
|
55
56
|
Done when `session.claims` is typed without casts, and a token whose claims
|
|
56
57
|
fail the schema gets a 401 with code `CLAIMS_INVALID`.
|
|
@@ -101,22 +102,40 @@ if (ended) return err(ended); // unauthorized, code SESSION_REVOKED
|
|
|
101
102
|
It needs a connection that can read `auth.sessions` (`createPostgres().admin`).
|
|
102
103
|
Nothing calls it by default; keep it to the actions that need it.
|
|
103
104
|
|
|
105
|
+
When RLS checks the session (so an ended session sees no rows), sign the
|
|
106
|
+
browser out on page loads instead of showing an empty app. Next.js:
|
|
107
|
+
`bs.proxy(request, { endedSession: { redirect: "/login" } })` asks Auth on
|
|
108
|
+
document loads (and on `paths`), clears the cookies and redirects with
|
|
109
|
+
`?reason=session_ended`.
|
|
110
|
+
A proxy or middleware with its own Supabase client calls
|
|
111
|
+
`sessionStatus(request, { url, publishableKey })` from `better-supabase/ssr`
|
|
112
|
+
(`"ended"` on a 401 or 403 from Auth; treat `"unknown"` as active) and
|
|
113
|
+
`clearSessionCookies(request, response, { url })` before redirecting.
|
|
114
|
+
|
|
104
115
|
Done when the irreversible action returns `SESSION_REVOKED` for a signed-out
|
|
105
116
|
session in a test.
|
|
106
117
|
|
|
118
|
+
To lock a user out, call `bs.suspendAccount(userId, { suspended: true })`
|
|
119
|
+
(it bans the user in Auth and ends every session and refresh token), or
|
|
120
|
+
`bs.endSessions(userId)` to sign them out everywhere without a ban. A ban
|
|
121
|
+
alone leaves the refresh tokens, which work again once the ban is lifted. To
|
|
122
|
+
switch a member off in one organization only, use the organizations block's
|
|
123
|
+
`suspendMember`.
|
|
124
|
+
|
|
107
125
|
## When claims change
|
|
108
126
|
|
|
109
127
|
A token carries the claims from when Auth issued it, so a revoked role or
|
|
110
128
|
membership lasts until the next refresh. When that window matters:
|
|
111
129
|
|
|
112
130
|
- Write policies that read the source of truth, for example
|
|
113
|
-
`organization_id in (select better_supabase.
|
|
131
|
+
`organization_id in (select better_supabase.member_organization_ids())`, instead of
|
|
114
132
|
the claim.
|
|
115
133
|
- For signed-out, banned or deleted users, add the `sessions` SQL module and a
|
|
116
134
|
restrictive policy with `using ((select better_supabase.session_active()))`
|
|
117
135
|
on the tables that guard sensitive data.
|
|
118
136
|
- After a change the user made themselves (joining an organization), call
|
|
119
|
-
`supabase.auth.refreshSession()` in the browser.
|
|
137
|
+
`supabase.auth.refreshSession()` in the browser (in Next.js, through
|
|
138
|
+
`useSessionChange`'s `refreshToken`, below).
|
|
120
139
|
- In Next.js, drop the user's cached views with
|
|
121
140
|
`bs.invalidateSession(userId, { tags })`.
|
|
122
141
|
|
|
@@ -126,16 +145,33 @@ membership lasts until the next refresh. When that window matters:
|
|
|
126
145
|
`'use cache: private'` function. It tags the entry `bs:session:<user id>`
|
|
127
146
|
and caps its lifetime at the token's.
|
|
128
147
|
- `bs.cached({ tags, life: { stale } })` adds tags and caps the stale time
|
|
129
|
-
further, for example for a
|
|
148
|
+
further, for example for a permission snapshot.
|
|
149
|
+
- `bs.cached({ tables: ["customers"] })` tags the entry by table, so an
|
|
150
|
+
action that writes the table drops it without a hand-written tag.
|
|
151
|
+
- `bs.invalidateSession(userId)` reaches the server caches and the caller's
|
|
152
|
+
router only; another user's browser keeps its private entries until they
|
|
153
|
+
go stale.
|
|
154
|
+
- After signing in or out: `useSessionChange(sessionChanged)` from
|
|
155
|
+
`better-supabase/next/client`. After switching the active organization:
|
|
156
|
+
`useSessionChange(sessionChanged, router, { refreshToken: supabase })`, so
|
|
157
|
+
the new token reaches the server before it renders.
|
|
158
|
+
- For a tenant from the route params, call `bs.cached({ tenant })` and take
|
|
159
|
+
the tenant as an argument of the `'use cache: private'` function, so it is
|
|
160
|
+
part of the cache key. Outside a cache, use `bs.context({ tenant })`.
|
|
161
|
+
- In the proxy, set `bs.proxy(request, { protect, expiredPrefetch: "render" })`
|
|
162
|
+
instead of returning early for `{ kind: "anon", reason: "expired" }` in
|
|
163
|
+
`protect`. A prefetch never refreshes, so without it the prefetch caches a
|
|
164
|
+
redirect to sign-in.
|
|
130
165
|
- Keep layouts synchronous: pass the `bs.session()` promise to
|
|
131
166
|
`<SessionProvider>` and read it with `useSession()`.
|
|
132
167
|
|
|
133
|
-
##
|
|
168
|
+
## Authorization providers
|
|
134
169
|
|
|
135
|
-
When
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
170
|
+
When `better-supabase.config.ts` has an `authorization` key, another package
|
|
171
|
+
answers permission checks and may own the access token hook, roles,
|
|
172
|
+
memberships and the tenant claim. Read
|
|
173
|
+
[references/authorization-providers.md](references/authorization-providers.md)
|
|
174
|
+
before touching the hook, claims, tenant or entitlements.
|
|
139
175
|
|
|
140
176
|
## Don't
|
|
141
177
|
|
|
@@ -154,4 +190,4 @@ https://bettersupabase.com/docs/auth.md,
|
|
|
154
190
|
https://bettersupabase.com/docs/frameworks/next.md (bearer callers),
|
|
155
191
|
https://bettersupabase.com/docs/auth/account-deletion.md,
|
|
156
192
|
https://bettersupabase.com/docs/frameworks/next-cache-components.md and
|
|
157
|
-
https://bettersupabase.com/docs/
|
|
193
|
+
https://bettersupabase.com/docs/extending/authorization-providers.md.
|