better-supabase 0.12.0 → 0.14.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 +129 -96
- package/dist/access-sql-CPoq9F86.js +207 -0
- package/dist/access-z7NwWtqx.js +34 -0
- package/dist/actor-CoveJgya.d.ts +106 -0
- package/dist/actor-hNajGNEK.js +150 -0
- package/dist/adapter-BCFAg58A.js +2190 -0
- package/dist/agents-CmZlLPXC.d.ts +117 -0
- package/dist/ai-cache-BxlOkc_M.d.ts +82 -0
- package/dist/ai-cache-DQikwXhJ.js +87 -0
- package/dist/ai-chat-DBxEz3o1.d.ts +619 -0
- package/dist/ai-files-t-kHmS5H.js +339 -0
- package/dist/ai-sdk/agents/index.d.ts +64 -52
- package/dist/ai-sdk/agents/index.js +35 -27
- package/dist/ai-sdk/batches/index.d.ts +16 -7
- package/dist/ai-sdk/batches/index.js +5 -5
- package/dist/ai-sdk/cache/index.d.ts +6 -3
- package/dist/ai-sdk/cache/index.js +1 -1
- package/dist/ai-sdk/chat/index.d.ts +1 -1
- package/dist/ai-sdk/chat/index.js +10 -10
- package/dist/ai-sdk/embeddings/index.d.ts +2 -2
- package/dist/ai-sdk/embeddings/index.js +1 -1
- package/dist/ai-sdk/files/index.d.ts +9 -9
- package/dist/ai-sdk/files/index.js +10 -10
- package/dist/ai-sdk/index.d.ts +48 -24
- package/dist/ai-sdk/index.js +50 -9
- package/dist/ai-sdk/mcp/index.d.ts +32 -26
- package/dist/ai-sdk/mcp/index.js +20 -20
- package/dist/ai-sdk/memory/index.d.ts +9 -9
- package/dist/ai-sdk/memory/index.js +6 -6
- package/dist/ai-sdk/react/index.d.ts +1 -1
- package/dist/ai-sdk/react/index.js +1 -1
- package/dist/ai-sdk/react/server.d.ts +5 -2
- package/dist/ai-sdk/react/server.js +4 -1
- package/dist/ai-sdk/workflow/index.d.ts +57 -36
- package/dist/ai-sdk/workflow/index.js +29 -23
- package/dist/ai-sdk/workflow/react/index.d.ts +7 -8
- package/dist/ai-sdk/workflow/react/index.js +7 -8
- package/dist/ai-sdk/workflow/react/server.d.ts +1 -1
- package/dist/ai-tasks-BDywBUgN.d.ts +166 -0
- package/dist/anchors-7F34QyHa.d.ts +40 -0
- package/dist/announcements-BeOD0zbc.js +128 -0
- package/dist/api-CWhpq24a.d.ts +174 -0
- package/dist/api-DKp2Ggz_.js +685 -0
- package/dist/api-keys-CboAenU8.d.ts +213 -0
- package/dist/api-keys-DT6Fi50R.js +318 -0
- package/dist/app-tables-BHrzAUFJ.d.ts +27 -0
- package/dist/app-tables-C5aoI5rZ.js +959 -0
- package/dist/approvals-bMb7dsBY.d.ts +129 -0
- package/dist/arazzo/index.d.ts +59 -36
- package/dist/arazzo/index.js +49 -41
- package/dist/assistant-D1yev_fR.d.ts +157 -0
- package/dist/astro/index.d.ts +44 -22
- package/dist/astro/index.js +14 -11
- package/dist/asyncapi/index.d.ts +23 -16
- package/dist/asyncapi/index.js +23 -20
- package/dist/attachments-Cjdgarpa.js +351 -0
- package/dist/attributes-BOFl922R.js +44 -0
- package/dist/audit-log-C3rQxeHd.js +788 -0
- package/dist/auth-DyF_LRxd.js +20 -0
- package/dist/auth-link-B4NL84XU.d.ts +104 -0
- package/dist/auth-link-D3-bU6yz.js +118 -0
- package/dist/auth-module-BEFESDC4.js +44 -0
- package/dist/auth-reply-jVKoAV6R.js +31 -0
- package/dist/authorization-BuT26_sR.d.ts +3455 -0
- package/dist/authorization-hooks-dLmUO_PZ.d.ts +217 -0
- package/dist/authorizer-DFP3gHv8.d.ts +82 -0
- package/dist/authorizer-DPTeL-7h.js +125 -0
- package/dist/availability-q3dZoZYM.d.ts +226 -0
- package/dist/base64-B9Wlsdj7.js +42 -0
- package/dist/before-route-B23K2zYU.js +30 -0
- package/dist/better-result/index.d.ts +26 -18
- package/dist/better-result/index.js +13 -9
- package/dist/bind-Dz8y3T5T.d.ts +95 -0
- package/dist/block-authors-BRTlT0qv.js +14 -0
- package/dist/block-authors-DzXLUiIq.d.ts +12 -0
- package/dist/block-controller-DTGuBemi.js +112 -0
- package/dist/block-env-DJiUu1fq.js +35 -0
- package/dist/block-env-kFcaaJLM.d.ts +10 -0
- package/dist/block-env-options-2e6IQrSw.js +26 -0
- package/dist/block-event-listener-Bu6G0TFH.js +16 -0
- package/dist/block-events-pBXPzwnW.js +83 -0
- package/dist/block-events-records-BGVyoz57.d.ts +343 -0
- package/dist/block-fields-3w4MZr8U.d.ts +58 -0
- package/dist/block-fields-DBSJSeaO.js +139 -0
- package/dist/block-helpers-BaugZlJV.d.ts +62 -0
- package/dist/block-helpers-CiKtrb6g.js +353 -0
- package/dist/block-hooks-BymdcD0V.js +130 -0
- package/dist/block-hooks-CmjPKqQ_.d.ts +117 -0
- package/dist/block-method-Bvsao626.js +21 -0
- package/dist/block-method-hsPAGFi5.d.ts +19 -0
- package/dist/block-names-Dbv_2wmE.js +66 -0
- package/dist/block-subjects-Dzq5Xn_0.js +55 -0
- package/dist/block-subjects-FHwLlIHU.d.ts +6 -0
- package/dist/block-tenant-C1sNV8_4.js +14 -0
- package/dist/block-transport-d53POsem.d.ts +69 -0
- package/dist/blocks/access/index.d.ts +9 -0
- package/dist/blocks/access/index.js +18 -0
- package/dist/blocks/access/react/index.d.ts +52 -0
- package/dist/blocks/access/react/index.js +73 -0
- package/dist/blocks/access/react/server.d.ts +11 -0
- package/dist/blocks/access/react/server.js +16 -0
- package/dist/blocks/access/solid/index.d.ts +13 -0
- package/dist/blocks/access/solid/index.js +14 -0
- package/dist/blocks/access/svelte/index.d.ts +13 -0
- package/dist/blocks/access/svelte/index.js +14 -0
- package/dist/blocks/access/vue/index.d.ts +13 -0
- package/dist/blocks/access/vue/index.js +14 -0
- package/dist/blocks/access-requests/index.d.ts +21 -15
- package/dist/blocks/access-requests/index.js +11 -9
- package/dist/blocks/activity/index.d.ts +116 -0
- package/dist/blocks/activity/index.js +164 -0
- package/dist/blocks/agents/index.d.ts +4 -4
- package/dist/blocks/agents/index.js +6 -7
- 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 +10 -7
- package/dist/blocks/ai-chat/index.js +4 -4
- package/dist/blocks/ai-chat/react/index.d.ts +18 -9
- package/dist/blocks/ai-chat/react/index.js +8 -8
- package/dist/blocks/ai-chat/react/server.d.ts +12 -3
- package/dist/blocks/ai-chat/react/server.js +12 -3
- package/dist/blocks/ai-chat/solid/index.d.ts +3 -3
- package/dist/blocks/ai-chat/solid/index.js +2 -2
- package/dist/blocks/ai-chat/svelte/index.d.ts +3 -3
- package/dist/blocks/ai-chat/svelte/index.js +2 -2
- package/dist/blocks/ai-chat/vue/index.d.ts +3 -3
- package/dist/blocks/ai-chat/vue/index.js +2 -2
- package/dist/blocks/ai-files/index.d.ts +5 -5
- package/dist/blocks/ai-files/index.js +3 -3
- package/dist/blocks/ai-providers/index.d.ts +4 -4
- package/dist/blocks/ai-providers/index.js +8 -9
- package/dist/blocks/ai-tasks/index.d.ts +3 -3
- package/dist/blocks/ai-tasks/index.js +9 -10
- package/dist/blocks/announcements/index.d.ts +4 -4
- package/dist/blocks/announcements/index.js +5 -5
- package/dist/blocks/announcements/react/index.d.ts +12 -5
- package/dist/blocks/announcements/react/index.js +7 -7
- package/dist/blocks/announcements/react/server.d.ts +4 -1
- package/dist/blocks/announcements/react/server.js +4 -1
- package/dist/blocks/announcements/solid/index.d.ts +3 -3
- package/dist/blocks/announcements/solid/index.js +2 -2
- package/dist/blocks/announcements/svelte/index.d.ts +3 -3
- package/dist/blocks/announcements/svelte/index.js +2 -2
- package/dist/blocks/announcements/vue/index.d.ts +3 -3
- package/dist/blocks/announcements/vue/index.js +2 -2
- package/dist/blocks/api-keys/index.d.ts +11 -8
- package/dist/blocks/api-keys/index.js +8 -8
- package/dist/blocks/api-keys/react/index.d.ts +11 -8
- package/dist/blocks/api-keys/react/index.js +9 -9
- package/dist/blocks/api-keys/react/server.d.ts +1 -1
- package/dist/blocks/api-keys/solid/index.d.ts +3 -3
- package/dist/blocks/api-keys/solid/index.js +2 -2
- package/dist/blocks/api-keys/svelte/index.d.ts +3 -3
- package/dist/blocks/api-keys/svelte/index.js +2 -2
- package/dist/blocks/api-keys/vue/index.d.ts +3 -3
- package/dist/blocks/api-keys/vue/index.js +2 -2
- package/dist/blocks/approvals/index.d.ts +4 -4
- package/dist/blocks/approvals/index.js +29 -25
- package/dist/blocks/assets/index.d.ts +283 -0
- package/dist/blocks/assets/index.js +288 -0
- package/dist/blocks/assignment/index.d.ts +124 -0
- package/dist/blocks/assignment/index.js +141 -0
- package/dist/blocks/attachments/index.d.ts +45 -6
- package/dist/blocks/attachments/index.js +96 -7
- package/dist/blocks/attachments/react/index.d.ts +53 -0
- package/dist/blocks/attachments/react/index.js +78 -0
- package/dist/blocks/attachments/react/server.d.ts +9 -0
- package/dist/blocks/attachments/react/server.js +10 -0
- package/dist/blocks/attachments/solid/index.d.ts +13 -0
- package/dist/blocks/attachments/solid/index.js +14 -0
- package/dist/blocks/attachments/svelte/index.d.ts +13 -0
- package/dist/blocks/attachments/svelte/index.js +14 -0
- package/dist/blocks/attachments/vue/index.d.ts +13 -0
- package/dist/blocks/attachments/vue/index.js +14 -0
- package/dist/blocks/audit/index.d.ts +14 -8
- package/dist/blocks/audit/index.js +9 -10
- package/dist/blocks/audit/react/index.d.ts +12 -7
- package/dist/blocks/audit/react/index.js +12 -10
- package/dist/blocks/audit/react/server.d.ts +1 -1
- package/dist/blocks/audit/solid/index.d.ts +3 -3
- package/dist/blocks/audit/solid/index.js +2 -2
- package/dist/blocks/audit/svelte/index.d.ts +3 -3
- package/dist/blocks/audit/svelte/index.js +2 -2
- package/dist/blocks/audit/vue/index.d.ts +3 -3
- package/dist/blocks/audit/vue/index.js +2 -2
- package/dist/blocks/billable-time/index.d.ts +203 -0
- package/dist/blocks/billable-time/index.js +260 -0
- package/dist/blocks/billing/index.d.ts +144 -53
- package/dist/blocks/billing/index.js +165 -47
- package/dist/blocks/billing/react/index.d.ts +19 -9
- package/dist/blocks/billing/react/index.js +12 -8
- package/dist/blocks/billing/react/server.d.ts +5 -2
- package/dist/blocks/billing/react/server.js +4 -1
- package/dist/blocks/billing/solid/index.d.ts +3 -3
- package/dist/blocks/billing/solid/index.js +2 -2
- package/dist/blocks/billing/svelte/index.d.ts +3 -3
- package/dist/blocks/billing/svelte/index.js +2 -2
- package/dist/blocks/billing/vue/index.d.ts +3 -3
- package/dist/blocks/billing/vue/index.js +2 -2
- package/dist/blocks/bookings/index.d.ts +19 -9
- package/dist/blocks/bookings/index.js +9 -7
- package/dist/blocks/bookings/react/index.d.ts +9 -4
- package/dist/blocks/bookings/react/index.js +12 -8
- package/dist/blocks/bookings/react/server.d.ts +4 -1
- package/dist/blocks/bookings/react/server.js +4 -1
- package/dist/blocks/bookings/solid/index.d.ts +3 -3
- package/dist/blocks/bookings/solid/index.js +2 -2
- package/dist/blocks/bookings/svelte/index.d.ts +3 -3
- package/dist/blocks/bookings/svelte/index.js +2 -2
- package/dist/blocks/bookings/vue/index.d.ts +3 -3
- package/dist/blocks/bookings/vue/index.js +2 -2
- package/dist/blocks/bulk/index.d.ts +27 -12
- package/dist/blocks/bulk/index.js +5 -5
- package/dist/blocks/calendar/index.d.ts +13 -5
- package/dist/blocks/calendar/index.js +113 -5
- package/dist/blocks/calendar/react/index.d.ts +5 -5
- package/dist/blocks/calendar/react/index.js +8 -8
- package/dist/blocks/calendar/react/server.d.ts +4 -1
- package/dist/blocks/calendar/react/server.js +4 -1
- package/dist/blocks/calendar/solid/index.d.ts +3 -3
- package/dist/blocks/calendar/solid/index.js +2 -2
- package/dist/blocks/calendar/svelte/index.d.ts +3 -3
- package/dist/blocks/calendar/svelte/index.js +2 -2
- package/dist/blocks/calendar/vue/index.d.ts +3 -3
- package/dist/blocks/calendar/vue/index.js +2 -2
- package/dist/blocks/catalog/index.d.ts +48 -36
- package/dist/blocks/catalog/index.js +49 -53
- package/dist/blocks/channels/index.d.ts +111 -0
- package/dist/blocks/channels/index.js +190 -0
- package/dist/blocks/collections/index.d.ts +101 -23
- package/dist/blocks/collections/index.js +88 -13
- package/dist/blocks/comments/index.d.ts +48 -47
- package/dist/blocks/comments/index.js +113 -16
- package/dist/blocks/comments/react/index.d.ts +17 -12
- package/dist/blocks/comments/react/index.js +38 -27
- package/dist/blocks/comments/react/server.d.ts +1 -1
- package/dist/blocks/comments/solid/index.d.ts +3 -3
- package/dist/blocks/comments/solid/index.js +2 -2
- package/dist/blocks/comments/svelte/index.d.ts +3 -3
- package/dist/blocks/comments/svelte/index.js +2 -2
- package/dist/blocks/comments/vue/index.d.ts +3 -3
- package/dist/blocks/comments/vue/index.js +2 -2
- package/dist/blocks/connectors/index.d.ts +4 -4
- package/dist/blocks/connectors/index.js +8 -9
- package/dist/blocks/contracts/index.d.ts +241 -0
- package/dist/blocks/contracts/index.js +361 -0
- package/dist/blocks/controls/index.d.ts +325 -0
- package/dist/blocks/controls/index.js +410 -0
- package/dist/blocks/courses/index.d.ts +341 -0
- package/dist/blocks/courses/index.js +445 -0
- package/dist/blocks/custom-fields/index.d.ts +50 -16
- package/dist/blocks/custom-fields/index.js +27 -22
- package/dist/blocks/data-lifecycle/index.d.ts +75 -51
- package/dist/blocks/data-lifecycle/index.js +17 -12
- package/dist/blocks/deals/index.d.ts +25 -45
- package/dist/blocks/deals/index.js +161 -71
- package/dist/blocks/dispatch/index.d.ts +327 -0
- package/dist/blocks/dispatch/index.js +406 -0
- package/dist/blocks/documents/index.d.ts +8 -5
- package/dist/blocks/documents/index.js +67 -8
- package/dist/blocks/domains/index.d.ts +35 -20
- package/dist/blocks/domains/index.js +9 -10
- package/dist/blocks/donations/index.d.ts +352 -0
- package/dist/blocks/donations/index.js +602 -0
- package/dist/blocks/drive/index.d.ts +91 -28
- package/dist/blocks/drive/index.js +71 -17
- package/dist/blocks/employees/index.d.ts +16 -190
- package/dist/blocks/employees/index.js +107 -38
- package/dist/blocks/engagements/index.d.ts +27 -111
- package/dist/blocks/engagements/index.js +285 -14
- package/dist/blocks/enrichment/index.d.ts +176 -0
- package/dist/blocks/enrichment/index.js +243 -0
- package/dist/blocks/enrollments/index.d.ts +184 -0
- package/dist/blocks/enrollments/index.js +173 -0
- package/dist/blocks/entitlements/index.d.ts +20 -14
- package/dist/blocks/entitlements/index.js +4 -4
- package/dist/blocks/entitlements/react/index.d.ts +10 -7
- package/dist/blocks/entitlements/react/index.js +7 -7
- package/dist/blocks/entitlements/react/server.d.ts +4 -1
- package/dist/blocks/entitlements/react/server.js +4 -1
- package/dist/blocks/entitlements/solid/index.d.ts +3 -3
- package/dist/blocks/entitlements/solid/index.js +2 -2
- package/dist/blocks/entitlements/svelte/index.d.ts +3 -3
- package/dist/blocks/entitlements/svelte/index.js +2 -2
- package/dist/blocks/entitlements/vue/index.d.ts +3 -3
- package/dist/blocks/entitlements/vue/index.js +2 -2
- package/dist/blocks/expenses/index.d.ts +214 -0
- package/dist/blocks/expenses/index.js +279 -0
- package/dist/blocks/field-history/index.d.ts +63 -0
- package/dist/blocks/field-history/index.js +48 -0
- package/dist/blocks/flags/index.d.ts +20 -14
- package/dist/blocks/flags/index.js +9 -10
- package/dist/blocks/forecasts/index.d.ts +119 -0
- package/dist/blocks/forecasts/index.js +129 -0
- package/dist/blocks/forms/index.d.ts +96 -148
- package/dist/blocks/forms/index.js +121 -157
- package/dist/blocks/forms/react/index.d.ts +9 -6
- package/dist/blocks/forms/react/index.js +10 -7
- package/dist/blocks/forms/react/server.d.ts +4 -1
- package/dist/blocks/forms/react/server.js +4 -1
- package/dist/blocks/forms/solid/index.d.ts +3 -3
- package/dist/blocks/forms/solid/index.js +2 -2
- package/dist/blocks/forms/svelte/index.d.ts +3 -3
- package/dist/blocks/forms/svelte/index.js +2 -2
- package/dist/blocks/forms/vue/index.d.ts +3 -3
- package/dist/blocks/forms/vue/index.js +2 -2
- package/dist/blocks/guests/index.d.ts +200 -0
- package/dist/blocks/guests/index.js +224 -0
- package/dist/blocks/hiring/index.d.ts +13 -13
- package/dist/blocks/hiring/index.js +9 -10
- package/dist/blocks/identities/index.d.ts +38 -20
- package/dist/blocks/identities/index.js +16 -11
- package/dist/blocks/imports/index.d.ts +30 -25
- package/dist/blocks/imports/index.js +19 -19
- package/dist/blocks/inbox/index.d.ts +9 -6
- package/dist/blocks/inbox/index.js +118 -54
- package/dist/blocks/inbox/react/index.d.ts +2 -2
- package/dist/blocks/inbox/react/index.js +15 -9
- package/dist/blocks/inbox/react/server.d.ts +12 -6
- package/dist/blocks/inbox/react/server.js +8 -2
- package/dist/blocks/inbox/solid/index.d.ts +6 -6
- package/dist/blocks/inbox/solid/index.js +2 -2
- package/dist/blocks/inbox/svelte/index.d.ts +6 -6
- package/dist/blocks/inbox/svelte/index.js +2 -2
- package/dist/blocks/inbox/vue/index.d.ts +6 -6
- package/dist/blocks/inbox/vue/index.js +2 -2
- package/dist/blocks/incidents/index.d.ts +337 -0
- package/dist/blocks/incidents/index.js +477 -0
- package/dist/blocks/index.d.ts +126 -11
- package/dist/blocks/index.js +171 -193
- package/dist/blocks/inventory/index.d.ts +36 -19
- package/dist/blocks/inventory/index.js +15 -10
- package/dist/blocks/invoices/index.d.ts +13 -13
- package/dist/blocks/invoices/index.js +11 -12
- package/dist/blocks/jobs/index.d.ts +123 -86
- package/dist/blocks/jobs/index.js +59 -49
- package/dist/blocks/knowledge/index.d.ts +3 -3
- package/dist/blocks/knowledge/index.js +3 -3
- package/dist/blocks/lead-scoring/index.d.ts +50 -0
- package/dist/blocks/lead-scoring/index.js +87 -0
- package/dist/blocks/leases/index.d.ts +278 -0
- package/dist/blocks/leases/index.js +319 -0
- package/dist/blocks/leave/index.d.ts +30 -15
- package/dist/blocks/leave/index.js +6 -7
- package/dist/blocks/ledger/index.d.ts +281 -0
- package/dist/blocks/ledger/index.js +229 -0
- package/dist/blocks/mail-sync/index.d.ts +37 -0
- package/dist/blocks/mail-sync/index.js +898 -0
- package/dist/blocks/memory/index.d.ts +4 -4
- package/dist/blocks/memory/index.js +7 -8
- package/dist/blocks/messaging/index.d.ts +86 -0
- package/dist/blocks/messaging/index.js +48 -0
- package/dist/blocks/messaging/react/index.d.ts +39 -0
- package/dist/blocks/messaging/react/index.js +80 -0
- package/dist/blocks/messaging/react/server.d.ts +12 -0
- package/dist/blocks/messaging/react/server.js +14 -0
- package/dist/blocks/messaging/solid/index.d.ts +20 -0
- package/dist/blocks/messaging/solid/index.js +23 -0
- package/dist/blocks/messaging/svelte/index.d.ts +20 -0
- package/dist/blocks/messaging/svelte/index.js +23 -0
- package/dist/blocks/messaging/vue/index.d.ts +20 -0
- package/dist/blocks/messaging/vue/index.js +23 -0
- package/dist/blocks/metrics/index.d.ts +36 -30
- package/dist/blocks/metrics/index.js +19 -20
- package/dist/blocks/mfa/index.d.ts +2 -2
- package/dist/blocks/mfa/index.js +2 -2
- package/dist/blocks/mfa/react/index.d.ts +7 -7
- package/dist/blocks/mfa/react/index.js +9 -9
- package/dist/blocks/mfa/react/server.d.ts +1 -1
- package/dist/blocks/mfa/react/server.js +1 -1
- package/dist/blocks/mfa/solid/index.d.ts +3 -3
- package/dist/blocks/mfa/solid/index.js +2 -2
- package/dist/blocks/mfa/svelte/index.d.ts +3 -3
- package/dist/blocks/mfa/svelte/index.js +2 -2
- package/dist/blocks/mfa/vue/index.d.ts +3 -3
- package/dist/blocks/mfa/vue/index.js +2 -2
- package/dist/blocks/moderation/index.d.ts +205 -0
- package/dist/blocks/moderation/index.js +199 -0
- package/dist/blocks/notifications/index.d.ts +132 -103
- package/dist/blocks/notifications/index.js +62 -48
- package/dist/blocks/notifications/react/index.d.ts +3 -3
- package/dist/blocks/notifications/react/index.js +5 -5
- package/dist/blocks/notifications/react/server.d.ts +5 -2
- package/dist/blocks/notifications/react/server.js +4 -1
- package/dist/blocks/notifications/solid/index.d.ts +3 -3
- package/dist/blocks/notifications/solid/index.js +2 -2
- package/dist/blocks/notifications/svelte/index.d.ts +3 -3
- package/dist/blocks/notifications/svelte/index.js +2 -2
- package/dist/blocks/notifications/vue/index.d.ts +3 -3
- package/dist/blocks/notifications/vue/index.js +2 -2
- package/dist/blocks/number-sequences/index.d.ts +15 -12
- package/dist/blocks/number-sequences/index.js +8 -5
- package/dist/blocks/oauth-server/index.d.ts +42 -21
- package/dist/blocks/oauth-server/index.js +16 -14
- package/dist/blocks/onboarding/index.d.ts +3 -3
- package/dist/blocks/onboarding/index.js +4 -4
- package/dist/blocks/onboarding/react/index.d.ts +10 -5
- package/dist/blocks/onboarding/react/index.js +10 -8
- package/dist/blocks/onboarding/react/server.d.ts +5 -2
- package/dist/blocks/onboarding/react/server.js +4 -1
- package/dist/blocks/onboarding/solid/index.d.ts +3 -3
- package/dist/blocks/onboarding/solid/index.js +2 -2
- package/dist/blocks/onboarding/svelte/index.d.ts +3 -3
- package/dist/blocks/onboarding/svelte/index.js +2 -2
- package/dist/blocks/onboarding/vue/index.d.ts +3 -3
- package/dist/blocks/onboarding/vue/index.js +2 -2
- package/dist/blocks/orders/index.d.ts +176 -31
- package/dist/blocks/orders/index.js +167 -25
- package/dist/blocks/organizations/index.d.ts +5 -5
- package/dist/blocks/organizations/index.js +6 -28
- package/dist/blocks/organizations/react/index.d.ts +40 -21
- package/dist/blocks/organizations/react/index.js +5 -5
- package/dist/blocks/organizations/react/server.d.ts +13 -4
- package/dist/blocks/organizations/react/server.js +12 -3
- package/dist/blocks/organizations/solid/index.d.ts +3 -3
- package/dist/blocks/organizations/solid/index.js +2 -2
- package/dist/blocks/organizations/svelte/index.d.ts +3 -3
- package/dist/blocks/organizations/svelte/index.js +2 -2
- package/dist/blocks/organizations/vue/index.d.ts +3 -3
- package/dist/blocks/organizations/vue/index.js +2 -2
- package/dist/blocks/outbox/index.d.ts +4 -4
- package/dist/blocks/outbox/index.js +21 -18
- package/dist/blocks/parties/index.d.ts +36 -35
- package/dist/blocks/parties/index.js +152 -52
- package/dist/blocks/passes/index.d.ts +308 -0
- package/dist/blocks/passes/index.js +411 -0
- package/dist/blocks/pipelines/index.d.ts +26 -17
- package/dist/blocks/pipelines/index.js +11 -12
- package/dist/blocks/posts/index.d.ts +190 -0
- package/dist/blocks/posts/index.js +230 -0
- package/dist/blocks/profiles/index.d.ts +23 -14
- package/dist/blocks/profiles/index.js +5 -6
- package/dist/blocks/promotions/index.d.ts +34 -16
- package/dist/blocks/promotions/index.js +12 -10
- package/dist/blocks/push/index.d.ts +43 -25
- package/dist/blocks/push/index.js +16 -17
- package/dist/blocks/quotes/index.d.ts +15 -12
- package/dist/blocks/quotes/index.js +9 -10
- package/dist/blocks/rank/index.d.ts +12 -12
- package/dist/blocks/rank/index.js +4 -4
- package/dist/blocks/reactions/index.d.ts +5 -5
- package/dist/blocks/reactions/index.js +4 -4
- package/dist/blocks/reactions/react/index.d.ts +20 -11
- package/dist/blocks/reactions/react/index.js +37 -26
- package/dist/blocks/reactions/react/server.d.ts +4 -1
- package/dist/blocks/reactions/react/server.js +4 -1
- package/dist/blocks/reactions/solid/index.d.ts +3 -3
- package/dist/blocks/reactions/solid/index.js +2 -2
- package/dist/blocks/reactions/svelte/index.d.ts +3 -3
- package/dist/blocks/reactions/svelte/index.js +2 -2
- package/dist/blocks/reactions/vue/index.d.ts +3 -3
- package/dist/blocks/reactions/vue/index.js +2 -2
- package/dist/blocks/relations/index.d.ts +82 -46
- package/dist/blocks/relations/index.js +120 -63
- package/dist/blocks/reminders/index.d.ts +45 -32
- package/dist/blocks/reminders/index.js +38 -33
- package/dist/blocks/reviews/index.d.ts +32 -17
- package/dist/blocks/reviews/index.js +6 -7
- package/dist/blocks/rules/index.d.ts +32 -26
- package/dist/blocks/rules/index.js +15 -15
- package/dist/blocks/rules/react/index.d.ts +9 -5
- package/dist/blocks/rules/react/index.js +12 -8
- package/dist/blocks/rules/solid/index.d.ts +3 -3
- package/dist/blocks/rules/solid/index.js +2 -2
- package/dist/blocks/rules/svelte/index.d.ts +3 -3
- package/dist/blocks/rules/svelte/index.js +2 -2
- package/dist/blocks/rules/vue/index.d.ts +3 -3
- package/dist/blocks/rules/vue/index.js +2 -2
- package/dist/blocks/saved-views/index.d.ts +3 -3
- package/dist/blocks/saved-views/index.js +3 -3
- package/dist/blocks/saved-views/react/index.d.ts +14 -8
- package/dist/blocks/saved-views/react/index.js +11 -8
- package/dist/blocks/saved-views/react/server.d.ts +5 -2
- package/dist/blocks/saved-views/react/server.js +4 -1
- package/dist/blocks/saved-views/solid/index.d.ts +3 -3
- package/dist/blocks/saved-views/solid/index.js +2 -2
- package/dist/blocks/saved-views/svelte/index.d.ts +3 -3
- package/dist/blocks/saved-views/svelte/index.js +2 -2
- package/dist/blocks/saved-views/vue/index.d.ts +3 -3
- package/dist/blocks/saved-views/vue/index.js +2 -2
- package/dist/blocks/scores/index.d.ts +50 -0
- package/dist/blocks/scores/index.js +40 -0
- package/dist/blocks/search/index.d.ts +12 -9
- package/dist/blocks/search/index.js +9 -10
- package/dist/blocks/search/react/index.d.ts +8 -5
- package/dist/blocks/search/react/index.js +6 -6
- package/dist/blocks/search/react/server.d.ts +5 -2
- package/dist/blocks/search/react/server.js +4 -1
- package/dist/blocks/search/solid/index.d.ts +3 -3
- package/dist/blocks/search/solid/index.js +2 -2
- package/dist/blocks/search/svelte/index.d.ts +3 -3
- package/dist/blocks/search/svelte/index.js +2 -2
- package/dist/blocks/search/vue/index.d.ts +3 -3
- package/dist/blocks/search/vue/index.js +2 -2
- package/dist/blocks/segments/index.d.ts +130 -0
- package/dist/blocks/segments/index.js +135 -0
- package/dist/blocks/sequences/index.d.ts +259 -0
- package/dist/blocks/sequences/index.js +370 -0
- package/dist/blocks/service-principals/index.d.ts +24 -18
- package/dist/blocks/service-principals/index.js +11 -9
- package/dist/blocks/sessions/index.d.ts +2 -2
- package/dist/blocks/sessions/index.js +2 -2
- package/dist/blocks/sessions/react/index.d.ts +10 -5
- package/dist/blocks/sessions/react/index.js +8 -6
- package/dist/blocks/sessions/react/server.d.ts +9 -3
- package/dist/blocks/sessions/react/server.js +8 -2
- package/dist/blocks/sessions/solid/index.d.ts +3 -3
- package/dist/blocks/sessions/solid/index.js +2 -2
- package/dist/blocks/sessions/svelte/index.d.ts +3 -3
- package/dist/blocks/sessions/svelte/index.js +2 -2
- package/dist/blocks/sessions/vue/index.d.ts +3 -3
- package/dist/blocks/sessions/vue/index.js +2 -2
- package/dist/blocks/settings/index.d.ts +6 -5
- package/dist/blocks/settings/index.js +7 -6
- package/dist/blocks/settings/react/index.d.ts +13 -7
- package/dist/blocks/settings/react/index.js +5 -5
- package/dist/blocks/settings/react/server.d.ts +5 -2
- package/dist/blocks/settings/react/server.js +4 -1
- package/dist/blocks/settings/solid/index.d.ts +3 -3
- package/dist/blocks/settings/solid/index.js +2 -2
- package/dist/blocks/settings/svelte/index.d.ts +3 -3
- package/dist/blocks/settings/svelte/index.js +2 -2
- package/dist/blocks/settings/vue/index.d.ts +3 -3
- package/dist/blocks/settings/vue/index.js +2 -2
- package/dist/blocks/share-links/index.d.ts +58 -23
- package/dist/blocks/share-links/index.js +74 -23
- package/dist/blocks/shared-signals/index.d.ts +82 -37
- package/dist/blocks/shared-signals/index.js +24 -19
- package/dist/blocks/shipments/index.d.ts +238 -0
- package/dist/blocks/shipments/index.js +540 -0
- package/dist/blocks/signatures/index.d.ts +151 -0
- package/dist/blocks/signatures/index.js +149 -0
- package/dist/blocks/signing-keys/index.d.ts +5 -5
- package/dist/blocks/signing-keys/index.js +5 -166
- package/dist/blocks/sla/index.d.ts +43 -31
- package/dist/blocks/sla/index.js +44 -15
- package/dist/blocks/sso/index.d.ts +35 -30
- package/dist/blocks/sso/index.js +31 -18
- package/dist/blocks/state-machine/index.d.ts +31 -22
- package/dist/blocks/state-machine/index.js +27 -27
- package/dist/blocks/subjects/index.d.ts +11 -0
- package/dist/blocks/subjects/index.js +21 -0
- package/dist/blocks/subjects/react/index.d.ts +31 -0
- package/dist/blocks/subjects/react/index.js +60 -0
- package/dist/blocks/subjects/react/server.d.ts +9 -0
- package/dist/blocks/subjects/react/server.js +12 -0
- package/dist/blocks/subjects/solid/index.d.ts +13 -0
- package/dist/blocks/subjects/solid/index.js +14 -0
- package/dist/blocks/subjects/svelte/index.d.ts +13 -0
- package/dist/blocks/subjects/svelte/index.js +14 -0
- package/dist/blocks/subjects/vue/index.d.ts +13 -0
- package/dist/blocks/subjects/vue/index.js +14 -0
- package/dist/blocks/tags/index.d.ts +37 -5
- package/dist/blocks/tags/index.js +50 -5
- package/dist/blocks/tags/react/index.d.ts +13 -12
- package/dist/blocks/tags/react/index.js +30 -24
- package/dist/blocks/tags/react/server.d.ts +1 -1
- package/dist/blocks/tags/solid/index.d.ts +3 -3
- package/dist/blocks/tags/solid/index.js +2 -2
- package/dist/blocks/tags/svelte/index.d.ts +3 -3
- package/dist/blocks/tags/svelte/index.js +2 -2
- package/dist/blocks/tags/vue/index.d.ts +3 -3
- package/dist/blocks/tags/vue/index.js +2 -2
- package/dist/blocks/targets/index.d.ts +13 -13
- package/dist/blocks/targets/index.js +7 -8
- package/dist/blocks/teams/index.d.ts +9 -9
- package/dist/blocks/teams/index.js +5 -5
- package/dist/blocks/templates/index.d.ts +67 -51
- package/dist/blocks/templates/index.js +23 -25
- package/dist/blocks/time-tracking/index.d.ts +63 -45
- package/dist/blocks/time-tracking/index.js +50 -47
- package/dist/blocks/trash/index.d.ts +13 -11
- package/dist/blocks/trash/index.js +5 -6
- package/dist/blocks/undo/index.d.ts +4 -4
- package/dist/blocks/undo/index.js +4 -4
- package/dist/blocks/undo/react/index.d.ts +3 -3
- package/dist/blocks/undo/react/index.js +4 -4
- package/dist/blocks/undo/react/server.d.ts +5 -2
- package/dist/blocks/undo/react/server.js +4 -1
- package/dist/blocks/undo/solid/index.d.ts +3 -3
- package/dist/blocks/undo/solid/index.js +2 -2
- package/dist/blocks/undo/svelte/index.d.ts +3 -3
- package/dist/blocks/undo/svelte/index.js +2 -2
- package/dist/blocks/undo/vue/index.d.ts +3 -3
- package/dist/blocks/undo/vue/index.js +2 -2
- package/dist/blocks/usage/index.d.ts +5 -5
- package/dist/blocks/usage/index.js +4 -4
- package/dist/blocks/usage/react/index.d.ts +12 -6
- package/dist/blocks/usage/react/index.js +8 -8
- package/dist/blocks/usage/react/server.d.ts +1 -1
- package/dist/blocks/usage/solid/index.d.ts +3 -3
- package/dist/blocks/usage/solid/index.js +2 -2
- package/dist/blocks/usage/svelte/index.d.ts +3 -3
- package/dist/blocks/usage/svelte/index.js +2 -2
- package/dist/blocks/usage/vue/index.d.ts +3 -3
- package/dist/blocks/usage/vue/index.js +2 -2
- package/dist/blocks/vercel-marketplace/index.d.ts +252 -17
- package/dist/blocks/vercel-marketplace/index.js +489 -57
- package/dist/blocks/versions/index.d.ts +55 -31
- package/dist/blocks/versions/index.js +75 -30
- package/dist/blocks/waitlist/index.d.ts +31 -18
- package/dist/blocks/waitlist/index.js +10 -8
- package/dist/blocks/webhooks/index.d.ts +126 -89
- package/dist/blocks/webhooks/index.js +72 -62
- package/dist/blocks/work-items/index.d.ts +63 -184
- package/dist/blocks/work-items/index.js +162 -36
- package/dist/blocks/workflow-builder/index.d.ts +15 -13
- package/dist/blocks/workflow-builder/index.js +11 -8
- package/dist/blocks/workflow-builder/react/index.d.ts +4 -4
- package/dist/blocks/workflow-builder/react/index.js +8 -8
- package/dist/blocks/workflow-builder/react/server.d.ts +8 -2
- package/dist/blocks/workflow-builder/react/server.js +8 -2
- package/dist/blocks/workflow-builder/solid/index.d.ts +3 -3
- package/dist/blocks/workflow-builder/solid/index.js +2 -2
- package/dist/blocks/workflow-builder/svelte/index.d.ts +3 -3
- package/dist/blocks/workflow-builder/svelte/index.js +2 -2
- package/dist/blocks/workflow-builder/vue/index.d.ts +3 -3
- package/dist/blocks/workflow-builder/vue/index.js +2 -2
- package/dist/blocks/workflows/index.d.ts +5 -5
- package/dist/blocks/workflows/index.js +5 -5
- package/dist/blocks/workflows/react/index.d.ts +13 -6
- package/dist/blocks/workflows/react/index.js +7 -7
- package/dist/blocks/workflows/react/server.d.ts +8 -2
- package/dist/blocks/workflows/react/server.js +8 -2
- package/dist/blocks/workflows/solid/index.d.ts +3 -3
- package/dist/blocks/workflows/solid/index.js +2 -2
- package/dist/blocks/workflows/svelte/index.d.ts +3 -3
- package/dist/blocks/workflows/svelte/index.js +2 -2
- package/dist/blocks/workflows/vue/index.d.ts +3 -3
- package/dist/blocks/workflows/vue/index.js +2 -2
- package/dist/bookings-BB5lFlNO.js +310 -0
- package/dist/bookings-CC7IeiRa.d.ts +290 -0
- package/dist/bucket-TkB7_xv8.d.ts +667 -0
- package/dist/build-DCfpwg78.js +1839 -0
- package/dist/build-g9wTbQdp.js +703 -0
- package/dist/calendar-T3Vdpq7E.js +952 -0
- package/dist/carrier-C7Q_21Kd.d.ts +169 -0
- package/dist/channel-BjvGO39m.d.ts +77 -0
- package/dist/channels-CfcFPuo_.js +114 -0
- package/dist/chat-sdk/index.d.ts +188 -80
- package/dist/chat-sdk/index.js +102 -57
- package/dist/chat-sdk/react/index.d.ts +2 -2
- package/dist/chat-sdk/react/server.d.ts +2 -2
- package/dist/claims-Bp9My7XP.js +88 -0
- package/dist/claims-T8TWZ53E.js +63 -0
- package/dist/cli/add-Bf3kE6PY.js +75 -0
- package/dist/cli/add-CYh6Sxk1.js +674 -0
- package/dist/cli/add-Dg40eFKE.js +1 -0
- package/dist/cli/adopt-B0vrj-4B.js +421 -0
- package/dist/cli/adopt-DJR1k3lS.js +1 -0
- package/dist/cli/agent-CbuPvI2x.js +185 -0
- package/dist/cli/apply-DUQ-5LC6.js +329 -0
- package/dist/cli/bin.js +3 -3
- package/dist/cli/blocks-DzgYfjVv.js +124 -0
- package/dist/cli/blocks-gGupqvBH.js +1 -0
- package/dist/cli/cache-C3K_wOE2.js +536 -0
- package/dist/cli/catalog-CNM0ViIh.js +199 -0
- package/dist/cli/codemod-Dz4R-tVY.js +1127 -0
- package/dist/cli/command-33pu13LT.js +963 -0
- package/dist/cli/completion-6M6Hr8TL.js +211 -0
- package/dist/cli/completion-Bqu8yq0q.js +1 -0
- package/dist/cli/completion-Ddr3yqd3.js +30 -0
- package/dist/cli/config-B31tIvAl.js +42 -0
- package/dist/cli/config-CjgXMZW2.js +1522 -0
- package/dist/cli/config-D9k5ckqV.js +1 -0
- package/dist/cli/config-edit-D46H0UHp.js +613 -0
- package/dist/cli/db-CQCLx7cx.js +78 -0
- package/dist/cli/db-CeagtENM.js +473 -0
- package/dist/cli/design-edit-B40ljpGZ.js +205 -0
- package/dist/cli/detect-RApSAA8v.js +84 -0
- package/dist/cli/dist-DSwzLVAG.js +129 -0
- package/dist/cli/doctor-COGJJ1gy.js +3898 -0
- package/dist/cli/emit-DbQeLlHt.js +1123 -0
- package/dist/cli/env-Ba-pOD3a.js +1 -0
- package/dist/cli/env-C-Bl6Awn.js +1 -0
- package/dist/cli/env-DMgjB_4y.js +1114 -0
- package/dist/cli/env-DlgfvI8U.js +143 -0
- package/dist/cli/errors-BTe6A15O.js +98 -0
- package/dist/cli/exec--Q1ZEWUW.js +463 -0
- package/dist/cli/files-C5JfVnj5.js +972 -0
- package/dist/cli/fresh-import-DzgsGHkX.js +40 -0
- package/dist/cli/gen-DHW1qENn.js +307 -0
- package/dist/cli/index.d.ts +252 -177
- package/dist/cli/index.js +16 -16
- package/dist/cli/init-CZifzAUD.js +397 -0
- package/dist/cli/introspect-Dfwu5vAg.js +51 -0
- package/dist/cli/io-DH1kcmmP.js +37 -0
- package/dist/cli/keys-iJs_1WT8.js +106 -0
- package/dist/cli/live-1eL2MIkS.js +344 -0
- package/dist/cli/mcp-CaFW6uKU.js +240 -0
- package/dist/cli/metadata-DkOQHZoH.js +146 -0
- package/dist/cli/migration-safety-BsCKKxPf.js +305 -0
- package/dist/cli/module-migration-CbX-jRhV.js +606 -0
- package/dist/cli/moved-CdNtCf4t.js +161 -0
- package/dist/cli/parse-CRZLku1b.js +182 -0
- package/dist/cli/preset-C4fagbhZ.js +130 -0
- package/dist/cli/prompts-jqnr94b9.js +1140 -0
- package/dist/cli/redact-KGAk2Ul9.js +38 -0
- package/dist/cli/run-CE2s5TDh.js +711 -0
- package/dist/cli/run-Du5XPOCv.js +63 -0
- package/dist/cli/run-KXjrgNCH.js +2378 -0
- package/dist/cli/scaffold-CPH8sEhw.js +901 -0
- package/dist/cli/scaffold-DS6g3INp.js +1 -0
- package/dist/cli/seed-D6V-T5Af.js +188 -0
- package/dist/cli/seed-DPQaA8aP.js +1 -0
- package/dist/cli/shared-CCpxS5if.js +151 -0
- package/dist/cli/skills-Bz4INB8f.js +121 -0
- package/dist/cli/snapshot-Dkwxc1uV.js +351 -0
- package/dist/cli/source-args-DZV4RnZL.js +59 -0
- package/dist/cli/spec-B3Tbc7Dm.js +7534 -0
- package/dist/cli/spec-Cv1GYrcW.js +1 -0
- package/dist/cli/sql-C58MS9DI.js +348 -0
- package/dist/cli/sql-DVPw5tvO.js +2 -0
- package/dist/cli/stack-_F_JhllX.js +135 -0
- package/dist/cli/stack-env-6hS-WEmh.js +93 -0
- package/dist/cli/stack-status-B_Ipd_-z.js +46 -0
- package/dist/cli/stacks-BYlQ96WS.js +232 -0
- package/dist/cli/style-Bm2X5JrN.js +35 -0
- package/dist/cli/supabase-toml-CncmQbO0.js +1164 -0
- package/dist/cli/sync-CjkKpI6d.js +91 -0
- package/dist/cli/topics-BpdnYmWb.js +30 -0
- package/dist/cli/typegen-F9GEjpvD.js +502 -0
- package/dist/cli/validate-B3lF3-jB.js +7522 -0
- package/dist/cli/version-CTqnp3HO.js +4 -0
- package/dist/cli/write-3qdrpS1v.js +201 -0
- package/dist/client/index.d.ts +6 -6
- package/dist/client/index.js +19 -12
- package/dist/client/native/index.d.ts +87 -53
- package/dist/client/native/index.js +65 -43
- package/dist/client--tyFmxDT.js +52 -0
- package/dist/client-7_4Y21ue.d.ts +122 -0
- package/dist/client-B1cjaIfv.js +116 -0
- package/dist/client-B2GCMvfd.d.ts +451 -0
- package/dist/client-B8cHiZfF.js +67 -0
- package/dist/client-BIMg9IiF.d.ts +349 -0
- package/dist/client-BKGVUgo7.js +380 -0
- package/dist/client-BNaOcfeH.js +58 -0
- package/dist/client-BQseXods.d.ts +309 -0
- package/dist/client-BSnf6fn6.d.ts +59 -0
- package/dist/client-BW3-RUbq.js +235 -0
- package/dist/client-BYAY7lLs.d.ts +137 -0
- package/dist/client-BcXmbm4f.js +173 -0
- package/dist/client-BgmVu505.js +167 -0
- package/dist/client-Bj0xrUzr.js +437 -0
- package/dist/client-Bn0qqRBg.d.ts +37 -0
- package/dist/client-Bni68sve.d.ts +136 -0
- package/dist/client-BrtwaIBh.d.ts +74 -0
- package/dist/client-BtRx0-kn.js +82 -0
- package/dist/client-BteuBPIy.js +337 -0
- package/dist/client-C1TxDBgX.js +111 -0
- package/dist/client-C1zOmnS8.js +89 -0
- package/dist/client-C56l0MnY.d.ts +177 -0
- package/dist/client-CA6KuLDu.d.ts +223 -0
- package/dist/client-CBcq7LBg.d.ts +178 -0
- package/dist/client-CGJrSTMZ.js +234 -0
- package/dist/client-CLIBcMzL.d.ts +116 -0
- package/dist/client-COuIfjbB.d.ts +46 -0
- package/dist/client-CVToJ4uI.js +84 -0
- package/dist/client-C_0XZieg.js +287 -0
- package/dist/client-CebKlRU7.js +157 -0
- package/dist/client-ChOJ4v0D.js +137 -0
- package/dist/client-CnENAa0E.d.ts +69 -0
- package/dist/client-Cp79i2ZE.d.ts +152 -0
- package/dist/client-CwKsEl6q.js +99 -0
- package/dist/client-D-LPdEDQ.d.ts +43 -0
- package/dist/client-D6gD9qt9.d.ts +45 -0
- package/dist/client-DBwWXQKF.d.ts +132 -0
- package/dist/client-DD3EcytK.js +65 -0
- package/dist/client-DScMvaty.js +38 -0
- package/dist/client-DT6Tvudr.d.ts +54 -0
- package/dist/client-DU1_Jq4e.d.ts +116 -0
- package/dist/client-Dd-a0tup.d.ts +475 -0
- package/dist/client-Dh8zXgpq.js +1060 -0
- package/dist/client-DkI0oyR7.js +76 -0
- package/dist/client-DmjG9PHH.js +211 -0
- package/dist/client-DnUFHmje.js +129 -0
- package/dist/client-Do5hykMK.d.ts +38 -0
- package/dist/client-DzOL3lsV.d.ts +110 -0
- package/dist/client-DzukpHS1.d.ts +165 -0
- package/dist/client-LngH55pZ.d.ts +83 -0
- package/dist/client-PPSwiJaK.js +291 -0
- package/dist/client-RoAuPQNB.d.ts +103 -0
- package/dist/client-WzuQExHk.js +253 -0
- package/dist/client-Y_HnZGF4.js +51 -0
- package/dist/client-bDXsvSXp.d.ts +90 -0
- package/dist/client-bx3Bk7c5.d.ts +64 -0
- package/dist/client-jgDU7Roj.d.ts +144 -0
- package/dist/client-kRvHKAKS.js +60 -0
- package/dist/client-pxXoQOdC.js +40 -0
- package/dist/client-yIxEJwTK.js +121 -0
- package/dist/clone-CkG0-hlI.js +33 -0
- package/dist/cloud-event-SPyXMdcd.d.ts +64 -0
- package/dist/cloud-event-XsM53POL.js +63 -0
- package/dist/codecs-CQrX3ZW4.js +358 -0
- package/dist/codecs-DAu2sYWn.d.ts +222 -0
- package/dist/comments-CB8pFSV1.js +142 -0
- package/dist/commerce/index.d.ts +39 -33
- package/dist/commerce/index.js +38 -28
- package/dist/compiler-BCyHFI6n.d.ts +14 -0
- package/dist/compose--4D1FoPN.js +53 -0
- package/dist/composite-Dv6o2BSw.js +130 -0
- package/dist/composite-KllwFim2.d.ts +82 -0
- package/dist/config/index.d.ts +7 -7
- package/dist/config/index.js +8 -8
- package/dist/config-BuOz_O-y.d.ts +2152 -0
- package/dist/config-Dh4D8lBa.js +13931 -0
- package/dist/config-Dn0cC3bM.js +1093 -0
- package/dist/connector-BdCE4Efp.d.ts +164 -0
- package/dist/connectors-DDiSNvkF.d.ts +147 -0
- package/dist/context-9Q23weHu.d.ts +524 -0
- package/dist/context-CMxVnPMY.js +9 -0
- package/dist/context-CYquqpA6.js +41 -0
- package/dist/controller-BEliOBOv.js +79 -0
- package/dist/controller-CSsC9s3s.js +73 -0
- package/dist/controller-DAD4hbl4.d.ts +52 -0
- package/dist/create/index.d.ts +309 -175
- package/dist/create/index.js +441 -299
- package/dist/create/lite/index.d.ts +19 -12
- package/dist/create/lite/index.js +10 -9
- package/dist/create/oauth/index.d.ts +2 -0
- package/dist/create/oauth/index.js +101 -0
- package/dist/create/supabase/index.d.ts +13 -34
- package/dist/create/supabase/index.js +16 -84
- package/dist/create-blocks-kPUhCvje.js +217 -0
- package/dist/credentials/index.d.ts +12 -12
- package/dist/credentials/index.js +12 -13
- package/dist/cron-_i5pBGkY.js +148 -0
- package/dist/cron-route-Y0eJ-FNi.js +24 -0
- package/dist/csv-2rXGPNtP.js +89 -0
- package/dist/csv-DhHQS2x_.d.ts +28 -0
- package/dist/db-exception-Lngc1W49.js +31 -0
- package/dist/deal-forecast-CBlp20PY.js +39 -0
- package/dist/deal-forecast-LwO-Z4_C.d.ts +23 -0
- package/dist/define-DQznpZYl.js +2023 -0
- package/dist/define-Dw7pRO4h.d.ts +1123 -0
- package/dist/define-block-COpcS6aT.d.ts +1338 -0
- package/dist/define-block-Dze77QTw.js +56 -0
- package/dist/delegation-CeXm9AJ3.js +146 -0
- package/dist/delivery-Bm0jxmzI.js +29 -0
- package/dist/delivery-n6lZGuGx.d.ts +71 -0
- package/dist/documents-kgDOHUfn.d.ts +152 -0
- package/dist/edge/index.d.ts +67 -40
- package/dist/edge/index.js +20 -17
- package/dist/elysia/index.d.ts +16 -14
- package/dist/elysia/index.js +11 -9
- package/dist/email-tt2QqiSc.d.ts +42 -0
- package/dist/embeddings-CcRP-cMN.d.ts +78 -0
- package/dist/embeddings-vVzseUw0.js +128 -0
- package/dist/employees-Dwyvxs4r.d.ts +180 -0
- package/dist/ended--Bd_Q6uL.d.ts +76 -0
- package/dist/engagements-CsJhf2OM.d.ts +179 -0
- package/dist/entitlements-B_ttRvI6.js +45 -0
- package/dist/entitlements-DDevu4ZE.d.ts +54 -0
- package/dist/entity-form-B67vq97h.d.ts +82 -0
- package/dist/entity-naming-DLDhHTbK.js +131 -0
- package/dist/entity-schema-BXXC1NnT.js +39 -0
- package/dist/env/index.d.ts +1 -1
- package/dist/env/index.js +16 -4
- package/dist/envelope-DCfHtVtZ.js +90 -0
- package/dist/errors-03ysrOt4.js +325 -0
- package/dist/errors-DZx8w-MH.js +44 -0
- package/dist/escape-like-BfXS-iVe.d.ts +30 -0
- package/dist/eve/index.d.ts +40 -22
- package/dist/eve/index.js +35 -26
- package/dist/eve-BlJI8ZXL.d.ts +157 -0
- package/dist/event-calendar-D3SVa3AE.d.ts +65 -0
- package/dist/event-map-CtPFhcOp.js +19 -0
- package/dist/events/index.d.ts +5 -4
- package/dist/events/index.js +11 -10
- package/dist/events-D6IZ5CE8.js +82 -0
- package/dist/events-DbLjvxDX.d.ts +852 -0
- package/dist/events-SqJLbb8q.js +24 -0
- package/dist/executor-BDAGTc_O.js +207 -0
- package/dist/executor-BElVQpaB.d.ts +188 -0
- package/dist/executor-CPyrQdjh.d.ts +700 -0
- package/dist/executor-CsTaO3AT.d.ts +37 -0
- package/dist/executor-DQoczQZJ.d.ts +104 -0
- package/dist/executor-QtVn0axs.js +147 -0
- package/dist/executor-o9HkOJ0m.js +869 -0
- package/dist/expo/index.d.ts +37 -26
- package/dist/expo/index.js +18 -15
- package/dist/expo-sqlite/index.d.ts +20 -17
- package/dist/expo-sqlite/index.js +19 -13
- package/dist/feature-BBLdbGu7.js +224 -0
- package/dist/field-errors-vshYTVKr.d.ts +166 -0
- package/dist/field-formats-C6QKA3UR.js +102 -0
- package/dist/field-formats-DbjaDXoZ.d.ts +39 -0
- package/dist/fields-CanaxA0U.d.ts +75 -0
- package/dist/fields-DK30XCgc.js +107 -0
- package/dist/filter-evaluate-C3i2bGfk.d.ts +37 -0
- package/dist/filter-evaluate-CRDXv0Dl.js +217 -0
- package/dist/filter-query-D4ZSwbcJ.js +524 -0
- package/dist/filter-query-o3b_GuyC.d.ts +133 -0
- package/dist/flags-BTDPaN11.d.ts +246 -0
- package/dist/flags-BhYByvP1.js +279 -0
- package/dist/flags-sdk/index.d.ts +13 -13
- package/dist/flags-sdk/index.js +18 -15
- package/dist/flows/index.d.ts +247 -0
- package/dist/flows/index.js +229 -0
- package/dist/form-definition-BTpM_tz1.js +363 -0
- package/dist/form-definition-BjEtH8BT.d.ts +119 -0
- package/dist/format-AYHceC2m.d.ts +79 -0
- package/dist/framework-CXoyWGgd.js +57 -0
- package/dist/framework-FxfJpyoF.d.ts +41 -0
- package/dist/function-contract-pEmsaUIf.js +8 -0
- package/dist/function-contract-vPqwt1j4.d.ts +27 -0
- package/dist/gateway-DI8dbOml.d.ts +115 -0
- package/dist/gateway-options-BlVCqgb8.d.ts +29 -0
- package/dist/gateway-options-Cl74B7k6.js +27 -0
- package/dist/graph-B4eubUQG.js +365 -0
- package/dist/guest-actions-1T1DeS5Y.d.ts +5 -0
- package/dist/guest-actions-B7zdhfnh.js +9 -0
- package/dist/h3/index.d.ts +19 -12
- package/dist/h3/index.js +15 -11
- package/dist/h3/v1/index.d.ts +34 -24
- package/dist/h3/v1/index.js +23 -19
- package/dist/hmac-B3CTTlfv.js +23 -0
- package/dist/hono/index.d.ts +54 -36
- package/dist/hono/index.js +18 -18
- package/dist/http-51t9xppD.js +28 -0
- package/dist/http-BjjojWg3.js +40 -0
- package/dist/http-DzbloBR-.js +141 -0
- package/dist/image-url-_d7xYsXK.js +84 -0
- package/dist/impersonation-CZD9AOAk.js +62 -0
- package/dist/impersonation-YTa9dZUv.d.ts +28 -0
- package/dist/inbox-BPBb6etH.d.ts +321 -0
- package/dist/index-BSUX4dlB.d.ts +305 -0
- package/dist/index-BgSuw4CC.d.ts +151 -0
- package/dist/index-C7CrdGgz.d.ts +562 -0
- package/dist/index-CvxK2BZS.d.ts +847 -0
- package/dist/index-CxZQgNVE.d.ts +62 -0
- package/dist/index-D4420jLW.d.ts +66 -0
- package/dist/index-DK-YTWLd.d.ts +443 -0
- package/dist/index-DbXWcrOI.d.ts +577 -0
- package/dist/index-DbyDZZlc.d.ts +53 -0
- package/dist/index-NRMMhhEi.d.ts +104 -0
- package/dist/index-U0o7kU0s.d.ts +69 -0
- package/dist/index-WEafENqH.d.ts +149 -0
- package/dist/index-X2fkPUwb.d.ts +51 -0
- package/dist/index-Yep7auV-.d.ts +287 -0
- package/dist/index-eTY4kJzo.d.ts +163 -0
- package/dist/index.d.ts +35 -99
- package/dist/index.js +24 -19
- package/dist/invalidate-BLiBFbLy.d.ts +19 -0
- package/dist/iso4217-B-durg_y.js +176 -0
- package/dist/json-DaByVJpw.js +22 -0
- package/dist/json-schema-DWDTfD8J.js +888 -0
- package/dist/jwks-cache-CRymV-Dr.js +49 -0
- package/dist/jws-D0toeQlA.d.ts +66 -0
- package/dist/jws-DOgHJKHb.js +205 -0
- package/dist/kit-Ct4Z6GIO.js +127 -0
- package/dist/kit-DKfbNTAA.d.ts +94 -0
- package/dist/knowledge-BKGrXdS_.js +272 -0
- package/dist/knowledge-CFkCRxO9.d.ts +202 -0
- package/dist/lint/index.d.ts +6 -6
- package/dist/lint/index.js +9 -6
- package/dist/list/index.d.ts +3 -3
- package/dist/list/index.js +3 -3
- package/dist/list-query-BtluNnYk.d.ts +222 -0
- package/dist/list-query-CuS1w2Af.js +559 -0
- package/dist/live-CZtRMh62.js +246 -0
- package/dist/management-wtecfrNf.d.ts +57 -0
- package/dist/mcp/index.d.ts +70 -42
- package/dist/mcp/index.js +53 -45
- package/dist/mcp/sdk/index.d.ts +37 -25
- package/dist/mcp/sdk/index.js +16 -13
- package/dist/mentions-ByYnRNIG.js +114 -0
- package/dist/message-Bg4TKA12.d.ts +99 -0
- package/dist/messages-DNzIVvgN.js +492 -0
- package/dist/messaging-BC-P-yAv.js +329 -0
- package/dist/messaging-CZ6aWb10.d.ts +297 -0
- package/dist/metric-definition-EAYI1r2n.d.ts +69 -0
- package/dist/mfa-wrx1rqJT.d.ts +36 -0
- package/dist/model-Btl8X9cs.d.ts +326 -0
- package/dist/model-messages-D-jVOIOK.js +206 -0
- package/dist/model-messages-DrR4lZ_c.d.ts +34 -0
- package/dist/money-BNRdJQzA.d.ts +91 -0
- package/dist/money-BZl985O-.js +197 -0
- package/dist/money-codec-jMP0PQLZ.js +41 -0
- package/dist/my-work-kinds-BU3SlA-6.js +11 -0
- package/dist/nestjs/index.d.ts +32 -17
- package/dist/nestjs/index.js +27 -18
- package/dist/next/client/index.d.ts +8 -7
- package/dist/next/client/index.js +8 -7
- package/dist/next/image/index.d.ts +8 -6
- package/dist/next/image/index.js +7 -5
- package/dist/next/index.d.ts +342 -110
- package/dist/next/index.js +225 -45
- package/dist/node/index.d.ts +3 -3
- package/dist/node/index.js +33 -23
- package/dist/node-headers-BPtMP4_V.d.ts +27 -0
- package/dist/nuxt/index.d.ts +7 -6
- package/dist/nuxt/index.js +7 -6
- package/dist/onboarding-CGMuX7sP.js +68 -0
- package/dist/openapi/index.d.ts +4 -3
- package/dist/openapi/index.js +10 -7
- package/dist/operations-DVHRHvv6.js +29 -0
- package/dist/operations-nWYRexee.d.ts +6 -0
- package/dist/optional-peer-C1NbBRJm.js +32 -0
- package/dist/options-289GJc2l.d.ts +52 -0
- package/dist/options-2EMA_x6_.js +16 -0
- package/dist/options-63AKQNv0.js +5 -0
- package/dist/options-70OsM-wK.js +10 -0
- package/dist/options-9gvPo1BC.js +8 -0
- package/dist/options-B5VUf4IT.js +8 -0
- package/dist/options-BPDiwSa-.js +5 -0
- package/dist/options-BYOtaF7w.js +5 -0
- package/dist/options-BZOliZvb.js +9 -0
- package/dist/options-BjtrC7o6.js +8 -0
- package/dist/options-BkpqTGrJ.js +8 -0
- package/dist/options-Bpl-WFPk.js +15 -0
- package/dist/options-Br1Xi2Hw.js +9 -0
- package/dist/options-CF7nRWXS.js +5 -0
- package/dist/options-CSCXNYJO.d.ts +8 -0
- package/dist/options-CYV4iZiQ.js +5 -0
- package/dist/options-CalPr6kN.d.ts +12 -0
- package/dist/options-CfxBliP6.d.ts +17 -0
- package/dist/options-CmoJsd4V.d.ts +8 -0
- package/dist/options-Cyu0hgmN.js +9 -0
- package/dist/options-D0bzZx9a.d.ts +10 -0
- package/dist/options-D1hSuf50.d.ts +12 -0
- package/dist/options-D4aD9qwB.js +5 -0
- package/dist/options-D65jzn7S.js +5 -0
- package/dist/options-D7sgG1bQ.js +16 -0
- package/dist/options-DJ-aYPVN.js +5 -0
- package/dist/options-DJm31rsi.d.ts +16 -0
- package/dist/options-DWML05Cp.js +5 -0
- package/dist/options-DXuA4JVa.d.ts +15 -0
- package/dist/options-DZupPoI0.d.ts +10 -0
- package/dist/options-DlohRAYd.d.ts +13 -0
- package/dist/options-Dm-2crCx.d.ts +273 -0
- package/dist/options-DrSkIBCD.js +9 -0
- package/dist/options-DujalSfR.js +10 -0
- package/dist/options-Dz3hJxUw.d.ts +10 -0
- package/dist/options-E7KcmHQv.js +8 -0
- package/dist/options-IHPg8ZoA.js +5 -0
- package/dist/options-MQfTGMgP.d.ts +14 -0
- package/dist/options-OMAUVcKK.d.ts +10 -0
- package/dist/options-a-28mlYT.js +9 -0
- package/dist/options-o2kfYU2x.js +8 -0
- package/dist/options-t_O5ldT6.js +5 -0
- package/dist/options-te6d5-yz.d.ts +19 -0
- package/dist/options-xD4_FRUq.js +10 -0
- package/dist/options-zkyhM3qi.js +8 -0
- package/dist/organizations-DtehZg3J.js +401 -0
- package/dist/orpc/index.d.ts +109 -38
- package/dist/orpc/index.js +53 -18
- package/dist/otel/index.d.ts +19 -16
- package/dist/otel/index.js +22 -19
- package/dist/outbox-CsF_iKjx.d.ts +199 -0
- package/dist/overlay/index.d.ts +71 -55
- package/dist/overlay/index.js +48 -41
- package/dist/payments-BtScsgPS.js +16 -0
- package/dist/payments-CBzQIjoX.d.ts +114 -0
- package/dist/permissions-BetA_Fo_.js +34 -0
- package/dist/pg-error-B5QLDcbG.js +26 -0
- package/dist/plugin-Ar5546xh.d.ts +202 -0
- package/dist/plugin-D9bYbYli.js +45 -0
- package/dist/plugins/actor/index.d.ts +9 -6
- package/dist/plugins/actor/index.js +6 -6
- package/dist/plugins/rules/index.d.ts +15 -15
- package/dist/plugins/rules/index.js +13 -7
- package/dist/plugins/soft-delete/index.d.ts +7 -7
- package/dist/plugins/soft-delete/index.js +7 -7
- package/dist/plugins/tenant/index.d.ts +16 -11
- package/dist/plugins/tenant/index.js +9 -10
- package/dist/plugins/timestamps/index.d.ts +3 -3
- package/dist/plugins/timestamps/index.js +4 -4
- package/dist/plugins/validation/index.d.ts +4 -4
- package/dist/plugins/validation/index.js +5 -5
- package/dist/pool-CRkU15dA.d.ts +123 -0
- package/dist/pool-errors-B17BQRW-.js +27 -0
- package/dist/ports-DsJicwI2.d.ts +89 -0
- package/dist/ports-yajgT0t0.js +139 -0
- package/dist/postgres/index.d.ts +15 -15
- package/dist/postgres/index.js +14 -8
- package/dist/postgrest-DHLlN2nS.d.ts +53 -0
- package/dist/powersync/index.d.ts +13 -14
- package/dist/powersync/index.js +65 -36
- package/dist/powersync/react/index.d.ts +13 -12
- package/dist/powersync/react/index.js +15 -11
- package/dist/preset/index.d.ts +4 -4
- package/dist/preset/index.js +4 -4
- package/dist/preset-DzcQ5CQM.js +841 -0
- package/dist/problem-BWElIgIb.js +162 -0
- package/dist/problem-DpHB7tWl.d.ts +79 -0
- package/dist/provider-DmiaI1qt.d.ts +112 -0
- package/dist/provider-EJ0-5GwJ.js +57 -0
- package/dist/push-token-BxKmYhwk.d.ts +24 -0
- package/dist/queries-Dw8y9bvz.js +245 -0
- package/dist/query/index.d.ts +4 -4
- package/dist/query/index.js +291 -3
- package/dist/rank-result-C_sHjkiz.js +18 -0
- package/dist/rank-result-DwR0FawB.d.ts +14 -0
- package/dist/rate-limit-B_U12PdL.js +49 -0
- package/dist/rate-limit-CrOuXfjj.d.ts +50 -0
- package/dist/rate-limit-DExDw3Cy.js +327 -0
- package/dist/ratelimit-headers-kEcXyO3H.js +62 -0
- package/dist/react/index.d.ts +11 -11
- package/dist/react/index.js +5 -5
- package/dist/react/native/index.d.ts +36 -21
- package/dist/react/native/index.js +32 -20
- package/dist/react/server.d.ts +77 -21
- package/dist/react/server.js +70 -14
- package/dist/react/session.d.ts +9 -7
- package/dist/react/session.js +7 -5
- package/dist/react-28VgUbm9.js +852 -0
- package/dist/react-BKCnIuZs.js +79 -0
- package/dist/react-controller-CKSdtJ10.js +43 -0
- package/dist/react-env-CfA3EdBH.js +20 -0
- package/dist/react-router/index.d.ts +35 -25
- package/dist/react-router/index.js +14 -13
- package/dist/read-set-BAR84kPC.js +199 -0
- package/dist/realtime/index.d.ts +8 -8
- package/dist/realtime/index.js +37 -5
- package/dist/realtime-status-BhNkb-Ow.d.ts +8 -0
- package/dist/realtime-status-asHvhiOh.js +11 -0
- package/dist/recordings-DgDu7AOt.d.ts +119 -0
- package/dist/records/index.d.ts +83 -0
- package/dist/records/index.js +315 -0
- package/dist/refusal-DXydjgsS.js +64 -0
- package/dist/refusal-efy5bZMd.d.ts +32 -0
- package/dist/resolve-CzUKTIMq.d.ts +289 -0
- package/dist/resolve-DAYdcs22.js +892 -0
- package/dist/resolved-names-Dr7brlLL.js +133 -0
- package/dist/resource-BRRU-A7j.js +91 -0
- package/dist/resource-DYDEnww-.d.ts +115 -0
- package/dist/resource-Dk_JYsOt.js +469 -0
- package/dist/resource-execute-bT9ltHVT.d.ts +15 -0
- package/dist/resource-schemas-up6bKOUi.js +82 -0
- package/dist/resource-types-Bzt_bpR5.d.ts +153 -0
- package/dist/resources-BV6j5TTD.js +64 -0
- package/dist/resources-Du5wcL3f.d.ts +7 -0
- package/dist/respond-CZYibxUx.d.ts +101 -0
- package/dist/respond-z_yfyitp.js +100 -0
- package/dist/result-B3m7xtRY.js +146 -0
- package/dist/result-C6jDfedy.d.ts +350 -0
- package/dist/rows-Bb0EPupt.js +80 -0
- package/dist/rows-CtLWqdGQ.js +39 -0
- package/dist/rrule-xDm2znty.js +290 -0
- package/dist/rules-DcW5mj1r.js +287 -0
- package/dist/run-watch-B-LoK5m1.js +53 -0
- package/dist/runtime-CoKxZibd.js +45 -0
- package/dist/sales-lines-9HsX89aO.d.ts +28 -0
- package/dist/sales-lines-BhrIx2oK.js +41 -0
- package/dist/sales-shared-C_u68eq2.js +22 -0
- package/dist/schemas-9Ci3K0Hk.js +103 -0
- package/dist/schemas-ypoQZ_6N.js +157 -0
- package/dist/scores-CsURQDUB.d.ts +172 -0
- package/dist/scores-DdPZVVt8.js +177 -0
- package/dist/search-Cn_DGluL.js +9 -0
- package/dist/search-ToCOlCZ8.js +106 -0
- package/dist/sections-DjxYmpu-.js +26 -0
- package/dist/server/index.d.ts +153 -116
- package/dist/server/index.js +49 -40
- package/dist/server-types-BOs-eFpo.d.ts +809 -0
- package/dist/session-BgsOPGZs.d.ts +97 -0
- package/dist/settings-mL-i7QUM.js +93 -0
- package/dist/shared-Bf-I13Ht.js +91 -0
- package/dist/shared-CRRfQAKG.d.ts +11 -0
- package/dist/shared-LmlfYPv4.js +60 -0
- package/dist/shared-eVrl39dX.js +17 -0
- package/dist/sign-in-D54FLMQy.d.ts +55 -0
- package/dist/sign-in-lAyf6Ohy.js +386 -0
- package/dist/signatures-GUBuhLOB.js +145 -0
- package/dist/signatures-zbu6KTNQ.d.ts +43 -0
- package/dist/signers-D6ecZl22.d.ts +390 -0
- package/dist/signing-keys-B3RHGMMu.d.ts +119 -0
- package/dist/signing-keys-fWapUzi0.js +164 -0
- package/dist/solid/index.d.ts +69 -24
- package/dist/solid/index.js +62 -17
- package/dist/solid-bind-C1jeq4Qm.d.ts +11 -0
- package/dist/solid-bind-iHGfGtBK.js +38 -0
- package/dist/solid-controller-DGuv7V8a.js +13 -0
- package/dist/solid-start/index.d.ts +27 -20
- package/dist/solid-start/index.js +9 -9
- package/dist/spec/index.d.ts +40 -25
- package/dist/spec/index.js +26 -21
- package/dist/spec-CoWHDoud.js +119 -0
- package/dist/spec-pins-CZ2CL8YZ.d.ts +120 -0
- package/dist/spec-pins-D3Tm6HJi.js +60 -0
- package/dist/sql/index.d.ts +5 -5
- package/dist/sql/index.js +5 -5
- package/dist/sql-CVYjOUyG.js +421 -0
- package/dist/sql-rQDL6PIL.js +122247 -0
- package/dist/sso-B744gHeS.d.ts +161 -0
- package/dist/sso-Bt9HocgW.js +217 -0
- package/dist/ssr/index.d.ts +4 -4
- package/dist/ssr/index.js +3 -3
- package/dist/standard-DbQsD2xZ.d.ts +7 -0
- package/dist/standard-DtkpFGkS.js +25 -0
- package/dist/stats-qCEV5M3B.js +1147 -0
- package/dist/statuses-DMMDwXpZ.js +29 -0
- package/dist/statuses-zRcc2TeZ.js +28 -0
- package/dist/storage/index.d.ts +4 -4
- package/dist/storage/index.js +138 -74
- package/dist/store-McN-2esd.js +69 -0
- package/dist/store-o0HwYXl8.d.ts +83 -0
- package/dist/streams/index.d.ts +24 -18
- package/dist/streams/index.js +3 -4
- package/dist/streams/redis/index.d.ts +10 -7
- package/dist/streams/redis/index.js +9 -9
- package/dist/stripe/index.d.ts +5 -2
- package/dist/stripe/index.js +2 -2
- package/dist/stripe-BJUfp5jM.js +32 -0
- package/dist/stripe-X22LjuH-.d.ts +156 -0
- package/dist/subject-readers-CsTpx44c.js +49 -0
- package/dist/subject-readers-DEZ45DQF.d.ts +21 -0
- package/dist/subjects-B6p4oAZJ.d.ts +78 -0
- package/dist/subjects-DXFmanh5.d.ts +90 -0
- package/dist/subjects-DevU_atb.js +107 -0
- package/dist/subscribers-BvZxcd63.js +33 -0
- package/dist/summaries-8jQTELIX.d.ts +69 -0
- package/dist/supabase-mcp-Dz9DgrKP.js +28 -0
- package/dist/supabase-mcp-Z4vtsuoO.d.ts +46 -0
- package/dist/support-Ds1-UCN4.js +534 -0
- package/dist/support-view-vwJbRMpV.d.ts +17 -0
- package/dist/svelte/index.d.ts +51 -15
- package/dist/svelte/index.js +46 -13
- package/dist/svelte-bind-BHN5a8VV.js +46 -0
- package/dist/svelte-bind-Ja6CtQGp.d.ts +13 -0
- package/dist/svelte-controller-oFKC9AYu.js +19 -0
- package/dist/sveltekit/index.d.ts +50 -35
- package/dist/sveltekit/index.js +19 -18
- package/dist/table-schema-BcB-VCQb.js +293 -0
- package/dist/table-schema-Cb-IV_pZ.d.ts +78 -0
- package/dist/tags-CLXi2c6O.d.ts +30 -0
- package/dist/tags-C_ym1yDM.js +39 -0
- package/dist/tags-EnvIccSJ.js +86 -0
- package/dist/tanstack-db/index.d.ts +17 -11
- package/dist/tanstack-db/index.js +7 -7
- package/dist/tanstack-db/supabase/index.d.ts +24 -9
- package/dist/tanstack-db/supabase/index.js +7 -4
- package/dist/tanstack-start/index.d.ts +45 -31
- package/dist/tanstack-start/index.js +33 -19
- package/dist/tax-CIIxd8Zf.d.ts +170 -0
- package/dist/tax-DmOMjrYc.js +140 -0
- package/dist/tee-DwkUvJD_.js +101 -0
- package/dist/template-BWP7IXZg.js +126 -0
- package/dist/temporal-DLZlWbOi.js +85 -0
- package/dist/temporal-required-B8qQHYbI.js +20 -0
- package/dist/tenant-Bg4PDLkG.d.ts +17 -0
- package/dist/tenant-DnMqeNIM.js +27 -0
- package/dist/tenant-source-bqWpSr86.js +8 -0
- package/dist/testing/index.d.ts +606 -267
- package/dist/testing/index.js +665 -210
- package/dist/timeline-0_hTBH0-.js +52 -0
- package/dist/timeline-DUUsPLv5.d.ts +152 -0
- package/dist/timing-C5NzaEgy.js +95 -0
- package/dist/topic-CPOmMgkf.js +643 -0
- package/dist/topic-D9j8G2dw.d.ts +415 -0
- package/dist/ttl-cache-Bhr9swjT.js +32 -0
- package/dist/types-BEDfwXL4.d.ts +251 -0
- package/dist/types-BRJHGhSq.d.ts +177 -0
- package/dist/types-BTK75521.js +8 -0
- package/dist/types-CGUDoF5I.d.ts +624 -0
- package/dist/types-DkPE7yd2.d.ts +194 -0
- package/dist/types-QHeku_6b.d.ts +217 -0
- package/dist/types-uHD9yANu.d.ts +700 -0
- package/dist/undo-B696duxr.d.ts +46 -0
- package/dist/undo-vutx78k8.js +44 -0
- package/dist/upload-claim-D_wgDbi7.js +33 -0
- package/dist/usage-BI1E2940.js +264 -0
- package/dist/usage-DBcVGqnr.d.ts +232 -0
- package/dist/user-change-CSR_prhd.js +133 -0
- package/dist/variants-DL7NpFJ7.js +53 -0
- package/dist/vault-BQTdu4eH.d.ts +62 -0
- package/dist/vercel-connect/index.d.ts +3 -3
- package/dist/vercel-connect/index.js +8 -8
- package/dist/verify-27w0I5C9.js +130 -0
- package/dist/verify-BmuCB4PW.d.ts +146 -0
- package/dist/view-2_I-2ukO.d.ts +90 -0
- package/dist/view-BtgqxQLM.js +108 -0
- package/dist/vue/index.d.ts +70 -28
- package/dist/vue/index.js +68 -22
- package/dist/vue-bind-CFxon-Vs.js +45 -0
- package/dist/vue-bind-TPkbLl4z.d.ts +11 -0
- package/dist/vue-controller-WtbuT-Ux.js +13 -0
- package/dist/watch-CfMT6vX7.js +139 -0
- package/dist/watch-DziJudwj.d.ts +93 -0
- package/dist/watch-topic-CIT3UlAh.d.ts +31 -0
- package/dist/watch-topic-CuaWfCuv.js +57 -0
- package/dist/wire-Bizdxvp-.js +66 -0
- package/dist/work-items-Cnntm8ij.d.ts +238 -0
- package/dist/workflow-builder-2q1iqHYG.js +699 -0
- package/dist/workflow-sdk/builder/index.d.ts +51 -37
- package/dist/workflow-sdk/builder/index.js +30 -24
- package/dist/workflow-sdk/index.d.ts +24 -15
- package/dist/workflow-sdk/index.js +9 -6
- package/dist/workflow-sdk/world/index.d.ts +56 -24
- package/dist/workflow-sdk/world/index.js +47 -24
- package/dist/workflow-sdk-BTYWQQg9.d.ts +163 -0
- package/dist/workflow-sdk-_pqDUwNK.js +242 -0
- package/dist/workflow-sdk-world-BIwGVy6S.js +2401 -0
- package/dist/workflows-D8U7KyXJ.d.ts +258 -0
- package/dist/workflows-VJBSV-QR.js +285 -0
- package/dist/yjs/index.d.ts +39 -12
- package/dist/yjs/index.js +63 -21
- package/package.json +216 -3
- package/schemas/cli-commands-v1.json +18 -0
- package/schemas/config-v1.json +742 -35
- package/schemas/design-v1.json +351 -0
- package/schemas/doctor-report-v1.json +5 -1
- package/schemas/snapshot-v2.json +25 -0
- package/skills/better-supabase/SKILL.md +6 -5
- package/skills/better-supabase/references/frontend.md +3 -2
- package/skills/better-supabase/references/troubleshooting.md +18 -18
- package/skills/better-supabase/references/ui-recipes.md +12686 -8024
- package/skills/better-supabase-api/SKILL.md +1 -1
- package/skills/better-supabase-api/references/adapters.md +3 -6
- package/skills/better-supabase-api/references/expo.md +1 -0
- package/skills/better-supabase-api/references/powersync.md +8 -1
- package/skills/better-supabase-testing/SKILL.md +2 -3
- package/dist/access-sql-CTJPHjCL.js +0 -201
- package/dist/actor-BAhb-d1S.d.ts +0 -104
- package/dist/actor-CAL8mMih.js +0 -151
- package/dist/adapter-CRNH2aX_.js +0 -2107
- package/dist/agents-CGP2AQge.d.ts +0 -111
- package/dist/ai-cache-BdeJKlrV.d.ts +0 -70
- package/dist/ai-cache-CLninP-F.js +0 -84
- package/dist/ai-chat-D-2MH1sU.d.ts +0 -608
- package/dist/ai-files-ChFDkMLN.js +0 -339
- package/dist/ai-tasks-ZvPnNudQ.d.ts +0 -157
- package/dist/announcements-BNxTW5HJ.js +0 -128
- package/dist/api-C43_FYDp.js +0 -680
- package/dist/api-DoWK3dTw.d.ts +0 -411
- package/dist/api-keys-AgDXbcql.d.ts +0 -205
- package/dist/api-keys-BSXwI2jF.js +0 -318
- package/dist/app-tables-BRjMcWhW.js +0 -819
- package/dist/app-tables-BrMBjyuq.d.ts +0 -35
- package/dist/approvals-CyX709B-.d.ts +0 -124
- package/dist/assistant-DZsHsYIx.d.ts +0 -148
- package/dist/attachments-CK8D8bIV.js +0 -270
- package/dist/attributes-D4mA7WhI.js +0 -38
- package/dist/audit-log-ovUlF4Mk.js +0 -786
- package/dist/auth-CdBKt0CS.js +0 -20
- package/dist/auth-link-BjFPqwLz.d.ts +0 -97
- package/dist/auth-link-DrDX9KOT.js +0 -114
- package/dist/auth-module-DbZv2WrR.js +0 -10
- package/dist/auth-reply-Daq72lY4.js +0 -31
- package/dist/authorization-ClWBcXJi.d.ts +0 -1456
- package/dist/authorization-hooks-WDQMKIsc.d.ts +0 -214
- package/dist/authorizer-B3yyCVUF.js +0 -126
- package/dist/authorizer-eiOjo-3l.d.ts +0 -73
- package/dist/base64-D4aqdnDR.js +0 -42
- package/dist/before-route-B98js9m_.js +0 -30
- package/dist/bind-Bfo40o63.d.ts +0 -70
- package/dist/block-env-CBd_SoL5.js +0 -29
- package/dist/block-env-Dxl7rsI0.d.ts +0 -10
- package/dist/block-events-DD9Q_NUz.js +0 -96
- package/dist/block-fields-Bv1hV855.js +0 -139
- package/dist/block-fields-DnaDbgZS.d.ts +0 -55
- package/dist/block-helpers-CjcQM1yA.d.ts +0 -37
- package/dist/block-helpers-DkVZNDrj.js +0 -264
- package/dist/block-hooks-C22vuIUd.js +0 -114
- package/dist/block-hooks-DcPJHztl.d.ts +0 -107
- package/dist/block-transport-DezJPPA0.d.ts +0 -70
- package/dist/block-transport-J7ZepTq2.js +0 -85
- package/dist/blocks-D2WQ63PI.js +0 -84
- package/dist/bookings-DQ7P888X.js +0 -181
- package/dist/bucket-BbePDVwc.d.ts +0 -598
- package/dist/build-C-D_vn0U.js +0 -694
- package/dist/build-CT6SPZkI.js +0 -1815
- package/dist/calendar-eqyuQAoy.js +0 -801
- package/dist/channel-D-LHCY11.d.ts +0 -78
- package/dist/channels-C-GCoNLd.js +0 -114
- package/dist/claims-0KZVT804.js +0 -61
- package/dist/claims-PqzCxaTD.js +0 -85
- package/dist/cli/add-BcOHumvq.js +0 -75
- package/dist/cli/add-DnAyR9w_.js +0 -1
- package/dist/cli/add-TT72pQk6.js +0 -651
- package/dist/cli/adopt-BuS-DC7_.js +0 -1
- package/dist/cli/adopt-mbB1bcIG.js +0 -412
- package/dist/cli/agent-CCrTYK3W.js +0 -176
- package/dist/cli/apply-CiBFOFGw.js +0 -326
- package/dist/cli/blocks-5-JGzwXX.js +0 -124
- package/dist/cli/blocks-DeLQOlUK.js +0 -1
- package/dist/cli/cache-DQwgb3rg.js +0 -507
- package/dist/cli/catalog-Cm6BtquM.js +0 -188
- package/dist/cli/codemod-BzAMX4el.js +0 -985
- package/dist/cli/command-dfdVhU_2.js +0 -891
- package/dist/cli/completion-4lLjtI49.js +0 -1
- package/dist/cli/completion-D4InNrxw.js +0 -30
- package/dist/cli/completion-zsp5s0zI.js +0 -205
- package/dist/cli/config-CCyweX7Y.js +0 -1
- package/dist/cli/config-DI6ielsx.js +0 -39
- package/dist/cli/config-edit-Ct1lXe8a.js +0 -603
- package/dist/cli/config-yZ55rsKZ.js +0 -1463
- package/dist/cli/db-DT1bGB02.js +0 -78
- package/dist/cli/db-TRymMyAW.js +0 -90
- package/dist/cli/design-edit-0U9iCTiS.js +0 -202
- package/dist/cli/detect-DQsVeBHg.js +0 -84
- package/dist/cli/dist-D_VbPAMR.js +0 -129
- package/dist/cli/doctor-DOfy6kjt.js +0 -3732
- package/dist/cli/emit-56LAG_Px.js +0 -1067
- package/dist/cli/env-B7TWPEt0.js +0 -1
- package/dist/cli/env-C8R7Nf0a.js +0 -1088
- package/dist/cli/env-Cmu99uKR.js +0 -1
- package/dist/cli/env-Dh5K5t2U.js +0 -143
- package/dist/cli/errors-Caiz_0so.js +0 -98
- package/dist/cli/files-DDvAwTko.js +0 -963
- package/dist/cli/fresh-import-BeYf9I3x.js +0 -40
- package/dist/cli/gen-D3sC5jDn.js +0 -304
- package/dist/cli/init-DNomoycJ.js +0 -394
- package/dist/cli/introspect-kYX06Q2g.js +0 -51
- package/dist/cli/io-BiPX-_J1.js +0 -37
- package/dist/cli/keys-B8dIJwwi.js +0 -106
- package/dist/cli/live-CkV3d3yp.js +0 -329
- package/dist/cli/mcp-DrxB2Wuw.js +0 -237
- package/dist/cli/metadata-BGkle6WM.js +0 -138
- package/dist/cli/migration-safety-DjVpz2D6.js +0 -206
- package/dist/cli/module-migration-CPhuiY8C.js +0 -592
- package/dist/cli/moved-BMQu1YNY.js +0 -152
- package/dist/cli/parse-QzDvMpXH.js +0 -170
- package/dist/cli/preset-CfIs24cc.js +0 -129
- package/dist/cli/prompts-Bvg_DBpe.js +0 -1137
- package/dist/cli/redact-PjNswZOs.js +0 -35
- package/dist/cli/run-Bck-p0MI.js +0 -63
- package/dist/cli/run-BhJKAanr.js +0 -1528
- package/dist/cli/run-DRZ10srj.js +0 -694
- package/dist/cli/scaffold-DoURlDEI.js +0 -898
- package/dist/cli/scaffold-mzy3OsN5.js +0 -1
- package/dist/cli/seed-C5q4UUIL.js +0 -1
- package/dist/cli/seed-CIdg6s7m.js +0 -114
- package/dist/cli/shared-DKLuA1Tp.js +0 -145
- package/dist/cli/skills-D3zwIlGA.js +0 -121
- package/dist/cli/snapshot-BBKFojqM.js +0 -347
- package/dist/cli/source-args-Cwo7zwvq.js +0 -53
- package/dist/cli/spec-DOgQUZwM.js +0 -1
- package/dist/cli/spec-DZeIP9ta.js +0 -7501
- package/dist/cli/sql-CL_Lbhwl.js +0 -2
- package/dist/cli/sql-DLOvvnBV.js +0 -326
- package/dist/cli/stack-env-_uWWNHWq.js +0 -87
- package/dist/cli/stack-status-_NUgd-g5.js +0 -496
- package/dist/cli/style-2JfIPVMQ.js +0 -29
- package/dist/cli/supabase-toml-BC5sNVKU.js +0 -1153
- package/dist/cli/sync-DBvknfOK.js +0 -88
- package/dist/cli/topics-BBE1-Vrg.js +0 -30
- package/dist/cli/typegen--TfvOPLh.js +0 -494
- package/dist/cli/validate-BfWNKvxy.js +0 -7522
- package/dist/cli/version-B7akdvDv.js +0 -4
- package/dist/cli/write-VZljwoTB.js +0 -198
- package/dist/client-B9CqzgPO.js +0 -75
- package/dist/client-BAOZuBhz.d.ts +0 -101
- package/dist/client-BDO6i2Oe.js +0 -128
- package/dist/client-BGnJ5WJi.js +0 -438
- package/dist/client-BJN0IMEp.d.ts +0 -34
- package/dist/client-BMcjLG0V.d.ts +0 -263
- package/dist/client-BN_fXOs7.d.ts +0 -39
- package/dist/client-BONsuFYf.d.ts +0 -100
- package/dist/client-BPn9XhAM.d.ts +0 -218
- package/dist/client-BfgwocyT.js +0 -155
- package/dist/client-BpS8a6Fm.js +0 -51
- package/dist/client-BtC-r4hE.d.ts +0 -52
- package/dist/client-BuneNd-C.d.ts +0 -419
- package/dist/client-BzCv4kKE.js +0 -65
- package/dist/client-C-2ajnhM.js +0 -89
- package/dist/client-C5mUEb2n.js +0 -55
- package/dist/client-CFKONrrU.js +0 -1051
- package/dist/client-CHR8IBNG.js +0 -318
- package/dist/client-CHwNV8Kz.d.ts +0 -455
- package/dist/client-CLQHsa-2.d.ts +0 -131
- package/dist/client-CMxxwT3N.d.ts +0 -122
- package/dist/client-CU7aNN_B.d.ts +0 -277
- package/dist/client-CYEdJKjk.d.ts +0 -157
- package/dist/client-CYhSGlCN.d.ts +0 -107
- package/dist/client-C_-NZRrg.js +0 -120
- package/dist/client-CcPxbHeT.js +0 -288
- package/dist/client-CosiUrUb.js +0 -98
- package/dist/client-D3gRTNSi.d.ts +0 -68
- package/dist/client-D7T7OLiw.js +0 -169
- package/dist/client-DB34f_7i.d.ts +0 -58
- package/dist/client-DCawyopp.d.ts +0 -65
- package/dist/client-DNq8xYb-.js +0 -52
- package/dist/client-Dqa4XyJ5.d.ts +0 -108
- package/dist/client-Dr5h2r9r.d.ts +0 -34
- package/dist/client-DrTqKgvy.d.ts +0 -155
- package/dist/client-DyfWYU8S.js +0 -84
- package/dist/client-Dz1jWDA2.js +0 -209
- package/dist/client-DzTtOVRR.js +0 -137
- package/dist/client-Ezlbskjq.js +0 -60
- package/dist/client-GCCRI9ge.d.ts +0 -135
- package/dist/client-P6v3h7vh.d.ts +0 -130
- package/dist/client-P8l8ncxV.d.ts +0 -103
- package/dist/client-UnM3e32l.js +0 -133
- package/dist/client-WgrPIHH-.js +0 -213
- package/dist/client-ZTtSV3l8.js +0 -40
- package/dist/client-arq4daO_.js +0 -104
- package/dist/client-ckXfdy1k.js +0 -38
- package/dist/client-eCDPjOMo.js +0 -438
- package/dist/client-iaFm0aVf.js +0 -67
- package/dist/client-kWg4OqIr.d.ts +0 -162
- package/dist/client-pxjbgOz6.js +0 -376
- package/dist/client-tvG258_1.d.ts +0 -59
- package/dist/client-wKmX-f3r.d.ts +0 -388
- package/dist/clone-dN9XOL1K.js +0 -29
- package/dist/cloud-event-CTh9Sr5w.js +0 -60
- package/dist/cloud-event-DXkNoI6v.d.ts +0 -64
- package/dist/codecs-D-rpDifG.js +0 -358
- package/dist/codecs-RwFNK8Jh.d.ts +0 -215
- package/dist/codegen-C64C0NZG.d.ts +0 -1665
- package/dist/comments-CV5O8q50.js +0 -230
- package/dist/compiler-D_Gjpw_O.d.ts +0 -14
- package/dist/compose-CP0ss-cQ.js +0 -53
- package/dist/composite-1kPAxXto.js +0 -130
- package/dist/composite-DzvBL5nb.d.ts +0 -67
- package/dist/config-DHhQmmuD.js +0 -3917
- package/dist/config-NQmw_wsk.js +0 -558
- package/dist/connector-D9NMNkv0.d.ts +0 -107
- package/dist/connectors-BwPNt-ZG.d.ts +0 -141
- package/dist/context-B8_p3MXo.js +0 -11
- package/dist/context-BiwgsycK.js +0 -41
- package/dist/context-C-bHOtoD.js +0 -5
- package/dist/context-Cv3KlxWY.d.ts +0 -377
- package/dist/context-D6ZMKc2L.js +0 -19
- package/dist/context-wDKxSl9x.js +0 -9
- package/dist/controller-BZhiIb-N.d.ts +0 -46
- package/dist/controller-D6NyNrlZ.js +0 -79
- package/dist/cron-BHdXZFsJ.js +0 -145
- package/dist/cron-route-mTvWhork.js +0 -24
- package/dist/csv-CVfXqaAu.js +0 -89
- package/dist/csv-D3eKxV1T.d.ts +0 -28
- package/dist/db-exception-CnWcYPxL.js +0 -15
- package/dist/define-Bu1v781m.js +0 -1962
- package/dist/define-DYZnvAbs.d.ts +0 -1058
- package/dist/define-block-B6Gjs57G.js +0 -52
- package/dist/define-block-BHxLHLys.d.ts +0 -256
- package/dist/delegation-B7uNnz6z.js +0 -140
- package/dist/delivery-B1mKaOen.js +0 -30
- package/dist/delivery-BeHgwS3k.d.ts +0 -69
- package/dist/documents-CqtVr2fg.d.ts +0 -96
- package/dist/email-BcmbIWOX.d.ts +0 -42
- package/dist/embeddings-CKhygw4C.d.ts +0 -78
- package/dist/embeddings-CVeOoufZ.js +0 -128
- package/dist/ended-De6H52nX.d.ts +0 -70
- package/dist/entitlements-C8UvF1Rz.js +0 -45
- package/dist/entitlements-CtBGXb3B.d.ts +0 -53
- package/dist/envelope-C4Z55LKW.js +0 -90
- package/dist/errors-BV1SKTVs.js +0 -315
- package/dist/errors-D3BR8iUk.js +0 -44
- package/dist/escape-like-B339PlP-.d.ts +0 -15
- package/dist/eve-B6ru2Bt4.d.ts +0 -151
- package/dist/event-calendar-DJXXMJ3x.d.ts +0 -217
- package/dist/event-map-Dy2vKHai.js +0 -19
- package/dist/events-P3raDX2E.d.ts +0 -800
- package/dist/events-xbpHkcK9.js +0 -82
- package/dist/executor-BWgJNbGh.d.ts +0 -95
- package/dist/executor-BiB0wMBA.js +0 -735
- package/dist/executor-BnMC0lj3.d.ts +0 -272
- package/dist/executor-CvsNcQsa.d.ts +0 -174
- package/dist/executor-CxGQiQN_.js +0 -206
- package/dist/executor-D1hECPGG.d.ts +0 -39
- package/dist/executor-D3K3tycZ.js +0 -147
- package/dist/field-errors-DZVRWRkf.js +0 -13
- package/dist/field-errors-Z-sgsdoN.d.ts +0 -113
- package/dist/field-formats-Cif5gr7c.js +0 -102
- package/dist/field-formats-DCvOQlOy.d.ts +0 -39
- package/dist/filter-evaluate-BJcaL3o1.d.ts +0 -34
- package/dist/filter-evaluate-C0ULNfS7.js +0 -214
- package/dist/filter-query-B3lhckKX.js +0 -518
- package/dist/filter-query-Bc_Qa8V_.d.ts +0 -121
- package/dist/flags-6KK6Vqkr.d.ts +0 -230
- package/dist/flags-aUR7Rod6.js +0 -279
- package/dist/form-definition-GVZTILhS.js +0 -311
- package/dist/form-definition-sagoefQr.d.ts +0 -95
- package/dist/format-CNwSjXUU.d.ts +0 -70
- package/dist/framework-BQhTsLX-.d.ts +0 -26
- package/dist/framework-C6PKBgme.js +0 -51
- package/dist/function-contract-DWqFl_QO.d.ts +0 -21
- package/dist/function-contract-DmkBg19r.js +0 -5
- package/dist/gateway-Bq_tWwxE.d.ts +0 -109
- package/dist/gateway-options-ClvvfuuU.d.ts +0 -29
- package/dist/gateway-options-DcLcWL5_.js +0 -27
- package/dist/graph-Cs28bOlK.js +0 -360
- package/dist/hmac-BgpThYQW.js +0 -23
- package/dist/http-C7trc6uN.js +0 -25
- package/dist/http-Cv4T29xh.js +0 -40
- package/dist/http-DdYadv-o.js +0 -126
- package/dist/image-url-pIVlO6R1.js +0 -41
- package/dist/impersonation-D5chOkrO.d.ts +0 -25
- package/dist/impersonation-DxU6yHJV.js +0 -62
- package/dist/inbox-Du5aPwKB.d.ts +0 -400
- package/dist/index-1Vsg-7YV.d.ts +0 -58
- package/dist/index-BJLPQr2s.d.ts +0 -377
- package/dist/index-BpFYMsi0.d.ts +0 -53
- package/dist/index-BpyBH5O2.d.ts +0 -227
- package/dist/index-C-_fs7EI.d.ts +0 -258
- package/dist/index-CXFf-c-j.d.ts +0 -131
- package/dist/index-Cm2-g_4H.d.ts +0 -722
- package/dist/index-CxmVzT-3.d.ts +0 -86
- package/dist/index-DTQSeHx2.d.ts +0 -97
- package/dist/index-Hc4tetmB.d.ts +0 -245
- package/dist/index-QWTq2o31.d.ts +0 -138
- package/dist/index-XcTBR4Gb.d.ts +0 -206
- package/dist/index-k-rrfG1g.d.ts +0 -202
- package/dist/index-wTnPJUhv.d.ts +0 -58
- package/dist/invalidate-BBqhpxyB.d.ts +0 -19
- package/dist/iso4217-A8ev-CNW.js +0 -176
- package/dist/json-CEnpTHlZ.js +0 -16
- package/dist/json-schema-CpYINXG8.js +0 -548
- package/dist/jwks-cache-C4rA69hD.js +0 -49
- package/dist/jws-35a8VhFV.d.ts +0 -60
- package/dist/jws-CwBB5QAT.js +0 -193
- package/dist/kit-De-EVRhw.d.ts +0 -66
- package/dist/kit-LTbHrWWD.js +0 -104
- package/dist/knowledge-B5zdpDD-.d.ts +0 -187
- package/dist/knowledge-BbdXOJvY.js +0 -272
- package/dist/list-query-CBXNfJt4.js +0 -549
- package/dist/list-query-aXr2WkGA.d.ts +0 -194
- package/dist/live-DwDreq1n.js +0 -239
- package/dist/management-D1gG89z2.d.ts +0 -53
- package/dist/message-B0fNJgq8.d.ts +0 -93
- package/dist/messages-D5nIfCCf.js +0 -493
- package/dist/metric-definition-95HFoW1V.d.ts +0 -70
- package/dist/mfa-YzkRjNad.d.ts +0 -30
- package/dist/model-lUafmeBQ.d.ts +0 -311
- package/dist/model-messages-CIdqdUtk.js +0 -206
- package/dist/model-messages-D4GZllOD.d.ts +0 -34
- package/dist/money-95Rff2vT.js +0 -185
- package/dist/money-DFpWzQvk.d.ts +0 -76
- package/dist/money-codec-C21MWw50.js +0 -41
- package/dist/node-headers-AO06VhqH.d.ts +0 -24
- package/dist/onboarding-Du6kCmhF.js +0 -68
- package/dist/operations-CsIfMED7.js +0 -29
- package/dist/operations-DQCWqkt3.d.ts +0 -6
- package/dist/optional-peer-Dx8TaYXw.js +0 -29
- package/dist/options-BAW2ZlZ8.js +0 -8
- package/dist/options-C1HR4UZd.js +0 -13
- package/dist/options-Dh4wu9Ks.js +0 -15
- package/dist/options-QKP9FFcK.js +0 -8
- package/dist/options-XgfTctbI.js +0 -5
- package/dist/options-ZQzNKKBS.d.ts +0 -52
- package/dist/options-vXMBEWSH.js +0 -5
- package/dist/organizations-CO2qg44D.js +0 -398
- package/dist/outbox-B1hZ7PPY.d.ts +0 -181
- package/dist/payments-CzjCdIcz.js +0 -16
- package/dist/pg-error-BV_X8Isq.js +0 -26
- package/dist/plugin-D-95Q0w0.d.ts +0 -190
- package/dist/plugin-tfXW1-qO.js +0 -45
- package/dist/pool-cM3rpOQr.d.ts +0 -117
- package/dist/pool-errors-CGqvTQOC.js +0 -27
- package/dist/ports-BCDIbC_U.d.ts +0 -86
- package/dist/ports-P0A5wo_-.d.ts +0 -285
- package/dist/ports-aALjot-D.js +0 -137
- package/dist/postgrest-CjnO1hbr.d.ts +0 -53
- package/dist/preset-Cf0T9GRt.js +0 -691
- package/dist/problem-DCDIQiTA.d.ts +0 -76
- package/dist/problem-JRCohp1j.js +0 -159
- package/dist/provider-C-Ti38J6.js +0 -57
- package/dist/provider-DXgx5oSA.d.ts +0 -113
- package/dist/push-token-y1Gnz5bQ.d.ts +0 -24
- package/dist/query-Ctz-qKRx.js +0 -303
- package/dist/rank-result-BcYfDA0x.d.ts +0 -14
- package/dist/rank-result-DtQuIvob.js +0 -18
- package/dist/rate-limit-DVZ7qIzW.js +0 -49
- package/dist/rate-limit-I3AncmM8.js +0 -325
- package/dist/rate-limit-c6c1mB6R.d.ts +0 -41
- package/dist/ratelimit-headers-Bsxx0Tj2.js +0 -62
- package/dist/react-4ZqkP8da.js +0 -79
- package/dist/react-DzukE6Wp.js +0 -410
- package/dist/react-controller-Xn-IU44p.js +0 -40
- package/dist/react-env-Cc7Vf6eb.js +0 -13
- package/dist/read-set-DeesfeL_.js +0 -314
- package/dist/realtime-status-D2dw1hOE.js +0 -12
- package/dist/realtime-status-DcsO00Gw.d.ts +0 -8
- package/dist/refusal-C7geIBRl.d.ts +0 -18
- package/dist/refusal-CFpfmjcS.js +0 -61
- package/dist/resolve-AtncaPTU.js +0 -877
- package/dist/resolve-Ceft-18-.d.ts +0 -270
- package/dist/resource-Bdkqi8jo.js +0 -463
- package/dist/resource-DO4gbVi5.js +0 -91
- package/dist/resource-DYEtc-KN.d.ts +0 -106
- package/dist/resource-execute-Bxvgmx-n.d.ts +0 -12
- package/dist/resource-schemas-BJ518zFH.js +0 -79
- package/dist/resource-types-LW1i5-h3.d.ts +0 -141
- package/dist/resources-Ck7itNeX.js +0 -64
- package/dist/resources-D3_FAz_H.d.ts +0 -7
- package/dist/respond-BSL36dQp.d.ts +0 -93
- package/dist/respond-Bhp3G__q.js +0 -95
- package/dist/result-BREt7qOh.d.ts +0 -312
- package/dist/result-DIeYscA3.js +0 -134
- package/dist/rrule-Cw4x4Pf_.js +0 -290
- package/dist/rules-BiQgmZ_U.js +0 -287
- package/dist/run-watch-CQRdpy-f.js +0 -53
- package/dist/runtime-BOXURhEW.js +0 -45
- package/dist/sales-lines-C6gafAwg.d.ts +0 -28
- package/dist/sales-lines-CQ1iC6QM.js +0 -41
- package/dist/sales-shared-CDSytDEn.js +0 -22
- package/dist/search-BtoWY6n_.js +0 -9
- package/dist/search-ZP13UTT4.js +0 -106
- package/dist/server-types-fLdep4gb.d.ts +0 -757
- package/dist/session-DObioXpX.d.ts +0 -95
- package/dist/settings-BiHDFglz.js +0 -90
- package/dist/shared-BmMcMoW9.js +0 -89
- package/dist/shared-C9zvURqC.js +0 -14
- package/dist/shared-D5Djh43x.js +0 -60
- package/dist/shared-DDSjEGDR.d.ts +0 -11
- package/dist/sign-in-BCV5S2WZ.d.ts +0 -49
- package/dist/sign-in-z2BaBdps.js +0 -367
- package/dist/signatures-BXlDXV3D.d.ts +0 -43
- package/dist/signatures-CeIoAelK.js +0 -145
- package/dist/signers-BwKV-9S6.d.ts +0 -385
- package/dist/signing-keys-v2MRYkDF.d.ts +0 -105
- package/dist/solid-controller-CWotGxcG.d.ts +0 -11
- package/dist/solid-controller-DLsmrczT.js +0 -33
- package/dist/spec-pins-Dqpml2dZ.d.ts +0 -84
- package/dist/spec-pins-S4PymRxp.js +0 -60
- package/dist/sql-BPKRNutj.js +0 -422
- package/dist/sql-CT1Jnwp8.js +0 -88660
- package/dist/sso-BaU_6ePE.js +0 -217
- package/dist/sso-Bu0mVh0V.d.ts +0 -131
- package/dist/standard-B1BigegP.js +0 -25
- package/dist/standard-BcUQuUgu.d.ts +0 -7
- package/dist/stats-Di5VAsYU.js +0 -1128
- package/dist/store-B18bIvKc.d.ts +0 -68
- package/dist/store-BdH5ruDx.js +0 -66
- package/dist/stripe-NVcNOhHy.d.ts +0 -140
- package/dist/stripe-XZrSmDTf.js +0 -32
- package/dist/subject-readers-BUChuOxL.d.ts +0 -21
- package/dist/subject-readers-BpwUFJtp.js +0 -46
- package/dist/subjects-DP-fvFkk.d.ts +0 -77
- package/dist/subscribers-Cq--DL1E.js +0 -34
- package/dist/supabase-mcp-C6tMoEjn.d.ts +0 -43
- package/dist/supabase-mcp-DomZ-amK.js +0 -28
- package/dist/support-C2wPYwD7.js +0 -522
- package/dist/support-view-Bj_lZ8Wr.d.ts +0 -17
- package/dist/svelte-controller-CDAujo-_.js +0 -50
- package/dist/svelte-controller-sS4X66yL.d.ts +0 -10
- package/dist/table-schema-pQlER3jj.js +0 -283
- package/dist/tags-B99_U9Pp.js +0 -39
- package/dist/tags-BqgaxCnv.js +0 -84
- package/dist/tags-BrGopDVG.d.ts +0 -30
- package/dist/tax-DMWDUzKt.d.ts +0 -273
- package/dist/tax-wm9g2mD2.js +0 -140
- package/dist/tee-Cw-iJAWL.js +0 -101
- package/dist/template-Dw3dTmKe.js +0 -123
- package/dist/temporal-CB5Fpo5d.js +0 -79
- package/dist/temporal-required-nfZ87U-0.js +0 -20
- package/dist/tenant-B-fiItlJ.js +0 -27
- package/dist/tenant-DZMLVuyQ.d.ts +0 -17
- package/dist/tenant-naming-Bsj3Uvap.js +0 -27
- package/dist/timing-BMCWgpdZ.js +0 -92
- package/dist/topic-DAY_HOX2.d.ts +0 -387
- package/dist/topic-mee21pux.js +0 -629
- package/dist/ttl-Hr34gRu8.js +0 -12
- package/dist/ttl-cache-XzZ-Q2eX.js +0 -29
- package/dist/types-BA1eTvy4.d.ts +0 -162
- package/dist/types-BEEFkNFY.d.ts +0 -564
- package/dist/types-BRTSpOIh.js +0 -5
- package/dist/types-Bels39_u.d.ts +0 -649
- package/dist/types-BrpW5ixT.d.ts +0 -370
- package/dist/types-DOC7wnh6.d.ts +0 -249
- package/dist/types-D_2rClz-.d.ts +0 -205
- package/dist/undo-B5LgpGLy.js +0 -44
- package/dist/undo-BsdYRox7.d.ts +0 -43
- package/dist/upload-claim-BBFCZbBF.js +0 -33
- package/dist/usage-C504GF55.d.ts +0 -220
- package/dist/usage-DdqT13_X.js +0 -261
- package/dist/user-change-XzvgafU4.js +0 -130
- package/dist/vault-ClkzMGTP.d.ts +0 -50
- package/dist/verify-DU4p9-Ve.d.ts +0 -142
- package/dist/verify-DnU-uWU2.js +0 -126
- package/dist/version-DSWxci83.js +0 -4
- package/dist/view-CYX1wsgp.js +0 -105
- package/dist/view-KQhe6eNc.d.ts +0 -90
- package/dist/vue-controller-BUo1oove.d.ts +0 -11
- package/dist/vue-controller-C9tFzqAc.js +0 -32
- package/dist/watch-5btote1y.d.ts +0 -84
- package/dist/watch-BAuIzC2r.js +0 -139
- package/dist/watch-topic-C79ZW5-R.d.ts +0 -28
- package/dist/watch-topic-miuymrli.js +0 -57
- package/dist/wire-BCJxCtHS.js +0 -45
- package/dist/workflow-builder-CynLqc6H.js +0 -697
- package/dist/workflow-sdk-CWdCWj7M.d.ts +0 -161
- package/dist/workflow-sdk-QnnzIQRc.js +0 -243
- package/dist/workflow-sdk-world-QzcxaaCD.js +0 -2103
- package/dist/workflows-DQBCzrHC.d.ts +0 -243
- package/dist/workflows-H9qJge3f.js +0 -282
|
@@ -0,0 +1,2378 @@
|
|
|
1
|
+
import { n as CliError, r as errorText } from "./errors-BTe6A15O.js";
|
|
2
|
+
import { a as sameText, n as importPath, t as display } from "./io-DH1kcmmP.js";
|
|
3
|
+
import { i as writeAtomic, n as cachedDatabaseTypes, t as CACHE_DIR } from "./cache-C3K_wOE2.js";
|
|
4
|
+
import { t as byCodePoint } from "./compare-BmIWVEui.js";
|
|
5
|
+
import { d as typegenVersion, f as typegenVersionNotice, i as oxfmtInstalled, l as stabilizeMetadata, r as generateDatabaseTypes } from "./typegen-F9GEjpvD.js";
|
|
6
|
+
import { t as detectProject } from "./detect-RApSAA8v.js";
|
|
7
|
+
import { a as buildModel, d as applyCasing, i as metaPaths, l as prop, n as emitMeta, o as generatorModel, r as emitModule, t as GENERATED_HEADER, u as q } from "./emit-DbQeLlHt.js";
|
|
8
|
+
import { C as accessRequirements, D as providerLabel, E as moduleKeyProblems, O as unsafeKey, S as accessProviderMode, T as entitlementsMode, c as writeLatestMigration, l as writesMigrations, n as READ_SETS_SUFFIX, r as latestMigration, s as sameModuleMigration, v as migrationsDir, w as entitlementRequirements, x as compiledReadSets } from "./module-migration-CbX-jRhV.js";
|
|
9
|
+
import { t as loadSnapshot } from "./snapshot-Dkwxc1uV.js";
|
|
10
|
+
import { a as hasConflicts, c as fileDiff, i as changedFiles, n as applyPlan, r as changeLines } from "./files-C5JfVnj5.js";
|
|
11
|
+
import { l as tableObject, n as exposed, o as policyObject, s as qualified, t as catalogOf } from "./shared-CCpxS5if.js";
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { basename, dirname, isAbsolute, posix, relative, resolve, sep } from "node:path";
|
|
14
|
+
import { readFile } from "node:fs/promises";
|
|
15
|
+
import { entityNames } from "better-supabase/blocks";
|
|
16
|
+
import { blockEntities, blockEntityRenames, blockSubjectTypes, tenantNameOf } from "better-supabase/config";
|
|
17
|
+
import { PRESET_CATALOG } from "better-supabase/preset";
|
|
18
|
+
import { BLOCK_OPTION_SCHEMAS, DEFAULT_ROLES, SQL_MODULES, appTableEventTypes, moduleHidingColumns, moduleLayout, modulePermissionKeys, renderModules, resolveModule, resolveModules, sameModuleFile } from "better-supabase/sql";
|
|
19
|
+
//#region src/cli/gen/block-names.ts
|
|
20
|
+
const PLACEHOLDER = /\{(\.\.\.)?([A-Za-z_][\w]*)\}/g;
|
|
21
|
+
function isRecord(value) {
|
|
22
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23
|
+
}
|
|
24
|
+
function camel$1(name) {
|
|
25
|
+
return name.replaceAll(/[-_]([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
26
|
+
}
|
|
27
|
+
function pascal$2(name) {
|
|
28
|
+
const camelled = camel$1(name);
|
|
29
|
+
return camelled.charAt(0).toUpperCase() + camelled.slice(1);
|
|
30
|
+
}
|
|
31
|
+
function union(values) {
|
|
32
|
+
return [...new Set(values)].toSorted().map((value) => q(value)).join(" | ");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* A template with `{placeholders}` as an arrow function over their values: `(v:
|
|
36
|
+
* { readonly userId: string }) => \`notifications:${v.userId}\``. `rename` maps
|
|
37
|
+
* a placeholder to the property the caller passes.
|
|
38
|
+
*/
|
|
39
|
+
function templateFunction(template, rename = (name) => name, value = "string") {
|
|
40
|
+
const names = [];
|
|
41
|
+
let body = "";
|
|
42
|
+
let last = 0;
|
|
43
|
+
for (const match of template.matchAll(PLACEHOLDER)) {
|
|
44
|
+
const name = rename(match[2] ?? "");
|
|
45
|
+
if (!names.includes(name)) names.push(name);
|
|
46
|
+
body += `${literalPart(template.slice(last, match.index))}\${String(v.${name})}`;
|
|
47
|
+
last = match.index + match[0].length;
|
|
48
|
+
}
|
|
49
|
+
body += literalPart(template.slice(last));
|
|
50
|
+
if (names.length === 0) return `() => ${q(template)}`;
|
|
51
|
+
return `(v: { ${names.map((name) => `readonly ${name}: ${value}`).join("; ")} }) => \`${body}\``;
|
|
52
|
+
}
|
|
53
|
+
function literalPart(text) {
|
|
54
|
+
return text.replaceAll(/[`\\]|\$\{/g, (match) => `\\${match}`);
|
|
55
|
+
}
|
|
56
|
+
/** Permission keys by owner (block, subject or app table), then action. */
|
|
57
|
+
function permissionGroups(config) {
|
|
58
|
+
const groups = {};
|
|
59
|
+
for (const entry of modulePermissionKeys(config.blocks, config.blockNames)) groups[entry.module] = {
|
|
60
|
+
...groups[entry.module],
|
|
61
|
+
[entry.action]: entry.key
|
|
62
|
+
};
|
|
63
|
+
for (const [name, subject] of Object.entries(config.subjects)) if (subject.permissions) groups[name] = {
|
|
64
|
+
...groups[name],
|
|
65
|
+
...subject.permissions
|
|
66
|
+
};
|
|
67
|
+
for (const table of Object.values(config.appTables)) {
|
|
68
|
+
const subject = table.subject;
|
|
69
|
+
if (subject?.permissions) groups[subject.type] = {
|
|
70
|
+
...groups[subject.type],
|
|
71
|
+
...subject.permissions
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return groups;
|
|
75
|
+
}
|
|
76
|
+
/** Whether `blocks.generated.ts` exports `permissions`. */
|
|
77
|
+
function hasPermissionConstants(config) {
|
|
78
|
+
return Object.values(permissionGroups(config)).some((group) => Object.keys(group).length > 0);
|
|
79
|
+
}
|
|
80
|
+
function permissionLines(config) {
|
|
81
|
+
const groups = permissionGroups(config);
|
|
82
|
+
const keys = Object.values(groups).flatMap((group) => Object.values(group));
|
|
83
|
+
if (keys.length === 0) return [];
|
|
84
|
+
return [
|
|
85
|
+
"",
|
|
86
|
+
"/**",
|
|
87
|
+
" * The permission keys the installed blocks, subjects and app tables check,",
|
|
88
|
+
" * by owner and action.",
|
|
89
|
+
" * @public",
|
|
90
|
+
" */",
|
|
91
|
+
"export const permissions = {",
|
|
92
|
+
...Object.entries(groups).toSorted(([a], [b]) => a.localeCompare(b)).flatMap(([owner, actions]) => [
|
|
93
|
+
` ${prop(owner)}: {`,
|
|
94
|
+
...Object.entries(actions).map(([action, key]) => ` ${prop(action)}: ${q(key)},`),
|
|
95
|
+
" },"
|
|
96
|
+
]),
|
|
97
|
+
"} as const;",
|
|
98
|
+
"",
|
|
99
|
+
"/**",
|
|
100
|
+
" * Every permission key, for `defineAuthorizer<PermissionKey>()` and",
|
|
101
|
+
" * the `permission` of actions and routes.",
|
|
102
|
+
" * @public",
|
|
103
|
+
" */",
|
|
104
|
+
`export type PermissionKey = ${union(keys)};`
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
function roleLines(config, entries) {
|
|
108
|
+
if (entries["access"] === void 0) return [];
|
|
109
|
+
const access = config.blocks.access;
|
|
110
|
+
const settings = typeof access === "object" ? access : void 0;
|
|
111
|
+
if ((settings?.model ?? "roles") !== "roles") return [];
|
|
112
|
+
const roles = settings?.roles ?? DEFAULT_ROLES;
|
|
113
|
+
return [
|
|
114
|
+
"",
|
|
115
|
+
"/** The roles `blocks.access.roles` defines. @public */",
|
|
116
|
+
`export type RoleName = ${union(Object.keys(roles))};`
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
function blockEventLists(entries) {
|
|
120
|
+
return PRESET_CATALOG.manifests.flatMap((manifest) => {
|
|
121
|
+
const entry = entries[manifest.name];
|
|
122
|
+
const events = manifest.events;
|
|
123
|
+
if (entry === void 0 || events === void 0 || !manifest.client) return [];
|
|
124
|
+
const names = entityNames(entry.names?.entities ?? []);
|
|
125
|
+
const renamed = names.rename(events.type);
|
|
126
|
+
return [{
|
|
127
|
+
specifier: renamed === events.type ? `import type { ${events.type} } from ${q(manifest.client.subpath)};` : "",
|
|
128
|
+
type: renamed,
|
|
129
|
+
types: events.types.map((type) => names.rename(type))
|
|
130
|
+
}];
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function eventLines(entries) {
|
|
134
|
+
const lists = blockEventLists(entries);
|
|
135
|
+
if (lists.length === 0) return {
|
|
136
|
+
specifiers: [],
|
|
137
|
+
imports: [],
|
|
138
|
+
lines: []
|
|
139
|
+
};
|
|
140
|
+
const types = [...new Set(lists.flatMap((list) => list.types))].toSorted();
|
|
141
|
+
return {
|
|
142
|
+
specifiers: ["type Events"],
|
|
143
|
+
imports: lists.flatMap((list) => list.specifier === "" ? [] : [list.specifier]),
|
|
144
|
+
lines: [
|
|
145
|
+
"",
|
|
146
|
+
"/** Every installed block's events: type to data. @public */",
|
|
147
|
+
`export type BlockEvents = ${lists.map((list) => list.type).join(" & ")};`,
|
|
148
|
+
"",
|
|
149
|
+
"/**",
|
|
150
|
+
" * The installed blocks' event types under the configured names, for",
|
|
151
|
+
" * `onBlockEvent` and the sinks.",
|
|
152
|
+
" * @public",
|
|
153
|
+
" */",
|
|
154
|
+
"export const blockEvents: Events<BlockEvents> = {",
|
|
155
|
+
" types: [",
|
|
156
|
+
...types.map((type) => ` ${q(type)},`),
|
|
157
|
+
" ],",
|
|
158
|
+
"};",
|
|
159
|
+
"",
|
|
160
|
+
"/**",
|
|
161
|
+
" * The block events with an open payload, for AsyncAPI's `cloudEvents.blocks`.",
|
|
162
|
+
" * @public",
|
|
163
|
+
" */",
|
|
164
|
+
"export const blockEventSchemas = {",
|
|
165
|
+
...types.map((type) => ` ${q(type)}: true,`),
|
|
166
|
+
"} as const;"
|
|
167
|
+
]
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function urlLines(config, entries) {
|
|
171
|
+
const templates = /* @__PURE__ */ new Map();
|
|
172
|
+
for (const name of Object.keys(entries)) for (const entity of blockEntities(name, config.blocks)) if (entity.url !== void 0) templates.set(camel$1(entity.to.singular), entity.url);
|
|
173
|
+
for (const [type, subject] of Object.entries(config.subjects)) {
|
|
174
|
+
const key = camel$1(type);
|
|
175
|
+
if (subject.url !== void 0 && !templates.has(key)) templates.set(key, subject.url);
|
|
176
|
+
}
|
|
177
|
+
const urls = [...templates].map(([key, template]) => ` ${prop(key)}: ${templateFunction(template, (column) => applyCasing(column, config.casing), "string | number")},`);
|
|
178
|
+
return urls.length === 0 ? [] : [
|
|
179
|
+
"",
|
|
180
|
+
"/**",
|
|
181
|
+
" * The path of each subject type with a `url`: block entities, `subjects`",
|
|
182
|
+
" * and app table subjects.",
|
|
183
|
+
" * @public",
|
|
184
|
+
" */",
|
|
185
|
+
"export const urls = {",
|
|
186
|
+
...urls,
|
|
187
|
+
"} as const;"
|
|
188
|
+
];
|
|
189
|
+
}
|
|
190
|
+
function topicLines(entries) {
|
|
191
|
+
const topics = Object.entries(entries).flatMap(([name, entry]) => Object.entries(entry.options).flatMap(([option, value]) => {
|
|
192
|
+
if (!/^(?:topic|[a-z]+Topic)$/.test(option) || typeof value !== "string") return [];
|
|
193
|
+
const key = option === "topic" ? camel$1(name) : `${camel$1(name)}${pascal$2(option.replace(/Topic$/, ""))}`;
|
|
194
|
+
return [` ${prop(key)}: ${templateFunction(value)},`];
|
|
195
|
+
}));
|
|
196
|
+
return topics.length === 0 ? [] : [
|
|
197
|
+
"",
|
|
198
|
+
"/** The realtime topics the blocks broadcast on, with their placeholders filled. @public */",
|
|
199
|
+
"export const topics = {",
|
|
200
|
+
...topics,
|
|
201
|
+
"} as const;"
|
|
202
|
+
];
|
|
203
|
+
}
|
|
204
|
+
function pathLines(config) {
|
|
205
|
+
const paths = Object.entries(config.buckets).map(([name, bucket]) => {
|
|
206
|
+
const key = prop(camel$1(name));
|
|
207
|
+
return typeof bucket.path === "string" ? ` ${key}: ${templateFunction(bucket.path)},` : ` ${key}: [${bucket.path.map((path) => templateFunction(path)).join(", ")}],`;
|
|
208
|
+
});
|
|
209
|
+
return paths.length === 0 ? [] : [
|
|
210
|
+
"",
|
|
211
|
+
"/** Object paths in each bucket, from `buckets.<name>.path`. @public */",
|
|
212
|
+
"export const paths = {",
|
|
213
|
+
...paths,
|
|
214
|
+
"} as const;"
|
|
215
|
+
];
|
|
216
|
+
}
|
|
217
|
+
function optionOf(config, module, option) {
|
|
218
|
+
return config.blockNames.includes(module) || config.blocks[module] !== void 0 ? resolveModule(config.blocks[module]).options[option] : void 0;
|
|
219
|
+
}
|
|
220
|
+
function settingKeys(config) {
|
|
221
|
+
const option = optionOf(config, "settings", "schemas");
|
|
222
|
+
const schemas = isRecord(option) && isRecord(option["schemas"]) ? option["schemas"] : option;
|
|
223
|
+
if (!isRecord(schemas)) return [];
|
|
224
|
+
return [
|
|
225
|
+
"user",
|
|
226
|
+
"organization",
|
|
227
|
+
"platform"
|
|
228
|
+
].flatMap((scope) => {
|
|
229
|
+
const keys = schemas[scope];
|
|
230
|
+
return isRecord(keys) ? Object.keys(keys) : [];
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
function meterNames(config) {
|
|
234
|
+
const option = optionOf(config, "usage", "meters");
|
|
235
|
+
return isRecord(option) && typeof option["table"] !== "string" ? Object.keys(option) : [];
|
|
236
|
+
}
|
|
237
|
+
function keyUnionLines(config) {
|
|
238
|
+
return [[
|
|
239
|
+
"SettingKey",
|
|
240
|
+
"`blocks.settings.options.schemas`",
|
|
241
|
+
settingKeys(config)
|
|
242
|
+
], [
|
|
243
|
+
"MeterName",
|
|
244
|
+
"`blocks.usage.options.meters`",
|
|
245
|
+
meterNames(config)
|
|
246
|
+
]].flatMap(([name, source, keys]) => keys.length === 0 ? [] : [
|
|
247
|
+
"",
|
|
248
|
+
`/** The keys ${source} names. @public */`,
|
|
249
|
+
`export type ${name} = ${union(keys)};`
|
|
250
|
+
]);
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The constants app code references by name, from the config: permission keys,
|
|
254
|
+
* role names, block events, entity URLs, realtime topics, bucket paths, and the
|
|
255
|
+
* settings and meter keys.
|
|
256
|
+
*/
|
|
257
|
+
function nameConstantLines(config, entries) {
|
|
258
|
+
const events = eventLines(entries);
|
|
259
|
+
return {
|
|
260
|
+
specifiers: events.specifiers,
|
|
261
|
+
imports: events.imports,
|
|
262
|
+
lines: [
|
|
263
|
+
...permissionLines(config),
|
|
264
|
+
...roleLines(config, entries),
|
|
265
|
+
...events.lines,
|
|
266
|
+
...urlLines(config, entries),
|
|
267
|
+
...topicLines(entries),
|
|
268
|
+
...pathLines(config),
|
|
269
|
+
...keyUnionLines(config)
|
|
270
|
+
]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
//#endregion
|
|
274
|
+
//#region src/cli/gen/blocks.ts
|
|
275
|
+
/** `blocks.generated.ts`, next to the main generated module. */
|
|
276
|
+
function blockConfigPath(config) {
|
|
277
|
+
return posix.join(posix.dirname(config.output), "blocks.generated.ts");
|
|
278
|
+
}
|
|
279
|
+
function hasSchema(module) {
|
|
280
|
+
return module in BLOCK_OPTION_SCHEMAS;
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* How the tenant rename, the modules' renamed entities and their
|
|
284
|
+
* `blocks.<module>.functions` rename the block's functions and payload keys, or
|
|
285
|
+
* undefined when nothing does. `blocks.access.functions` is the custom model's
|
|
286
|
+
* templates, not renames.
|
|
287
|
+
*/
|
|
288
|
+
function namingOf(config, modules) {
|
|
289
|
+
const functions = Object.fromEntries(modules.flatMap((module) => module === "access" ? [] : Object.entries(resolveModule(config.blocks[module]).functions)));
|
|
290
|
+
const entities = modules.flatMap((module) => blockEntityRenames(module, config.blocks));
|
|
291
|
+
const tenant = tenantNameOf(config.blocks);
|
|
292
|
+
const renames = Object.keys(functions).length > 0;
|
|
293
|
+
if (tenant === void 0 && !renames && entities.length === 0) return;
|
|
294
|
+
return {
|
|
295
|
+
...tenant === void 0 ? {} : { tenant },
|
|
296
|
+
...renames ? { functions } : {},
|
|
297
|
+
...entities.length === 0 ? {} : { entities }
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The generated config of every installed block: its schema, its API schema,
|
|
302
|
+
* and the options marked `client` with the configured value or the module's
|
|
303
|
+
* default. Blocks without a creator get an entry too, since `block.using(...)`
|
|
304
|
+
* builds them with these options.
|
|
305
|
+
*/
|
|
306
|
+
function blockConfigEntries(config) {
|
|
307
|
+
const installed = new Set(resolveModules(config.blockNames, {
|
|
308
|
+
modules: config.blocks,
|
|
309
|
+
...config.sql.scope === void 0 ? {} : { scope: config.sql.scope }
|
|
310
|
+
}).map((module) => module.name));
|
|
311
|
+
const entries = [];
|
|
312
|
+
for (const manifest of PRESET_CATALOG.manifests) {
|
|
313
|
+
const modules = manifest.sql.filter((module) => installed.has(module));
|
|
314
|
+
const [main] = modules;
|
|
315
|
+
if (main === void 0) continue;
|
|
316
|
+
const resolved = resolveModule(config.blocks[main]);
|
|
317
|
+
const options = {};
|
|
318
|
+
for (const module of modules) {
|
|
319
|
+
if (!hasSchema(module)) continue;
|
|
320
|
+
const configured = resolveModule(config.blocks[module]).options;
|
|
321
|
+
for (const [key, spec] of Object.entries(BLOCK_OPTION_SCHEMAS[module].specs)) {
|
|
322
|
+
if (!spec.client) continue;
|
|
323
|
+
const value = configured[key] ?? spec.default;
|
|
324
|
+
if (value !== void 0) options[key] = value;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
const names = namingOf(config, modules);
|
|
328
|
+
entries.push([manifest.name, {
|
|
329
|
+
schema: resolved.schema,
|
|
330
|
+
...resolved.api === void 0 ? {} : { api: resolved.api.schema },
|
|
331
|
+
options,
|
|
332
|
+
...names === void 0 ? {} : { names }
|
|
333
|
+
}]);
|
|
334
|
+
}
|
|
335
|
+
return Object.fromEntries(entries);
|
|
336
|
+
}
|
|
337
|
+
function literal(value, indent) {
|
|
338
|
+
if (Array.isArray(value)) return `[${value.map((entry) => literal(entry, indent)).join(", ")}]`;
|
|
339
|
+
if (typeof value === "object" && value !== null) {
|
|
340
|
+
const entries = Object.entries(value);
|
|
341
|
+
if (entries.length === 0) return "{}";
|
|
342
|
+
const inner = `${indent} `;
|
|
343
|
+
return `{\n${entries.map(([key, entry]) => `${inner}${prop(key)}: ${literal(entry, inner)},`).join("\n")}\n${indent}}`;
|
|
344
|
+
}
|
|
345
|
+
return JSON.stringify(value);
|
|
346
|
+
}
|
|
347
|
+
/** Every event type the app tables emit, in config order. */
|
|
348
|
+
function appTableEvents(config) {
|
|
349
|
+
return Object.entries(config.appTables).flatMap(([name, table]) => appTableEventTypes(name, table));
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* `appTableEvents` and `appTableEventSchemas`, for app tables that set
|
|
353
|
+
* `events`.
|
|
354
|
+
*/
|
|
355
|
+
function appTableEventLines(types) {
|
|
356
|
+
if (types.length === 0) return [];
|
|
357
|
+
return [
|
|
358
|
+
"",
|
|
359
|
+
"/**",
|
|
360
|
+
" * The events `appTables.<table>.events` writes to the outbox, for `onBlockEvent` and the sinks.",
|
|
361
|
+
" * @public",
|
|
362
|
+
" */",
|
|
363
|
+
"export const appTableEvents = defineEvents({",
|
|
364
|
+
...types.map((type) => ` ${prop(type)}: event<AppTableEventData>(),`),
|
|
365
|
+
"});",
|
|
366
|
+
"",
|
|
367
|
+
"/**",
|
|
368
|
+
" * The app table events with an open payload, for AsyncAPI's `cloudEvents.blocks`.",
|
|
369
|
+
" * @public",
|
|
370
|
+
" */",
|
|
371
|
+
"export const appTableEventSchemas = {",
|
|
372
|
+
...types.map((type) => ` ${prop(type)}: true,`),
|
|
373
|
+
"} as const;"
|
|
374
|
+
];
|
|
375
|
+
}
|
|
376
|
+
const CATALOG_BLOCKS = new Map(PRESET_CATALOG.blocks.map((block) => [block.name, block]));
|
|
377
|
+
const MANIFESTS = new Map(PRESET_CATALOG.manifests.map((manifest) => [manifest.name, manifest]));
|
|
378
|
+
/** The installed blocks with their final names, for `GeneratorModel.blocks`. */
|
|
379
|
+
function generatorBlocks(config) {
|
|
380
|
+
return Object.entries(blockConfigEntries(config)).map(([name, entry]) => {
|
|
381
|
+
const manifest = MANIFESTS.get(CATALOG_BLOCKS.get(name)?.manifest ?? "");
|
|
382
|
+
const owned = manifest?.name === name ? manifest : void 0;
|
|
383
|
+
const client = owned?.client ?? void 0;
|
|
384
|
+
const renames = entityNames(entry.names?.entities ?? []);
|
|
385
|
+
return {
|
|
386
|
+
name,
|
|
387
|
+
schema: entry.schema,
|
|
388
|
+
client: client === void 0 ? void 0 : {
|
|
389
|
+
export: renames.rename(client.export),
|
|
390
|
+
subpath: client.subpath
|
|
391
|
+
},
|
|
392
|
+
entities: blockEntities(name, config.blocks).map((entity) => ({
|
|
393
|
+
key: entity.key,
|
|
394
|
+
from: { ...entity.from },
|
|
395
|
+
to: { ...entity.to },
|
|
396
|
+
primary: entity.primary,
|
|
397
|
+
table: entity.table,
|
|
398
|
+
url: entity.url,
|
|
399
|
+
schemas: owned?.entitySchemas?.[entity.key] ?? {}
|
|
400
|
+
}))
|
|
401
|
+
};
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* For each installed block whose entities `blocks.<name>.entities` renames: the
|
|
406
|
+
* block under its renamed constant (`tasksBlock`) and an alias for each type
|
|
407
|
+
* named after one of its entities (`Task<F>`, `TasksEvents`).
|
|
408
|
+
*/
|
|
409
|
+
function renamedBlockLines(entries) {
|
|
410
|
+
const imports = [];
|
|
411
|
+
const lines = [];
|
|
412
|
+
for (const manifest of PRESET_CATALOG.manifests) {
|
|
413
|
+
const renames = entries[manifest.name]?.names?.entities ?? [];
|
|
414
|
+
if (manifest.client === null || renames.length === 0) continue;
|
|
415
|
+
const names = entityNames(renames);
|
|
416
|
+
const block = manifest.client.export;
|
|
417
|
+
const renamed = names.rename(block);
|
|
418
|
+
const local = renamed === block ? `default${pascal$1(block)}` : block;
|
|
419
|
+
const types = (manifest.entityTypes ?? []).filter((type) => !(type.name.endsWith("Options") && manifest.entityTypes?.some((other) => `${other.name}Options` === type.name)));
|
|
420
|
+
const alias = `${pascal$1(camelOf(manifest.name))}Renames`;
|
|
421
|
+
const key = q(manifest.name);
|
|
422
|
+
const localOf = (name) => names.rename(name) === name ? `Default${name}` : name;
|
|
423
|
+
const specifiers = [...types.map((type) => localOf(type.name) === type.name ? ` type ${type.name},` : ` type ${type.name} as ${localOf(type.name)},`), ` ${local === block ? block : `${block} as ${local}`},`];
|
|
424
|
+
imports.push([
|
|
425
|
+
"import {",
|
|
426
|
+
...specifiers,
|
|
427
|
+
`} from ${q(manifest.client.subpath)};`
|
|
428
|
+
].join("\n"));
|
|
429
|
+
lines.push("", `type ${alias} = (typeof blockConfig)[${key}]["names"]["entities"];`, "", "/**", ` * The \`${manifest.name}\` block under the names \`blocks.${manifest.name}.entities\` gives it.`, " * @public", " */", `export const ${renamed} = renameBlock(${local}, blockConfig[${key}].names);`, ...types.flatMap((type) => {
|
|
430
|
+
const name = names.rename(type.name);
|
|
431
|
+
const source = localOf(type.name);
|
|
432
|
+
if (type.name.endsWith("Events")) return [
|
|
433
|
+
"",
|
|
434
|
+
"/** @public */",
|
|
435
|
+
`export type ${name} = RenamedEvents<${source}, ${alias}>;`
|
|
436
|
+
];
|
|
437
|
+
return type.fields === true ? [
|
|
438
|
+
"",
|
|
439
|
+
"/** @public */",
|
|
440
|
+
`export type ${name}<F extends object = Record<never, never>> = RenamedType<${source}<F>, ${alias}>;`
|
|
441
|
+
] : [
|
|
442
|
+
"",
|
|
443
|
+
"/** @public */",
|
|
444
|
+
`export type ${name} = RenamedType<${source}, ${alias}>;`
|
|
445
|
+
];
|
|
446
|
+
}));
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
specifiers: imports.length === 0 ? [] : [
|
|
450
|
+
"renameBlock",
|
|
451
|
+
"type RenamedEvents",
|
|
452
|
+
"type RenamedType"
|
|
453
|
+
],
|
|
454
|
+
imports,
|
|
455
|
+
lines
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
function camelOf(name) {
|
|
459
|
+
return name.replaceAll(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
460
|
+
}
|
|
461
|
+
function pascal$1(name) {
|
|
462
|
+
return name.charAt(0).toUpperCase() + name.slice(1);
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* `blocks.generated.ts`: each installed block's schema, API schema and the
|
|
466
|
+
* options its TypeScript side reads, for `defineBlocks(blockConfig, ...)`, and
|
|
467
|
+
* the app table events. `undefined` when the config installs no blocks.
|
|
468
|
+
*/
|
|
469
|
+
function emitBlockConfig(config, options = {}) {
|
|
470
|
+
if (config.blockNames.length === 0) return;
|
|
471
|
+
const entries = blockConfigEntries(config);
|
|
472
|
+
const events = appTableEvents(config);
|
|
473
|
+
const runtime = options.runtimeImport ?? "better-supabase";
|
|
474
|
+
const renamed = renamedBlockLines(entries);
|
|
475
|
+
const constants = nameConstantLines(config, entries);
|
|
476
|
+
const specifiers = [
|
|
477
|
+
...events.length === 0 ? [] : [
|
|
478
|
+
"type AppTableEventData",
|
|
479
|
+
"defineEvents",
|
|
480
|
+
"event"
|
|
481
|
+
],
|
|
482
|
+
"type GeneratedBlocks",
|
|
483
|
+
...renamed.specifiers,
|
|
484
|
+
...constants.specifiers
|
|
485
|
+
].toSorted((a, b) => a.replace("type ", "").localeCompare(b.replace("type ", "")));
|
|
486
|
+
const blocksImport = specifiers.length === 1 ? `import type { GeneratedBlocks } from ${q(`${runtime}/blocks`)};` : `import {\n${specifiers.map((name) => ` ${name},`).join("\n")}\n} from ${q(`${runtime}/blocks`)};`;
|
|
487
|
+
return {
|
|
488
|
+
path: blockConfigPath(config),
|
|
489
|
+
contents: [
|
|
490
|
+
GENERATED_HEADER,
|
|
491
|
+
"",
|
|
492
|
+
blocksImport,
|
|
493
|
+
...renamed.imports,
|
|
494
|
+
...constants.imports,
|
|
495
|
+
"",
|
|
496
|
+
"/**",
|
|
497
|
+
" * The installed blocks' settings from the `blocks` config, for",
|
|
498
|
+
" * `defineBlocks(blockConfig, { ... })`: each block's schema, API schema",
|
|
499
|
+
" * and the options its SQL and TypeScript halves share.",
|
|
500
|
+
" */",
|
|
501
|
+
`export const blockConfig = ${literal(entries, "")} as const satisfies GeneratedBlocks;`,
|
|
502
|
+
...renamed.lines,
|
|
503
|
+
...appTableEventLines(events),
|
|
504
|
+
...constants.lines,
|
|
505
|
+
""
|
|
506
|
+
].join("\n")
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
//#endregion
|
|
510
|
+
//#region src/cli/gen/features.ts
|
|
511
|
+
/** `names` and every block they require, from the catalog. */
|
|
512
|
+
function withRequired(names) {
|
|
513
|
+
const requires = new Map(PRESET_CATALOG.blocks.map((block) => [block.name, block.requires]));
|
|
514
|
+
const found = /* @__PURE__ */ new Set();
|
|
515
|
+
const add = (name) => {
|
|
516
|
+
if (!found.has(name)) {
|
|
517
|
+
found.add(name);
|
|
518
|
+
for (const required of requires.get(name) ?? []) add(required);
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
for (const name of names) add(name);
|
|
522
|
+
return [...found];
|
|
523
|
+
}
|
|
524
|
+
function camel(name) {
|
|
525
|
+
return name.replaceAll(/[-_]([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
526
|
+
}
|
|
527
|
+
function pascal(name) {
|
|
528
|
+
const named = camel(name);
|
|
529
|
+
return named.charAt(0).toUpperCase() + named.slice(1);
|
|
530
|
+
}
|
|
531
|
+
function kebab(name) {
|
|
532
|
+
return name.replaceAll("_", "-");
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* The subject types a block's SQL serves, which is where its sections load: the
|
|
536
|
+
* types `blocks.<name>.options.subjects` names, or every tenant-scoped
|
|
537
|
+
* registered subject when it names none. Versions keep only the listed types
|
|
538
|
+
* and the subjects with `versions` set.
|
|
539
|
+
*/
|
|
540
|
+
function servedSubjects(config, block) {
|
|
541
|
+
const listed = resolveModule(config.blocks[block]).options["subjects"];
|
|
542
|
+
const registry = Object.entries(config.subjects);
|
|
543
|
+
const named = Array.isArray(listed) ? listed.filter((type) => typeof type === "string") : typeof listed === "object" && listed !== null ? Object.keys(listed) : void 0;
|
|
544
|
+
if (block === "versions") {
|
|
545
|
+
const versioned = registry.filter(([, entry]) => entry.versions !== void 0).map(([type]) => type);
|
|
546
|
+
return /* @__PURE__ */ new Set([...named ?? [], ...versioned]);
|
|
547
|
+
}
|
|
548
|
+
if (named !== void 0) return new Set(named);
|
|
549
|
+
return new Set(registry.filter(([, entry]) => entry.tenant !== false).map(([type]) => type));
|
|
550
|
+
}
|
|
551
|
+
function sectionBlocks(config) {
|
|
552
|
+
const manifests = new Map(PRESET_CATALOG.manifests.map((manifest) => [manifest.name, manifest]));
|
|
553
|
+
return generatorBlocks(config).flatMap((block) => {
|
|
554
|
+
const manifest = manifests.get(block.name);
|
|
555
|
+
if (manifest?.sections === void 0 || manifest.client === null || block.client === void 0) return [];
|
|
556
|
+
const renamed = block.client.export !== manifest.client.export;
|
|
557
|
+
return [{
|
|
558
|
+
name: block.name,
|
|
559
|
+
key: camel(block.name),
|
|
560
|
+
local: block.client.export,
|
|
561
|
+
from: renamed ? void 0 : block.client.subpath,
|
|
562
|
+
sections: manifest.sections
|
|
563
|
+
}];
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
/** Each section name once, from the first block that declares it. */
|
|
567
|
+
function ownedSections(blocks) {
|
|
568
|
+
const seen = /* @__PURE__ */ new Map();
|
|
569
|
+
for (const block of blocks) for (const [name, writes] of Object.entries(block.sections)) if (!seen.has(name)) seen.set(name, writes);
|
|
570
|
+
return [...seen];
|
|
571
|
+
}
|
|
572
|
+
function featureFile(config, path, type, blocks, extras) {
|
|
573
|
+
const generated = importPath(path, blockConfigPath(config));
|
|
574
|
+
const fromGenerated = [
|
|
575
|
+
"blockConfig",
|
|
576
|
+
...extras.permissions ? ["permissions"] : [],
|
|
577
|
+
...blocks.filter((block) => block.from === void 0).map((b) => b.local)
|
|
578
|
+
].toSorted((a, b) => a.localeCompare(b));
|
|
579
|
+
const imports = [
|
|
580
|
+
"import { defineRecordFeature } from \"better-supabase/records\";",
|
|
581
|
+
...blocks.flatMap((block) => block.from === void 0 ? [] : [`import { ${block.local} } from ${q(block.from)};`]),
|
|
582
|
+
...extras.access === void 0 ? [] : [`import { accessBlock } from ${q(extras.access)};`]
|
|
583
|
+
].toSorted((a, b) => a.localeCompare(b));
|
|
584
|
+
return {
|
|
585
|
+
path,
|
|
586
|
+
contents: [
|
|
587
|
+
GENERATED_HEADER,
|
|
588
|
+
"",
|
|
589
|
+
...imports,
|
|
590
|
+
"",
|
|
591
|
+
`import { ${fromGenerated.join(", ")} } from ${q(generated)};`,
|
|
592
|
+
"",
|
|
593
|
+
"/**",
|
|
594
|
+
` * The ${type} record page: a section for each installed block that adds one.`,
|
|
595
|
+
" * Pass it to `recordServer`, `recordQueries` or `createRecordProvider`.",
|
|
596
|
+
" */",
|
|
597
|
+
`export const ${camel(type)}Feature = defineRecordFeature({`,
|
|
598
|
+
` type: ${q(type)},`,
|
|
599
|
+
" blocks: {",
|
|
600
|
+
...blocks.map((block) => block.key === block.local ? ` ${block.key},` : ` ${block.key}: ${block.local},`),
|
|
601
|
+
" },",
|
|
602
|
+
" config: blockConfig,",
|
|
603
|
+
...extras.permissions ? [" permissions,"] : [],
|
|
604
|
+
...extras.access === void 0 ? [] : [" access: accessBlock,"],
|
|
605
|
+
"});",
|
|
606
|
+
""
|
|
607
|
+
].join("\n")
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
function actionName(type, section, write) {
|
|
611
|
+
return `${write}${pascal(type)}${pascal(section)}`;
|
|
612
|
+
}
|
|
613
|
+
function serverFile(config, path, type, feature) {
|
|
614
|
+
const server = posix.join(posix.dirname(config.output), "server.ts");
|
|
615
|
+
const name = camel(type);
|
|
616
|
+
return {
|
|
617
|
+
path,
|
|
618
|
+
contents: [
|
|
619
|
+
GENERATED_HEADER,
|
|
620
|
+
"",
|
|
621
|
+
"import \"server-only\";",
|
|
622
|
+
"",
|
|
623
|
+
"import { recordServer } from \"better-supabase/next\";",
|
|
624
|
+
"",
|
|
625
|
+
`import { bs } from ${q(importPath(path, server))};`,
|
|
626
|
+
`import { ${name}Feature } from ${q(importPath(path, feature))};`,
|
|
627
|
+
"",
|
|
628
|
+
"/**",
|
|
629
|
+
` * Loads a ${type}'s sections in a Server Component, outside \`"use cache"\`,`,
|
|
630
|
+
" * and runs its section writes as Server Actions.",
|
|
631
|
+
" */",
|
|
632
|
+
`export const ${name}Record = recordServer(bs, ${name}Feature);`,
|
|
633
|
+
""
|
|
634
|
+
].join("\n")
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
function actionsFile(path, type, server, sections) {
|
|
638
|
+
const name = camel(type);
|
|
639
|
+
return {
|
|
640
|
+
path,
|
|
641
|
+
contents: [
|
|
642
|
+
GENERATED_HEADER,
|
|
643
|
+
"",
|
|
644
|
+
"\"use server\";",
|
|
645
|
+
"",
|
|
646
|
+
`import { ${name}Record } from ${q(importPath(path, server))};`,
|
|
647
|
+
...sections.flatMap(([section, writes]) => writes.map((write) => `\nexport const ${actionName(type, section, write)} = ${name}Record.actions.${section}.${write};`)),
|
|
648
|
+
""
|
|
649
|
+
].join("\n")
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
function providerFile(path, type, feature, actions) {
|
|
653
|
+
const name = camel(type);
|
|
654
|
+
const Name = pascal(type);
|
|
655
|
+
const names = actions?.sections.flatMap(([section, writes]) => writes.map((write) => actionName(type, section, write))) ?? [];
|
|
656
|
+
const withActions = actions === void 0 || names.length === 0 ? void 0 : {
|
|
657
|
+
path: actions.path,
|
|
658
|
+
sections: actions.sections
|
|
659
|
+
};
|
|
660
|
+
return {
|
|
661
|
+
path,
|
|
662
|
+
contents: [
|
|
663
|
+
GENERATED_HEADER,
|
|
664
|
+
"",
|
|
665
|
+
"\"use client\";",
|
|
666
|
+
"",
|
|
667
|
+
"import { createElement, type ReactNode } from \"react\";",
|
|
668
|
+
"",
|
|
669
|
+
"import { createRecordProvider } from \"better-supabase/react\";",
|
|
670
|
+
"",
|
|
671
|
+
...withActions === void 0 ? [] : [
|
|
672
|
+
"import {",
|
|
673
|
+
...names.map((action) => ` ${action},`),
|
|
674
|
+
`} from ${q(importPath(path, withActions.path))};`
|
|
675
|
+
],
|
|
676
|
+
`import { ${name}Feature } from ${q(importPath(path, feature))};`,
|
|
677
|
+
"",
|
|
678
|
+
`const kit = createRecordProvider(${name}Feature);`,
|
|
679
|
+
"",
|
|
680
|
+
...withActions === void 0 ? [] : [
|
|
681
|
+
"const writes = {",
|
|
682
|
+
...withActions.sections.flatMap(([section, writes]) => writes.length === 0 ? [] : [
|
|
683
|
+
` ${section}: {`,
|
|
684
|
+
...writes.map((write) => ` ${write}: ${actionName(type, section, write)},`),
|
|
685
|
+
" },"
|
|
686
|
+
]),
|
|
687
|
+
"};",
|
|
688
|
+
""
|
|
689
|
+
],
|
|
690
|
+
`export type ${Name}RecordProviderProps = Omit<`,
|
|
691
|
+
" Parameters<typeof kit.RecordProvider>[0],",
|
|
692
|
+
" \"writes\"",
|
|
693
|
+
">;",
|
|
694
|
+
"",
|
|
695
|
+
"/**",
|
|
696
|
+
` * Holds a ${type}'s sections for its children and follows \`topic\`.`,
|
|
697
|
+
withActions === void 0 ? " * Writes run on the client, under RLS." : " * Writes run as the generated Server Actions.",
|
|
698
|
+
" */",
|
|
699
|
+
`export function ${Name}RecordProvider(`,
|
|
700
|
+
` props: ${Name}RecordProviderProps,`,
|
|
701
|
+
"): ReactNode {",
|
|
702
|
+
withActions === void 0 ? " return createElement(kit.RecordProvider, props);" : " return createElement(kit.RecordProvider, { ...props, writes });",
|
|
703
|
+
"}",
|
|
704
|
+
"",
|
|
705
|
+
`/** The ${type} record context: \`{ state, actions, meta }\`. */`,
|
|
706
|
+
`export const use${Name}Record = kit.useRecord;`,
|
|
707
|
+
""
|
|
708
|
+
].join("\n")
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
function queriesFile(path, type, feature) {
|
|
712
|
+
const name = camel(type);
|
|
713
|
+
return {
|
|
714
|
+
path,
|
|
715
|
+
contents: [
|
|
716
|
+
GENERATED_HEADER,
|
|
717
|
+
"",
|
|
718
|
+
"import {",
|
|
719
|
+
" recordQueries,",
|
|
720
|
+
" type RecordQueriesOptions,",
|
|
721
|
+
"} from \"better-supabase/query\";",
|
|
722
|
+
"",
|
|
723
|
+
`import { ${name}Feature } from ${q(importPath(path, feature))};`,
|
|
724
|
+
"",
|
|
725
|
+
"/**",
|
|
726
|
+
` * TanStack Query options for a ${type}'s sections and writes, over the`,
|
|
727
|
+
" * block clients `createBlocks` builds.",
|
|
728
|
+
" */",
|
|
729
|
+
`export const ${name}Queries = (`,
|
|
730
|
+
" clients: Parameters<typeof recordQueries>[1],",
|
|
731
|
+
" options?: RecordQueriesOptions,",
|
|
732
|
+
`) => recordQueries(${name}Feature, clients, options);`,
|
|
733
|
+
""
|
|
734
|
+
].join("\n")
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* `features/` next to the main module: one record feature per subject with a
|
|
739
|
+
* section for each installed block that serves it, and the bindings for the
|
|
740
|
+
* project's frameworks. Subjects the section blocks and the blocks they require
|
|
741
|
+
* register themselves (a comment's message, an attachment) get none. Empty with
|
|
742
|
+
* `generateFeatures: false`.
|
|
743
|
+
*/
|
|
744
|
+
function emitFeatures(config, frameworks = []) {
|
|
745
|
+
if (!config.generateFeatures || config.blockNames.length === 0) return [];
|
|
746
|
+
const blocks = sectionBlocks(config);
|
|
747
|
+
if (blocks.length === 0) return [];
|
|
748
|
+
const served = new Map(blocks.map((block) => [block.name, servedSubjects(config, block.name)]));
|
|
749
|
+
const access = PRESET_CATALOG.manifests.find((manifest) => manifest.name === "access")?.client;
|
|
750
|
+
const extras = {
|
|
751
|
+
access: new Set(generatorBlocks(config).map((block) => block.name)).has("access") ? access?.subpath : void 0,
|
|
752
|
+
permissions: hasPermissionConstants(config)
|
|
753
|
+
};
|
|
754
|
+
const next = frameworks.includes("next");
|
|
755
|
+
const react = next || frameworks.includes("vite") || frameworks.includes("expo");
|
|
756
|
+
const query = frameworks.includes("tanstack-query");
|
|
757
|
+
const dir = posix.join(posix.dirname(config.output), "features");
|
|
758
|
+
const files = [];
|
|
759
|
+
const features = [];
|
|
760
|
+
const inner = new Set(withRequired(blocks.map((block) => block.name)).flatMap((name) => blockSubjectTypes(name, config.blocks)));
|
|
761
|
+
for (const type of Object.keys(config.subjects).toSorted()) {
|
|
762
|
+
if (inner.has(type)) continue;
|
|
763
|
+
const own = blocks.filter((block) => served.get(block.name)?.has(type));
|
|
764
|
+
if (own.length === 0) continue;
|
|
765
|
+
const base = posix.join(dir, kebab(type), kebab(type));
|
|
766
|
+
const feature = `${base}-feature.ts`;
|
|
767
|
+
const sections = ownedSections(own);
|
|
768
|
+
files.push(featureFile(config, feature, type, own, extras));
|
|
769
|
+
features.push([type, feature]);
|
|
770
|
+
if (next) {
|
|
771
|
+
const server = `${base}-server.ts`;
|
|
772
|
+
const actions = `${base}-actions.ts`;
|
|
773
|
+
files.push(serverFile(config, server, type, feature), actionsFile(actions, type, server, sections), providerFile(`${base}-provider.ts`, type, feature, {
|
|
774
|
+
path: actions,
|
|
775
|
+
sections
|
|
776
|
+
}));
|
|
777
|
+
} else if (react) files.push(providerFile(`${base}-provider.ts`, type, feature, void 0));
|
|
778
|
+
if (query) files.push(queriesFile(`${base}-queries.ts`, type, feature));
|
|
779
|
+
}
|
|
780
|
+
if (features.length === 0) return [];
|
|
781
|
+
const index = posix.join(dir, "index.ts");
|
|
782
|
+
files.push({
|
|
783
|
+
path: index,
|
|
784
|
+
contents: [
|
|
785
|
+
GENERATED_HEADER,
|
|
786
|
+
"",
|
|
787
|
+
...features.map(([type, path]) => `export { ${camel(type)}Feature } from ${q(importPath(index, path))};`),
|
|
788
|
+
""
|
|
789
|
+
].join("\n")
|
|
790
|
+
});
|
|
791
|
+
return files;
|
|
792
|
+
}
|
|
793
|
+
//#endregion
|
|
794
|
+
//#region src/cli/gen/navigation.ts
|
|
795
|
+
function plural(word) {
|
|
796
|
+
if (/[^aeiou]y$/.test(word)) return `${word.slice(0, -1)}ies`;
|
|
797
|
+
if (/(?:s|x|z|ch|sh)$/.test(word)) return `${word}es`;
|
|
798
|
+
return `${word}s`;
|
|
799
|
+
}
|
|
800
|
+
function label(type) {
|
|
801
|
+
const words = type.split(/[-_]/);
|
|
802
|
+
const last = words.length - 1;
|
|
803
|
+
const named = words.map((word, index) => index === last ? plural(word) : word).join(" ");
|
|
804
|
+
return named.charAt(0).toUpperCase() + named.slice(1);
|
|
805
|
+
}
|
|
806
|
+
/**
|
|
807
|
+
* The subjects whose `url` has a list route: the path without its last segment,
|
|
808
|
+
* such as `/customers` for `/customers/{id}`. A route with a placeholder before
|
|
809
|
+
* the last segment is nested under another record and has no top-level entry.
|
|
810
|
+
*/
|
|
811
|
+
function listedSubjects(config) {
|
|
812
|
+
return Object.entries(config.subjects).toSorted(([a], [b]) => a.localeCompare(b)).flatMap(([type, entry]) => {
|
|
813
|
+
const url = entry.url;
|
|
814
|
+
if (url === void 0) return [];
|
|
815
|
+
const last = url.lastIndexOf("/");
|
|
816
|
+
const href = url.slice(last) === `/{${entry.id ?? "id"}}` ? url.slice(0, last) : url;
|
|
817
|
+
if (href === "" || href.includes("{")) return [];
|
|
818
|
+
return [{
|
|
819
|
+
type,
|
|
820
|
+
label: label(type),
|
|
821
|
+
href,
|
|
822
|
+
record: url,
|
|
823
|
+
permission: entry.permissions?.["read"]
|
|
824
|
+
}];
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
function navigationFile(path, listed) {
|
|
828
|
+
const hrefs = /* @__PURE__ */ new Set();
|
|
829
|
+
const items = listed.filter((subject) => !hrefs.has(subject.href) && hrefs.add(subject.href)).map((subject) => [
|
|
830
|
+
" {",
|
|
831
|
+
` type: ${q(subject.type)},`,
|
|
832
|
+
` label: ${q(subject.label)},`,
|
|
833
|
+
` href: ${q(subject.href)},`,
|
|
834
|
+
` record: ${q(subject.record)},`,
|
|
835
|
+
` permission: ${subject.permission === void 0 ? "undefined" : q(subject.permission)},`,
|
|
836
|
+
" },"
|
|
837
|
+
].join("\n"));
|
|
838
|
+
return {
|
|
839
|
+
path,
|
|
840
|
+
contents: [
|
|
841
|
+
GENERATED_HEADER,
|
|
842
|
+
"",
|
|
843
|
+
"/** A list route for a registered subject, from `subjects.<type>.url`. */",
|
|
844
|
+
"export interface NavigationItem {",
|
|
845
|
+
" readonly type: string;",
|
|
846
|
+
" readonly label: string;",
|
|
847
|
+
" /** The list route. */",
|
|
848
|
+
" readonly href: string;",
|
|
849
|
+
" /** The record route, with `{column}` placeholders. */",
|
|
850
|
+
" readonly record: string;",
|
|
851
|
+
" /** The permission key `subjects.<type>.permissions.read` names. */",
|
|
852
|
+
" readonly permission: string | undefined;",
|
|
853
|
+
"}",
|
|
854
|
+
"",
|
|
855
|
+
"export const navigation: readonly NavigationItem[] = [",
|
|
856
|
+
...items,
|
|
857
|
+
"];",
|
|
858
|
+
""
|
|
859
|
+
].join("\n")
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
function commandsFile(path, subjects) {
|
|
863
|
+
const items = subjects.map((subject) => [
|
|
864
|
+
" {",
|
|
865
|
+
` id: ${q(`go-to-${subject.type.replaceAll("_", "-")}`)},`,
|
|
866
|
+
` label: ${q(`Go to ${subject.label.toLowerCase()}`)},`,
|
|
867
|
+
` group: "Navigation",`,
|
|
868
|
+
` keywords: [${q(subject.type)}],`,
|
|
869
|
+
` href: ${q(subject.href)},`,
|
|
870
|
+
` permission: ${subject.permission === void 0 ? "undefined" : q(subject.permission)},`,
|
|
871
|
+
" },"
|
|
872
|
+
].join("\n"));
|
|
873
|
+
return {
|
|
874
|
+
path,
|
|
875
|
+
contents: [
|
|
876
|
+
GENERATED_HEADER,
|
|
877
|
+
"",
|
|
878
|
+
"/** A command palette entry that opens a subject's list route. */",
|
|
879
|
+
"export interface Command {",
|
|
880
|
+
" readonly id: string;",
|
|
881
|
+
" readonly label: string;",
|
|
882
|
+
" readonly group: string;",
|
|
883
|
+
" readonly keywords: readonly string[];",
|
|
884
|
+
" readonly href: string;",
|
|
885
|
+
" /** The permission key the command needs, when the subject names one. */",
|
|
886
|
+
" readonly permission: string | undefined;",
|
|
887
|
+
"}",
|
|
888
|
+
"",
|
|
889
|
+
"export const commands: readonly Command[] = [",
|
|
890
|
+
...items,
|
|
891
|
+
"];",
|
|
892
|
+
""
|
|
893
|
+
].join("\n")
|
|
894
|
+
};
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* `navigation.generated.ts` and `commands.generated.ts` next to the typed
|
|
898
|
+
* client: plain typed arrays with one entry per subject that has a list route,
|
|
899
|
+
* carrying the read permission so the app can hide what the caller can't open.
|
|
900
|
+
* Subjects that share a list route share one navigation entry, the first by
|
|
901
|
+
* type name.
|
|
902
|
+
*/
|
|
903
|
+
function emitNavigation(config) {
|
|
904
|
+
const subjects = listedSubjects(config);
|
|
905
|
+
if (subjects.length === 0) return [];
|
|
906
|
+
const dir = posix.dirname(config.output);
|
|
907
|
+
return [navigationFile(posix.join(dir, "navigation.generated.ts"), subjects), commandsFile(posix.join(dir, "commands.generated.ts"), subjects)];
|
|
908
|
+
}
|
|
909
|
+
//#endregion
|
|
910
|
+
//#region src/cli/gen/render.ts
|
|
911
|
+
/**
|
|
912
|
+
* Renders every generated file for a snapshot, without touching disk:
|
|
913
|
+
* `database.types.ts` (what `supabase gen types` prints), the main module,
|
|
914
|
+
* `blocks.generated.ts` when the config installs blocks, the record features in
|
|
915
|
+
* `features/`, then each configured generator's files.
|
|
916
|
+
*/
|
|
917
|
+
async function renderFiles(config, snapshot, options = {}) {
|
|
918
|
+
return (await render(config, snapshot, options)).files;
|
|
919
|
+
}
|
|
920
|
+
async function render(config, snapshot, options = {}) {
|
|
921
|
+
const model = buildModel(snapshot, config);
|
|
922
|
+
const runtime = options.runtimeImport ? { runtimeImport: options.runtimeImport } : {};
|
|
923
|
+
const output = resolve(config.root, config.output);
|
|
924
|
+
const typegenOptions = {
|
|
925
|
+
schemas: config.schemas,
|
|
926
|
+
postgrestVersion: config.postgrestVersion
|
|
927
|
+
};
|
|
928
|
+
const databaseTypes = await cachedDatabaseTypes(config.root, [
|
|
929
|
+
typegenOptions,
|
|
930
|
+
await oxfmtInstalled(),
|
|
931
|
+
snapshot.generator
|
|
932
|
+
], () => generateDatabaseTypes(snapshot.generator, typegenOptions));
|
|
933
|
+
const metaFiles = metaPaths(config.output);
|
|
934
|
+
const main = emitModule(model, {
|
|
935
|
+
databaseTypesImport: importPath(output, resolve(config.root, config.databaseTypesOutput)),
|
|
936
|
+
importPathFor: (from) => importPath(output, resolve(config.root, from)),
|
|
937
|
+
metaImport: `./${basename(metaFiles.js)}`,
|
|
938
|
+
...options.inlineMeta ? { inlineMeta: true } : {},
|
|
939
|
+
...runtime
|
|
940
|
+
});
|
|
941
|
+
const meta = emitMeta(model, {
|
|
942
|
+
types: `./${basename(metaFiles.dts)}`,
|
|
943
|
+
...runtime
|
|
944
|
+
});
|
|
945
|
+
const files = [
|
|
946
|
+
{
|
|
947
|
+
path: config.databaseTypesOutput,
|
|
948
|
+
contents: databaseTypes
|
|
949
|
+
},
|
|
950
|
+
{
|
|
951
|
+
path: config.output,
|
|
952
|
+
contents: main
|
|
953
|
+
},
|
|
954
|
+
{
|
|
955
|
+
path: metaFiles.js,
|
|
956
|
+
contents: meta.js
|
|
957
|
+
},
|
|
958
|
+
{
|
|
959
|
+
path: metaFiles.dts,
|
|
960
|
+
contents: meta.dts
|
|
961
|
+
}
|
|
962
|
+
];
|
|
963
|
+
const blockConfig = emitBlockConfig(config, runtime);
|
|
964
|
+
if (blockConfig) files.push(blockConfig);
|
|
965
|
+
if (config.generateFeatures) {
|
|
966
|
+
const frameworks = options.frameworks ?? (await detectProject(config.root)).frameworks;
|
|
967
|
+
files.push(...emitFeatures(config, frameworks), ...emitNavigation(config));
|
|
968
|
+
}
|
|
969
|
+
const owners = new Map(files.map((file) => [resolve(config.root, file.path), "gen"]));
|
|
970
|
+
let view;
|
|
971
|
+
for (const generator of config.generators) {
|
|
972
|
+
let extra;
|
|
973
|
+
try {
|
|
974
|
+
extra = await generator.generate({
|
|
975
|
+
meta: model.meta,
|
|
976
|
+
introspection: model.introspection,
|
|
977
|
+
extras: snapshot.extras,
|
|
978
|
+
config,
|
|
979
|
+
output,
|
|
980
|
+
importPath: (from, to) => importPath(resolve(config.root, from), resolve(config.root, to)),
|
|
981
|
+
model: view ??= generatorModel(model, generatorBlocks(config)),
|
|
982
|
+
...runtime
|
|
983
|
+
});
|
|
984
|
+
} catch (cause) {
|
|
985
|
+
throw new CliError("generator_failed", `generator "${generator.name}" failed: ${errorText(cause)}`, { cause });
|
|
986
|
+
}
|
|
987
|
+
for (const file of extra) {
|
|
988
|
+
const path = resolve(config.root, file.path);
|
|
989
|
+
const inside = relative(config.root, path);
|
|
990
|
+
if (inside === "" || inside.startsWith("..") || isAbsolute(inside)) throw new CliError("generator_failed", `generator "${generator.name}" wrote ${file.path}, which is outside the project root`);
|
|
991
|
+
const owner = owners.get(path);
|
|
992
|
+
if (owner !== void 0) throw new CliError("generator_failed", `generator "${generator.name}" wrote ${file.path}, which ${owner === "gen" ? "better-supabase gen writes" : `generator "${owner}" also writes`}`);
|
|
993
|
+
owners.set(path, generator.name);
|
|
994
|
+
files.push(file);
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return {
|
|
998
|
+
files,
|
|
999
|
+
warnings: model.warnings,
|
|
1000
|
+
notices: model.notices
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
//#endregion
|
|
1004
|
+
//#region src/cli/doctor/advisor-rules.ts
|
|
1005
|
+
/**
|
|
1006
|
+
* One request per advisor category, shared by the advisor rules and the rules
|
|
1007
|
+
* that defer to them.
|
|
1008
|
+
*/
|
|
1009
|
+
const fetched = /* @__PURE__ */ new WeakMap();
|
|
1010
|
+
function lintsOf(advisors, category) {
|
|
1011
|
+
let byCategory = fetched.get(advisors);
|
|
1012
|
+
if (!byCategory) {
|
|
1013
|
+
byCategory = /* @__PURE__ */ new Map();
|
|
1014
|
+
fetched.set(advisors, byCategory);
|
|
1015
|
+
}
|
|
1016
|
+
let lints = byCategory.get(category);
|
|
1017
|
+
if (!lints) {
|
|
1018
|
+
lints = advisors.lints(category);
|
|
1019
|
+
byCategory.set(category, lints);
|
|
1020
|
+
}
|
|
1021
|
+
return lints;
|
|
1022
|
+
}
|
|
1023
|
+
const ADVISOR_SEVERITY = {
|
|
1024
|
+
ERROR: "error",
|
|
1025
|
+
WARN: "warning",
|
|
1026
|
+
INFO: "info"
|
|
1027
|
+
};
|
|
1028
|
+
function lintObject(lint) {
|
|
1029
|
+
const { schema, name, type } = lint.metadata ?? {};
|
|
1030
|
+
if (typeof schema !== "string" || typeof name !== "string") return;
|
|
1031
|
+
if (type === "table" || type === "view") return {
|
|
1032
|
+
kind: "table",
|
|
1033
|
+
schema,
|
|
1034
|
+
name
|
|
1035
|
+
};
|
|
1036
|
+
if (type === "function") return {
|
|
1037
|
+
kind: "function",
|
|
1038
|
+
schema,
|
|
1039
|
+
name
|
|
1040
|
+
};
|
|
1041
|
+
}
|
|
1042
|
+
function lintFinding(lint) {
|
|
1043
|
+
const object = lintObject(lint);
|
|
1044
|
+
return {
|
|
1045
|
+
severity: ADVISOR_SEVERITY[lint.level] ?? "warning",
|
|
1046
|
+
title: lint.title,
|
|
1047
|
+
message: `${lint.detail.replaceAll("\\`", "`")} [${lint.name}]`,
|
|
1048
|
+
target: object ? `${object.schema}.${object.name}` : lint.cache_key,
|
|
1049
|
+
help: lint.remediation,
|
|
1050
|
+
...object ? { object } : {}
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* A rule that reports one category of Supabase's advisors (splinter) as
|
|
1055
|
+
* findings.
|
|
1056
|
+
*/
|
|
1057
|
+
function advisorRule(code, category, title, description) {
|
|
1058
|
+
return {
|
|
1059
|
+
code,
|
|
1060
|
+
severity: "warning",
|
|
1061
|
+
title,
|
|
1062
|
+
description,
|
|
1063
|
+
async check(context) {
|
|
1064
|
+
const { advisors } = context;
|
|
1065
|
+
if (!advisors) return [];
|
|
1066
|
+
if ("skipped" in advisors) return [{
|
|
1067
|
+
severity: "info",
|
|
1068
|
+
message: `Skipped the ${category} advisor: ${advisors.skipped}`
|
|
1069
|
+
}];
|
|
1070
|
+
try {
|
|
1071
|
+
return (await lintsOf(advisors, category)).map(lintFinding);
|
|
1072
|
+
} catch (cause) {
|
|
1073
|
+
return [{ message: `The ${category} advisor could not run (${advisors.describe}): ${errorText(cause)}` }];
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
};
|
|
1077
|
+
}
|
|
1078
|
+
/** The performance advisor rule the duplicate rules defer to. */
|
|
1079
|
+
const PERFORMANCE_ADVISOR = "BS200";
|
|
1080
|
+
/**
|
|
1081
|
+
* The tables splinter reports `lint` for (`schema.table`), when the performance
|
|
1082
|
+
* advisor runs in this run and its lints loaded. A rule that repeats the lint
|
|
1083
|
+
* (BS207, BS216) drops its findings for these tables; with `undefined` (no
|
|
1084
|
+
* advisors, a saved snapshot, an advisor error, or BS200 not in the run) it
|
|
1085
|
+
* reports them itself.
|
|
1086
|
+
*/
|
|
1087
|
+
async function splinterTables(context, lint) {
|
|
1088
|
+
const { advisors } = context;
|
|
1089
|
+
if (!advisors || "skipped" in advisors) return;
|
|
1090
|
+
if (!context.codes?.includes(PERFORMANCE_ADVISOR)) return;
|
|
1091
|
+
let lints;
|
|
1092
|
+
try {
|
|
1093
|
+
lints = await lintsOf(advisors, "performance");
|
|
1094
|
+
} catch {
|
|
1095
|
+
return;
|
|
1096
|
+
}
|
|
1097
|
+
return new Set(lints.flatMap((entry) => {
|
|
1098
|
+
if (entry.name !== lint) return [];
|
|
1099
|
+
const object = lintObject(entry);
|
|
1100
|
+
return object ? [`${object.schema}.${object.name}`] : [];
|
|
1101
|
+
}));
|
|
1102
|
+
}
|
|
1103
|
+
//#endregion
|
|
1104
|
+
//#region src/cli/doctor/rls.ts
|
|
1105
|
+
const escape = (name) => name.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1106
|
+
/** `'it''s'` and other string literals, blanked so their text can't match. */
|
|
1107
|
+
const withoutStrings = (text) => text.replaceAll(/'(?:[^']|'')*'/g, "''");
|
|
1108
|
+
const functionName = (fn) => `${fn.schema}.${fn.name}`;
|
|
1109
|
+
const functionObject = (fn) => ({
|
|
1110
|
+
kind: "function",
|
|
1111
|
+
schema: fn.schema,
|
|
1112
|
+
name: fn.name
|
|
1113
|
+
});
|
|
1114
|
+
/** The functions policies call, by `schema.name`; overloads share a key. */
|
|
1115
|
+
function functionsByName(context) {
|
|
1116
|
+
const map = /* @__PURE__ */ new Map();
|
|
1117
|
+
for (const fn of context.snapshot.extras.functions ?? []) {
|
|
1118
|
+
const key = functionName(fn);
|
|
1119
|
+
const list = map.get(key);
|
|
1120
|
+
if (list) list.push(fn);
|
|
1121
|
+
else map.set(key, [fn]);
|
|
1122
|
+
}
|
|
1123
|
+
return map;
|
|
1124
|
+
}
|
|
1125
|
+
/** Argument lists of every call to `schema.name(...)` in an expression. */
|
|
1126
|
+
function callArguments(expression, fn) {
|
|
1127
|
+
if (!expression) return [];
|
|
1128
|
+
const text = withoutStrings(expression);
|
|
1129
|
+
const pattern = new RegExp(`(?<![\\w."])(?:"?${escape(fn.schema)}"?\\.)?"?${escape(fn.name)}"?\\s*\\(`, "g");
|
|
1130
|
+
const calls = [];
|
|
1131
|
+
for (const match of text.matchAll(pattern)) {
|
|
1132
|
+
const start = match.index + match[0].length;
|
|
1133
|
+
let depth = 1;
|
|
1134
|
+
let end = start;
|
|
1135
|
+
while (end < text.length && depth > 0) {
|
|
1136
|
+
if (text[end] === "(") depth += 1;
|
|
1137
|
+
else if (text[end] === ")") depth -= 1;
|
|
1138
|
+
end += 1;
|
|
1139
|
+
}
|
|
1140
|
+
calls.push(text.slice(start, end - 1));
|
|
1141
|
+
}
|
|
1142
|
+
return calls;
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* The first column of `table` an argument list refers to, bare or as
|
|
1146
|
+
* `table.column`.
|
|
1147
|
+
*/
|
|
1148
|
+
function columnArgument(args, table) {
|
|
1149
|
+
return table.columns.find((column) => new RegExp(`(?<![\\w."$:])(?:"?${escape(table.name)}"?\\.)?"?${escape(column.name)}"?(?![\\w"(.$])`).test(args))?.name;
|
|
1150
|
+
}
|
|
1151
|
+
const expressions = (policy) => [policy.using, policy.check];
|
|
1152
|
+
/**
|
|
1153
|
+
* Why Postgres can't inline `fn` into the query that calls it, or `undefined`
|
|
1154
|
+
* when it can: only `language sql` functions that are not volatile, not
|
|
1155
|
+
* security definer and have no `set` options are inlined.
|
|
1156
|
+
*/
|
|
1157
|
+
function notInlinable(fn) {
|
|
1158
|
+
if (fn.language !== "sql") return `a ${fn.language} function`;
|
|
1159
|
+
if (fn.volatility === "volatile") return "a volatile function";
|
|
1160
|
+
if (fn.securityDefiner) return "a security definer function";
|
|
1161
|
+
const settings = Object.keys(fn.settings);
|
|
1162
|
+
if (settings.length > 0) return `a function with \`set ${settings.join(", ")}\``;
|
|
1163
|
+
}
|
|
1164
|
+
const rlsTables$1 = (context) => exposed(context).filter((table) => table.rls);
|
|
1165
|
+
const COMMANDS = [
|
|
1166
|
+
"select",
|
|
1167
|
+
"insert",
|
|
1168
|
+
"update",
|
|
1169
|
+
"delete"
|
|
1170
|
+
];
|
|
1171
|
+
/** Policies apply to every role when they list `public` or none. */
|
|
1172
|
+
const appliesTo = (policy, role) => policy.roles.length === 0 || policy.roles.includes("public") || policy.roles.includes(role);
|
|
1173
|
+
/** Commands and roles that more than one permissive policy of the table covers. */
|
|
1174
|
+
function permissiveOverlaps(table) {
|
|
1175
|
+
const permissive = table.policies.filter((policy) => policy.permissive);
|
|
1176
|
+
const roles = /* @__PURE__ */ new Set();
|
|
1177
|
+
for (const policy of permissive) {
|
|
1178
|
+
const named = policy.roles.filter((role) => role !== "public");
|
|
1179
|
+
if (named.length < policy.roles.length || policy.roles.length === 0) {
|
|
1180
|
+
roles.add("anon");
|
|
1181
|
+
roles.add("authenticated");
|
|
1182
|
+
}
|
|
1183
|
+
for (const role of named) roles.add(role);
|
|
1184
|
+
}
|
|
1185
|
+
const overlaps = [];
|
|
1186
|
+
for (const command of COMMANDS) for (const role of [...roles].toSorted()) {
|
|
1187
|
+
const policies = permissive.filter((policy) => (policy.command === "all" || policy.command === command) && appliesTo(policy, role)).map((policy) => policy.name);
|
|
1188
|
+
if (policies.length > 1) overlaps.push({
|
|
1189
|
+
command,
|
|
1190
|
+
role,
|
|
1191
|
+
policies
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1194
|
+
return overlaps;
|
|
1195
|
+
}
|
|
1196
|
+
const WRITES = ["insert", "update"];
|
|
1197
|
+
const API_ROLES = ["anon", "authenticated"];
|
|
1198
|
+
const NOT_ALIAS = /* @__PURE__ */ new Set([
|
|
1199
|
+
"where",
|
|
1200
|
+
"join",
|
|
1201
|
+
"inner",
|
|
1202
|
+
"left",
|
|
1203
|
+
"right",
|
|
1204
|
+
"full",
|
|
1205
|
+
"cross",
|
|
1206
|
+
"on",
|
|
1207
|
+
"using",
|
|
1208
|
+
"group",
|
|
1209
|
+
"order",
|
|
1210
|
+
"limit",
|
|
1211
|
+
"union",
|
|
1212
|
+
"natural",
|
|
1213
|
+
"lateral",
|
|
1214
|
+
"as"
|
|
1215
|
+
]);
|
|
1216
|
+
/**
|
|
1217
|
+
* The body of `schema.name` from the snapshot, else from the first SQL file
|
|
1218
|
+
* that creates it.
|
|
1219
|
+
*/
|
|
1220
|
+
function functionBody(context, schema, name) {
|
|
1221
|
+
const introspected = context.snapshot.generator.functions.find((fn) => fn.schema === schema && fn.name === name && fn.definition)?.definition;
|
|
1222
|
+
if (introspected) return introspected;
|
|
1223
|
+
const creates = new RegExp(`create\\s+(?:or\\s+replace\\s+)?function\\s+(?:"?${escape(schema)}"?\\.)?"?${escape(name)}"?\\s*\\([\\s\\S]*?\\bas\\s+(\\$\\w*\\$)([\\s\\S]*?)\\1`, "i");
|
|
1224
|
+
for (const file of context.sqlFiles ?? []) {
|
|
1225
|
+
const match = creates.exec(file.text);
|
|
1226
|
+
if (match) return match[2];
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
const helpersByContext = /* @__PURE__ */ new WeakMap();
|
|
1230
|
+
/** The functions policies call, and the functions those call, with their bodies. */
|
|
1231
|
+
function policyHelpers(context) {
|
|
1232
|
+
let helpers = helpersByContext.get(context);
|
|
1233
|
+
if (!helpers) {
|
|
1234
|
+
helpers = findPolicyHelpers(context);
|
|
1235
|
+
helpersByContext.set(context, helpers);
|
|
1236
|
+
}
|
|
1237
|
+
return helpers;
|
|
1238
|
+
}
|
|
1239
|
+
function findPolicyHelpers(context) {
|
|
1240
|
+
const known = context.snapshot.generator.functions;
|
|
1241
|
+
const queue = catalogOf(context).tables.flatMap((table) => table.policies.flatMap((policy) => policy.functions ?? []));
|
|
1242
|
+
const bodies = /* @__PURE__ */ new Map();
|
|
1243
|
+
while (queue.length > 0) {
|
|
1244
|
+
const key = queue.pop();
|
|
1245
|
+
if (bodies.has(key)) continue;
|
|
1246
|
+
const dot = key.indexOf(".");
|
|
1247
|
+
const body = functionBody(context, key.slice(0, dot), key.slice(dot + 1));
|
|
1248
|
+
if (!body) continue;
|
|
1249
|
+
const text = withoutStrings(body);
|
|
1250
|
+
bodies.set(key, text);
|
|
1251
|
+
for (const fn of known) {
|
|
1252
|
+
const called = `${fn.schema}.${fn.name}`;
|
|
1253
|
+
if (!bodies.has(called) && callArguments(text, fn).length > 0) queue.push(called);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
return bodies;
|
|
1257
|
+
}
|
|
1258
|
+
/**
|
|
1259
|
+
* Tables a function body reads (`from` and `join`), with the names it refers to
|
|
1260
|
+
* them by.
|
|
1261
|
+
*/
|
|
1262
|
+
function readTables(body, tables) {
|
|
1263
|
+
const found = /* @__PURE__ */ new Map();
|
|
1264
|
+
for (const match of body.matchAll(/\b(?:from|join)\s+(?:"?(\w+)"?\s*\.\s*)?"?(\w+)"?(?:\s+(?:as\s+)?"?(\w+)"?)?/gi)) {
|
|
1265
|
+
const [, schema, name, alias] = match;
|
|
1266
|
+
const table = tables.find((t) => t.name === name && t.schema === schema) ?? (schema ? void 0 : tables.find((t) => t.name === name && t.schema === "public") ?? tables.find((t) => t.name === name));
|
|
1267
|
+
if (!table) continue;
|
|
1268
|
+
const names = found.get(table) ?? /* @__PURE__ */ new Set([table.name]);
|
|
1269
|
+
if (alias && !NOT_ALIAS.has(alias.toLowerCase())) names.add(alias);
|
|
1270
|
+
found.set(table, names);
|
|
1271
|
+
}
|
|
1272
|
+
return [...found].map(([table, names]) => ({
|
|
1273
|
+
table,
|
|
1274
|
+
names: [...names]
|
|
1275
|
+
}));
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Columns that decide who may read other rows, by `schema.table`: the columns
|
|
1279
|
+
* of the tables policy helpers read that their bodies mention (qualified, or
|
|
1280
|
+
* bare when the body reads one table), and the manifest's `decidingColumns`. A
|
|
1281
|
+
* subject's `deletedAt` column and a module's `hidingColumns` only hide rows,
|
|
1282
|
+
* so they count only when the manifest lists them.
|
|
1283
|
+
*/
|
|
1284
|
+
function grantColumns(context) {
|
|
1285
|
+
const tables = catalogOf(context).tables;
|
|
1286
|
+
const columns = /* @__PURE__ */ new Map();
|
|
1287
|
+
const entry = (table, column) => {
|
|
1288
|
+
const byColumn = columns.get(table) ?? /* @__PURE__ */ new Map();
|
|
1289
|
+
columns.set(table, byColumn);
|
|
1290
|
+
const existing = byColumn.get(column);
|
|
1291
|
+
if (existing) return existing;
|
|
1292
|
+
const created = {
|
|
1293
|
+
helpers: /* @__PURE__ */ new Set(),
|
|
1294
|
+
provider: false
|
|
1295
|
+
};
|
|
1296
|
+
byColumn.set(column, created);
|
|
1297
|
+
return created;
|
|
1298
|
+
};
|
|
1299
|
+
const softDeleted = /* @__PURE__ */ new Set([...Object.values(context.config.subjects).flatMap((subject) => subject.deletedAt === void 0 ? [] : [`${subject.table.includes(".") ? subject.table : `public.${subject.table}`}.${subject.deletedAt}`]), ...context.config.blockNames.length > 0 ? moduleHidingColumns(context.config.blockNames, moduleLayout(context.config)) : []]);
|
|
1300
|
+
for (const [helper, body] of policyHelpers(context)) {
|
|
1301
|
+
const read = readTables(body, tables);
|
|
1302
|
+
for (const { table, names } of read) for (const column of table.columns) {
|
|
1303
|
+
if (softDeleted.has(`${qualified(table)}.${column.name}`)) continue;
|
|
1304
|
+
const col = `"?${escape(column.name)}"?(?![\\w"(])`;
|
|
1305
|
+
const qualifiedColumn = new RegExp(`(?<![\\w"])(?:${names.map((name) => `"?${escape(name)}"?`).join("|")})\\s*\\.\\s*${col}`, "i");
|
|
1306
|
+
const bare = new RegExp(`(?<![\\w."])${col}`, "i");
|
|
1307
|
+
if (qualifiedColumn.test(body) || read.length === 1 && bare.test(body)) entry(qualified(table), column.name).helpers.add(helper);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
for (const deciding of context.config.authorization?.decidingColumns ?? []) {
|
|
1311
|
+
const dot = deciding.lastIndexOf(".");
|
|
1312
|
+
if (dot > 0) entry(deciding.slice(0, dot), deciding.slice(dot + 1)).provider = true;
|
|
1313
|
+
}
|
|
1314
|
+
return columns;
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Whether `role` may run `command` on rows of `table` at all: no RLS, or a
|
|
1318
|
+
* permissive policy for it.
|
|
1319
|
+
*/
|
|
1320
|
+
const policyAllows = (table, command, role) => !table.rls || table.policies.some((policy) => policy.permissive && (policy.command === "all" || policy.command === command) && appliesTo(policy, role));
|
|
1321
|
+
/**
|
|
1322
|
+
* Whether `grant` reaches `role`: granted to it, or to PUBLIC, which every role
|
|
1323
|
+
* inherits.
|
|
1324
|
+
*/
|
|
1325
|
+
const grantsTo = (grant, role) => grant.role === role || grant.role === "PUBLIC";
|
|
1326
|
+
/**
|
|
1327
|
+
* Whether every call of `name` (`schema.function`) in `expressions` takes no
|
|
1328
|
+
* arguments inside `(select ...)`, which Postgres runs once per statement. An
|
|
1329
|
+
* argument may come from the row, and then it runs per row.
|
|
1330
|
+
*/
|
|
1331
|
+
function onlyWrapped(name, expressions) {
|
|
1332
|
+
const dot = name.indexOf(".");
|
|
1333
|
+
const call = `"?${escape(name.slice(0, dot))}"?\\s*\\.\\s*"?${escape(name.slice(dot + 1))}"?\\s*\\(`;
|
|
1334
|
+
const any = new RegExp(`(?<![\\w."])${call}`, "gi");
|
|
1335
|
+
const wrapped = new RegExp(`\\(\\s*select\\s+${call}\\s*\\)`, "gi");
|
|
1336
|
+
let calls = 0;
|
|
1337
|
+
let wraps = 0;
|
|
1338
|
+
for (const expression of expressions) if (expression) {
|
|
1339
|
+
calls += expression.match(any)?.length ?? 0;
|
|
1340
|
+
wraps += expression.match(wrapped)?.length ?? 0;
|
|
1341
|
+
}
|
|
1342
|
+
return calls > 0 && calls === wraps;
|
|
1343
|
+
}
|
|
1344
|
+
/**
|
|
1345
|
+
* Whether every permissive policy that lets `role` run `command` holds `column`
|
|
1346
|
+
* to a tenant the caller acts in, with no `or` around it: equal to
|
|
1347
|
+
* `current_tenant_id()`, passed to `can('tenant', column, ...)`, or in `(select
|
|
1348
|
+
* tenant_ids_with(...))` or `(select member_<tenant>_ids())`. A write can't
|
|
1349
|
+
* name a tenant the caller isn't in then. The guest branch `ctx.scope.guest`
|
|
1350
|
+
* adds (`or (column, ...) in (select g.tenant ... portal_subjects(...) g)`)
|
|
1351
|
+
* pins it to a tenant the caller is a guest of, so it doesn't count as an
|
|
1352
|
+
* `or`.
|
|
1353
|
+
*/
|
|
1354
|
+
function pinnedToTenant(table, column, command, role) {
|
|
1355
|
+
if (!table.rls) return false;
|
|
1356
|
+
const col = `"?${escape(column)}"?`;
|
|
1357
|
+
const pin = new RegExp([
|
|
1358
|
+
`(?<![\\w."])${col}\\s*=\\s*\\(?\\s*(?:select\\s+)?better_supabase\\.current_tenant_id\\(\\)`,
|
|
1359
|
+
`better_supabase\\.can\\(\\s*'tenant'(?:::text)?\\s*,\\s*${col}\\s*,`,
|
|
1360
|
+
`(?<![\\w."])${col}\\s+in\\s+\\(\\s*select\\s+better_supabase\\.(?:tenant_ids_with|member_\\w+_ids)\\(`
|
|
1361
|
+
].join("|"), "i");
|
|
1362
|
+
const guest = new RegExp(`\\bor\\s+\\(*\\(?${col}\\)?(?:::text)?\\s*,(?:[^()]|\\([^()]*\\))*\\)\\s+in\\s+\\(\\s*select\\s+g\\.tenant\\b[^()]*from\\s+better_supabase\\.portal_(?:subjects|parties)\\([^()]*\\)\\s+g(?:\\([^()]*\\))?\\)`, "gi");
|
|
1363
|
+
const applying = table.policies.filter((policy) => policy.permissive && (policy.command === "all" || policy.command === command) && appliesTo(policy, role));
|
|
1364
|
+
return applying.length > 0 && applying.every((policy) => {
|
|
1365
|
+
const check = (policy.check ?? policy.using)?.replaceAll(guest, "");
|
|
1366
|
+
return check !== void 0 && !/\bor\b/i.test(check) && pin.test(check);
|
|
1367
|
+
});
|
|
1368
|
+
}
|
|
1369
|
+
/**
|
|
1370
|
+
* The grant columns `role` may write with `command`, through a table-level or a
|
|
1371
|
+
* column-level grant. A single-column primary key is left out (its uniqueness
|
|
1372
|
+
* stops a write from taking over another row), and so is a column every policy
|
|
1373
|
+
* pins to the request's tenant, unless the provider lists it in `deciding`.
|
|
1374
|
+
*/
|
|
1375
|
+
function writableColumns(table, columns, command, role, deciding = /* @__PURE__ */ new Set()) {
|
|
1376
|
+
if (!policyAllows(table, command, role)) return [];
|
|
1377
|
+
const privilege = command.toUpperCase();
|
|
1378
|
+
const tableLevel = table.grants.some((grant) => grantsTo(grant, role) && grant.privileges.includes(privilege));
|
|
1379
|
+
const risky = columns.filter((column) => deciding.has(column) || !(table.primaryKey.length === 1 && table.primaryKey[0] === column) && !pinnedToTenant(table, column, command, role));
|
|
1380
|
+
if (tableLevel) return risky;
|
|
1381
|
+
return risky.filter((column) => (table.columnGrants ?? []).some((grant) => grantsTo(grant, role) && grant.column === column && grant.privileges.includes(privilege)));
|
|
1382
|
+
}
|
|
1383
|
+
/** PostgREST's default for `db-hoisted-tx-settings`. */
|
|
1384
|
+
const DEFAULT_HOISTED = [
|
|
1385
|
+
"statement_timeout",
|
|
1386
|
+
"plan_filter.statement_cost_limit",
|
|
1387
|
+
"default_transaction_isolation"
|
|
1388
|
+
];
|
|
1389
|
+
const TIMEOUT_ROLES = [
|
|
1390
|
+
"anon",
|
|
1391
|
+
"authenticated",
|
|
1392
|
+
"authenticator"
|
|
1393
|
+
];
|
|
1394
|
+
/**
|
|
1395
|
+
* Partitions of an RLS table that have RLS off: queried by name, they skip the
|
|
1396
|
+
* parent's policies.
|
|
1397
|
+
*/
|
|
1398
|
+
function partitionsWithoutRls(context) {
|
|
1399
|
+
const tables = catalogOf(context).tables;
|
|
1400
|
+
const byName = new Map(tables.map((table) => [qualified(table), table]));
|
|
1401
|
+
return tables.flatMap((table) => {
|
|
1402
|
+
if (table.partitionOf === void 0 || table.rls || !context.config.schemas.includes(table.schema)) return [];
|
|
1403
|
+
if (!byName.get(table.partitionOf)?.rls) return [];
|
|
1404
|
+
return [{
|
|
1405
|
+
message: `${qualified(table)} is a partition of ${table.partitionOf}, which has RLS on, but RLS is off on the partition. A query that names the partition skips the parent's policies, and Data API roles with a grant on it read every row. Run \`alter table ${qualified(table)} enable row level security;\`, and add the same enable to the code that creates new partitions.`,
|
|
1406
|
+
target: qualified(table),
|
|
1407
|
+
object: tableObject(table)
|
|
1408
|
+
}];
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
const RLS_RULES = [
|
|
1412
|
+
{
|
|
1413
|
+
code: "BS343",
|
|
1414
|
+
severity: "error",
|
|
1415
|
+
title: "Partition without row level security",
|
|
1416
|
+
description: "A table in `schemas` is a partition of a table with RLS on, but has RLS off itself. Policies belong to the parent, so a query that names the partition (`select * from events_default`) never applies them. This includes the default partition. Enable RLS on every partition when you create it; the partition functions of the SQL modules (`ensure_partitions`, ADR 0038) already do.",
|
|
1417
|
+
check: partitionsWithoutRls
|
|
1418
|
+
},
|
|
1419
|
+
{
|
|
1420
|
+
code: "BS205",
|
|
1421
|
+
severity: "warning",
|
|
1422
|
+
title: "Policy calls a slow function once per row",
|
|
1423
|
+
description: "A policy passes a column of the row to a function Postgres cannot inline: plpgsql, volatile, security definer, or with a `set` option such as `search_path`. It runs once for every row the query reads.",
|
|
1424
|
+
check: (context) => {
|
|
1425
|
+
const functions = functionsByName(context);
|
|
1426
|
+
return rlsTables$1(context).flatMap((table) => table.policies.flatMap((policy) => {
|
|
1427
|
+
for (const name of policy.functions ?? []) {
|
|
1428
|
+
const slow = functions.get(name)?.find((fn) => notInlinable(fn) !== void 0);
|
|
1429
|
+
if (!slow) continue;
|
|
1430
|
+
const column = expressions(policy).flatMap((expression) => callArguments(expression, slow)).map((args) => columnArgument(args, table)).find((found) => found !== void 0);
|
|
1431
|
+
if (!column) continue;
|
|
1432
|
+
const fix = slow.securityDefiner || Object.keys(slow.settings).length > 0 ? "" : `, or make it \`language sql stable\` so Postgres inlines it`;
|
|
1433
|
+
return [{
|
|
1434
|
+
message: `Policy "${policy.name}" on ${qualified(table)} calls ${name}(${column}), ${notInlinable(slow)}, with a column of the row, so it runs once per row. Have a helper return the allowed values once and compare: \`${column} in (select <helper>())\`${fix}.`,
|
|
1435
|
+
target: `${qualified(table)}.${policy.name}`,
|
|
1436
|
+
object: policyObject(table, policy)
|
|
1437
|
+
}];
|
|
1438
|
+
}
|
|
1439
|
+
return [];
|
|
1440
|
+
}));
|
|
1441
|
+
}
|
|
1442
|
+
},
|
|
1443
|
+
{
|
|
1444
|
+
code: "BS206",
|
|
1445
|
+
severity: "warning",
|
|
1446
|
+
title: "Security definer policy helper that cannot be inlined",
|
|
1447
|
+
description: "A security definer function is used in many policies. Postgres never inlines a security definer function, so a call that takes a column of the row runs once per row. Wrapped in `(select ...)`, or returning a set the policy compares with `in (select ...)`, it runs once per statement.",
|
|
1448
|
+
check: (context) => {
|
|
1449
|
+
const limit = context.config.doctor.policyHelperLimit;
|
|
1450
|
+
const functions = functionsByName(context);
|
|
1451
|
+
const uses = /* @__PURE__ */ new Map();
|
|
1452
|
+
for (const table of rlsTables$1(context)) for (const policy of table.policies) for (const name of policy.functions ?? []) {
|
|
1453
|
+
if (onlyWrapped(name, [policy.using, policy.check])) continue;
|
|
1454
|
+
const list = uses.get(name) ?? [];
|
|
1455
|
+
list.push(`${qualified(table)}.${policy.name}`);
|
|
1456
|
+
uses.set(name, list);
|
|
1457
|
+
}
|
|
1458
|
+
return [...uses].flatMap(([name, policies]) => {
|
|
1459
|
+
if (policies.length <= limit) return [];
|
|
1460
|
+
const fn = functions.get(name)?.find((candidate) => candidate.securityDefiner);
|
|
1461
|
+
if (!fn) return [];
|
|
1462
|
+
const shown = policies.slice(0, 5).join(", ");
|
|
1463
|
+
const more = policies.length > 5 ? ` and ${policies.length - 5} more` : "";
|
|
1464
|
+
return [{
|
|
1465
|
+
message: `${name} is a security definer ${fn.language} function used in ${policies.length} policies (${shown}${more}; the limit is ${limit}). Postgres can't inline it, so call it as \`(select ${name}(...))\` when its arguments don't come from the row, or return the allowed ids as a set and compare with \`column in (select ${name}())\`, so it runs once per statement.`,
|
|
1466
|
+
target: name,
|
|
1467
|
+
object: functionObject(fn)
|
|
1468
|
+
}];
|
|
1469
|
+
});
|
|
1470
|
+
}
|
|
1471
|
+
},
|
|
1472
|
+
{
|
|
1473
|
+
code: "BS207",
|
|
1474
|
+
severity: "warning",
|
|
1475
|
+
title: "Several permissive policies for one command and role",
|
|
1476
|
+
description: "Postgres evaluates every permissive policy that applies and ORs them, so each extra policy adds its cost to every row. Merge them into one policy per command and role. When the performance advisor (BS200) runs, splinter's `multiple_permissive_policies` reports a table it covers and this rule skips it; on a saved snapshot this rule reports every table.",
|
|
1477
|
+
check: async (context) => {
|
|
1478
|
+
const splinter = await splinterTables(context, "multiple_permissive_policies");
|
|
1479
|
+
return rlsTables$1(context).flatMap((table) => {
|
|
1480
|
+
if (splinter?.has(qualified(table))) return [];
|
|
1481
|
+
const overlaps = permissiveOverlaps(table);
|
|
1482
|
+
if (overlaps.length === 0) return [];
|
|
1483
|
+
const first = table.policies.find((policy) => policy.name === overlaps[0].policies[0]);
|
|
1484
|
+
const list = overlaps.map((overlap) => `${overlap.command} for ${overlap.role}: ${overlap.policies.join(", ")}`).join("; ");
|
|
1485
|
+
return [{
|
|
1486
|
+
message: `${qualified(table)} has several permissive policies per command and role (${list}). Postgres runs all of them for every row; merge each group into one policy.`,
|
|
1487
|
+
target: qualified(table),
|
|
1488
|
+
object: policyObject(table, first)
|
|
1489
|
+
}];
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
},
|
|
1493
|
+
{
|
|
1494
|
+
code: "BS213",
|
|
1495
|
+
severity: "warning",
|
|
1496
|
+
title: "API roles can write the columns that grant access",
|
|
1497
|
+
description: "RLS helpers decide access from columns such as `memberships.user_id`, `memberships.role` or `contacts.customer_id`, and an authorization provider lists them as `decidingColumns`. When `anon` or `authenticated` may insert or update one of them, and a policy lets them write the row, a user can grant themselves access. A table-level grant counts even after a column-level revoke. A single-column primary key, a tenant column every write policy pins to a tenant the caller acts in (`current_tenant_id()`, `can('tenant', column, ...)`, `tenant_ids_with(...)` or the membership helper `member_organization_ids()`, alone or next to a guest's grant from `portal_subjects()`), a subject's `deletedAt` column in `config.subjects` and a block's soft-delete column (they only hide rows) don't count unless the provider lists them.",
|
|
1498
|
+
check: (context) => {
|
|
1499
|
+
const tables = new Map(catalogOf(context).tables.map((table) => [qualified(table), table]));
|
|
1500
|
+
return [...grantColumns(context)].flatMap(([name, byColumn]) => {
|
|
1501
|
+
const table = tables.get(name);
|
|
1502
|
+
if (!table) return [];
|
|
1503
|
+
const columns = table.columns.map((column) => column.name).filter((column) => byColumn.has(column)).toSorted();
|
|
1504
|
+
const deciding = new Set(columns.filter((column) => byColumn.get(column).provider));
|
|
1505
|
+
const writes = [];
|
|
1506
|
+
const fix = [];
|
|
1507
|
+
for (const role of API_ROLES) {
|
|
1508
|
+
const tableLevel = [];
|
|
1509
|
+
const revoked = /* @__PURE__ */ new Set();
|
|
1510
|
+
for (const command of WRITES) {
|
|
1511
|
+
const writable = writableColumns(table, columns, command, role, deciding);
|
|
1512
|
+
if (writable.length === 0) continue;
|
|
1513
|
+
writes.push(`${role} may ${command} ${writable.join(", ")}`);
|
|
1514
|
+
const privilege = command.toUpperCase();
|
|
1515
|
+
if (table.grants.some((grant) => grantsTo(grant, role) && grant.privileges.includes(privilege))) {
|
|
1516
|
+
tableLevel.push(command);
|
|
1517
|
+
for (const column of writable) revoked.add(column);
|
|
1518
|
+
continue;
|
|
1519
|
+
}
|
|
1520
|
+
const fromPublic = (table.columnGrants ?? []).some((grant) => grant.role === "PUBLIC" && writable.includes(grant.column) && grant.privileges.includes(privilege));
|
|
1521
|
+
fix.push(`revoke ${command} (${writable.join(", ")}) on ${name} from ${fromPublic ? `${role}, public` : role};`);
|
|
1522
|
+
}
|
|
1523
|
+
if (tableLevel.length === 0) continue;
|
|
1524
|
+
const fromPublic = table.grants.some((grant) => grant.role === "PUBLIC" && tableLevel.some((command) => grant.privileges.includes(command.toUpperCase())));
|
|
1525
|
+
fix.push(`revoke ${tableLevel.join(", ")} on ${name} from ${fromPublic ? `${role}, public` : role};`);
|
|
1526
|
+
const rest = table.columns.map((column) => column.name).filter((column) => !revoked.has(column));
|
|
1527
|
+
if (rest.length > 0) fix.push(`grant ${tableLevel.map((command) => `${command} (${rest.join(", ")})`).join(", ")} on ${name} to ${role};`);
|
|
1528
|
+
}
|
|
1529
|
+
if (writes.length === 0) return [];
|
|
1530
|
+
const helpers = [...new Set(columns.flatMap((column) => [...byColumn.get(column).helpers]))].toSorted();
|
|
1531
|
+
const listed = [...deciding];
|
|
1532
|
+
const readers = [...helpers.length > 0 ? [`${helpers.join(", ")} read${helpers.length === 1 ? "s" : ""} them to decide access`] : [], ...listed.length > 0 ? [`the authorization provider lists ${listed.join(", ")} as deciding columns`] : []].join(", and ");
|
|
1533
|
+
return [{
|
|
1534
|
+
message: `${name}: ${writes.join("; ")}. ${readers}, so a user who writes them can grant themselves access. Revoke the columns and grant the rest:\n${fix.join("\n")}`,
|
|
1535
|
+
target: name,
|
|
1536
|
+
object: tableObject(table)
|
|
1537
|
+
}];
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
},
|
|
1541
|
+
{
|
|
1542
|
+
code: "BS211",
|
|
1543
|
+
severity: "info",
|
|
1544
|
+
title: "Statement timeouts for the Data API roles",
|
|
1545
|
+
description: "PostgREST switches to `anon` or `authenticated` for each request, so their `statement_timeout` limits Data API queries. A function's own `set statement_timeout` only applies when PostgREST hoists it (`pgrst.db_hoisted_tx_settings`). `idle_in_transaction_session_timeout` ends sessions that leave a transaction open; it applies to the role a connection logs in as.",
|
|
1546
|
+
check: (context) => {
|
|
1547
|
+
const settings = context.snapshot.extras.roleSettings;
|
|
1548
|
+
if (!settings) return [];
|
|
1549
|
+
const values = (setting) => TIMEOUT_ROLES.map((role) => `${role} ${settings[role]?.[setting] ?? "not set"}`).join(", ");
|
|
1550
|
+
const findings = [{
|
|
1551
|
+
message: `statement_timeout: ${values("statement_timeout")}. idle_in_transaction_session_timeout: ${values("idle_in_transaction_session_timeout")}. Unset roles use the database default.`,
|
|
1552
|
+
target: "roles:statement_timeout"
|
|
1553
|
+
}];
|
|
1554
|
+
const configured = settings["authenticator"]?.["pgrst.db_hoisted_tx_settings"];
|
|
1555
|
+
if ((configured ? configured.split(",").map((setting) => setting.trim()) : DEFAULT_HOISTED).includes("statement_timeout")) return findings;
|
|
1556
|
+
for (const fn of context.snapshot.extras.functions ?? []) {
|
|
1557
|
+
const timeout = fn.settings["statement_timeout"];
|
|
1558
|
+
if (!timeout || !context.config.schemas.includes(fn.schema)) continue;
|
|
1559
|
+
findings.push({
|
|
1560
|
+
severity: "warning",
|
|
1561
|
+
message: `${functionName(fn)}(${fn.signature}) sets statement_timeout = ${timeout}, but pgrst.db_hoisted_tx_settings (${configured}) leaves it out, so the setting doesn't limit the RPC. Add statement_timeout to it, or set the timeout on the role.`,
|
|
1562
|
+
target: `${functionName(fn)}:statement_timeout`,
|
|
1563
|
+
object: functionObject(fn)
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
return findings;
|
|
1567
|
+
}
|
|
1568
|
+
},
|
|
1569
|
+
{
|
|
1570
|
+
code: "BS224",
|
|
1571
|
+
severity: "warning",
|
|
1572
|
+
title: "Data API role without a timeout",
|
|
1573
|
+
description: "Without `statement_timeout`, one slow Data API query holds a connection until it finishes; without `idle_in_transaction_session_timeout`, a client that leaves a transaction open holds its locks. PostgREST applies the settings of `anon` and `authenticated` to each request, and the login role's (`authenticator`) apply when the request role sets none, so doctor accepts either. A value of 0 turns the timeout off and counts as unset.",
|
|
1574
|
+
check: (context) => {
|
|
1575
|
+
const settings = context.snapshot.extras.roleSettings;
|
|
1576
|
+
if (!settings) return [];
|
|
1577
|
+
const value = (role, setting) => {
|
|
1578
|
+
const set = settings[role]?.[setting];
|
|
1579
|
+
return set === void 0 || /^0(?:\s*m?s)?$/i.test(set.trim()) ? void 0 : set;
|
|
1580
|
+
};
|
|
1581
|
+
const example = {
|
|
1582
|
+
statement_timeout: "'8s'",
|
|
1583
|
+
idle_in_transaction_session_timeout: "'60s'"
|
|
1584
|
+
};
|
|
1585
|
+
return ["anon", "authenticated"].flatMap((role) => Object.keys(example).filter((setting) => value(role, setting) === void 0 && value("authenticator", setting) === void 0).map((setting) => ({
|
|
1586
|
+
message: `${role} has no ${setting}, and authenticator sets none either, so a Data API request as ${role} has no limit. Run \`alter role ${role} set ${setting} = ${example[setting]};\` in a migration, then \`notify pgrst, 'reload config';\`.`,
|
|
1587
|
+
target: `${role}:${setting}`
|
|
1588
|
+
})));
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
];
|
|
1592
|
+
//#endregion
|
|
1593
|
+
//#region src/cli/doctor/authorization.ts
|
|
1594
|
+
const TEMPLATE_EFFECT = {
|
|
1595
|
+
memberIds: "their membership checks read the tenant module's memberships table instead of the provider",
|
|
1596
|
+
idsWithFor: "their checks of another user's tenant permissions (can_user, member_can) raise 0A000 (ACCESS_CALLER_ONLY) or are skipped",
|
|
1597
|
+
isPlatformFor: "their checks of another user's platform permissions (platform_can) answer false or are skipped",
|
|
1598
|
+
canAssignFor: "better_supabase.can_assign_as is not written and the inviter's right to assign the role is not checked again when the invitation is accepted"
|
|
1599
|
+
};
|
|
1600
|
+
/** The optional templates installed modules call that the provider doesn't set. */
|
|
1601
|
+
function missingTemplates(context, provider) {
|
|
1602
|
+
const installed = new Set(context.config.blockNames);
|
|
1603
|
+
const callers = /* @__PURE__ */ new Map();
|
|
1604
|
+
for (const module of Object.values(SQL_MODULES)) {
|
|
1605
|
+
if (!installed.has(module.name)) continue;
|
|
1606
|
+
for (const name of module.providerFunctions ?? []) {
|
|
1607
|
+
if (provider.functions[name] !== void 0) continue;
|
|
1608
|
+
if (name === "canAssignFor" && context.config.blocks.access?.functions?.canAssignFor) continue;
|
|
1609
|
+
callers.set(name, [...callers.get(name) ?? [], module.name]);
|
|
1610
|
+
}
|
|
1611
|
+
}
|
|
1612
|
+
return [...callers].map(([name, modules]) => ({
|
|
1613
|
+
severity: "warning",
|
|
1614
|
+
message: `The ${modules.join(", ")} ${modules.length > 1 ? "modules call" : "module calls"} authorization.functions.${name}, which ${providerLabel(provider)} doesn't set, so under the provider model ${TEMPLATE_EFFECT[name] ?? "those calls fail"}. Use a provider that sets ${name}${name === "canAssignFor" ? ", or set blocks.access.functions.canAssignFor" : ""}.`,
|
|
1615
|
+
target: `authorization.functions.${name}`
|
|
1616
|
+
}));
|
|
1617
|
+
}
|
|
1618
|
+
/**
|
|
1619
|
+
* Tables whose generated policies call the provider's functions by role and
|
|
1620
|
+
* scope only.
|
|
1621
|
+
*/
|
|
1622
|
+
const SUPPORT_SESSION_APPROVAL = "support-session";
|
|
1623
|
+
const POLICY_TABLES = /* @__PURE__ */ new Set(["storage.objects", "realtime.messages"]);
|
|
1624
|
+
const POLICY = /create\s+policy\s+("(?:[^"]|"")+"|[\w$]+)\s+on\s+((?:"[^"]+"|\w+)\s*\.\s*(?:"[^"]+"|\w+))([\s\S]*?);/gi;
|
|
1625
|
+
const unquote = (name) => name.replaceAll(/^"|"$/g, "").replaceAll("\"\"", "\"");
|
|
1626
|
+
const escapeRegExp = (text) => text.replaceAll(/[.*+?^${}()|[\]\\]/g, String.raw`\$&`);
|
|
1627
|
+
/**
|
|
1628
|
+
* A pattern for a filled template: `{permission}` captures the key literal
|
|
1629
|
+
* (optionally passed by name), `{scope}` captures the scope name, and
|
|
1630
|
+
* whitespace may differ.
|
|
1631
|
+
*/
|
|
1632
|
+
function templatePattern(template) {
|
|
1633
|
+
const source = template.split(/(\{\w+\})/).map((part) => {
|
|
1634
|
+
if (part === "{permission}") return String.raw`(?:\w+\s*=>\s*)?'((?:[^']|'')*)'`;
|
|
1635
|
+
if (part === "{scope}") return "([a-z][a-z0-9_]*)";
|
|
1636
|
+
if (/^\{\w+\}$/.test(part)) return String.raw`[\s\S]*?`;
|
|
1637
|
+
return escapeRegExp(part.trim()).replaceAll(/\s+/g, String.raw`\s*`);
|
|
1638
|
+
}).filter((part) => part !== "").join(String.raw`\s*`);
|
|
1639
|
+
return new RegExp(source, "gi");
|
|
1640
|
+
}
|
|
1641
|
+
/**
|
|
1642
|
+
* The keys and scopes a policy body passes to the provider's `idsWith` and
|
|
1643
|
+
* `isPlatform`.
|
|
1644
|
+
*/
|
|
1645
|
+
function providerCalls(provider, body) {
|
|
1646
|
+
const calls = [];
|
|
1647
|
+
const { idsWith, isPlatform } = provider.functions;
|
|
1648
|
+
const groups = (template) => [...template.matchAll(/\{(permission|scope)\}/g)].map((match) => match[1]);
|
|
1649
|
+
const idsGroups = groups(idsWith);
|
|
1650
|
+
for (const match of body.matchAll(templatePattern(idsWith))) {
|
|
1651
|
+
const key = match[idsGroups.indexOf("permission") + 1];
|
|
1652
|
+
if (key === void 0) continue;
|
|
1653
|
+
const scopeIndex = idsGroups.indexOf("scope");
|
|
1654
|
+
calls.push({
|
|
1655
|
+
key: key.replaceAll("''", "'"),
|
|
1656
|
+
scope: scopeIndex === -1 ? provider.tenantScope : match[scopeIndex + 1]
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
const platformGroups = groups(isPlatform);
|
|
1660
|
+
for (const match of body.matchAll(templatePattern(isPlatform))) {
|
|
1661
|
+
const key = match[platformGroups.indexOf("permission") + 1];
|
|
1662
|
+
if (key !== void 0) calls.push({
|
|
1663
|
+
key: key.replaceAll("''", "'"),
|
|
1664
|
+
scope: "platform"
|
|
1665
|
+
});
|
|
1666
|
+
}
|
|
1667
|
+
return calls;
|
|
1668
|
+
}
|
|
1669
|
+
/**
|
|
1670
|
+
* Policies better-supabase generates (`bs_` names) on `storage.objects` and
|
|
1671
|
+
* `realtime.messages` that call the provider's templates, with the keys they
|
|
1672
|
+
* pass. The first file that declares a policy wins, matching the `sqlFiles`
|
|
1673
|
+
* order (declarative schemas, then the newest migration).
|
|
1674
|
+
*/
|
|
1675
|
+
function providerPolicies(provider, files) {
|
|
1676
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1677
|
+
const found = [];
|
|
1678
|
+
for (const file of files) for (const match of file.text.matchAll(POLICY)) {
|
|
1679
|
+
const name = unquote(match[1]);
|
|
1680
|
+
const table = match[2].split(".").map((part) => unquote(part.trim())).join(".");
|
|
1681
|
+
if (!POLICY_TABLES.has(table) || !name.startsWith("bs_")) continue;
|
|
1682
|
+
const id = `${table}.${name}`;
|
|
1683
|
+
if (seen.has(id)) continue;
|
|
1684
|
+
seen.add(id);
|
|
1685
|
+
const calls = providerCalls(provider, match[3]);
|
|
1686
|
+
if (calls.length === 0) continue;
|
|
1687
|
+
found.push({
|
|
1688
|
+
name,
|
|
1689
|
+
table,
|
|
1690
|
+
calls,
|
|
1691
|
+
file: file.path,
|
|
1692
|
+
line: file.text.slice(0, match.index).split("\n").length
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1695
|
+
return found;
|
|
1696
|
+
}
|
|
1697
|
+
/**
|
|
1698
|
+
* `buckets` entries whose access policy reaches the provider's functions:
|
|
1699
|
+
* through `sql` templates, or through the access contract under the `provider`
|
|
1700
|
+
* model. Their keys and scope (the tenant scope for `tenant`).
|
|
1701
|
+
*/
|
|
1702
|
+
function providerBucketKeys(config) {
|
|
1703
|
+
const provider = config.authorization;
|
|
1704
|
+
if (!provider) return [];
|
|
1705
|
+
const providerModel = config.blocks.access?.model === "provider";
|
|
1706
|
+
return Object.entries(config.buckets).flatMap(([bucket, entry]) => {
|
|
1707
|
+
const policy = entry.policy;
|
|
1708
|
+
if (policy === void 0 || typeof policy === "string") return [];
|
|
1709
|
+
if (policy.sql === void 0 && !providerModel) return [];
|
|
1710
|
+
const scope = policy.scope ?? "tenant";
|
|
1711
|
+
return [{
|
|
1712
|
+
bucket,
|
|
1713
|
+
keys: [...new Set(Object.values(policy.access).filter((key) => typeof key === "string"))],
|
|
1714
|
+
scope: scope === "tenant" ? provider.tenantScope : scope
|
|
1715
|
+
}];
|
|
1716
|
+
});
|
|
1717
|
+
}
|
|
1718
|
+
/**
|
|
1719
|
+
* Why a policy's scope can't work with the provider: a scope it doesn't
|
|
1720
|
+
* declare, or a key it grants only at other scopes.
|
|
1721
|
+
*/
|
|
1722
|
+
function placementProblems(provider, call, where) {
|
|
1723
|
+
if (call.scope === "platform") return [];
|
|
1724
|
+
const label = providerLabel(provider);
|
|
1725
|
+
if (!provider.scopes.some((scope) => scope.name === call.scope)) return [`${where} uses scope "${call.scope}", which ${label} doesn't declare. Use one of ${provider.scopes.map((scope) => scope.name).join(", ") || "its scopes"}.`];
|
|
1726
|
+
const declared = provider.permissions?.find((permission) => permission.key === call.key)?.scopes;
|
|
1727
|
+
if (!declared || declared.length === 0 || declared.includes(call.scope)) return [];
|
|
1728
|
+
return [`${where} checks "${call.key}" at scope "${call.scope}", but ${label} grants it at ${declared.map((scope) => `"${scope}"`).join(", ")}, so its SQL functions never grant it there. Use scope "${declared[0]}".`];
|
|
1729
|
+
}
|
|
1730
|
+
/**
|
|
1731
|
+
* The provider's memberships for the `entitlements` SQL module, when that mode
|
|
1732
|
+
* is valid.
|
|
1733
|
+
*/
|
|
1734
|
+
function entitlementsModule(context) {
|
|
1735
|
+
const mode = entitlementsMode(context.config);
|
|
1736
|
+
return mode.kind === "provider" ? mode.provider : void 0;
|
|
1737
|
+
}
|
|
1738
|
+
/**
|
|
1739
|
+
* The provider for the `provider` access model, when `blocks` installs
|
|
1740
|
+
* `access`.
|
|
1741
|
+
*/
|
|
1742
|
+
function accessModule(context) {
|
|
1743
|
+
if (!resolveModules(context.config.blockNames, {}).some((module) => module.name === "access")) return { kind: "off" };
|
|
1744
|
+
return accessProviderMode(context.config);
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* Checks a function a template calls against `authorization.requires` and the
|
|
1748
|
+
* database: listed, executable by `role`, and present when the snapshot read
|
|
1749
|
+
* its schema. `undefined` when it passes.
|
|
1750
|
+
*/
|
|
1751
|
+
function requirementProblem(context, provider, requirement, caller) {
|
|
1752
|
+
const label = providerLabel(provider);
|
|
1753
|
+
const listed = (provider.requires ?? []).filter((entry) => entry.function === requirement.function);
|
|
1754
|
+
if (provider.requires !== void 0 && listed.length === 0) return { message: `${caller} calls ${requirement.function}, but ${label} doesn't list it in authorization.requires. Use a provider version that lists every function its templates call.` };
|
|
1755
|
+
if (listed.length > 0 && !listed.some((entry) => entry.role === requirement.role)) return { message: `${label} says only ${listed.map((entry) => entry.role).join(", ")} may execute ${requirement.function}, but ${caller} calls it as ${requirement.role}. Grant it execute to ${requirement.role} through the provider.` };
|
|
1756
|
+
const schema = requirement.function.slice(0, requirement.function.indexOf("."));
|
|
1757
|
+
if (!context.snapshot.schemas.includes(schema)) return;
|
|
1758
|
+
return catalogOf(context).functions.some((fn) => `${fn.schema}.${fn.name}` === requirement.function) ? void 0 : { message: `${requirement.function} is not in the database, but ${caller} calls it. Apply the provider's migration before the SQL modules.` };
|
|
1759
|
+
}
|
|
1760
|
+
const AUTHORIZATION_RULES = [
|
|
1761
|
+
{
|
|
1762
|
+
code: "BS214",
|
|
1763
|
+
severity: "error",
|
|
1764
|
+
title: "Permission the provider's SQL functions don't fully answer in a Storage or Realtime policy",
|
|
1765
|
+
description: "An access policy on a bucket or topic that reaches the authorization provider's functions (through `sql` templates, or through the access contract under the `provider` model) decides by role and scope only. A permission whose `authorization.permissions` entry isn't `sqlComplete: true` would grant every object or topic in the scope, so it is reported, and so is a key the provider doesn't list or every key when it lists no permissions. A scope the provider doesn't declare, and a key checked at another scope than its entry's `scopes`, are reported too. Doctor reads the keys from `buckets` in the config and from the generated `bs_` policies on `storage.objects` and `realtime.messages`. It also warns when a bucket's `sql` templates differ from the provider's `idsWith` and `isPlatform`, since a copy goes stale when the provider changes; `sql: \"provider\"` renders them at `gen` time instead.",
|
|
1766
|
+
check: (context) => {
|
|
1767
|
+
const provider = context.config.authorization;
|
|
1768
|
+
if (!provider) return [];
|
|
1769
|
+
const findings = [];
|
|
1770
|
+
for (const { bucket, keys, scope } of providerBucketKeys(context.config)) for (const key of keys) {
|
|
1771
|
+
for (const message of placementProblems(provider, {
|
|
1772
|
+
key,
|
|
1773
|
+
scope
|
|
1774
|
+
}, `buckets.${bucket} ("${key}")`)) findings.push({
|
|
1775
|
+
message,
|
|
1776
|
+
target: `buckets.${bucket}:${key}`
|
|
1777
|
+
});
|
|
1778
|
+
const problem = unsafeKey(provider, key);
|
|
1779
|
+
if (!problem) continue;
|
|
1780
|
+
findings.push({
|
|
1781
|
+
message: `buckets.${bucket} uses "${key}", which ${problem.reason}. The bucket policy could grant every object in the scope. ${problem.fix}`,
|
|
1782
|
+
target: `buckets.${bucket}:${key}`
|
|
1783
|
+
});
|
|
1784
|
+
}
|
|
1785
|
+
for (const [bucket, entry] of Object.entries(context.config.buckets)) {
|
|
1786
|
+
const sql = typeof entry.policy === "object" ? entry.policy.sql : void 0;
|
|
1787
|
+
if (typeof sql !== "object") continue;
|
|
1788
|
+
const stale = ["idsWith", "isPlatform"].filter((name) => sql[name] !== provider.functions[name]);
|
|
1789
|
+
if (stale.length === 0) continue;
|
|
1790
|
+
findings.push({
|
|
1791
|
+
severity: "warning",
|
|
1792
|
+
message: `buckets.${bucket} copies sql templates that differ from ${providerLabel(provider)}'s ${stale.join(" and ")}. Set sql: "provider" so gen renders the provider's templates.`,
|
|
1793
|
+
target: `buckets.${bucket}.policy.sql`
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
for (const policy of providerPolicies(provider, context.sqlFiles ?? [])) {
|
|
1797
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1798
|
+
for (const call of policy.calls) for (const message of placementProblems(provider, call, `Policy "${policy.name}" on ${policy.table}`)) {
|
|
1799
|
+
if (seen.has(message)) continue;
|
|
1800
|
+
seen.add(message);
|
|
1801
|
+
findings.push({
|
|
1802
|
+
message,
|
|
1803
|
+
target: `${policy.table}.${policy.name}:${call.key}`,
|
|
1804
|
+
location: {
|
|
1805
|
+
file: policy.file,
|
|
1806
|
+
line: policy.line
|
|
1807
|
+
}
|
|
1808
|
+
});
|
|
1809
|
+
}
|
|
1810
|
+
for (const key of new Set(policy.calls.map((call) => call.key))) {
|
|
1811
|
+
const problem = unsafeKey(provider, key);
|
|
1812
|
+
if (!problem) continue;
|
|
1813
|
+
findings.push({
|
|
1814
|
+
message: `Policy "${policy.name}" on ${policy.table} passes "${key}" to the provider's SQL functions, but it ${problem.reason}. ${problem.fix}`,
|
|
1815
|
+
target: `${policy.table}.${policy.name}:${key}`,
|
|
1816
|
+
location: {
|
|
1817
|
+
file: policy.file,
|
|
1818
|
+
line: policy.line
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
return findings;
|
|
1824
|
+
}
|
|
1825
|
+
},
|
|
1826
|
+
{
|
|
1827
|
+
code: "BS408",
|
|
1828
|
+
severity: "warning",
|
|
1829
|
+
title: "The entitlements module can't read the provider's memberships",
|
|
1830
|
+
description: "With `entitlements.memberships: 'provider'` (the default with `authorization`), the `entitlements` SQL module reads memberships through the provider's `memberIds` template (in `has_entitlement`, as `authenticated`) and `memberIdsFor` (in `feature_claims`, which the provider's hook calls as `supabase_auth_admin`). Doctor warns when the provider can't back that mode (no tenant scope, an id type the module doesn't render, no `memberIds` or `memberIdsFor`), when its hook doesn't fill `claims.features` from `better_supabase.feature_claims` (unless `entitlements.claim` is `false`), when no membership table covers the tenant scope, and when a function those templates call is missing from `authorization.requires`, not executable by that role, or not in the database.",
|
|
1831
|
+
check: (context) => {
|
|
1832
|
+
if (!context.config.blockNames.includes("entitlements")) return [];
|
|
1833
|
+
const mode = entitlementsMode(context.config);
|
|
1834
|
+
if (mode.kind === "tenant") return [];
|
|
1835
|
+
if (mode.kind === "invalid") return [{
|
|
1836
|
+
message: mode.problem,
|
|
1837
|
+
target: "entitlements.memberships"
|
|
1838
|
+
}];
|
|
1839
|
+
const provider = context.config.authorization;
|
|
1840
|
+
const label = providerLabel(provider);
|
|
1841
|
+
const findings = [];
|
|
1842
|
+
const features = context.config.claims.features;
|
|
1843
|
+
const hook = provider.tokenHook;
|
|
1844
|
+
if (hook && context.config.entitlements.claim !== false) {
|
|
1845
|
+
const claims = hook.registeredClaims ?? [];
|
|
1846
|
+
const featureClaim = claims.find((claim) => claim.name === features);
|
|
1847
|
+
if (featureClaim?.function !== "better_supabase.feature_claims") {
|
|
1848
|
+
const registered = claims.find((claim) => claim.function === "better_supabase.feature_claims");
|
|
1849
|
+
findings.push({
|
|
1850
|
+
message: registered ? `The hook of ${label} fills the "${registered.name}" claim from better_supabase.feature_claims, but claims.features is "${features}", so hasEntitlement() never finds the plan features. Set claims.features to "${registered.name}".` : featureClaim ? `The hook of ${label} fills the "${features}" claim from ${featureClaim.function}, not better_supabase.feature_claims, so the claim doesn't carry the entitlements module's features. Point the provider's "${features}" claim at better_supabase.feature_claims.` : `The hook of ${label} has no "${features}" claim, so it never writes the plan features hasEntitlement() reads. Have it fill "${features}" from better_supabase.feature_claims, or set \`entitlements.claim: false\` to keep the features out of the token and check them in SQL with has_entitlement.`,
|
|
1851
|
+
target: `claims.${features}`
|
|
1852
|
+
});
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
const scope = mode.provider.scope;
|
|
1856
|
+
if (provider.memberships === void 0) findings.push({
|
|
1857
|
+
severity: "info",
|
|
1858
|
+
message: `${label} lists no authorization.memberships, so entitlement_members() can't tell which tables hold "${scope}" memberships and plan changes never invalidate sessions.`,
|
|
1859
|
+
target: "authorization.memberships"
|
|
1860
|
+
});
|
|
1861
|
+
else if (mode.provider.memberships.length === 0) findings.push({
|
|
1862
|
+
message: `${label} maps no membership table to scope "${scope}", so entitlement_members() finds no users and plan changes never invalidate sessions. Add a membership table for "${scope}" to the provider.`,
|
|
1863
|
+
target: "authorization.memberships"
|
|
1864
|
+
});
|
|
1865
|
+
for (const requirement of entitlementRequirements(mode.provider)) {
|
|
1866
|
+
const problem = requirementProblem(context, provider, requirement, requirement.caller);
|
|
1867
|
+
if (!problem) continue;
|
|
1868
|
+
findings.push({
|
|
1869
|
+
...requirement.kind === "member-for" && problem.message.includes("may execute") ? { severity: "info" } : {},
|
|
1870
|
+
message: problem.message,
|
|
1871
|
+
target: requirement.function
|
|
1872
|
+
});
|
|
1873
|
+
}
|
|
1874
|
+
return findings;
|
|
1875
|
+
}
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
code: "BS409",
|
|
1879
|
+
severity: "warning",
|
|
1880
|
+
title: "The authorization provider and the better-supabase config disagree",
|
|
1881
|
+
description: "The provider's hook writes the active tenant to `tokenHook.tenantClaim`, and its tenant scope is `tenantScope`. Doctor warns when `claims.tenant` names another claim (the tenant plugin, guards and RLS would read a claim the hook never writes), notes when `claims.scope` is neither `tenant` nor the provider's tenant scope, notes when the provider sets `suspension` or `roleSources` but `blocks.access.model` is not `provider` (only that model reads them), and reports the `problems` the provider found while it was built.",
|
|
1882
|
+
check: (context) => {
|
|
1883
|
+
const provider = context.config.authorization;
|
|
1884
|
+
if (!provider) return [];
|
|
1885
|
+
const label = providerLabel(provider);
|
|
1886
|
+
const findings = (provider.problems ?? []).map((problem) => ({
|
|
1887
|
+
message: `${label}: ${problem}`,
|
|
1888
|
+
target: "authorization"
|
|
1889
|
+
}));
|
|
1890
|
+
const tenantClaim = provider.tokenHook?.tenantClaim;
|
|
1891
|
+
if (tenantClaim !== void 0 && tenantClaim !== context.config.claims.tenant) findings.push({
|
|
1892
|
+
message: `The hook of ${label} writes the active tenant to "${tenantClaim}", but claims.tenant is "${context.config.claims.tenant}". Set claims.tenant to "${tenantClaim}", or change the provider's tenant claim.`,
|
|
1893
|
+
target: "claims.tenant"
|
|
1894
|
+
});
|
|
1895
|
+
const scope = context.config.claims.scope;
|
|
1896
|
+
if (scope !== "tenant" && scope !== provider.tenantScope) findings.push({
|
|
1897
|
+
severity: "info",
|
|
1898
|
+
message: `claims.scope is "${scope}", but the tenant scope of ${label} is "${provider.tenantScope}". The tenant module's membership claims then use another scope than the provider's. Set claims.scope to "${provider.tenantScope}" (or "tenant").`,
|
|
1899
|
+
target: "claims.scope"
|
|
1900
|
+
});
|
|
1901
|
+
const model = context.config.blocks.access?.model ?? "roles";
|
|
1902
|
+
const unread = [...provider.suspension ? ["suspension"] : [], ...provider.roleSources && provider.roleSources.length > 0 ? ["roleSources"] : []];
|
|
1903
|
+
if (model !== "provider" && unread.length > 0) findings.push({
|
|
1904
|
+
severity: "info",
|
|
1905
|
+
message: `${label} sets ${unread.join(" and ")}, but blocks.access.model is "${model}", so the SQL modules ignore ${unread.length > 1 ? "them" : "it"}. Set blocks.access.model to "provider" to use them, or set blocks.access.disabled yourself.`,
|
|
1906
|
+
target: `authorization.${unread[0]}`
|
|
1907
|
+
});
|
|
1908
|
+
return findings;
|
|
1909
|
+
}
|
|
1910
|
+
},
|
|
1911
|
+
{
|
|
1912
|
+
code: "BS411",
|
|
1913
|
+
severity: "error",
|
|
1914
|
+
title: "The provider access model can't use the authorization provider",
|
|
1915
|
+
description: "With `blocks.access.model: 'provider'`, the `access` module fills the provider's `idsWith` template for tenant checks and `isPlatform` for platform checks, at its tenant scope. Doctor reports a config without `authorization`, a tenant scope or id type the module can't render, a function those templates call that `authorization.requires` doesn't list, doesn't let `authenticated` execute or the database lacks, and every module permission key (from `modulePermissionKeys`) the provider doesn't mark `sqlComplete: true`, since its functions are trusted with role and scope only. It warns when neither `blocks.access.functions.canAssign` nor the provider's `canAssign` is set, because only the service role then assigns roles, and when an installed module calls a template the provider doesn't set (`idsWithFor` and `isPlatformFor` to check another user, `canAssignFor` to recheck an inviter).",
|
|
1916
|
+
check: (context) => {
|
|
1917
|
+
const mode = accessModule(context);
|
|
1918
|
+
if (mode.kind === "off") return [];
|
|
1919
|
+
if (mode.kind === "invalid") return [{
|
|
1920
|
+
message: mode.problem,
|
|
1921
|
+
target: "authorization"
|
|
1922
|
+
}];
|
|
1923
|
+
const provider = context.config.authorization;
|
|
1924
|
+
const findings = [];
|
|
1925
|
+
for (const requirement of accessRequirements(mode.access)) {
|
|
1926
|
+
const problem = requirementProblem(context, provider, requirement, "the provider access model (can() and the SQL modules)");
|
|
1927
|
+
if (problem) findings.push({
|
|
1928
|
+
message: problem.message,
|
|
1929
|
+
target: requirement.function
|
|
1930
|
+
});
|
|
1931
|
+
}
|
|
1932
|
+
findings.push(...moduleKeyProblems(provider, modulePermissionKeys(context.config.blocks, context.config.blockNames)));
|
|
1933
|
+
if ((context.config.blocks.access?.functions?.canAssign ?? provider.functions.canAssign) === void 0) findings.push({
|
|
1934
|
+
severity: "warning",
|
|
1935
|
+
message: `Neither blocks.access.functions.canAssign nor ${providerLabel(provider)} sets canAssign, so under the provider model only the service role assigns roles: the memberships guard refuses every membership a member adds or changes. Use a provider that sets authorization.functions.canAssign, or set blocks.access.functions.canAssign.`,
|
|
1936
|
+
target: "blocks.access.functions.canAssign"
|
|
1937
|
+
});
|
|
1938
|
+
findings.push(...missingTemplates(context, provider));
|
|
1939
|
+
return findings;
|
|
1940
|
+
}
|
|
1941
|
+
},
|
|
1942
|
+
{
|
|
1943
|
+
code: "BS413",
|
|
1944
|
+
severity: "warning",
|
|
1945
|
+
title: "Support sessions are not tied to the provider's read-only check",
|
|
1946
|
+
description: "Support sessions default to read-only. Write functions refuse them through the built-in act check, or through authorization.functions.actorMayWrite when the provider sets it. With the provider access model, doctor warns when support is installed and actorMayWrite is missing, so the provider's helper is not the one the writes call.",
|
|
1947
|
+
check: (context) => {
|
|
1948
|
+
if (!context.config.blockNames.includes("support-sessions")) return [];
|
|
1949
|
+
if ((context.config.blocks.access?.model ?? "roles") !== "provider") return [];
|
|
1950
|
+
const provider = context.config.authorization;
|
|
1951
|
+
if (provider === void 0 || provider.functions.actorMayWrite !== void 0) return [];
|
|
1952
|
+
return [{
|
|
1953
|
+
message: `Support sessions are installed and blocks.access.model is "provider", but ${providerLabel(provider)} does not set authorization.functions.actorMayWrite. Writes use the built-in act check. Set actorMayWrite to the provider's read-only helper.`,
|
|
1954
|
+
target: "authorization.functions.actorMayWrite"
|
|
1955
|
+
}];
|
|
1956
|
+
}
|
|
1957
|
+
},
|
|
1958
|
+
{
|
|
1959
|
+
code: "BS414",
|
|
1960
|
+
severity: "warning",
|
|
1961
|
+
title: "Access contract answers from built-in roles next to a provider",
|
|
1962
|
+
description: "With `authorization` set, `blocks.access.model` defaults to `provider`, so `better_supabase.can()` and `better_supabase.tenant_ids_with()` answer from the provider's templates. When the config sets another model, those functions answer from the built-in roles instead, which the provider never sees. Doctor reports each policy and each function in `schemas` that calls them, so a check that looks provider-backed is not silently role-backed.",
|
|
1963
|
+
check: (context) => {
|
|
1964
|
+
const provider = context.config.authorization;
|
|
1965
|
+
const model = context.config.blocks.access?.model;
|
|
1966
|
+
if (provider === void 0 || !context.config.blockNames.includes("access") || model === void 0 || model === "provider") return [];
|
|
1967
|
+
const why = `blocks.access.model is "${model}", so it answers from the built-in roles, not ${providerLabel(provider)}. Remove the model to use the provider, or call the provider's function directly.`;
|
|
1968
|
+
const findings = [];
|
|
1969
|
+
for (const table of catalogOf(context).tables) for (const policy of table.policies) {
|
|
1970
|
+
const calls = contractCalls(`${policy.using ?? ""} ${policy.check ?? ""}`);
|
|
1971
|
+
if (calls.length === 0) continue;
|
|
1972
|
+
findings.push({
|
|
1973
|
+
message: `Policy "${policy.name}" on ${qualified(table)} calls ${calls.join(" and ")}, but ${why}`,
|
|
1974
|
+
target: `${qualified(table)}.${policy.name}`,
|
|
1975
|
+
object: policyObject(table, policy)
|
|
1976
|
+
});
|
|
1977
|
+
}
|
|
1978
|
+
for (const fn of context.snapshot.generator.functions) {
|
|
1979
|
+
if (fn.schema === "better_supabase" || !context.config.schemas.includes(fn.schema) || !fn.definition) continue;
|
|
1980
|
+
const calls = contractCalls(fn.definition);
|
|
1981
|
+
if (calls.length === 0) continue;
|
|
1982
|
+
findings.push({
|
|
1983
|
+
message: `${fn.schema}.${fn.name} calls ${calls.join(" and ")}, but ${why}`,
|
|
1984
|
+
target: `${fn.schema}.${fn.name}`
|
|
1985
|
+
});
|
|
1986
|
+
}
|
|
1987
|
+
return findings;
|
|
1988
|
+
}
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
code: "BS334",
|
|
1992
|
+
severity: "info",
|
|
1993
|
+
title: "A policy checks a role name instead of a permission",
|
|
1994
|
+
description: "`member_organization_ids()`, `has_organization_role()` and `organization_member_role()` answer by role name. Under an authorization provider they take membership from its `memberIds`, but a role list in the policy still names roles the provider may not have. `better_supabase.tenant_ids_with('<permission>')` and `member_can()` check a permission, so they follow renames, the provider and the delegation cap. Doctor reports each app policy and each function in `schemas` that calls a role helper.",
|
|
1995
|
+
check: (context) => {
|
|
1996
|
+
if (!context.config.blockNames.includes("tenant")) return [];
|
|
1997
|
+
const findings = [];
|
|
1998
|
+
const advice = "check a permission with better_supabase.tenant_ids_with('<permission>') or member_can() instead, so it follows the provider and the delegation cap.";
|
|
1999
|
+
for (const table of catalogOf(context).tables) {
|
|
2000
|
+
if (table.schema === "better_supabase") continue;
|
|
2001
|
+
for (const policy of table.policies) {
|
|
2002
|
+
if (policy.name.startsWith("bs_")) continue;
|
|
2003
|
+
const calls = roleHelperCalls(`${policy.using ?? ""} ${policy.check ?? ""}`);
|
|
2004
|
+
if (calls.length === 0) continue;
|
|
2005
|
+
findings.push({
|
|
2006
|
+
message: `Policy "${policy.name}" on ${qualified(table)} calls ${calls.join(" and ")}; ${advice}`,
|
|
2007
|
+
target: `${qualified(table)}.${policy.name}`,
|
|
2008
|
+
object: policyObject(table, policy)
|
|
2009
|
+
});
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
for (const fn of context.snapshot.generator.functions) {
|
|
2013
|
+
if (fn.schema === "better_supabase" || !context.config.schemas.includes(fn.schema) || !fn.definition) continue;
|
|
2014
|
+
const calls = roleHelperCalls(fn.definition);
|
|
2015
|
+
if (calls.length === 0) continue;
|
|
2016
|
+
findings.push({
|
|
2017
|
+
message: `${fn.schema}.${fn.name} calls ${calls.join(" and ")}; ${advice}`,
|
|
2018
|
+
target: `${fn.schema}.${fn.name}`
|
|
2019
|
+
});
|
|
2020
|
+
}
|
|
2021
|
+
return findings;
|
|
2022
|
+
}
|
|
2023
|
+
},
|
|
2024
|
+
{
|
|
2025
|
+
code: "BS415",
|
|
2026
|
+
severity: "warning",
|
|
2027
|
+
title: "The provider sets the deprecated canApprove template",
|
|
2028
|
+
description: "`authorization.functions.isApprover` replaces `canApprove`: one eligibility check for tool calls, support sessions and the app's own approvals, with `{kind}` and `{subject}` instead of `{tool}`. 0.9 still reads `canApprove` when `isApprover` is unset, and drops it in a later minor release.",
|
|
2029
|
+
check: (context) => {
|
|
2030
|
+
const provider = context.config.authorization;
|
|
2031
|
+
if (provider?.functions.canApprove === void 0) return [];
|
|
2032
|
+
return [{
|
|
2033
|
+
message: `${providerLabel(provider)} sets authorization.functions.canApprove, which is deprecated. Set isApprover with {kind}, {subject} and {tenant}; {kind} is 'ai-tool' and {subject} the tool name for AI tool calls.`,
|
|
2034
|
+
target: "authorization.functions.canApprove"
|
|
2035
|
+
}];
|
|
2036
|
+
}
|
|
2037
|
+
},
|
|
2038
|
+
{
|
|
2039
|
+
code: "BS416",
|
|
2040
|
+
severity: "warning",
|
|
2041
|
+
title: "isApprover has no branch for support sessions",
|
|
2042
|
+
description: "With the provider access model, the `support-sessions` module asks `authorization.functions.isApprover` who may approve a support request, with `{kind}` set to `'support-session'`, instead of its built-in platform check. A template that only handles `'ai-tool'` answers false, so no admin can approve a support request and every start that needs a second admin stays pending. Doctor warns when the template, and every function it calls, never names `support-session`.",
|
|
2043
|
+
check: (context) => {
|
|
2044
|
+
const provider = context.config.authorization;
|
|
2045
|
+
const support = context.config.blocks["support-sessions"];
|
|
2046
|
+
const isApprover = provider?.functions.isApprover;
|
|
2047
|
+
if (provider === void 0 || isApprover === void 0 || !context.config.blockNames.includes("support-sessions") || (context.config.blocks.access?.model ?? "roles") !== "provider" || support?.options?.["approval"] === "none") return [];
|
|
2048
|
+
if (isApprover.includes(SUPPORT_SESSION_APPROVAL)) return [];
|
|
2049
|
+
const called = new Set(templateCalls(isApprover));
|
|
2050
|
+
if (context.snapshot.generator.functions.some((fn) => called.has(`${fn.schema}.${fn.name}`.toLowerCase()) && fn.definition.includes(SUPPORT_SESSION_APPROVAL))) return [];
|
|
2051
|
+
return [{
|
|
2052
|
+
message: `Support sessions are installed, but ${providerLabel(provider)}'s isApprover template never handles {kind} = '${SUPPORT_SESSION_APPROVAL}', so it answers false and no admin can approve a support request. Add a '${SUPPORT_SESSION_APPROVAL}' branch (for example platform staff with the support permission), or set blocks["support-sessions"].options.approval to "none".`,
|
|
2053
|
+
target: "authorization.functions.isApprover"
|
|
2054
|
+
}];
|
|
2055
|
+
}
|
|
2056
|
+
},
|
|
2057
|
+
{
|
|
2058
|
+
code: "BS417",
|
|
2059
|
+
severity: "warning",
|
|
2060
|
+
title: "The provider declares teams but sets no teamIdsOf template",
|
|
2061
|
+
description: "With the provider access model, `team_ids_of()` and the team sharing in `saved-views` and `collections` call `authorization.functions.teamIdsOf` for a caller's teams. Without it, `team_ids_of()` reads the teams block's own `team_members`, which a provider that keeps its own teams never fills, and `saved-views` and `collections` without the teams block share with no team. Doctor warns when the provider declares a `team` scope, one of those blocks is installed, and the template is unset.",
|
|
2062
|
+
check: (context) => {
|
|
2063
|
+
const provider = context.config.authorization;
|
|
2064
|
+
if (provider === void 0 || provider.functions.teamIdsOf !== void 0 || (context.config.blocks.access?.model ?? "roles") !== "provider" || !provider.scopes.some((scope) => TEAM_SCOPE.test(scope.name))) return [];
|
|
2065
|
+
const sharing = TEAM_BLOCKS.filter((name) => context.config.blockNames.includes(name));
|
|
2066
|
+
if (sharing.length === 0) return [];
|
|
2067
|
+
return [{
|
|
2068
|
+
message: `${providerLabel(provider)} declares a team scope, but sets no authorization.functions.teamIdsOf, so ${sharing.join(", ")} can't see its teams. Set teamIdsOf to a set-returning call with {user}, for example "provider.team_ids_of({user})".`,
|
|
2069
|
+
target: "authorization.functions.teamIdsOf"
|
|
2070
|
+
}];
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
];
|
|
2074
|
+
const TEAM_SCOPE = /^teams?$/;
|
|
2075
|
+
const TEAM_BLOCKS = [
|
|
2076
|
+
"teams",
|
|
2077
|
+
"saved-views",
|
|
2078
|
+
"collections"
|
|
2079
|
+
];
|
|
2080
|
+
const TEMPLATE_CALL = /\b("?[a-z_][a-z0-9_$]*"?)\s*\.\s*("?[a-z_][a-z0-9_$]*"?)\s*\(/gi;
|
|
2081
|
+
/** The `schema.function` names a template calls, lowercased and unquoted. */
|
|
2082
|
+
function templateCalls(template) {
|
|
2083
|
+
return [...withoutStrings(template).matchAll(TEMPLATE_CALL)].map((match) => `${match[1]}.${match[2]}`.replaceAll("\"", "").toLowerCase());
|
|
2084
|
+
}
|
|
2085
|
+
const CONTRACT_CALL = /\bbetter_supabase"?\s*\.\s*"?(can|tenant_ids_with)"?\s*\(/gi;
|
|
2086
|
+
const ROLE_HELPER_CALL = /\bbetter_supabase"?\s*\.\s*"?(member_organization_ids|has_organization_role|organization_member_role)"?\s*\(/gi;
|
|
2087
|
+
/** The tenant role helpers `text` calls, outside string literals. */
|
|
2088
|
+
function roleHelperCalls(text) {
|
|
2089
|
+
const names = /* @__PURE__ */ new Set();
|
|
2090
|
+
for (const match of withoutStrings(text).matchAll(ROLE_HELPER_CALL)) names.add(`better_supabase.${match[1].toLowerCase()}()`);
|
|
2091
|
+
return [...names].toSorted();
|
|
2092
|
+
}
|
|
2093
|
+
/** The access contract functions `text` calls, outside string literals. */
|
|
2094
|
+
function contractCalls(text) {
|
|
2095
|
+
const names = /* @__PURE__ */ new Set();
|
|
2096
|
+
for (const match of withoutStrings(text).matchAll(CONTRACT_CALL)) names.add(`better_supabase.${match[1].toLowerCase()}()`);
|
|
2097
|
+
return [...names].toSorted();
|
|
2098
|
+
}
|
|
2099
|
+
//#endregion
|
|
2100
|
+
//#region src/cli/gen/manifest.ts
|
|
2101
|
+
/**
|
|
2102
|
+
* The files the last `gen` wrote, so the next one can remove those it no longer
|
|
2103
|
+
* writes.
|
|
2104
|
+
*/
|
|
2105
|
+
const MANIFEST = `${CACHE_DIR}/gen-manifest.json`;
|
|
2106
|
+
const manifestPath = (root, path) => relative(root, resolve(root, path)).split(sep).join("/");
|
|
2107
|
+
async function readManifest(root) {
|
|
2108
|
+
const parsed = await readFile(resolve(root, MANIFEST), "utf-8").then((text) => JSON.parse(text)).catch(() => void 0);
|
|
2109
|
+
if (typeof parsed !== "object" || parsed === null || !("version" in parsed) || parsed.version !== 1 || !("files" in parsed) || !Array.isArray(parsed.files)) return [];
|
|
2110
|
+
return parsed.files.filter((path) => typeof path === "string");
|
|
2111
|
+
}
|
|
2112
|
+
/**
|
|
2113
|
+
* Files in the last manifest that this run doesn't generate and that still
|
|
2114
|
+
* exist inside the root.
|
|
2115
|
+
*/
|
|
2116
|
+
async function leftoverFiles(root, generated) {
|
|
2117
|
+
const current = new Set(generated);
|
|
2118
|
+
return (await readManifest(root)).filter((path) => {
|
|
2119
|
+
const inside = relative(root, resolve(root, path));
|
|
2120
|
+
return !current.has(path) && inside !== "" && !inside.startsWith("..") && !isAbsolute(inside) && existsSync(resolve(root, path));
|
|
2121
|
+
});
|
|
2122
|
+
}
|
|
2123
|
+
const writeManifest = (root, files) => writeAtomic(resolve(root, MANIFEST), `${JSON.stringify({
|
|
2124
|
+
version: 1,
|
|
2125
|
+
files: files.toSorted()
|
|
2126
|
+
}, null, 2)}\n`).catch(() => void 0);
|
|
2127
|
+
//#endregion
|
|
2128
|
+
//#region src/cli/introspect/from-metadata.ts
|
|
2129
|
+
/**
|
|
2130
|
+
* What the extras query set reads that a `GeneratorMetadata` document leaves
|
|
2131
|
+
* out.
|
|
2132
|
+
*/
|
|
2133
|
+
const METADATA_GAPS = [
|
|
2134
|
+
"multi-column unique keys and checks",
|
|
2135
|
+
"foreign key actions",
|
|
2136
|
+
"indexes",
|
|
2137
|
+
"triggers",
|
|
2138
|
+
"policies",
|
|
2139
|
+
"grants",
|
|
2140
|
+
"storage buckets",
|
|
2141
|
+
"the realtime publication"
|
|
2142
|
+
];
|
|
2143
|
+
/** `METADATA_GAPS` as one phrase for notices. */
|
|
2144
|
+
const METADATA_GAPS_TEXT = `${METADATA_GAPS.slice(0, -1).join(", ")} or ${METADATA_GAPS.at(-1) ?? ""}`;
|
|
2145
|
+
/**
|
|
2146
|
+
* Builds a snapshot from a `GeneratorMetadata` document alone, for `gen
|
|
2147
|
+
* --metadata`. Relations come from `relationships`, single-column unique keys
|
|
2148
|
+
* from `is_unique` and single-column checks from `check`, named as Postgres
|
|
2149
|
+
* names them by default (`<table>_<column>_key`, `<table>_<column>_check`).
|
|
2150
|
+
* Everything else the extras carry is empty, and `extras.fromMetadata` says
|
|
2151
|
+
* so.
|
|
2152
|
+
*/
|
|
2153
|
+
function fromMetadata(document) {
|
|
2154
|
+
const { metadata } = stabilizeMetadata(document);
|
|
2155
|
+
const tableIds = new Set(metadata.tables.map((table) => table.id));
|
|
2156
|
+
const tables = [
|
|
2157
|
+
...metadata.tables,
|
|
2158
|
+
...metadata.foreignTables,
|
|
2159
|
+
...metadata.views,
|
|
2160
|
+
...metadata.materializedViews
|
|
2161
|
+
].map((relation) => {
|
|
2162
|
+
const columns = metadata.columns.filter((column) => column.table_id === relation.id).toSorted((a, b) => a.ordinal_position - b.ordinal_position);
|
|
2163
|
+
const own = tableIds.has(relation.id);
|
|
2164
|
+
return {
|
|
2165
|
+
id: relation.id,
|
|
2166
|
+
schema: relation.schema,
|
|
2167
|
+
name: relation.name,
|
|
2168
|
+
primaryKey: [],
|
|
2169
|
+
uniques: own ? columns.filter((column) => column.is_unique).map((column) => ({
|
|
2170
|
+
name: `${relation.name}_${column.name}_key`,
|
|
2171
|
+
columns: [column.name]
|
|
2172
|
+
})) : [],
|
|
2173
|
+
foreignKeys: own ? metadata.relationships.filter((fk) => fk.schema === relation.schema && fk.relation === relation.name).map((fk) => ({
|
|
2174
|
+
name: fk.foreign_key_name,
|
|
2175
|
+
onDelete: "no action",
|
|
2176
|
+
onUpdate: "no action"
|
|
2177
|
+
})).toSorted((a, b) => byCodePoint(a.name, b.name)) : [],
|
|
2178
|
+
checks: own ? columns.flatMap((column) => column.check === null ? [] : [{
|
|
2179
|
+
name: `${relation.name}_${column.name}_check`,
|
|
2180
|
+
definition: `CHECK ((${column.check}))`
|
|
2181
|
+
}]) : [],
|
|
2182
|
+
indexes: [],
|
|
2183
|
+
policies: [],
|
|
2184
|
+
triggers: [],
|
|
2185
|
+
grants: []
|
|
2186
|
+
};
|
|
2187
|
+
});
|
|
2188
|
+
return {
|
|
2189
|
+
version: 2,
|
|
2190
|
+
schemas: [...new Set(metadata.schemas.map((schema) => schema.name))].toSorted(byCodePoint),
|
|
2191
|
+
generator: metadata,
|
|
2192
|
+
extras: {
|
|
2193
|
+
tables,
|
|
2194
|
+
buckets: [],
|
|
2195
|
+
realtime: [],
|
|
2196
|
+
fromMetadata: true
|
|
2197
|
+
}
|
|
2198
|
+
};
|
|
2199
|
+
}
|
|
2200
|
+
//#endregion
|
|
2201
|
+
//#region src/cli/gen/notices.ts
|
|
2202
|
+
const UNFORMATTED = "oxfmt is not installed, so database.types.ts is not formatted like `supabase gen types` output. Install it: pnpm add -D oxfmt. @supabase/postgrest-typegen pins oxfmt 0.66.0 as its peer; to allow a newer one, add it to peerDependencyRules.allowedVersions in pnpm-workspace.yaml, keyed \"@supabase/postgrest-typegen>oxfmt\".";
|
|
2203
|
+
const METADATA_ONLY = `Notice: the schema came from a GeneratorMetadata document, which has no ${METADATA_GAPS_TEXT}. Unique keys and checks cover single columns, relations have no onDelete, and columns a before-insert trigger fills stay required on insert. Run \`better-supabase gen\` against the database for the full model.`;
|
|
2204
|
+
/**
|
|
2205
|
+
* The formatter, typegen version and metadata-only notices, the model's notices
|
|
2206
|
+
* and the config warnings, one line each.
|
|
2207
|
+
*/
|
|
2208
|
+
async function generationNotices(snapshot, warnings, notices = []) {
|
|
2209
|
+
const typegen = typegenVersionNotice(await typegenVersion());
|
|
2210
|
+
return [
|
|
2211
|
+
...await oxfmtInstalled() ? [] : [UNFORMATTED],
|
|
2212
|
+
...typegen ? [typegen] : [],
|
|
2213
|
+
...snapshot.extras.fromMetadata ? [METADATA_ONLY] : [],
|
|
2214
|
+
...notices,
|
|
2215
|
+
...warnings.map((warning) => `Warning: ${warning}`)
|
|
2216
|
+
];
|
|
2217
|
+
}
|
|
2218
|
+
//#endregion
|
|
2219
|
+
//#region src/cli/gen/run.ts
|
|
2220
|
+
/** The `read-sets` SQL module file for `config.readSets`, if any are configured. */
|
|
2221
|
+
async function readSetFile(config) {
|
|
2222
|
+
if (config.readSets.length === 0) return;
|
|
2223
|
+
const readSets = await compiledReadSets(config);
|
|
2224
|
+
const { appTables: _appTables, ...layout } = moduleLayout(config, config.sql.testsDir, readSets);
|
|
2225
|
+
return renderModules(["read-sets"], layout)[0];
|
|
2226
|
+
}
|
|
2227
|
+
/**
|
|
2228
|
+
* `buckets` keys that reach the authorization provider's functions but aren't
|
|
2229
|
+
* marked `sqlComplete: true` in `authorization.permissions`, as error lines.
|
|
2230
|
+
*/
|
|
2231
|
+
function rowConditionedBuckets(config) {
|
|
2232
|
+
const provider = config.authorization;
|
|
2233
|
+
if (!provider) return [];
|
|
2234
|
+
return providerBucketKeys(config).flatMap(({ bucket, keys }) => keys.flatMap((key) => {
|
|
2235
|
+
const problem = unsafeKey(provider, key);
|
|
2236
|
+
return problem ? [` buckets.${bucket}: "${key}" ${problem.reason}. ${problem.fix}`] : [];
|
|
2237
|
+
}));
|
|
2238
|
+
}
|
|
2239
|
+
/**
|
|
2240
|
+
* The exit `gen` stops with when bucket keys aren't fully answered by the
|
|
2241
|
+
* provider's SQL functions.
|
|
2242
|
+
*/
|
|
2243
|
+
function refuseRowConditionedBuckets(config) {
|
|
2244
|
+
const refused = rowConditionedBuckets(config);
|
|
2245
|
+
return refused.length === 0 || !config.authorization ? void 0 : {
|
|
2246
|
+
code: 1,
|
|
2247
|
+
error: `The SQL functions of ${providerLabel(config.authorization)} decide by role and scope only, so these bucket policies could grant every object in the scope:\n${refused.join("\n")}\nSee doctor BS214.`
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
async function runGen(options) {
|
|
2251
|
+
const { config } = options;
|
|
2252
|
+
const refused = refuseRowConditionedBuckets(config);
|
|
2253
|
+
if (refused) return refused;
|
|
2254
|
+
const snapshot = options.snapshot ?? await loadSnapshot(config, options.env, options);
|
|
2255
|
+
const { files, warnings, notices } = await render(config, snapshot);
|
|
2256
|
+
const migrations = !options.isolated && await writesMigrations(config);
|
|
2257
|
+
const pathsOf = (readSets) => [...files, ...readSets && !migrations ? [readSets] : []].map((file) => manifestPath(config.root, file.path));
|
|
2258
|
+
const notice = (await generationNotices(snapshot, warnings, notices)).map((line) => `\n${line}`).join("");
|
|
2259
|
+
const readSetsOf = () => options.isolated ? Promise.resolve(void 0) : readSetFile(config);
|
|
2260
|
+
const leftoversOf = (generated) => options.isolated ? Promise.resolve([]) : leftoverFiles(config.root, generated);
|
|
2261
|
+
if (options.check) {
|
|
2262
|
+
const readSets = await readSetsOf();
|
|
2263
|
+
const generated = pathsOf(readSets);
|
|
2264
|
+
const leftovers = await leftoversOf(generated);
|
|
2265
|
+
const stale = [];
|
|
2266
|
+
const diffs = [];
|
|
2267
|
+
const compare = (file, current) => {
|
|
2268
|
+
const shown = display(config.root, file.path);
|
|
2269
|
+
stale.push(shown);
|
|
2270
|
+
diffs.push(fileDiff(shown, current, file.contents, options.paint));
|
|
2271
|
+
};
|
|
2272
|
+
for (const file of files) {
|
|
2273
|
+
const path = resolve(config.root, file.path);
|
|
2274
|
+
const current = existsSync(path) ? await readFile(path, "utf-8") : void 0;
|
|
2275
|
+
if (!sameText(current, file.contents)) compare(file, current);
|
|
2276
|
+
}
|
|
2277
|
+
if (readSets && migrations) {
|
|
2278
|
+
const latest = await latestMigration(config, READ_SETS_SUFFIX);
|
|
2279
|
+
if (!sameModuleMigration(latest?.text, readSets.contents)) compare({
|
|
2280
|
+
path: latest?.path ?? `${migrationsDir(config)}/<stamp>_better_supabase_read_sets.sql`,
|
|
2281
|
+
contents: readSets.contents
|
|
2282
|
+
}, latest?.text);
|
|
2283
|
+
} else if (readSets) {
|
|
2284
|
+
const path = resolve(config.root, readSets.path);
|
|
2285
|
+
const current = existsSync(path) ? await readFile(path, "utf-8") : void 0;
|
|
2286
|
+
if (!sameModuleFile(current, readSets.contents)) compare(readSets, current);
|
|
2287
|
+
}
|
|
2288
|
+
if (stale.length > 0 || leftovers.length > 0) {
|
|
2289
|
+
const lines = [...stale.map((path) => ` ${path}`), ...leftovers.map((path) => ` ${path} (no longer generated)`)];
|
|
2290
|
+
return {
|
|
2291
|
+
code: 1,
|
|
2292
|
+
output: `${diffs.join("\n\n")}${notice}`,
|
|
2293
|
+
error: `Generated files are out of date:\n${lines.join("\n")}\nRun \`better-supabase gen\`.`,
|
|
2294
|
+
errorCode: "check_failed",
|
|
2295
|
+
data: {
|
|
2296
|
+
upToDate: false,
|
|
2297
|
+
stale,
|
|
2298
|
+
leftovers,
|
|
2299
|
+
warnings
|
|
2300
|
+
}
|
|
2301
|
+
};
|
|
2302
|
+
}
|
|
2303
|
+
return {
|
|
2304
|
+
code: 0,
|
|
2305
|
+
output: `Generated files are up to date (${generated.length}).${notice}`,
|
|
2306
|
+
data: {
|
|
2307
|
+
upToDate: true,
|
|
2308
|
+
stale: [],
|
|
2309
|
+
leftovers: [],
|
|
2310
|
+
warnings
|
|
2311
|
+
}
|
|
2312
|
+
};
|
|
2313
|
+
}
|
|
2314
|
+
const flags = {
|
|
2315
|
+
"dry-run": options.dryRun,
|
|
2316
|
+
force: options.force
|
|
2317
|
+
};
|
|
2318
|
+
const plan = (entries, remove = []) => ({
|
|
2319
|
+
root: config.root,
|
|
2320
|
+
regenerate: "better-supabase gen",
|
|
2321
|
+
files: entries.map((file) => ({
|
|
2322
|
+
path: file.path,
|
|
2323
|
+
contents: file.contents
|
|
2324
|
+
})),
|
|
2325
|
+
remove
|
|
2326
|
+
});
|
|
2327
|
+
const changes = [...(await applyPlan(plan(files), flags)).changes];
|
|
2328
|
+
const readSets = await readSetsOf();
|
|
2329
|
+
if (readSets && migrations) {
|
|
2330
|
+
const migration = await writeLatestMigration(config, READ_SETS_SUFFIX, readSets.contents, {
|
|
2331
|
+
now: /* @__PURE__ */ new Date(),
|
|
2332
|
+
dryRun: options.dryRun === true
|
|
2333
|
+
});
|
|
2334
|
+
changes.push({
|
|
2335
|
+
file: migration.path,
|
|
2336
|
+
outcome: migration.line.startsWith("Unchanged ") ? "unchanged" : "create"
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
2339
|
+
const generated = pathsOf(readSets);
|
|
2340
|
+
changes.push(...(await applyPlan(plan([], await leftoversOf(generated)), flags)).changes);
|
|
2341
|
+
if (readSets && !migrations) {
|
|
2342
|
+
const path = resolve(config.root, readSets.path);
|
|
2343
|
+
changes.push(...(await applyPlan({
|
|
2344
|
+
...plan([{
|
|
2345
|
+
...readSets,
|
|
2346
|
+
path
|
|
2347
|
+
}]),
|
|
2348
|
+
root: dirname(path),
|
|
2349
|
+
base: config.root
|
|
2350
|
+
}, flags)).changes);
|
|
2351
|
+
}
|
|
2352
|
+
const applied = {
|
|
2353
|
+
mode: options.dryRun === true ? "dry-run" : "write",
|
|
2354
|
+
changes,
|
|
2355
|
+
diffs: [],
|
|
2356
|
+
drift: false
|
|
2357
|
+
};
|
|
2358
|
+
const written = changedFiles(applied);
|
|
2359
|
+
if (!options.isolated && options.dryRun !== true) await writeManifest(config.root, generated);
|
|
2360
|
+
const tables = snapshot.extras.tables.filter((table) => config.schemas.includes(table.schema)).length;
|
|
2361
|
+
const lines = changeLines(applied).filter((line) => !line.startsWith("Unchanged "));
|
|
2362
|
+
return {
|
|
2363
|
+
...hasConflicts(applied) ? {
|
|
2364
|
+
code: 1,
|
|
2365
|
+
errorCode: "file_conflict",
|
|
2366
|
+
error: "Some generated files were written by hand, so gen left them alone. Pass --force to overwrite them."
|
|
2367
|
+
} : { code: 0 },
|
|
2368
|
+
output: `${lines.length === 0 ? `No changes (${tables} tables).` : `${lines.join("\n")}\n${options.dryRun === true ? "Would generate" : "Generated"} ${tables} tables.`}${notice}`,
|
|
2369
|
+
data: {
|
|
2370
|
+
tables,
|
|
2371
|
+
written,
|
|
2372
|
+
files: changes,
|
|
2373
|
+
warnings
|
|
2374
|
+
}
|
|
2375
|
+
};
|
|
2376
|
+
}
|
|
2377
|
+
//#endregion
|
|
2378
|
+
export { emitBlockConfig as S, withoutStrings as _, METADATA_GAPS_TEXT as a, render as b, accessModule as c, RLS_RULES as d, appliesTo as f, policyHelpers as g, functionObject as h, generationNotices as i, entitlementsModule as l, functionBody as m, runGen as n, fromMetadata as o, escape as p, UNFORMATTED as r, AUTHORIZATION_RULES as s, refuseRowConditionedBuckets as t, COMMANDS as u, advisorRule as v, renderFiles as x, splinterTables as y };
|