better-supabase 0.7.0 → 0.8.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 +6 -2
- package/dist/{access-sql-B0dF-SoF.js → access-sql-CrSbK1q-.js} +1 -1
- package/dist/{adapter-B-tL8hqg.js → adapter-CN45ibbV.js} +663 -157
- package/dist/{agents-CVHGd7It.d.ts → agents-BY_LQXtQ.d.ts} +4 -4
- package/dist/{ai-cache-CBWs1W0k.js → ai-cache-Dfgk8nBT.js} +2 -1
- package/dist/{ai-cache-DaDu_G5L.d.ts → ai-cache-DrUMMgp6.d.ts} +4 -4
- package/dist/{ai-chat-B24UI962.js → ai-chat-CVLRWbtS.js} +4 -3
- package/dist/{ai-chat-7amvXjmQ.d.ts → ai-chat-DXkMy74O.d.ts} +5 -5
- package/dist/{ai-files-CSPNswUY.js → ai-files-CioLu5du.js} +5 -4
- package/dist/ai-message-DfaP8sis.js +14 -0
- package/dist/ai-sdk/agents/index.d.ts +4 -4
- package/dist/ai-sdk/batches/index.d.ts +4 -4
- package/dist/ai-sdk/batches/index.js +4 -4
- package/dist/ai-sdk/cache/index.d.ts +2 -2
- package/dist/ai-sdk/cache/index.js +2 -2
- package/dist/ai-sdk/chat/index.d.ts +1 -1
- package/dist/ai-sdk/chat/index.js +8 -20
- package/dist/ai-sdk/embeddings/index.d.ts +2 -2
- package/dist/ai-sdk/files/index.d.ts +3 -3
- package/dist/ai-sdk/files/index.js +4 -4
- package/dist/ai-sdk/index.d.ts +37 -9
- package/dist/ai-sdk/index.js +3 -2
- package/dist/ai-sdk/mcp/index.d.ts +43 -6
- package/dist/ai-sdk/mcp/index.js +36 -7
- package/dist/ai-sdk/memory/index.d.ts +2 -2
- package/dist/ai-sdk/memory/index.js +1 -1
- package/dist/ai-sdk/workflow/index.d.ts +6 -6
- package/dist/ai-sdk/workflow/index.js +13 -24
- package/dist/{ai-tasks-Cd1HMFvB.d.ts → ai-tasks-BRQ6iQLc.d.ts} +4 -4
- package/dist/{announcements-ZRGnScWI.d.ts → announcements-Bouy0Ski.d.ts} +3 -3
- package/dist/{announcements-CiyOs-xP.js → announcements-p_BFofiR.js} +1 -1
- package/dist/api-Dnf2q-Ht.d.ts +370 -0
- package/dist/api-DtHFC037.js +676 -0
- package/dist/{api-keys-CIjghYjV.d.ts → api-keys-C8BlF3L2.d.ts} +4 -4
- package/dist/arazzo/index.d.ts +255 -0
- package/dist/arazzo/index.js +622 -0
- package/dist/{assistant-DwdpDH1q.d.ts → assistant-DBlFDZsi.d.ts} +5 -5
- package/dist/astro/index.d.ts +7 -7
- package/dist/astro/index.js +7 -7
- package/dist/asyncapi/index.d.ts +103 -0
- package/dist/asyncapi/index.js +569 -0
- package/dist/authorizer-ayxUDXXP.js +126 -0
- package/dist/authorizer-eiOjo-3l.d.ts +73 -0
- package/dist/better-result/index.d.ts +118 -0
- package/dist/better-result/index.js +64 -0
- package/dist/{bind-l4kAvYSv.js → bind-ButSzrHe.js} +1 -1
- package/dist/{bind-Bu_ZNa3W.d.ts → bind-CQ5mPyX1.d.ts} +3 -3
- package/dist/{block-events-CrT8r7Fe.js → block-events-DTxU5tfr.js} +18 -3
- package/dist/{block-fields-GFkxl4dP.js → block-fields-CroxUuF2.js} +3 -3
- package/dist/{block-fields-SJ6fEf3o.d.ts → block-fields-D1pfrcIY.d.ts} +2 -2
- package/dist/{block-helpers-CKtbFcRv.d.ts → block-helpers-C0Xj8War.d.ts} +2 -2
- package/dist/{block-helpers-DWHxHsEQ.js → block-helpers-Cy3pB96I.js} +41 -9
- package/dist/{block-hooks-BmjMyXTa.js → block-hooks-BPNMIlLl.js} +3 -3
- package/dist/{block-hooks-plbZ0AbJ.d.ts → block-hooks-DaOVC7SC.d.ts} +3 -3
- package/dist/{block-transport-BLr-ZgLc.js → block-transport-bAKh-dGc.js} +28 -2
- package/dist/{block-transport-DvaoPuZ9.d.ts → block-transport-inD4fFq-.d.ts} +24 -2
- package/dist/blocks/agents/index.d.ts +3 -3
- package/dist/blocks/agents/index.js +5 -4
- package/dist/blocks/ai-cache/index.d.ts +3 -3
- package/dist/blocks/ai-cache/index.js +3 -3
- package/dist/blocks/ai-chat/index.d.ts +9 -4
- package/dist/blocks/ai-chat/index.js +5 -5
- package/dist/blocks/ai-chat/react/index.d.ts +3 -3
- package/dist/blocks/ai-chat/react/index.js +5 -5
- package/dist/blocks/ai-files/index.d.ts +3 -3
- package/dist/blocks/ai-files/index.js +3 -3
- package/dist/blocks/ai-providers/index.d.ts +3 -3
- package/dist/blocks/ai-providers/index.js +8 -7
- package/dist/blocks/ai-tasks/index.d.ts +3 -3
- package/dist/blocks/ai-tasks/index.js +7 -6
- package/dist/blocks/announcements/index.d.ts +3 -3
- package/dist/blocks/announcements/index.js +3 -3
- package/dist/blocks/announcements/react/index.d.ts +3 -3
- package/dist/blocks/announcements/react/index.js +3 -3
- package/dist/blocks/api-keys/index.d.ts +5 -5
- package/dist/blocks/api-keys/index.js +8 -8
- package/dist/blocks/attachments/index.d.ts +12 -8
- package/dist/blocks/attachments/index.js +22 -13
- package/dist/blocks/audit/index.d.ts +21 -10
- package/dist/blocks/audit/index.js +30 -11
- package/dist/blocks/billing/index.d.ts +11 -9
- package/dist/blocks/billing/index.js +15 -15
- package/dist/blocks/comments/index.d.ts +8 -8
- package/dist/blocks/comments/index.js +8 -7
- package/dist/blocks/connectors/index.d.ts +3 -3
- package/dist/blocks/connectors/index.js +7 -6
- package/dist/blocks/data-lifecycle/index.d.ts +12 -8
- package/dist/blocks/data-lifecycle/index.js +13 -8
- package/dist/blocks/entitlements/index.d.ts +3 -3
- package/dist/blocks/entitlements/index.js +1 -1
- package/dist/blocks/flags/index.d.ts +4 -4
- package/dist/blocks/flags/index.js +4 -3
- package/dist/blocks/inbox/index.d.ts +3 -3
- package/dist/blocks/inbox/index.js +4 -5
- package/dist/blocks/inbox/react/index.d.ts +1 -1
- package/dist/blocks/inbox/react/index.js +1 -1
- package/dist/blocks/inbox/react/server.d.ts +1 -1
- package/dist/blocks/index.d.ts +10 -10
- package/dist/blocks/index.js +6 -6
- package/dist/blocks/jobs/index.d.ts +48 -32
- package/dist/blocks/jobs/index.js +44 -287
- package/dist/blocks/knowledge/index.d.ts +3 -3
- package/dist/blocks/knowledge/index.js +3 -3
- package/dist/blocks/memory/index.d.ts +4 -4
- package/dist/blocks/memory/index.js +7 -6
- package/dist/blocks/notifications/index.d.ts +11 -9
- package/dist/blocks/notifications/index.js +20 -25
- package/dist/blocks/notifications/react/index.d.ts +1 -1
- package/dist/blocks/notifications/react/index.js +1 -1
- package/dist/blocks/onboarding/index.d.ts +3 -3
- package/dist/blocks/onboarding/index.js +3 -3
- package/dist/blocks/onboarding/react/index.d.ts +2 -2
- package/dist/blocks/onboarding/react/index.js +2 -2
- package/dist/blocks/onboarding/react/server.d.ts +1 -1
- package/dist/blocks/organizations/index.d.ts +9 -9
- package/dist/blocks/organizations/index.js +11 -18
- package/dist/blocks/outbox/index.d.ts +2 -2
- package/dist/blocks/outbox/index.js +16 -25
- package/dist/blocks/profiles/index.d.ts +7 -7
- package/dist/blocks/profiles/index.js +7 -6
- package/dist/blocks/push/index.d.ts +4 -4
- package/dist/blocks/push/index.js +3 -3
- package/dist/blocks/settings/index.d.ts +4 -4
- package/dist/blocks/settings/index.js +7 -6
- package/dist/blocks/sso/index.d.ts +5 -5
- package/dist/blocks/sso/index.js +6 -5
- package/dist/blocks/usage/index.d.ts +3 -3
- package/dist/blocks/usage/index.js +5 -4
- package/dist/blocks/waitlist/index.d.ts +5 -5
- package/dist/blocks/waitlist/index.js +5 -4
- package/dist/blocks/webhooks/index.d.ts +22 -13
- package/dist/blocks/webhooks/index.js +41 -70
- package/dist/blocks/workflow-builder/index.d.ts +4 -4
- package/dist/blocks/workflow-builder/index.js +3 -3
- package/dist/blocks/workflow-builder/react/index.d.ts +4 -4
- package/dist/blocks/workflow-builder/react/index.js +4 -4
- package/dist/blocks/workflows/index.d.ts +3 -3
- package/dist/blocks/workflows/index.js +3 -3
- package/dist/blocks/workflows/react/index.d.ts +3 -3
- package/dist/blocks/workflows/react/index.js +3 -3
- package/dist/build-hPwk3_X5.js +1296 -0
- package/dist/{build-BXIzE6Xv.js → build-meLuYGri.js} +3 -3
- package/dist/casing-DdFWEtqr.js +16 -0
- package/dist/chat-sdk/index.d.ts +6 -6
- package/dist/chat-sdk/index.js +5 -4
- package/dist/chat-sdk/react/index.d.ts +1 -1
- package/dist/chat-sdk/react/server.d.ts +1 -1
- package/dist/{claims-DDBQT6BK.js → claims-0KZVT804.js} +1 -1
- package/dist/cli/add-1dc5wM5k.js +69 -0
- package/dist/cli/arazzo-1.0-BalU61-_.js +532 -0
- package/dist/cli/arazzo-1.1-Bnfasbun.js +705 -0
- package/dist/cli/asyncapi-3.0.0-C78dBjR6.js +5593 -0
- package/dist/cli/asyncapi-3.1.0-g-7aIfV1.js +5833 -0
- package/dist/cli/bin.js +4 -4
- package/dist/cli/cache-CIfA-jBV.js +483 -0
- package/dist/cli/{codemod-Bl_tQpHn.js → codemod-JVlTQQG2.js} +4 -4
- package/dist/cli/{command-CK14fP91.js → command-DV-StG1x.js} +5 -0
- package/dist/cli/{config-DU7EJImt.js → config-C2Pz2_4A.js} +7 -4
- package/dist/cli/config-DpbF8ML3.js +2 -0
- package/dist/cli/{config-NiPxAmUF.js → config-M-WzL9O2.js} +116 -18
- package/dist/cli/{db-DOBPt660.js → db-BkcfOlyB.js} +2 -1
- package/dist/cli/{diff-SjkO5rNr.js → diff-D1jGdb3Y.js} +1 -1
- package/dist/cli/{doctor-CVdnLahA.js → doctor-VcDtuusV.js} +317 -222
- package/dist/cli/emit-BHHfwUoT.js +1136 -0
- package/dist/cli/{env-qXgyMV6r.js → env-B--LMhEe.js} +13 -10
- package/dist/cli/env-vzBG90Um.js +2 -0
- package/dist/cli/{env-CJLbUVPB.js → env-zHJtMIBo.js} +11 -3
- package/dist/cli/{errors-4v4DTtda.js → errors-CqTLXe2M.js} +18 -2
- package/dist/cli/{fastest-levenshtein-CFN-lNDv.js → fastest-levenshtein-CF7BCi9l.js} +1 -1
- package/dist/cli/files-BVupXPIC.js +34 -0
- package/dist/cli/gen-DmVj3u4L.js +322 -0
- package/dist/cli/{init-Cr6arjXU.js → glue-C1UE8gQN.js} +16 -313
- package/dist/cli/index.d.ts +59 -31
- package/dist/cli/index.js +8 -6
- package/dist/cli/init-CVZ3s5kl.js +258 -0
- package/dist/cli/{introspect-Bzuv1HHj.js → introspect-BToGNfm-.js} +14 -14
- package/dist/cli/{io-DI1mTdSA.js → io-CFzJVJ68.js} +5 -1
- package/dist/cli/{keys-BGCnnb-s.js → keys-CJhtIxJ3.js} +4 -4
- package/dist/cli/metadata-DSRKCaf-.js +133 -0
- package/dist/cli/names-D6LrQnOv.js +6 -0
- package/dist/cli/openapi-3.0-t7xwkuRH.js +928 -0
- package/dist/cli/openapi-3.1-CVze7tBS.js +870 -0
- package/dist/cli/openapi-3.2-CFoMYM01.js +1031 -0
- package/dist/cli/{openapi-BlRJ18s3.js → openapi-DWa4Ir1q.js} +8 -14
- package/dist/cli/prompts-BdeVmVpg.js +2 -0
- package/dist/cli/{prompts-BNcNfAve.js → prompts-DZJB1nTw.js} +6 -6
- package/dist/cli/{rolldown-runtime-BPOCksWG.js → rolldown-runtime-CMFfr-1z.js} +3 -1
- package/dist/cli/run-DA6_lg3w.js +389 -0
- package/dist/cli/run-DuN1MX-7.js +705 -0
- package/dist/cli/scaffold-5DenHSxF.js +292 -0
- package/dist/cli/scaffold-CwQUMFRb.js +2 -0
- package/dist/cli/{seed-DQzqT7LP.js → seed-CzBmrGON.js} +14 -18
- package/dist/cli/seed-DOmit9Hq.js +2 -0
- package/dist/cli/{skills-QQs4q68J.js → skills-CnO8QFS7.js} +7 -6
- package/dist/cli/snapshot-Bstk6ulj.js +287 -0
- package/dist/cli/source-args-BYfq6imV.js +31 -0
- package/dist/cli/spec-CzosTYm3.js +7438 -0
- package/dist/cli/spec-T_0Bcyw7.js +2 -0
- package/dist/cli/{sql-B8csQPyn.js → sql-BKOOQAX3.js} +240 -218
- package/dist/cli/sql-DJrNDxQm.js +3 -0
- package/dist/cli/{style-C0NFdJRL.js → style-CB3vxgh0.js} +3 -3
- package/dist/cli/typegen-Demi5-VQ.js +486 -0
- package/dist/cli/validate-Ca13ktgz.js +7522 -0
- package/dist/cli/{version-Bp4fyubI.js → version-B4k0aUxS.js} +1 -1
- package/dist/client/index.d.ts +4 -3
- package/dist/client/index.js +60 -3
- package/dist/client/native/index.d.ts +3 -3
- package/dist/client/native/index.js +3 -3
- package/dist/{client-CI0Z2zWX.js → client-wxeTQFtB.js} +36 -3
- package/dist/{clone-BfgmLU90.js → clone-dN9XOL1K.js} +9 -1
- package/dist/{cloud-event-BnmD5fb9.js → cloud-event-CTh9Sr5w.js} +16 -2
- package/dist/{cloud-event-C1JCc1bH.d.ts → cloud-event-Dune0KI7.d.ts} +16 -2
- package/dist/{compiler-DY_wkj4R.d.ts → compiler-V1qvcST1.d.ts} +2 -2
- package/dist/{compose-BIBNgAnq.js → compose-BHej1acw.js} +3 -3
- package/dist/{composite-CpHLEo-G.d.ts → composite-CWAJTRBF.d.ts} +6 -6
- package/dist/{composite-C6I8ZyaF.js → composite-zTe0TCqj.js} +4 -4
- package/dist/config/index.d.ts +3 -4
- package/dist/config/index.js +4 -4
- package/dist/config-DlKvtt95.js +540 -0
- package/dist/{connector-Dv8kK0MO.d.ts → connector-CySQEFcW.d.ts} +1 -1
- package/dist/{connectors-CrpknU0P.d.ts → connectors--PGhmiu0.d.ts} +4 -4
- package/dist/{context-BCrWe7ow.d.ts → context-DsV2SueA.d.ts} +11 -2
- package/dist/context-nPDvQ-Zl.js +41 -0
- package/dist/credentials/index.d.ts +5 -5
- package/dist/credentials/index.js +9 -17
- package/dist/{cron-DVPUg5k3.js → cron-D25Ukpxy.js} +1 -1
- package/dist/cron-route-D2AN9SA1.js +24 -0
- package/dist/{csv-DCK-PT1n.js → csv-BZnHA1Py.js} +1 -1
- package/dist/{define-B-TVjC25.js → define-CFQcvM20.js} +263 -229
- package/dist/{define-CJJkkr1-.d.ts → define-DmcfoNXB.d.ts} +136 -111
- package/dist/edge/index.d.ts +66 -13
- package/dist/edge/index.js +65 -39
- package/dist/elysia/index.d.ts +1 -1
- package/dist/elysia/index.js +1 -1
- package/dist/{embeddings-C9KGQnXt.d.ts → embeddings-B4vhS-dY.d.ts} +1 -1
- package/dist/{ended-XjeGQ5XW.d.ts → ended-CcvcRqEd.d.ts} +7 -1
- package/dist/{entitlements-DRl6ZJUm.js → entitlements-BYFf0Cdh.js} +2 -2
- package/dist/{entitlements-BKSVGtrG.d.ts → entitlements-Ds8qoYZ-.d.ts} +1 -1
- package/dist/env/index.d.ts +1 -1
- package/dist/env/index.js +9 -2
- package/dist/{errors-B11Duf73.js → errors-2M6CKMP4.js} +5 -0
- package/dist/{errors-DLjJHPLK.js → errors-rZ7VIqp6.js} +2 -2
- package/dist/{escape-like-ImTK0ps_.d.ts → escape-like-DDWoHzh_.d.ts} +1 -1
- package/dist/eve/index.d.ts +5 -5
- package/dist/eve/index.js +5 -11
- package/dist/{eve-gT2Fpjut.d.ts → eve-CoAIcCkq.d.ts} +2 -2
- package/dist/events/index.d.ts +4 -4
- package/dist/events/index.js +7 -2
- package/dist/{events-DWDhx77e.d.ts → events-D1BOCll8.d.ts} +6 -4
- package/dist/{executor-Bq28caBo.js → executor-B-fD7DLt.js} +52 -35
- package/dist/executor-B_Hfobee.js +162 -0
- package/dist/{executor-BVBFM86G.d.ts → executor-CpxLPCiz.d.ts} +1 -1
- package/dist/{executor-CaWigTyR.d.ts → executor-DfEtf0cq.d.ts} +43 -27
- package/dist/{executor-DvsBbNBS.d.ts → executor-Drzu3dBK.d.ts} +2 -2
- package/dist/{executor-DbvExCFC.d.ts → executor-ngjKL_Pe.d.ts} +2 -2
- package/dist/expo/index.d.ts +4 -4
- package/dist/expo/index.js +6 -6
- package/dist/expo-sqlite/index.d.ts +3 -3
- package/dist/expo-sqlite/index.js +2 -2
- package/dist/extra-CGQ2_q3S.js +10 -0
- package/dist/{field-errors-BFOa7WhB.d.ts → field-errors-DIe9XYWL.d.ts} +17 -7
- package/dist/{field-errors-VF1yb8yI.js → field-errors-DZVRWRkf.js} +1 -1
- package/dist/format-DTXdu8ya.d.ts +70 -0
- package/dist/{framework-KIPvRQJU.d.ts → framework-148t1m3C.d.ts} +5 -5
- package/dist/{framework-BDCpJI7o.js → framework-3ey3QmrO.js} +2 -2
- package/dist/function-contract-BcZenXMO.d.ts +8 -0
- package/dist/{gateway-C1ssRHnf.d.ts → gateway-S9vicgeo.d.ts} +4 -4
- package/dist/{guards-BnzDvFrz.js → guards-6F2bCtQR.js} +3 -1
- package/dist/h3/index.d.ts +1 -1
- package/dist/h3/index.js +1 -1
- package/dist/h3/v1/index.d.ts +1 -1
- package/dist/h3/v1/index.js +1 -1
- package/dist/{message-CaKlqdsX.js → history-GH1HJWQV.js} +65 -13
- package/dist/hmac-DCud0myt.js +22 -0
- package/dist/hono/index.d.ts +19 -14
- package/dist/hono/index.js +21 -16
- package/dist/{hooks-1BTCJsiw.js → hooks-Bhza9Hnr.js} +68 -100
- package/dist/http-sbmBe5d2.js +25 -0
- package/dist/{inbox-i7E1ppo6.d.ts → inbox-Cd1KCEBL.d.ts} +3 -3
- package/dist/index-B72Rvv_j.d.ts +89 -0
- package/dist/{index-DunNRdnT.d.ts → index-BCHR4Ucl.d.ts} +4 -4
- package/dist/{index-CLg87OBW.d.ts → index-BUK7jUzR.d.ts} +6 -0
- package/dist/{config-D44Y7PAv.d.ts → index-Ba1SI-uO.d.ts} +625 -278
- package/dist/{index-D48jVS-N.d.ts → index-BfxOaOYs.d.ts} +4 -5
- package/dist/{index-ClmjK_o-.d.ts → index-CicIyqOe.d.ts} +4 -4
- package/dist/{index-ACiNPN4Z.d.ts → index-D69h4QqD.d.ts} +1 -1
- package/dist/index-DG2SUXDQ.d.ts +58 -0
- package/dist/{index-Bepi-Hgg.d.ts → index-DoNVLHOU.d.ts} +3 -3
- package/dist/{index-CdZKQF98.d.ts → index-R274XFlg.d.ts} +1 -1
- package/dist/{index-CewnYSpv.d.ts → index-_4R4b01v.d.ts} +8 -18
- package/dist/index.d.ts +89 -14
- package/dist/index.js +12 -11
- package/dist/{json-schema-CvER4kgT.js → json-schema-CT4tvrkA.js} +148 -102
- package/dist/{kit-Fm-Fv7q5.js → kit-BhHr9T9v.js} +36 -10
- package/dist/{kit-CkNzZUqv.d.ts → kit-W99LCPBS.d.ts} +13 -7
- package/dist/{knowledge-BXBbT0Tr.d.ts → knowledge-CAReFpRA.d.ts} +5 -5
- package/dist/{knowledge-CDmiMLew.js → knowledge-DnHtb64A.js} +4 -3
- package/dist/list/index.d.ts +1 -2
- package/dist/{list-query-BRt-zDF7.d.ts → list-query-D3JQeEL7.d.ts} +4 -4
- package/dist/mcp/index.d.ts +49 -19
- package/dist/mcp/index.js +158 -94
- package/dist/mcp/sdk/index.d.ts +38 -6
- package/dist/mcp/sdk/index.js +88 -6
- package/dist/{message-CfDoR0Y6.d.ts → message-B0fNJgq8.d.ts} +1 -2
- package/dist/{messages-B9-5887d.js → messages-CJoHHCWT.js} +4 -205
- package/dist/{mfa-Daak8ukG.d.ts → mfa-SZc9YYyb.d.ts} +1 -1
- package/dist/model-OgBxvk3N.d.ts +300 -0
- package/dist/model-messages-Cxw_Up4f.js +206 -0
- package/dist/model-messages-D4GZllOD.d.ts +34 -0
- package/dist/modules-DksjZyMW.js +77 -0
- package/dist/nestjs/index.d.ts +2 -2
- package/dist/nestjs/index.js +1 -1
- package/dist/next/index.d.ts +105 -55
- package/dist/next/index.js +204 -170
- package/dist/node/index.d.ts +2 -2
- package/dist/node/index.js +1 -1
- package/dist/{onboarding-BZGHYJks.d.ts → onboarding-LZvlK1P4.d.ts} +3 -3
- package/dist/openapi/index.d.ts +4 -2
- package/dist/openapi/index.js +21 -343
- package/dist/optional-peer-D1pi-skw.js +24 -0
- package/dist/orpc/index.d.ts +8 -8
- package/dist/orpc/index.js +21 -20
- package/dist/otel/index.d.ts +3 -3
- package/dist/otel/index.js +7 -7
- package/dist/{outbox-Cq7pPYvl.d.ts → outbox-DZfAvfzC.d.ts} +6 -6
- package/dist/overlay/index.d.ts +233 -0
- package/dist/overlay/index.js +554 -0
- package/dist/{plugin-FGY8UhYm.d.ts → plugin-CPK2HsbY.d.ts} +42 -3
- package/dist/plugins/actor/index.d.ts +1 -1
- package/dist/plugins/actor/index.js +1 -1
- package/dist/plugins/rules/index.d.ts +2 -2
- package/dist/plugins/rules/index.js +1 -1
- package/dist/plugins/soft-delete/index.d.ts +3 -3
- package/dist/plugins/soft-delete/index.js +9 -2
- package/dist/plugins/tenant/index.d.ts +7 -2
- package/dist/plugins/tenant/index.js +16 -2
- package/dist/plugins/timestamps/index.d.ts +1 -1
- package/dist/plugins/timestamps/index.js +8 -1
- package/dist/plugins/validation/index.d.ts +2 -2
- package/dist/plugins/validation/index.js +4 -4
- package/dist/{pool-CAu2nLrL.d.ts → pool-gkhbGp2E.d.ts} +2 -2
- package/dist/postgres/index.d.ts +4 -4
- package/dist/postgres/index.js +2 -1
- package/dist/{postgrest-BLVdEnfe.d.ts → postgrest-BUqLag2Q.d.ts} +1 -1
- package/dist/powersync/index.d.ts +5 -5
- package/dist/powersync/index.js +4 -4
- package/dist/powersync/react/index.d.ts +3 -3
- package/dist/powersync/react/index.js +1 -1
- package/dist/{problem-BreOl8b8.js → problem-CJvFeGu7.js} +13 -2
- package/dist/{problem-DD8LZFjc.d.ts → problem-TvGdxO1t.d.ts} +7 -1
- package/dist/{provider-Di3sRutW.js → provider-DxRTex4x.js} +1 -1
- package/dist/{provider-D-UEMvSD.d.ts → provider-ib9wzUDz.d.ts} +2 -2
- package/dist/query/index.d.ts +2 -2
- package/dist/query/index.js +1 -1
- package/dist/{query-BQ-NaZon.js → query-Ctz-qKRx.js} +1 -1
- package/dist/rate-limit-Bw7HgmFj.js +260 -0
- package/dist/react/index.d.ts +9 -9
- package/dist/react/index.js +4 -4
- package/dist/react/native/index.d.ts +1 -1
- package/dist/react/native/index.js +2 -2
- package/dist/react/server.d.ts +10 -10
- package/dist/react/server.js +3 -3
- package/dist/react/session.d.ts +2 -2
- package/dist/{react-F80mF4-t.js → react-Bmpo59D7.js} +4 -4
- package/dist/react-router/index.d.ts +6 -6
- package/dist/react-router/index.js +9 -11
- package/dist/{read-set-DuKWC9Mj.js → read-set-DAeWhqPf.js} +2 -2
- package/dist/realtime/index.d.ts +3 -3
- package/dist/realtime/index.js +30 -36
- package/dist/{refusal-DhSU2Vvr.d.ts → refusal-CFI8-5nf.d.ts} +4 -1
- package/dist/{refusal-CeJWxmkH.js → refusal-K78A1Vmq.js} +5 -5
- package/dist/{resolve-tJZY3FEa.js → resolve-Bvgf3ut_.js} +131 -42
- package/dist/{resolve-ChTYeTEl.d.ts → resolve-MxXVWyhd.d.ts} +12 -8
- package/dist/resource--vTrBe6I.d.ts +103 -0
- package/dist/resource-BqNqlYg9.js +91 -0
- package/dist/resource-DA811u_4.js +463 -0
- package/dist/resource-execute-rbKvuCsY.d.ts +12 -0
- package/dist/resource-schemas-BJ518zFH.js +79 -0
- package/dist/resource-types-CqB6GWGT.d.ts +141 -0
- package/dist/resources-BVYPnuLo.js +56 -0
- package/dist/resources-DZSk8tXJ.d.ts +7 -0
- package/dist/{respond-DprrgyXX.d.ts → respond-Cw-zanCm.d.ts} +3 -3
- package/dist/{respond-BUgsXNgk.js → respond-volM3ByS.js} +4 -4
- package/dist/{result-D7y2fT87.d.ts → result-BchM1XZn.d.ts} +7 -1
- package/dist/{result-DzUbqgdW.js → result-DEqHCMKP.js} +1 -1
- package/dist/server/index.d.ts +81 -19
- package/dist/server/index.js +16 -14
- package/dist/{server-ZSJ9rCcV.d.ts → server-types-CrAmZ8jv.d.ts} +110 -36
- package/dist/{shared-CxWmcyqB.js → shared-DHjhfRdV.js} +2 -15
- package/dist/shared-DTneRoxi.js +14 -0
- package/dist/{sign-in-Cb1mwv6X.js → sign-in-D_yoP0PF.js} +1 -1
- package/dist/signatures-BRS_p3WD.d.ts +34 -0
- package/dist/signatures-DsWv_bYR.js +103 -0
- package/dist/{signers-4y62_VIi.d.ts → signers-cpdmZYrv.d.ts} +1 -1
- package/dist/solid/index.d.ts +9 -18
- package/dist/solid/index.js +2 -2
- package/dist/solid-start/index.d.ts +6 -6
- package/dist/solid-start/index.js +7 -7
- package/dist/spec/index.d.ts +134 -0
- package/dist/spec/index.js +353 -0
- package/dist/{spec-pins-C89s6DyW.d.ts → spec-pins-CwzDY25w.d.ts} +18 -1
- package/dist/{spec-pins--j6mTok4.js → spec-pins-DsLfUH7l.js} +14 -1
- package/dist/sql/index.d.ts +145 -119
- package/dist/sql/index.js +19921 -19798
- package/dist/{executor-De1Of3m3.js → sql-CwuqaQ4Y.js} +34 -169
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +3 -2
- package/dist/{standard-BK0cqJ7y.js → standard-DkzZUneg.js} +2 -2
- package/dist/{standard-CYsm7xpT.d.ts → standard-lmkbOtPB.d.ts} +1 -1
- package/dist/{stats-D_AD9GGu.js → stats-DhU78Ctf.js} +8 -4
- package/dist/storage/index.d.ts +4 -6
- package/dist/storage/index.js +16 -17
- package/dist/{bucket-Cl46E3jS.d.ts → storage-api-CB7Zl1Ci.d.ts} +243 -8
- package/dist/{store-CGjgWu5n.d.ts → store-DsIYEBnv.d.ts} +1 -1
- package/dist/streams/index.d.ts +4 -4
- package/dist/streams/index.js +5 -4
- package/dist/streams/redis/index.d.ts +1 -1
- package/dist/streams/redis/index.js +5 -11
- package/dist/{stripe-BMj5LtsT.js → stripe-v-Y2lmop.js} +2 -8
- package/dist/supabase-mcp-C6tMoEjn.d.ts +43 -0
- package/dist/supabase-mcp-Cpn5A4i-.js +28 -0
- package/dist/{support-DWwzVf-O.js → support-D1pFFouF.js} +71 -35
- package/dist/{support-view-CVOJJLpc.d.ts → support-view-scqMgtOo.d.ts} +1 -1
- package/dist/svelte/index.d.ts +8 -17
- package/dist/svelte/index.js +2 -2
- package/dist/sveltekit/index.d.ts +7 -7
- package/dist/sveltekit/index.js +10 -12
- package/dist/table-schema-htM_SbCW.js +286 -0
- package/dist/{tags-Cx-LnIQP.d.ts → tags-BO9LjtWG.d.ts} +1 -1
- package/dist/tanstack-db/index.d.ts +2 -2
- package/dist/tanstack-db/supabase/index.d.ts +52 -0
- package/dist/tanstack-db/supabase/index.js +97 -0
- package/dist/tanstack-start/index.d.ts +6 -6
- package/dist/tanstack-start/index.js +8 -12
- package/dist/{tee-CoEppCER.js → tee-Cb98Vn3b.js} +1 -1
- package/dist/{template--jDkl3UP.js → template-lPVh-EwW.js} +11 -2
- package/dist/{temporal-required-BVvW7SYJ.js → temporal-required-BtynQtM-.js} +1 -1
- package/dist/{tenant-BxNFk9bx.d.ts → tenant-CM368LXb.d.ts} +2 -2
- package/dist/testing/index.d.ts +249 -118
- package/dist/testing/index.js +1418 -870
- package/dist/ttl-cache-XzZ-Q2eX.js +29 -0
- package/dist/types-BRTSpOIh.js +5 -0
- package/dist/{types-C05bxW-W.d.ts → types-Bb_4-vdW.d.ts} +4 -4
- package/dist/{types-AYOvcyep.d.ts → types-CD6yCDx3.d.ts} +5 -5
- package/dist/{types-6rocye-y.d.ts → types-CbOUc5IH.d.ts} +4 -4
- package/dist/{types-6BdhkmZe.d.ts → types-CoE5Zwy4.d.ts} +8 -0
- package/dist/{types-DGs5L0VN.d.ts → types-DSJ3-m9X.d.ts} +4 -4
- package/dist/{queue-CLJurhdy.d.ts → types-D__3EN0q.d.ts} +17 -19
- package/dist/{usage-CrvrL2vw.d.ts → usage-D0NNUFfr.d.ts} +3 -3
- package/dist/{vault-wlbBhqm7.d.ts → vault-BpmApxxW.d.ts} +3 -3
- package/dist/vercel-connect/index.d.ts +1 -1
- package/dist/vercel-connect/index.js +5 -11
- package/dist/{verify-DPuWngD4.d.ts → verify-C91Wyp40.d.ts} +5 -35
- package/dist/verify-CJbYfADA.js +124 -0
- package/dist/{version--AolB5ej.js → version-Cq8gfDbd.js} +1 -1
- package/dist/{view-BeFcRV6G.js → view-D5ryq3gz.js} +1 -1
- package/dist/{view-CF7ihnkg.d.ts → view-TpXEUcVN.d.ts} +3 -3
- package/dist/vue/index.d.ts +9 -18
- package/dist/vue/index.js +2 -2
- package/dist/{watch-Xuxrvxq-.js → watch-BcvtAHOd.js} +2 -2
- package/dist/{watch-DI34G86j.d.ts → watch-COzRWvVN.d.ts} +23 -9
- package/dist/{wire-DtZQ4sdE.js → wire-Df3EWkG8.js} +2 -2
- package/dist/{workflow-builder-DJ1oHn8g.js → workflow-builder-CHqHpAVt.js} +6 -5
- package/dist/workflow-sdk/builder/index.d.ts +3 -3
- package/dist/workflow-sdk/index.d.ts +1 -1
- package/dist/workflow-sdk/world/index.d.ts +23 -17
- package/dist/workflow-sdk/world/index.js +59 -76
- package/dist/{workflow-sdk-B3yLD6Br.d.ts → workflow-sdk-DTZyrvNo.d.ts} +3 -3
- package/dist/{workflow-sdk-world-D-prir6O.js → workflow-sdk-world-CMV1ahFW.js} +528 -526
- package/dist/{workflows-B0j9WKPu.d.ts → workflows-CcpCBfIe.d.ts} +3 -3
- package/dist/{workflows-wu1WWBn7.js → workflows-IvxzG2cl.js} +5 -4
- package/package.json +54 -3
- package/schemas/config-v1.json +243 -0
- package/schemas/doctor-report-v1.json +4 -1
- package/schemas/spec-manifest-v1.json +95 -0
- package/skills/better-supabase/SKILL.md +8 -4
- package/skills/better-supabase/references/troubleshooting.md +20 -20
- package/skills/better-supabase-api/references/expo.md +6 -3
- package/skills/better-supabase-api/references/powersync.md +2 -1
- package/skills/better-supabase-auth/SKILL.md +8 -4
- package/dist/cli/config-B9HkL8nF.js +0 -2
- package/dist/cli/gen-AIf4MREI.js +0 -3100
- package/dist/cli/gen-DSrahEdX.js +0 -2
- package/dist/cli/prompts-BTYQGunc.js +0 -2
- package/dist/cli/run-BO052mki.js +0 -361
- package/dist/config-Dn7F5k9A.js +0 -202
- package/dist/history-BZih6SFP.js +0 -64
- package/dist/index-BkWT_uBO.d.ts +0 -51
- package/dist/index-Bxih3l0u.d.ts +0 -81
- package/dist/index-CaxrMD1A.d.ts +0 -1
- package/dist/index-DQh4VCc9.d.ts +0 -98
- package/dist/keys-4MnkWTTh.js +0 -35
- package/dist/messages-DYP0sUTe.d.ts +0 -59
- package/dist/modules-dxrVK3ID.js +0 -228
- package/dist/path-Cv__-OTj.d.ts +0 -17
- package/dist/resource-BsvzCMlX.js +0 -212
- package/dist/resource-IPS5xi9q.d.ts +0 -74
- package/dist/template-CwO38Do8.d.ts +0 -6
- package/dist/verify-DL41hbvY.js +0 -232
- package/dist/cli/{read-sets-CETOSFx4.js → read-sets-DjJrm8Wj.js} +1 -1
|
@@ -1,105 +1,28 @@
|
|
|
1
|
-
import { a as list, r as defineCliCommand } from "./command-
|
|
2
|
-
import { n as CliError } from "./errors-
|
|
3
|
-
import {
|
|
4
|
-
import { i as plain, r as painter } from "./style-
|
|
5
|
-
import { t as VERSION } from "./version-
|
|
6
|
-
import {
|
|
7
|
-
import { s as stdinDatabaseUrl } from "./config-NiPxAmUF.js";
|
|
8
|
-
import { c as migrationCommand, d as schemaPaths, i as findRepoRoot, l as pgFunctionHooks, p as tomlGet, r as diffEngine, s as httpHooks, u as readSupabaseToml } from "./supabase-toml-B-bIukQF.js";
|
|
1
|
+
import { a as list, r as defineCliCommand } from "./command-DV-StG1x.js";
|
|
2
|
+
import { n as CliError, r as errorText } from "./errors-CqTLXe2M.js";
|
|
3
|
+
import { a as writeIfChanged, i as sameText, t as display } from "./io-CFzJVJ68.js";
|
|
4
|
+
import { i as plain, r as painter } from "./style-CB3vxgh0.js";
|
|
5
|
+
import { t as VERSION } from "./version-B4k0aUxS.js";
|
|
6
|
+
import { t as CACHE_DIR } from "./cache-CIfA-jBV.js";
|
|
9
7
|
import { t as byCodePoint } from "./compare-BmIWVEui.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
8
|
+
import { h as satisfies, m as peerVersions, t as MetadataRejectedError } from "./typegen-Demi5-VQ.js";
|
|
9
|
+
import { s as configFor } from "./emit-BHHfwUoT.js";
|
|
10
|
+
import { _ as tableObject, a as METADATA_GAPS_TEXT, c as accessModule, d as exposed, f as exposedSchemas, g as qualified, h as policyObject, l as entitlementsModule, m as permissionCatalogKeys, p as lineOf, s as AUTHORIZATION_RULES, u as catalogOf, y as renderFiles } from "./run-DuN1MX-7.js";
|
|
11
|
+
import { s as providerLabel, t as compiledReadSets } from "./read-sets-DjJrm8Wj.js";
|
|
12
|
+
import { c as stdinDatabaseUrl } from "./config-M-WzL9O2.js";
|
|
13
|
+
import { c as migrationCommand, d as schemaPaths, i as findRepoRoot, l as pgFunctionHooks, p as tomlGet, r as diffEngine, s as httpHooks, u as readSupabaseToml } from "./supabase-toml-B-bIukQF.js";
|
|
14
|
+
import { t as connect } from "./db-BkcfOlyB.js";
|
|
15
|
+
import { c as isSqliteLiteDriver, n as managementTarget, o as snapshotFile, r as openSource, s as liteDriverOf, t as loadSnapshot } from "./snapshot-Bstk6ulj.js";
|
|
13
16
|
import { n as moduleLayoutFor } from "./sql-layout-D6cphHT3.js";
|
|
17
|
+
import { n as readMetadataSnapshot } from "./metadata-DSRKCaf-.js";
|
|
18
|
+
import { n as withSpinner } from "./prompts-DZJB1nTw.js";
|
|
14
19
|
import { dirname, resolve } from "node:path";
|
|
15
20
|
import { existsSync } from "node:fs";
|
|
16
21
|
import { glob, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
|
|
22
|
+
import { createHash } from "node:crypto";
|
|
17
23
|
import { DEFAULT_ACTIVE_TENANT, tenantClaimPaths } from "better-supabase/config";
|
|
18
24
|
import { SQL_MODULES, contractSignature, customContracts, migrationOptionUses, moduleDeprecations, moduleEventTriggers, moduleFileVersion, moduleLayout, moduleVersion, renderModules, sameModuleFile, sharedRolesProblems } from "better-supabase/sql";
|
|
19
|
-
import { createHash } from "node:crypto";
|
|
20
25
|
import { defineBucket, parseSize } from "better-supabase/storage";
|
|
21
|
-
//#region src/cli/doctor/advisors.ts
|
|
22
|
-
/**
|
|
23
|
-
* splinter (https://github.com/supabase/splinter), the linter behind the
|
|
24
|
-
* dashboard's Security and Performance Advisors. It has no license, so it is
|
|
25
|
-
* downloaded at this commit and checked against the hash instead of bundled.
|
|
26
|
-
*/
|
|
27
|
-
const SPLINTER_COMMIT = "e74a9e36cb12258cb67d1464bc1cb196e9cd8446";
|
|
28
|
-
const SPLINTER_SHA256 = "d8d558baad3e03832e521c527907fa50a9a172fabd899dd0f5c2504a5a0e9349";
|
|
29
|
-
const SPLINTER_URL = `https://raw.githubusercontent.com/supabase/splinter/${SPLINTER_COMMIT}/splinter.sql`;
|
|
30
|
-
function isLint(value) {
|
|
31
|
-
const lint = value;
|
|
32
|
-
return typeof lint === "object" && lint !== null && typeof lint.name === "string" && typeof lint.level === "string" && Array.isArray(lint.categories);
|
|
33
|
-
}
|
|
34
|
-
/** The hosted project's advisors (`GET /v1/projects/{ref}/advisors/{category}`). */
|
|
35
|
-
function managementAdvisors(options) {
|
|
36
|
-
const base = (options.apiUrl ?? "https://api.supabase.com").replace(/\/$/, "");
|
|
37
|
-
const doFetch = options.fetch ?? fetch;
|
|
38
|
-
return {
|
|
39
|
-
describe: `project ${options.projectRef} advisors (Management API)`,
|
|
40
|
-
async lints(category) {
|
|
41
|
-
const url = `${base}/v1/projects/${encodeURIComponent(options.projectRef)}/advisors/${category}`;
|
|
42
|
-
const response = await doFetch(url, { headers: { authorization: `Bearer ${options.accessToken}` } });
|
|
43
|
-
const text = await response.text();
|
|
44
|
-
if (!response.ok) throw new Error(`Management API ${category} advisors failed (${response.status}): ${text.slice(0, 300)}`);
|
|
45
|
-
const body = JSON.parse(text);
|
|
46
|
-
if (!Array.isArray(body.lints)) throw new TypeError(`Management API ${category} advisors returned no "lints".`);
|
|
47
|
-
return body.lints.filter(isLint);
|
|
48
|
-
}
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
/** The `[api] schemas` list of a `config.toml`, when it names any. */
|
|
52
|
-
function apiSchemas(document) {
|
|
53
|
-
const value = document ? tomlGet(document, ["api", "schemas"]) : void 0;
|
|
54
|
-
if (!Array.isArray(value)) return [];
|
|
55
|
-
return value.filter((schema) => typeof schema === "string" && schema.trim() !== "");
|
|
56
|
-
}
|
|
57
|
-
const literal$1 = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
58
|
-
/** The read-only transaction splinter runs in, with `pgrst.db_schemas` set first. */
|
|
59
|
-
function splinterScript(sql, schemas = []) {
|
|
60
|
-
return `begin read only;\n${schemas.length > 0 ? `set local pgrst.db_schemas = ${literal$1(schemas.join(","))};\n` : ""}${sql}\n;\nrollback;`;
|
|
61
|
-
}
|
|
62
|
-
const sha256 = (text) => createHash("sha256").update(text).digest("hex");
|
|
63
|
-
/** Downloads (once) and verifies the pinned `splinter.sql`. */
|
|
64
|
-
async function splinterSql(options) {
|
|
65
|
-
const file = resolve(options.cacheDir, `splinter-${SPLINTER_COMMIT}.sql`);
|
|
66
|
-
if (existsSync(file)) {
|
|
67
|
-
const cached = await readFile(file, "utf8");
|
|
68
|
-
if (sha256(cached) === SPLINTER_SHA256) return cached;
|
|
69
|
-
}
|
|
70
|
-
const response = await (options.fetch ?? fetch)(SPLINTER_URL);
|
|
71
|
-
if (!response.ok) throw new Error(`Downloading splinter.sql failed (${response.status}) from ${SPLINTER_URL}`);
|
|
72
|
-
const text = await response.text();
|
|
73
|
-
if (sha256(text) !== SPLINTER_SHA256) throw new Error(`splinter.sql from ${SPLINTER_URL} does not match the pinned hash; refusing to run it.`);
|
|
74
|
-
await mkdir(dirname(file), { recursive: true });
|
|
75
|
-
await writeFile(file, text);
|
|
76
|
-
return text;
|
|
77
|
-
}
|
|
78
|
-
/** `pg` returns one result per statement for a multi-statement query. */
|
|
79
|
-
function lintRows(result) {
|
|
80
|
-
const results = Array.isArray(result) ? result : [result];
|
|
81
|
-
return results.find((entry) => entry.fields?.some((field) => field.name === "cache_key"))?.rows ?? results.at(-1)?.rows ?? [];
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Runs splinter against a database (local stack, `$DATABASE_URL` or `--db-url-stdin`) in a
|
|
85
|
-
* read-only transaction that is rolled back.
|
|
86
|
-
*/
|
|
87
|
-
function splinterAdvisors(queryable, describe, options) {
|
|
88
|
-
let all;
|
|
89
|
-
const run = async () => {
|
|
90
|
-
const sql = await splinterSql(options);
|
|
91
|
-
return lintRows(await queryable.query(splinterScript(sql, options.schemas))).filter(isLint);
|
|
92
|
-
};
|
|
93
|
-
return {
|
|
94
|
-
describe: `${describe} (splinter ${SPLINTER_COMMIT.slice(0, 7)})`,
|
|
95
|
-
async lints(category) {
|
|
96
|
-
all ??= run();
|
|
97
|
-
const wanted = category.toUpperCase();
|
|
98
|
-
return (await all).filter((lint) => lint.categories.includes(wanted));
|
|
99
|
-
}
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
//#endregion
|
|
103
26
|
//#region src/cli/doctor/advisor-rules.ts
|
|
104
27
|
/** One request per advisor category, shared by the advisor rules and the rules that defer to them. */
|
|
105
28
|
const fetched = /* @__PURE__ */ new WeakMap();
|
|
@@ -163,7 +86,7 @@ function advisorRule(code, category, title, description) {
|
|
|
163
86
|
try {
|
|
164
87
|
return (await lintsOf(advisors, category)).map(lintFinding);
|
|
165
88
|
} catch (cause) {
|
|
166
|
-
return [{ message: `The ${category} advisor could not run (${advisors.describe}): ${
|
|
89
|
+
return [{ message: `The ${category} advisor could not run (${advisors.describe}): ${errorText(cause)}` }];
|
|
167
90
|
}
|
|
168
91
|
}
|
|
169
92
|
};
|
|
@@ -247,6 +170,18 @@ const COOKIE_RULES = [{
|
|
|
247
170
|
check: encodingDrift
|
|
248
171
|
}];
|
|
249
172
|
//#endregion
|
|
173
|
+
//#region src/cli/doctor/dependencies.ts
|
|
174
|
+
const DEPENDENCY_RULES = [{
|
|
175
|
+
code: "BS601",
|
|
176
|
+
severity: "warning",
|
|
177
|
+
title: "Peer outside its range",
|
|
178
|
+
description: "An optional peer of better-supabase is installed at a version outside the range better-supabase declares. With strict peer checks the install fails, and the subpath that needs the peer can break at runtime.",
|
|
179
|
+
check: (context) => (context.peers ?? []).flatMap((peer) => peer.installed !== void 0 && satisfies(peer.installed, peer.range) === false ? [{
|
|
180
|
+
message: `${peer.name}@${peer.installed} is installed, but better-supabase needs ${peer.range}. Install a version in that range, or remove ${peer.name} if nothing imports it.`,
|
|
181
|
+
target: peer.name
|
|
182
|
+
}] : [])
|
|
183
|
+
}];
|
|
184
|
+
//#endregion
|
|
250
185
|
//#region src/cli/doctor/live.ts
|
|
251
186
|
/** Statements slower than this (ms, mean) with more calls than `SLOW_CALLS` are BS209. */
|
|
252
187
|
const SLOW_MEAN_MS = 50;
|
|
@@ -255,8 +190,7 @@ const SLOW_CALLS = 1e3;
|
|
|
255
190
|
const EXPLAIN_LIMIT = 1e3;
|
|
256
191
|
const escape$2 = (name) => name.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
257
192
|
const ident$1 = (name) => `"${name.replaceAll("\"", "\"\"")}"`;
|
|
258
|
-
const literal = (text) => `'${text.replaceAll("'", "''")}'`;
|
|
259
|
-
const errorText = (cause) => cause instanceof Error ? cause.message : String(cause);
|
|
193
|
+
const literal$1 = (text) => `'${text.replaceAll("'", "''")}'`;
|
|
260
194
|
const oneLine = (query, max = 160) => {
|
|
261
195
|
const flat = query.replaceAll(/\s+/g, " ").trim();
|
|
262
196
|
return flat.length > max ? `${flat.slice(0, max - 1)}…` : flat;
|
|
@@ -328,7 +262,7 @@ async function explainTable(db, table, claims) {
|
|
|
328
262
|
tracked = false;
|
|
329
263
|
await db.query("rollback to savepoint bs_track");
|
|
330
264
|
}
|
|
331
|
-
await db.query(`select set_config('request.jwt.claims', ${literal(JSON.stringify(claims))}, true)`);
|
|
265
|
+
await db.query(`select set_config('request.jwt.claims', ${literal$1(JSON.stringify(claims))}, true)`);
|
|
332
266
|
const before = tracked ? await functionTimes(db) : /* @__PURE__ */ new Map();
|
|
333
267
|
await db.query(`set local role ${ident$1(role)}`);
|
|
334
268
|
const [row] = await db.query(`explain (analyze, buffers, format json) select * from ${ident$1(table.schema)}.${ident$1(table.name)} limit ${EXPLAIN_LIMIT}`);
|
|
@@ -433,7 +367,7 @@ const LIVE_RULES = [
|
|
|
433
367
|
const db = live(context);
|
|
434
368
|
if (!db || "skipped" in db || !db.session) return [{
|
|
435
369
|
severity: "warning",
|
|
436
|
-
message: `--explain needs a direct database connection (local stack, $DATABASE_URL or --db-url-stdin)${db && "skipped" in db ? `: ${db.skipped}` : "."}`
|
|
370
|
+
message: `--explain needs a direct database connection (local stack, $DATABASE_URL, $SUPABASE_DB_URL or --db-url-stdin)${db && "skipped" in db ? `: ${db.skipped}` : "."}`
|
|
437
371
|
}];
|
|
438
372
|
const who = typeof request.claims["sub"] === "string" ? `${String(request.claims["role"] ?? "anon")} ${request.claims["sub"]}` : String(request.claims["role"] ?? "anon");
|
|
439
373
|
const findings = [];
|
|
@@ -679,12 +613,12 @@ async function withHookEvent(db, userId, run) {
|
|
|
679
613
|
'amr', jsonb_build_array(jsonb_build_object(
|
|
680
614
|
'method', 'password', 'timestamp', extract(epoch from now())::int8
|
|
681
615
|
)),
|
|
682
|
-
'iss', ${literal(DOCTOR_ISSUER)},
|
|
616
|
+
'iss', ${literal$1(DOCTOR_ISSUER)},
|
|
683
617
|
'iat', extract(epoch from now())::int8,
|
|
684
618
|
'exp', extract(epoch from now())::int8 + 3600
|
|
685
619
|
)
|
|
686
620
|
)::text, true) as event
|
|
687
|
-
from auth.users u where u.id = ${literal(userId)}::uuid`);
|
|
621
|
+
from auth.users u where u.id = ${literal$1(userId)}::uuid`);
|
|
688
622
|
if (!user?.event) return void 0;
|
|
689
623
|
const [role] = await db.query(`select case when exists(select 1 from pg_roles where rolname = 'supabase_auth_admin')
|
|
690
624
|
then pg_has_role('supabase_auth_admin', 'member') else false end as member`);
|
|
@@ -705,8 +639,8 @@ async function hookClaims(db, fn, userId) {
|
|
|
705
639
|
});
|
|
706
640
|
}
|
|
707
641
|
async function hookClaimsSize(db, fn, userId, budget) {
|
|
708
|
-
const budgetSql = budget && budget.claims.length > 0 ? budget.claims.map((claim) => `coalesce(octet_length((c -> ${literal(claim)})::text), 0)`).join(" + ") : "0";
|
|
709
|
-
const truncatedSql = budget?.truncatedClaim ? `c ->> ${literal(budget.truncatedClaim)} = 'true'` : "false";
|
|
642
|
+
const budgetSql = budget && budget.claims.length > 0 ? budget.claims.map((claim) => `coalesce(octet_length((c -> ${literal$1(claim)})::text), 0)`).join(" + ") : "0";
|
|
643
|
+
const truncatedSql = budget?.truncatedClaim ? `c ->> ${literal$1(budget.truncatedClaim)} = 'true'` : "false";
|
|
710
644
|
return withHookEvent(db, userId, async () => {
|
|
711
645
|
const [row] = await db.query(`select octet_length(c::text) as bytes,
|
|
712
646
|
octet_length((c -> 'memberships')::text) as memberships,
|
|
@@ -799,7 +733,7 @@ const HOOK_RULES = [
|
|
|
799
733
|
if (!db || "skipped" in db || !db.session) {
|
|
800
734
|
findings.push({
|
|
801
735
|
severity: "info",
|
|
802
|
-
message: `Measuring the hook's claims needs a direct database connection (local stack, $DATABASE_URL or --db-url-stdin)${db && "skipped" in db ? `: ${db.skipped}` : "."}`,
|
|
736
|
+
message: `Measuring the hook's claims needs a direct database connection (local stack, $DATABASE_URL, $SUPABASE_DB_URL or --db-url-stdin)${db && "skipped" in db ? `: ${db.skipped}` : "."}`,
|
|
803
737
|
target: `${signatureOf(fn)}:claims`
|
|
804
738
|
});
|
|
805
739
|
continue;
|
|
@@ -937,6 +871,68 @@ const HOOK_RULES = [
|
|
|
937
871
|
}
|
|
938
872
|
];
|
|
939
873
|
//#endregion
|
|
874
|
+
//#region src/cli/doctor/lite.ts
|
|
875
|
+
const RPC_CALL = /(?:\.|\$)rpc\s*\(|\brpcTransport\s*\(/;
|
|
876
|
+
const MISSING_FEATURES = [{
|
|
877
|
+
feature: "Realtime",
|
|
878
|
+
pattern: /from\s+["']better-supabase\/realtime["']|\.channel\s*\(|\.removeChannel\s*\(/
|
|
879
|
+
}, {
|
|
880
|
+
feature: "Edge Functions",
|
|
881
|
+
pattern: /\.functions\.invoke\s*\(|\bfunctions\(\)\.invoke\s*\(/
|
|
882
|
+
}];
|
|
883
|
+
/** The `[db] driver` of a Supabase Lite project, or `undefined` for any other project. */
|
|
884
|
+
function liteDriver(context) {
|
|
885
|
+
try {
|
|
886
|
+
return liteDriverOf(context.configToml);
|
|
887
|
+
} catch {
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
function rpcOnSqlite(context) {
|
|
892
|
+
const driver = liteDriver(context);
|
|
893
|
+
if (driver === void 0 || !isSqliteLiteDriver(driver)) return [];
|
|
894
|
+
return context.sources.flatMap((file) => {
|
|
895
|
+
const line = lineOf(file.text, RPC_CALL);
|
|
896
|
+
if (line === void 0) return [];
|
|
897
|
+
return [{
|
|
898
|
+
message: `${file.path} calls a Postgres function, but Supabase Lite's ${driver} driver has no rpc(), so the call returns an unsupported error. Switch [db] driver to "pglite" or "postgres" in supabase/config.toml, or replace the function with table queries.`,
|
|
899
|
+
target: `${file.path}:rpc`,
|
|
900
|
+
location: {
|
|
901
|
+
file: file.path,
|
|
902
|
+
line
|
|
903
|
+
}
|
|
904
|
+
}];
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
function missingLiteFeature(context) {
|
|
908
|
+
if (liteDriver(context) === void 0) return [];
|
|
909
|
+
return context.sources.flatMap((file) => MISSING_FEATURES.flatMap(({ feature, pattern }) => {
|
|
910
|
+
const line = lineOf(file.text, pattern);
|
|
911
|
+
if (line === void 0) return [];
|
|
912
|
+
return [{
|
|
913
|
+
message: `${file.path} uses ${feature}, which Supabase Lite does not implement on any driver. Run the full Supabase stack for this feature, or move the project off Lite with \`supabase lite upgrade\`.`,
|
|
914
|
+
target: `${file.path}:${feature}`,
|
|
915
|
+
location: {
|
|
916
|
+
file: file.path,
|
|
917
|
+
line
|
|
918
|
+
}
|
|
919
|
+
}];
|
|
920
|
+
}));
|
|
921
|
+
}
|
|
922
|
+
const LITE_RULES = [{
|
|
923
|
+
code: "BS328",
|
|
924
|
+
severity: "warning",
|
|
925
|
+
title: "rpc() on a Supabase Lite SQLite driver",
|
|
926
|
+
description: "`[db] driver` in `config.toml` is `sqlite-postgres` or `sqlite`, which have no `rpc()`, but the app calls a Postgres function. Those calls return an `unsupported` error.",
|
|
927
|
+
check: rpcOnSqlite
|
|
928
|
+
}, {
|
|
929
|
+
code: "BS329",
|
|
930
|
+
severity: "warning",
|
|
931
|
+
title: "Feature Supabase Lite does not implement",
|
|
932
|
+
description: "`config.toml` sets `[db] driver`, so the project runs on Supabase Lite, but the app uses Realtime or Edge Functions, which Lite does not implement.",
|
|
933
|
+
check: missingLiteFeature
|
|
934
|
+
}];
|
|
935
|
+
//#endregion
|
|
940
936
|
//#region src/cli/doctor/metadata.ts
|
|
941
937
|
/**
|
|
942
938
|
* Rules that read what a `GeneratorMetadata` document leaves out (policies,
|
|
@@ -1114,7 +1110,7 @@ async function missingContracts(context) {
|
|
|
1114
1110
|
name: check.name
|
|
1115
1111
|
}
|
|
1116
1112
|
}));
|
|
1117
|
-
const names = checks.map((check) => `(${literal(check.schema)}, ${literal(check.name)})`).join(", ");
|
|
1113
|
+
const names = checks.map((check) => `(${literal$1(check.schema)}, ${literal$1(check.name)})`).join(", ");
|
|
1118
1114
|
let rows;
|
|
1119
1115
|
try {
|
|
1120
1116
|
rows = await live.query(`select n.nspname as schema, p.proname as name,
|
|
@@ -2623,7 +2619,7 @@ const RULES = [
|
|
|
2623
2619
|
code: "BS106",
|
|
2624
2620
|
severity: "error",
|
|
2625
2621
|
title: "Table not granted to the Data API",
|
|
2626
|
-
description: "Supabase no longer grants new tables to anon and authenticated. Without a grant, every Data API request fails with 42501 before RLS runs. Tables in `expose` need the privileges listed there; other tables need `select` for authenticated, except tables with no permissive policy under `sql.modules.grants.options.fromPolicies`, which are service-only. Tables marked `serviceRole` in `tables` must have no grants for either role.",
|
|
2622
|
+
description: "Supabase no longer grants new tables to anon and authenticated. Without a grant, every Data API request fails with 42501 before RLS runs. Tables in `expose` need the privileges listed there; other tables need `select` for authenticated, except tables with RLS on and no permissive policy under `sql.modules.grants.options.fromPolicies`, which are service-only. Tables marked `serviceRole` in `tables` must have no grants for either role.",
|
|
2627
2623
|
check: (context) => {
|
|
2628
2624
|
const auto = context.configToml ? tomlGet(context.configToml.document, ["api", "auto_expose_new_tables"]) : void 0;
|
|
2629
2625
|
const note = auto === false || auto === "false" ? " config.toml sets [api] auto_expose_new_tables = false, so new tables start without grants." : "";
|
|
@@ -2826,7 +2822,7 @@ const RULES = [
|
|
|
2826
2822
|
const stale = [];
|
|
2827
2823
|
for (const file of await renderFiles(context.config, context.snapshot)) {
|
|
2828
2824
|
const current = await readFile(resolve(context.config.root, file.path), "utf8").catch(() => void 0);
|
|
2829
|
-
if (current
|
|
2825
|
+
if (!sameText(current, file.contents)) stale.push({
|
|
2830
2826
|
message: `${file.path} is ${current === void 0 ? "missing" : "out of date"}. Run \`better-supabase gen\`.`,
|
|
2831
2827
|
target: file.path,
|
|
2832
2828
|
...current === void 0 ? {} : { location: {
|
|
@@ -2965,7 +2961,7 @@ const RULES = [
|
|
|
2965
2961
|
title: "Local stack signs tokens with a shared secret",
|
|
2966
2962
|
description: "Hosted projects sign with asymmetric keys. Using the same locally means local tokens verify through JWKS just like production.",
|
|
2967
2963
|
check: (context) => {
|
|
2968
|
-
if (!context.configToml || authSetting(context, "signing_keys_path")) return [];
|
|
2964
|
+
if (!context.configToml || authSetting(context, "signing_keys_path") || tomlGet(context.configToml.document, ["db", "driver"]) !== void 0) return [];
|
|
2969
2965
|
const location = tomlLocation(context, "signing_keys_path");
|
|
2970
2966
|
return [{
|
|
2971
2967
|
message: "No [auth] signing_keys_path. Run `better-supabase keys` to sign local tokens with ES256.",
|
|
@@ -3033,7 +3029,9 @@ const RULES = [
|
|
|
3033
3029
|
...AUTHORIZATION_RULES,
|
|
3034
3030
|
...LIVE_RULES,
|
|
3035
3031
|
...MODULE_RULES,
|
|
3036
|
-
...PGDELTA_RULES
|
|
3032
|
+
...PGDELTA_RULES,
|
|
3033
|
+
...LITE_RULES,
|
|
3034
|
+
...DEPENDENCY_RULES
|
|
3037
3035
|
].sort((a, b) => byCodePoint(a.code, b.code));
|
|
3038
3036
|
const RULE_CODES = RULES.map((rule) => rule.code);
|
|
3039
3037
|
async function runRules(context, rules = RULES) {
|
|
@@ -3167,75 +3165,7 @@ function formatReport(findings, options) {
|
|
|
3167
3165
|
}
|
|
3168
3166
|
}
|
|
3169
3167
|
//#endregion
|
|
3170
|
-
//#region src/cli/
|
|
3171
|
-
const ARGS = {
|
|
3172
|
-
format: {
|
|
3173
|
-
type: "string",
|
|
3174
|
-
description: "text (default), sarif (code scanning) or github (workflow annotations); --json for the JSON report",
|
|
3175
|
-
valueHint: "format"
|
|
3176
|
-
},
|
|
3177
|
-
out: {
|
|
3178
|
-
type: "string",
|
|
3179
|
-
description: "Write the report to a file",
|
|
3180
|
-
valueHint: "file"
|
|
3181
|
-
},
|
|
3182
|
-
only: {
|
|
3183
|
-
type: "string",
|
|
3184
|
-
description: "Run only these checks, e.g. --only BS100,BS304",
|
|
3185
|
-
valueHint: "codes"
|
|
3186
|
-
},
|
|
3187
|
-
ignore: {
|
|
3188
|
-
type: "string",
|
|
3189
|
-
description: "Skip checks; also doctor.ignore in the config",
|
|
3190
|
-
valueHint: "codes"
|
|
3191
|
-
},
|
|
3192
|
-
strict: {
|
|
3193
|
-
type: "boolean",
|
|
3194
|
-
description: "Fail on warnings; also doctor.strict"
|
|
3195
|
-
},
|
|
3196
|
-
snapshot: {
|
|
3197
|
-
type: "string",
|
|
3198
|
-
description: "Check a saved snapshot instead of the database",
|
|
3199
|
-
valueHint: "file"
|
|
3200
|
-
},
|
|
3201
|
-
metadata: {
|
|
3202
|
-
type: "string",
|
|
3203
|
-
description: "Check a GeneratorMetadata document (- for stdin); checks it lacks data for are skipped",
|
|
3204
|
-
valueHint: "path|-"
|
|
3205
|
-
},
|
|
3206
|
-
"db-url-stdin": {
|
|
3207
|
-
type: "boolean",
|
|
3208
|
-
description: "Read the connection string from stdin instead of $DATABASE_URL or the config"
|
|
3209
|
-
},
|
|
3210
|
-
"project-ref": {
|
|
3211
|
-
type: "string",
|
|
3212
|
-
description: "Read a hosted project through the Management API",
|
|
3213
|
-
valueHint: "ref"
|
|
3214
|
-
},
|
|
3215
|
-
stats: {
|
|
3216
|
-
type: "boolean",
|
|
3217
|
-
description: "Report slow frequent statements from pg_stat_statements (BS209)"
|
|
3218
|
-
},
|
|
3219
|
-
explain: {
|
|
3220
|
-
type: "string",
|
|
3221
|
-
description: "EXPLAIN ANALYZE these tables under RLS, rolled back (BS212)",
|
|
3222
|
-
valueHint: "tables"
|
|
3223
|
-
},
|
|
3224
|
-
as: {
|
|
3225
|
-
type: "string",
|
|
3226
|
-
description: "Plan as this authenticated user, and measure the claims the custom access token hook returns for them (BS405)",
|
|
3227
|
-
valueHint: "uuid"
|
|
3228
|
-
},
|
|
3229
|
-
claims: {
|
|
3230
|
-
type: "string",
|
|
3231
|
-
description: "Plan with these JWT claims ({\"role\":\"authenticated\",...})",
|
|
3232
|
-
valueHint: "json"
|
|
3233
|
-
},
|
|
3234
|
-
"fix-grants": {
|
|
3235
|
-
type: "boolean",
|
|
3236
|
-
description: "Print the grant and revoke SQL BS404 asks for, to add to your schema or migration"
|
|
3237
|
-
}
|
|
3238
|
-
};
|
|
3168
|
+
//#region src/cli/doctor/inputs.ts
|
|
3239
3169
|
const ENV_FILES = [
|
|
3240
3170
|
".env",
|
|
3241
3171
|
".env.local",
|
|
@@ -3276,44 +3206,90 @@ async function sourceFiles(config) {
|
|
|
3276
3206
|
});
|
|
3277
3207
|
return files.sort((a, b) => byCodePoint(a.path, b.path));
|
|
3278
3208
|
}
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3209
|
+
//#endregion
|
|
3210
|
+
//#region src/cli/doctor/advisors.ts
|
|
3211
|
+
/**
|
|
3212
|
+
* splinter (https://github.com/supabase/splinter), the linter behind the
|
|
3213
|
+
* dashboard's Security and Performance Advisors. It has no license, so it is
|
|
3214
|
+
* downloaded at this commit and checked against the hash instead of bundled.
|
|
3215
|
+
*/
|
|
3216
|
+
const SPLINTER_COMMIT = "e74a9e36cb12258cb67d1464bc1cb196e9cd8446";
|
|
3217
|
+
const SPLINTER_SHA256 = "d8d558baad3e03832e521c527907fa50a9a172fabd899dd0f5c2504a5a0e9349";
|
|
3218
|
+
const SPLINTER_URL = `https://raw.githubusercontent.com/supabase/splinter/${SPLINTER_COMMIT}/splinter.sql`;
|
|
3219
|
+
function isLint(value) {
|
|
3220
|
+
const lint = value;
|
|
3221
|
+
return typeof lint === "object" && lint !== null && typeof lint.name === "string" && typeof lint.level === "string" && Array.isArray(lint.categories);
|
|
3222
|
+
}
|
|
3223
|
+
/** The hosted project's advisors (`GET /v1/projects/{ref}/advisors/{category}`). */
|
|
3224
|
+
function managementAdvisors(options) {
|
|
3225
|
+
const base = (options.apiUrl ?? "https://api.supabase.com").replace(/\/$/, "");
|
|
3226
|
+
const doFetch = options.fetch ?? fetch;
|
|
3227
|
+
return {
|
|
3228
|
+
describe: `project ${options.projectRef} advisors (Management API)`,
|
|
3229
|
+
async lints(category) {
|
|
3230
|
+
const url = `${base}/v1/projects/${encodeURIComponent(options.projectRef)}/advisors/${category}`;
|
|
3231
|
+
const response = await doFetch(url, { headers: { authorization: `Bearer ${options.accessToken}` } });
|
|
3232
|
+
const text = await response.text();
|
|
3233
|
+
if (!response.ok) throw new Error(`Management API ${category} advisors failed (${response.status}): ${text.slice(0, 300)}`);
|
|
3234
|
+
const body = JSON.parse(text);
|
|
3235
|
+
if (!Array.isArray(body.lints)) throw new TypeError(`Management API ${category} advisors returned no "lints".`);
|
|
3236
|
+
return body.lints.filter(isLint);
|
|
3292
3237
|
}
|
|
3293
|
-
|
|
3294
|
-
}
|
|
3295
|
-
const pattern = object.kind === "table" ? new RegExp(`create\\s+(?:unlogged\\s+)?table\\s+(?:if\\s+not\\s+exists\\s+)?${qualifiedName}(?:\\s|\\(|$)`, "i") : object.kind === "function" ? new RegExp(`create\\s+(?:or\\s+replace\\s+)?function\\s+${qualifiedName}\\s*\\(`, "i") : new RegExp(`create\\s+policy\\s+${name}`, "i");
|
|
3296
|
-
for (const file of files) {
|
|
3297
|
-
const line = lineOf(file.text, pattern);
|
|
3298
|
-
if (line) return {
|
|
3299
|
-
file: file.path,
|
|
3300
|
-
line
|
|
3301
|
-
};
|
|
3302
|
-
}
|
|
3238
|
+
};
|
|
3303
3239
|
}
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
if (
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3240
|
+
/** The `[api] schemas` list of a `config.toml`, when it names any. */
|
|
3241
|
+
function apiSchemas(document) {
|
|
3242
|
+
const value = document ? tomlGet(document, ["api", "schemas"]) : void 0;
|
|
3243
|
+
if (!Array.isArray(value)) return [];
|
|
3244
|
+
return value.filter((schema) => typeof schema === "string" && schema.trim() !== "");
|
|
3245
|
+
}
|
|
3246
|
+
const literal = (value) => `'${value.replaceAll("'", "''")}'`;
|
|
3247
|
+
/** The read-only transaction splinter runs in, with `pgrst.db_schemas` set first. */
|
|
3248
|
+
function splinterScript(sql, schemas = []) {
|
|
3249
|
+
return `begin read only;\n${schemas.length > 0 ? `set local pgrst.db_schemas = ${literal(schemas.join(","))};\n` : ""}${sql}\n;\nrollback;`;
|
|
3250
|
+
}
|
|
3251
|
+
const sha256 = (text) => createHash("sha256").update(text).digest("hex");
|
|
3252
|
+
/** Downloads (once) and verifies the pinned `splinter.sql`. */
|
|
3253
|
+
async function splinterSql(options) {
|
|
3254
|
+
const file = resolve(options.cacheDir, `splinter-${SPLINTER_COMMIT}.sql`);
|
|
3255
|
+
if (existsSync(file)) {
|
|
3256
|
+
const cached = await readFile(file, "utf8");
|
|
3257
|
+
if (sha256(cached) === SPLINTER_SHA256) return cached;
|
|
3311
3258
|
}
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3259
|
+
const response = await (options.fetch ?? fetch)(SPLINTER_URL);
|
|
3260
|
+
if (!response.ok) throw new Error(`Downloading splinter.sql failed (${response.status}) from ${SPLINTER_URL}`);
|
|
3261
|
+
const text = await response.text();
|
|
3262
|
+
if (sha256(text) !== SPLINTER_SHA256) throw new Error(`splinter.sql from ${SPLINTER_URL} does not match the pinned hash; refusing to run it.`);
|
|
3263
|
+
await mkdir(dirname(file), { recursive: true });
|
|
3264
|
+
await writeFile(file, text);
|
|
3265
|
+
return text;
|
|
3266
|
+
}
|
|
3267
|
+
/** `pg` returns one result per statement for a multi-statement query. */
|
|
3268
|
+
function lintRows(result) {
|
|
3269
|
+
const results = Array.isArray(result) ? result : [result];
|
|
3270
|
+
return results.find((entry) => entry.fields?.some((field) => field.name === "cache_key"))?.rows ?? results.at(-1)?.rows ?? [];
|
|
3271
|
+
}
|
|
3272
|
+
/**
|
|
3273
|
+
* Runs splinter against a database (local stack, `$DATABASE_URL` or `--db-url-stdin`) in a
|
|
3274
|
+
* read-only transaction that is rolled back.
|
|
3275
|
+
*/
|
|
3276
|
+
function splinterAdvisors(queryable, describe, options) {
|
|
3277
|
+
let all;
|
|
3278
|
+
const run = async () => {
|
|
3279
|
+
const sql = await splinterSql(options);
|
|
3280
|
+
return lintRows(await queryable.query(splinterScript(sql, options.schemas))).filter(isLint);
|
|
3281
|
+
};
|
|
3282
|
+
return {
|
|
3283
|
+
describe: `${describe} (splinter ${SPLINTER_COMMIT.slice(0, 7)})`,
|
|
3284
|
+
async lints(category) {
|
|
3285
|
+
all ??= run();
|
|
3286
|
+
const wanted = category.toUpperCase();
|
|
3287
|
+
return (await all).filter((lint) => lint.categories.includes(wanted));
|
|
3288
|
+
}
|
|
3289
|
+
};
|
|
3316
3290
|
}
|
|
3291
|
+
//#endregion
|
|
3292
|
+
//#region src/cli/doctor/live-source.ts
|
|
3317
3293
|
/** Checks that read the database itself rather than the snapshot. */
|
|
3318
3294
|
const LIVE_CODES = /* @__PURE__ */ new Set([
|
|
3319
3295
|
"BS100",
|
|
@@ -3331,7 +3307,7 @@ function openLive(config, env, source, pg) {
|
|
|
3331
3307
|
const none = { close: () => Promise.resolve() };
|
|
3332
3308
|
const file = snapshotFile(config, source);
|
|
3333
3309
|
if (file) {
|
|
3334
|
-
const skipped = `reading the saved snapshot ${file}; set $DATABASE_URL, or pass --db-url-stdin or --project-ref, to check a database.`;
|
|
3310
|
+
const skipped = `reading the saved snapshot ${file}; set $DATABASE_URL or $SUPABASE_DB_URL, or pass --db-url-stdin or --project-ref, to check a database.`;
|
|
3335
3311
|
return {
|
|
3336
3312
|
...none,
|
|
3337
3313
|
advisors: { skipped },
|
|
@@ -3375,6 +3351,48 @@ function openLive(config, env, source, pg) {
|
|
|
3375
3351
|
close
|
|
3376
3352
|
};
|
|
3377
3353
|
}
|
|
3354
|
+
//#endregion
|
|
3355
|
+
//#region src/cli/doctor/locate.ts
|
|
3356
|
+
const escape = (name) => name.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3357
|
+
/** Where a table, function or policy is declared: declarative schemas first, then the newest migration. */
|
|
3358
|
+
function locate(files, object) {
|
|
3359
|
+
const name = `"?${escape(object.name)}"?`;
|
|
3360
|
+
const qualifiedName = `(?:"?${escape(object.schema)}"?\\.)?${name}`;
|
|
3361
|
+
if (object.kind === "policy" && object.table !== void 0) {
|
|
3362
|
+
const onTable = new RegExp(`create\\s+policy\\s+${name}\\s+on\\s+(?:only\\s+)?(?:"?${escape(object.schema)}"?\\.)?"?${escape(object.table)}"?(?:\\s|;|$)`, "i");
|
|
3363
|
+
for (const file of files) {
|
|
3364
|
+
const match = onTable.exec(file.text);
|
|
3365
|
+
if (match) return {
|
|
3366
|
+
file: file.path,
|
|
3367
|
+
line: file.text.slice(0, match.index).split("\n").length
|
|
3368
|
+
};
|
|
3369
|
+
}
|
|
3370
|
+
return;
|
|
3371
|
+
}
|
|
3372
|
+
const pattern = object.kind === "table" ? new RegExp(`create\\s+(?:unlogged\\s+)?table\\s+(?:if\\s+not\\s+exists\\s+)?${qualifiedName}(?:\\s|\\(|$)`, "i") : object.kind === "function" ? new RegExp(`create\\s+(?:or\\s+replace\\s+)?function\\s+${qualifiedName}\\s*\\(`, "i") : new RegExp(`create\\s+policy\\s+${name}`, "i");
|
|
3373
|
+
for (const file of files) {
|
|
3374
|
+
const line = lineOf(file.text, pattern);
|
|
3375
|
+
if (line) return {
|
|
3376
|
+
file: file.path,
|
|
3377
|
+
line
|
|
3378
|
+
};
|
|
3379
|
+
}
|
|
3380
|
+
}
|
|
3381
|
+
//#endregion
|
|
3382
|
+
//#region src/cli/doctor/options.ts
|
|
3383
|
+
const FLAG_FORMATS = DOCTOR_FORMATS.filter((format) => format !== "json");
|
|
3384
|
+
/** `--json` picks the JSON report; `--format`, then `doctor.format`, picks between the others. */
|
|
3385
|
+
function reportFormat(args, configured) {
|
|
3386
|
+
if (args.format === "json") throw new CliError("usage", "--format json is now the global --json flag");
|
|
3387
|
+
if (args.json === true) {
|
|
3388
|
+
if (args.format !== void 0) throw new CliError("usage", "Pass --json or --format, not both");
|
|
3389
|
+
return "json";
|
|
3390
|
+
}
|
|
3391
|
+
if (args.format === void 0) return configured;
|
|
3392
|
+
const format = FLAG_FORMATS.find((candidate) => candidate === args.format);
|
|
3393
|
+
if (!format) throw new CliError("usage", `--format must be one of ${FLAG_FORMATS.join(", ")}`);
|
|
3394
|
+
return format;
|
|
3395
|
+
}
|
|
3378
3396
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
3379
3397
|
/** `--as <uuid>` or `--claims <json>` as `request.jwt.claims`. */
|
|
3380
3398
|
function explainClaims(args) {
|
|
@@ -3397,12 +3415,82 @@ function explainClaims(args) {
|
|
|
3397
3415
|
...parsed
|
|
3398
3416
|
};
|
|
3399
3417
|
} catch (cause) {
|
|
3400
|
-
return { error: `--claims is not valid JSON: ${
|
|
3418
|
+
return { error: `--claims is not valid JSON: ${errorText(cause)}` };
|
|
3401
3419
|
}
|
|
3402
3420
|
}
|
|
3421
|
+
//#endregion
|
|
3422
|
+
//#region src/cli/commands/doctor.ts
|
|
3423
|
+
const ARGS = {
|
|
3424
|
+
format: {
|
|
3425
|
+
type: "string",
|
|
3426
|
+
description: "text, sarif (code scanning) or github (workflow annotations); also doctor.format, default text. --json for the JSON report",
|
|
3427
|
+
valueHint: "format"
|
|
3428
|
+
},
|
|
3429
|
+
out: {
|
|
3430
|
+
type: "string",
|
|
3431
|
+
description: "Write the report to a file; also doctor.output",
|
|
3432
|
+
valueHint: "file"
|
|
3433
|
+
},
|
|
3434
|
+
only: {
|
|
3435
|
+
type: "string",
|
|
3436
|
+
description: "Run only these checks, e.g. --only BS100,BS304; also doctor.only",
|
|
3437
|
+
valueHint: "codes"
|
|
3438
|
+
},
|
|
3439
|
+
ignore: {
|
|
3440
|
+
type: "string",
|
|
3441
|
+
description: "Skip checks; also doctor.ignore in the config",
|
|
3442
|
+
valueHint: "codes"
|
|
3443
|
+
},
|
|
3444
|
+
strict: {
|
|
3445
|
+
type: "boolean",
|
|
3446
|
+
description: "Fail on warnings; also doctor.strict"
|
|
3447
|
+
},
|
|
3448
|
+
snapshot: {
|
|
3449
|
+
type: "string",
|
|
3450
|
+
description: "Check a saved snapshot instead of the database",
|
|
3451
|
+
valueHint: "file"
|
|
3452
|
+
},
|
|
3453
|
+
metadata: {
|
|
3454
|
+
type: "string",
|
|
3455
|
+
description: "Check a GeneratorMetadata document (- for stdin); checks it lacks data for are skipped",
|
|
3456
|
+
valueHint: "path|-"
|
|
3457
|
+
},
|
|
3458
|
+
"db-url-stdin": {
|
|
3459
|
+
type: "boolean",
|
|
3460
|
+
description: "Read the connection string from stdin instead of the config, $DATABASE_URL or $SUPABASE_DB_URL"
|
|
3461
|
+
},
|
|
3462
|
+
"project-ref": {
|
|
3463
|
+
type: "string",
|
|
3464
|
+
description: "Read a hosted project through the Management API",
|
|
3465
|
+
valueHint: "ref"
|
|
3466
|
+
},
|
|
3467
|
+
stats: {
|
|
3468
|
+
type: "boolean",
|
|
3469
|
+
description: "Report slow frequent statements from pg_stat_statements (BS209)"
|
|
3470
|
+
},
|
|
3471
|
+
explain: {
|
|
3472
|
+
type: "string",
|
|
3473
|
+
description: "EXPLAIN ANALYZE these tables under RLS, rolled back (BS212)",
|
|
3474
|
+
valueHint: "tables"
|
|
3475
|
+
},
|
|
3476
|
+
as: {
|
|
3477
|
+
type: "string",
|
|
3478
|
+
description: "Plan as this authenticated user, and measure the claims the custom access token hook returns for them (BS405)",
|
|
3479
|
+
valueHint: "uuid"
|
|
3480
|
+
},
|
|
3481
|
+
claims: {
|
|
3482
|
+
type: "string",
|
|
3483
|
+
description: "Plan with these JWT claims ({\"role\":\"authenticated\",...})",
|
|
3484
|
+
valueHint: "json"
|
|
3485
|
+
},
|
|
3486
|
+
"fix-grants": {
|
|
3487
|
+
type: "boolean",
|
|
3488
|
+
description: "Print the grant and revoke SQL BS404 asks for, to add to your schema or migration"
|
|
3489
|
+
}
|
|
3490
|
+
};
|
|
3403
3491
|
async function runDoctor(config, args, env, options = {}) {
|
|
3404
|
-
const format = reportFormat(args);
|
|
3405
|
-
const only = list(args.only);
|
|
3492
|
+
const format = reportFormat(args, config.doctor.format);
|
|
3493
|
+
const only = args.only === void 0 ? [...config.doctor.only] : list(args.only);
|
|
3406
3494
|
const ignore = /* @__PURE__ */ new Set([...config.doctor.ignore, ...list(args.ignore)]);
|
|
3407
3495
|
const unknown = [...only, ...ignore].filter((code) => !RULE_CODES.includes(code));
|
|
3408
3496
|
if (unknown.length > 0) return {
|
|
@@ -3445,17 +3533,23 @@ async function runDoctor(config, args, env, options = {}) {
|
|
|
3445
3533
|
...options.advisors === void 0 ? {} : { advisors: options.advisors },
|
|
3446
3534
|
...options.database === void 0 ? {} : { database: options.database }
|
|
3447
3535
|
};
|
|
3448
|
-
const [snapshot, envFiles, [configToml, sql], gitignore, sources, readSets] = await Promise.all([
|
|
3536
|
+
const [snapshot, envFiles, [configToml, sql], gitignore, sources, readSets, peers] = await Promise.all([
|
|
3449
3537
|
options.snapshot ?? loadSnapshot(config, env, source, pg, opened.open),
|
|
3450
3538
|
Promise.all(ENV_FILES.map((path) => readText(config.root, path))).then((files) => files.filter((file) => file !== void 0)),
|
|
3451
3539
|
readSupabaseToml(config.root).then(async (toml) => [toml, await sqlFiles(config.root, toml)]),
|
|
3452
3540
|
readText(config.root, ".gitignore"),
|
|
3453
3541
|
sourceFiles(config),
|
|
3454
|
-
compiledReadSets(config).catch((cause) => ({ skipped:
|
|
3542
|
+
compiledReadSets(config).catch((cause) => ({ skipped: errorText(cause) })),
|
|
3543
|
+
options.peers ?? peerVersions(config.root).catch(() => [])
|
|
3455
3544
|
]).catch(async (cause) => {
|
|
3456
3545
|
await opened.close();
|
|
3457
3546
|
throw cause;
|
|
3458
3547
|
});
|
|
3548
|
+
const replay = opened.open ? (await opened.open()).replay : void 0;
|
|
3549
|
+
const live = replay ? {
|
|
3550
|
+
advisors: options.advisors ?? { skipped: replay },
|
|
3551
|
+
database: options.database ?? { skipped: replay }
|
|
3552
|
+
} : opened;
|
|
3459
3553
|
const context = {
|
|
3460
3554
|
config,
|
|
3461
3555
|
snapshot,
|
|
@@ -3465,8 +3559,9 @@ async function runDoctor(config, args, env, options = {}) {
|
|
|
3465
3559
|
gitignore: gitignore?.text ?? "",
|
|
3466
3560
|
sources,
|
|
3467
3561
|
readSets,
|
|
3468
|
-
|
|
3469
|
-
...
|
|
3562
|
+
peers,
|
|
3563
|
+
...live.advisors ? { advisors: live.advisors } : {},
|
|
3564
|
+
...live.database ? { database: live.database } : {},
|
|
3470
3565
|
...stats ? { stats } : {},
|
|
3471
3566
|
...hookUser ? { hookUser } : {},
|
|
3472
3567
|
...explainTables.length > 0 ? { explain: {
|
|
@@ -3495,7 +3590,7 @@ async function runDoctor(config, args, env, options = {}) {
|
|
|
3495
3590
|
location
|
|
3496
3591
|
} : finding;
|
|
3497
3592
|
});
|
|
3498
|
-
const out = args.out;
|
|
3593
|
+
const out = args.out ?? (format === config.doctor.format ? config.doctor.output : void 0);
|
|
3499
3594
|
const fromRepo = format === "sarif" || format === "github";
|
|
3500
3595
|
const repoRoot = findRepoRoot(config.root);
|
|
3501
3596
|
const repoPath = (file) => display(repoRoot, resolve(config.root, file));
|
|
@@ -3571,7 +3666,7 @@ const doctorCommand = defineCliCommand({
|
|
|
3571
3666
|
};
|
|
3572
3667
|
throw cause;
|
|
3573
3668
|
}
|
|
3574
|
-
const skipped = `reading a GeneratorMetadata document; set $DATABASE_URL, or pass --db-url-stdin or --project-ref, to check a database.`;
|
|
3669
|
+
const skipped = `reading a GeneratorMetadata document; set $DATABASE_URL or $SUPABASE_DB_URL, or pass --db-url-stdin or --project-ref, to check a database.`;
|
|
3575
3670
|
return runDoctor(config, args, env, {
|
|
3576
3671
|
snapshot,
|
|
3577
3672
|
advisors: { skipped },
|