permdock 0.9.0 → 0.10.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.
Files changed (108) hide show
  1. package/dist/active-tenant-DVee32-T.js +39 -0
  2. package/dist/{adoption-scan-Ch07MdxN.js → adoption-scan-0oFt2RD5.js} +1 -1
  3. package/dist/{arazzo-BpS7LnV0.js → arazzo-DA9PCXew.js} +1 -1
  4. package/dist/{arazzo-CmQaGPkM.js → arazzo-DhxDfYt-.js} +1 -1
  5. package/dist/better-supabase/index.d.ts +188 -23
  6. package/dist/better-supabase/index.js +246 -62
  7. package/dist/{casbin-bHyIxTNQ.js → casbin-BJu2liqU.js} +1 -1
  8. package/dist/{casbin-B7_yS-oo.js → casbin-BkhqGh2z.js} +1 -1
  9. package/dist/cli/bin.js +1 -1
  10. package/dist/cli/index.d.ts +6 -1
  11. package/dist/cli/index.js +10 -2
  12. package/dist/{cloud-3kWfjnYy.js → cloud-3RIuS4E9.js} +2 -2
  13. package/dist/{codemod-D9Aiii1r.js → codemod-DLcp-B6v.js} +2 -2
  14. package/dist/{codemod-Bv5i-Mzo.js → codemod-DRl_w-bY.js} +1 -1
  15. package/dist/{collect-B80GYEot.js → collect-D9Tt0Bcx.js} +1 -1
  16. package/dist/{completion-_bc0OUQ-.js → completion-VSWvaaPO.js} +1 -1
  17. package/dist/{config-BwPBfN0t.js → config-BR23fL8m.js} +2 -2
  18. package/dist/{config-D5XrLWpk.js → config-kL36AxkE.js} +1 -1
  19. package/dist/{config-report-BmWIskD7.js → config-report-osnfUNg5.js} +2 -2
  20. package/dist/{config-shape-ykV0Vm2n.js → config-shape-tsxHx71E.js} +2 -1
  21. package/dist/{create-BamXmeob.d.ts → create-CDd9c22W.d.ts} +10 -1
  22. package/dist/{doctor-LPMYjSqO.js → doctor-B9FY9H0F.js} +2 -2
  23. package/dist/{doctor-ClRVAtXQ.js → doctor-DfTnMaUt.js} +142 -14
  24. package/dist/{fields-D0vUI6dq.js → fields-DI8s3cPl.js} +1 -1
  25. package/dist/{gen-BtfFWGbz.js → gen-DuAhghDw.js} +1 -1
  26. package/dist/{gen-BFfzZSLH.js → gen-DwgCSC6V.js} +1 -1
  27. package/dist/{import-CST57XLp.js → import-CNBF96hB.js} +2 -2
  28. package/dist/{import-ACkOrv6g.js → import-Iuk9mx8A.js} +1 -1
  29. package/dist/{index-vYjMrXyK.d.ts → index-Cay5-Kvx.d.ts} +3 -51
  30. package/dist/index.d.ts +2 -1
  31. package/dist/{init-BjuFDYT1.js → init-DeoSvkh2.js} +1 -1
  32. package/dist/{init-txYTuW9u.js → init-fNF_XmTa.js} +3 -3
  33. package/dist/{login-CgfCTO3F.js → login-CutVtcmQ.js} +1 -1
  34. package/dist/{login-CfImTJGb.js → login-DYazeWc9.js} +3 -3
  35. package/dist/{manifest-B2QPh19C.js → manifest-B4ENCp2I.js} +33 -33
  36. package/dist/{manifest-CzzWtnAb.d.ts → manifest-B5yF3CIq.d.ts} +19 -0
  37. package/dist/{manifest-wg8WkkpD.js → manifest-BXTbHNIV.js} +1 -1
  38. package/dist/{manifest-schema-2r37XRhD.js → manifest-schema-DQkBK2Mr.js} +28 -1
  39. package/dist/{migrate-B7oP_sQU.js → migrate-BJHxQqT5.js} +2 -2
  40. package/dist/{module-values-BJTBdo6y.js → module-values-B1EVTkHP.js} +1 -1
  41. package/dist/next/index.d.ts +16 -3
  42. package/dist/next/index.js +1 -1
  43. package/dist/next/plugin.d.ts +1 -1
  44. package/dist/next/plugin.js +1 -1
  45. package/dist/{openapi-BGeuunWC.js → openapi-C-ADypaY.js} +1 -1
  46. package/dist/{openapi-BIpw3Mb7.js → openapi-DFj0cirS.js} +2 -2
  47. package/dist/{output-DV5dwOTs.js → output-LsbLe41I.js} +1 -1
  48. package/dist/{ownership-DA5YdYTm.js → ownership-qqBuGJXr.js} +3 -3
  49. package/dist/{postgrest-5Dr3W64L.js → postgrest-DAxFltvO.js} +1 -1
  50. package/dist/{powersync-Bg8u-JcR.js → powersync-B_8uwz7f.js} +2 -2
  51. package/dist/powersync-CSzDCHRu.js +1 -0
  52. package/dist/{powersync-CJrT1DSc.js → powersync-DUT-UKgw.js} +188 -36
  53. package/dist/{pull-2nJr0qg_.js → pull-DQCgvJSC.js} +2 -2
  54. package/dist/pull-DYbyod1f.js +1 -0
  55. package/dist/{push-Bn-lMEmI.js → push-Dq_ca4-j.js} +1 -1
  56. package/dist/{resolve-names-ConCSj1y.js → resolve-names-Y1Cb22cp.js} +4 -4
  57. package/dist/{rls-Cx0dtsB7.js → rls-B57mIeVq.js} +22 -15
  58. package/dist/{rls-Ba9wN0SP.js → rls-j0YrFPpW.js} +1 -1
  59. package/dist/run-BATawNVH.js +1 -0
  60. package/dist/{run-PbRlXTfh.js → run-CLP_fQUF.js} +3 -3
  61. package/dist/{run-ticket-Dv7aF7Dk.js → run-ticket-DfnZCh-u.js} +19 -6
  62. package/dist/{run-ticket-B2o2Kxz8.d.ts → run-ticket-ylovhyFQ.d.ts} +16 -1
  63. package/dist/{scan-CRTj6fke.js → scan-B7xrAvRm.js} +1 -1
  64. package/dist/{schema-BTsE1WRT.js → schema-3PJ8wAeL.js} +1 -1
  65. package/dist/server/index.d.ts +2 -2
  66. package/dist/server/index.js +1 -1
  67. package/dist/{shared-Afctg7B0.js → shared-DrGLwM3s.js} +1 -1
  68. package/dist/{skills-C9uKfSF5.js → skills-BUI8DMqy.js} +1 -1
  69. package/dist/{skills-CQQcuGBi.js → skills-iwbRxavw.js} +1 -1
  70. package/dist/{sources-CMAM-2A3.js → sources-C4vkzZJV.js} +12 -7
  71. package/dist/{types-BMVDHvI0.d.ts → sources-oB1Hg1Fm.d.ts} +316 -2
  72. package/dist/supabase/index.d.ts +2 -3
  73. package/dist/supabase/index.js +4 -4
  74. package/dist/{supabase-DnMMg5Fn.js → supabase-B1EfuD47.js} +2 -2
  75. package/dist/{supabase-SBs3MYUE.js → supabase-BaizG0n7.js} +2 -2
  76. package/dist/{supabase-hook-CrgU06WH.js → supabase-hook-BT2P9wah.js} +110 -47
  77. package/dist/supabase-hook-CbvGAutK.js +1 -0
  78. package/dist/{supautils-ByezN3b8.js → supautils-DBKOoyjn.js} +8 -8
  79. package/dist/{tables-BqrxBCir.js → tables-DimBcVWY.js} +2 -2
  80. package/dist/testing/fixtures/index.d.ts +1 -1
  81. package/dist/testing/fixtures/index.js +26 -28
  82. package/dist/testing/index.d.ts +4 -3
  83. package/dist/testing/index.js +3 -2
  84. package/dist/{types-CzOeVvcC.d.ts → types-Cklw5hJo.d.ts} +23 -2
  85. package/dist/unplugin/index.d.ts +1 -1
  86. package/dist/unplugin/index.js +1 -1
  87. package/dist/{usage-CBzgwfIs.js → usage-B1ZJOUdr.js} +1 -1
  88. package/dist/{usage-B9EtHWLa.js → usage-t_nXnwCW.js} +2 -2
  89. package/dist/usage-weohzv2f.js +1 -0
  90. package/dist/{verify-DlUcTDBz.js → verify-jHrbmn-E.js} +6 -6
  91. package/dist/version-cache-Df11C2Qp.d.ts +51 -0
  92. package/dist/{watch-BFDKqmUa.js → watch-Bpci3hBY.js} +1 -1
  93. package/dist/watch-COuvly20.js +1 -0
  94. package/dist/workflow/index.d.ts +1 -1
  95. package/dist/workflow/index.js +22 -6
  96. package/dist/workflow-sdk/index.d.ts +1 -1
  97. package/package.json +2 -2
  98. package/schemas/run-v1.json +16 -0
  99. package/schemas/supabase-manifest-v1.json +28 -0
  100. package/skills/permdock-agents/references/operations-automations-chat.md +1 -0
  101. package/skills/permdock-wire/references/adapters.md +2 -2
  102. package/dist/powersync-B701tvhE.js +0 -1
  103. package/dist/pull-C3EEGzSw.js +0 -1
  104. package/dist/run-Ck22anC2.js +0 -1
  105. package/dist/sources-CWG32C0G.d.ts +0 -312
  106. package/dist/supabase-hook-C0FyEACZ.js +0 -1
  107. package/dist/usage-0hjZPIRX.js +0 -1
  108. package/dist/watch-ClLuO2TL.js +0 -1
@@ -8,23 +8,23 @@ import { a as SUPABASE_MANIFEST_SCHEMA } from "./version-DMQ0dnN5.js";
8
8
  import { c as requirePolicy } from "./load-DjSU5KXO.js";
9
9
  import { i as qualifySqlTable } from "./sql-0WjxIp9g.js";
10
10
  import { i as scopeColumn } from "./compile-EzEMB-7v.js";
11
- import { t as authorizeSql } from "./supabase-DnMMg5Fn.js";
11
+ import { t as authorizeSql } from "./supabase-B1EfuD47.js";
12
12
  import "./budget-BELja5A9.js";
13
- import { a as hookApiNames, d as keptKeys, t as AUTHZ_VERSION_TABLE, u as roleManifest } from "./sources-CMAM-2A3.js";
14
- import { o as readMemberships } from "./postgrest-5Dr3W64L.js";
13
+ import { a as hookApiNames, d as keptKeys, t as AUTHZ_VERSION_TABLE, u as roleManifest } from "./sources-C4vkzZJV.js";
14
+ import { o as readMemberships } from "./postgrest-DAxFltvO.js";
15
15
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
16
16
  import { n as GRANTS_MARKER, r as HOOK_MARKER, s as hookMarkerFields } from "./markers-BeHZ4x9Q.js";
17
17
  import { n as formatManifestJson, t as MANIFEST_FILE } from "./manifest-json-CAGzls-C.js";
18
18
  import { n as MIGRATION_DIRS } from "./constants-DcJABbLW.js";
19
19
  import { f as writeOutputFiles, l as partPath, r as driftOf, u as pgDeltaPath } from "./output-files-BIQ_9pIs.js";
20
- import { A as quoteQualified, D as qualified, F as firstScopeType, I as scopeTypeOf, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, l as USER_ID_HELPER, r as HELPERS, y as subjectIdSql } from "./shared-Afctg7B0.js";
21
- import { E as TOKEN_SCOPE_ALLOWS, J as apiKeyFields, K as API_KEY_ALLOWS, R as globalRoleSource, _ as PERMISSION_HELPERS, at as memberForHelper, b as permissionKeysForHelper, bt as checkSuspension, ct as memberIdsHelper, dt as permittedForHelper, et as hasMemberFor, ft as permittedIdsHelper, g as OWNERSHIP, h as ASSIGNMENTS, lt as memberOfHelper, ot as memberForSources, rt as isTeamScope, st as memberForTable, tt as hasPermittedUsers, ut as memberRoleOf, v as checkName, vt as activeRowSql, x as permittedByPermissionHelper } from "./tables-BqrxBCir.js";
22
- import { a as guardedTables, t as ownershipRules, u as roleNames } from "./ownership-DA5YdYTm.js";
20
+ import { A as quoteQualified, D as qualified, F as firstScopeType, I as scopeTypeOf, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, l as USER_ID_HELPER, r as HELPERS, y as subjectIdSql } from "./shared-DrGLwM3s.js";
21
+ import { E as TOKEN_SCOPE_ALLOWS, J as apiKeyFields, K as API_KEY_ALLOWS, R as globalRoleSource, _ as PERMISSION_HELPERS, at as memberForHelper, b as permissionKeysForHelper, bt as checkSuspension, ct as memberIdsHelper, dt as permittedForHelper, et as hasMemberFor, ft as permittedIdsHelper, g as OWNERSHIP, h as ASSIGNMENTS, lt as memberOfHelper, ot as memberForSources, rt as isTeamScope, st as memberForTable, tt as hasPermittedUsers, ut as memberRoleOf, v as checkName, vt as activeRowSql, x as permittedByPermissionHelper } from "./tables-DimBcVWY.js";
22
+ import { a as guardedTables, t as ownershipRules, u as roleNames } from "./ownership-qqBuGJXr.js";
23
23
  import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
24
24
  import { a as splitUndiffed, r as tableKey, t as decidingColumns } from "./deciding-columns-NB4wcyBf.js";
25
25
  import { n as pgConnector } from "./pg-DQTqRrou.js";
26
- import { r as permittedUsersHelper, t as resolveNames } from "./resolve-names-ConCSj1y.js";
27
- import { c as ACTOR_MAY_WRITE, f as readOnlyActorKinds } from "./fields-D0vUI6dq.js";
26
+ import { c as ACTOR_MAY_WRITE, f as readOnlyActorKinds } from "./fields-DI8s3cPl.js";
27
+ import { r as permittedUsersHelper, t as resolveNames } from "./resolve-names-Y1Cb22cp.js";
28
28
  import { existsSync, readFileSync, readdirSync } from "node:fs";
29
29
  import { dirname, join, posix, resolve } from "node:path";
30
30
  //#region ../../node_modules/.pnpm/smol-toml@1.9.1/node_modules/smol-toml/dist/error.js
@@ -1577,28 +1577,39 @@ function positiveInteger(value, label) {
1577
1577
  return number;
1578
1578
  }
1579
1579
  /**
1580
- * SQL for the active first-scope id, as text, for user `uid`; a table source
1581
- * compares its id column with `v_active_user`, declared as `userType`.
1580
+ * Where the hook reads the active first-scope id: `supabase.hook.activeFrom`,
1581
+ * or `app_metadata.active_<root>` by default.
1582
1582
  */
1583
- function activeFromSql(input, root) {
1583
+ function activeSource(input, root) {
1584
1584
  const spec = input ?? `app_metadata.active_${root}`;
1585
1585
  if (typeof spec === "string" && spec.startsWith("app_metadata.")) {
1586
1586
  const key = spec.slice(13);
1587
1587
  if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(key)) throw configError(`PermDock CLI: unsafe app_metadata key '${key}'`);
1588
- return { sql: `claims -> 'app_metadata' ->> ${quoteLiteral(key)}` };
1588
+ return { appMetadata: key };
1589
1589
  }
1590
- const parsed = typeof spec === "string" ? (() => {
1591
- const dot = spec.lastIndexOf(".");
1592
- if (dot <= 0) throw configError(`PermDock CLI: --active-from must be app_metadata.<key> or <table>.<column>, got '${spec}'`);
1593
- return {
1594
- table: spec.slice(0, dot),
1595
- column: spec.slice(dot + 1)
1596
- };
1597
- })() : spec;
1598
- const id = "id" in parsed && parsed.id !== void 0 ? parsed.id : "id";
1590
+ if (typeof spec !== "string") return {
1591
+ table: spec.table,
1592
+ column: spec.column,
1593
+ id: spec.id ?? "id"
1594
+ };
1595
+ const dot = spec.lastIndexOf(".");
1596
+ if (dot <= 0) throw configError(`PermDock CLI: --active-from must be app_metadata.<key> or <table>.<column>, got '${spec}'`);
1599
1597
  return {
1600
- sql: `(select a.${quoteIdent(parsed.column)}::text from ${quoteQualified(parsed.table)} a where a.${quoteIdent(id)} = v_active_user)`,
1601
- userType: `${quoteQualified(parsed.table)}.${quoteIdent(id)}%type`
1598
+ table: spec.slice(0, dot),
1599
+ column: spec.slice(dot + 1),
1600
+ id: "id"
1601
+ };
1602
+ }
1603
+ /**
1604
+ * SQL for the active first-scope id, as text, for user `uid`; a table source
1605
+ * compares its id column with `v_active_user`, declared as `userType`.
1606
+ */
1607
+ function activeFromSql(input, root) {
1608
+ const from = activeSource(input, root);
1609
+ if ("appMetadata" in from) return { sql: `claims -> 'app_metadata' ->> ${quoteLiteral(from.appMetadata)}` };
1610
+ return {
1611
+ sql: `(select a.${quoteIdent(from.column)}::text from ${quoteQualified(from.table)} a where a.${quoteIdent(from.id)} = v_active_user)`,
1612
+ userType: `${quoteQualified(from.table)}.${quoteIdent(from.id)}%type`
1602
1613
  };
1603
1614
  }
1604
1615
  /**
@@ -1615,9 +1626,9 @@ function typedUsers(parts) {
1615
1626
  ].map((line) => `\n ${line}`).join("");
1616
1627
  }
1617
1628
  function checkSources(parts) {
1618
- if (parts.sources.length === 0) throw configError("PermDock CLI: supabase.hook.memberships needs at least one tableMembershipSource or junctionMembershipSource source");
1629
+ if (parts.sources.length === 0) throw configError("PermDock CLI: supabase.hook.memberships needs at least one tableMembershipSource, junctionMembershipSource or blockMembershipSource source");
1619
1630
  for (const source of parts.sources) {
1620
- if (source.sql === void 0 || typeof source.sql.select !== "function") throw configError("PermDock CLI: supabase.hook.memberships takes tableMembershipSource / junctionMembershipSource sources from permdock/supabase");
1631
+ if (source.sql === void 0 || typeof source.sql.select !== "function") throw configError("PermDock CLI: supabase.hook.memberships takes tableMembershipSource, junctionMembershipSource or blockMembershipSource sources from permdock/supabase");
1621
1632
  const scope = source.sql.scope;
1622
1633
  if (scope === void 0) continue;
1623
1634
  if (resolveScope(parts.scopes, scope) !== scope) throw configError(`PermDock CLI: the ${source.sql.table} source names scope '${scope}', which the policy does not declare by that name`);
@@ -2177,9 +2188,11 @@ grant execute on function ${fn}(jsonb, text) to authenticated;
2177
2188
  }
2178
2189
  /**
2179
2190
  * Everything `rls.approvals` writes: the generated or adopted store, the
2180
- * approver check and, with `delegations: true`, the covers.
2191
+ * approver check and, with `delegations: true`, the covers. With
2192
+ * `actorMayWrite`, the covers' write policies call
2193
+ * `permdock_actor_may_write()`.
2181
2194
  */
2182
- function approvalsSql(ctx, approvals, jsonSchema) {
2195
+ function approvalsSql(ctx, approvals, jsonSchema, actorMayWrite = false) {
2183
2196
  if (approvals === void 0 || approvals === false) return;
2184
2197
  if (approvals === true) return approvalStoreSql(ctx, jsonSchema) + isApproverSql(ctx);
2185
2198
  const { table, delegations } = approvals;
@@ -2199,7 +2212,7 @@ function approvalsSql(ctx, approvals, jsonSchema) {
2199
2212
  ...approvals,
2200
2213
  table
2201
2214
  }, jsonSchema);
2202
- return store + isApproverSql(ctx) + (delegations === true ? approvalDelegationsSql(ctx) : "");
2215
+ return store + isApproverSql(ctx) + (delegations === true ? approvalDelegationsSql(ctx, actorMayWrite) : "");
2203
2216
  }
2204
2217
  /**
2205
2218
  * The objects `rls.approvals.delegations` adds; `tableApprovalDelegationSource`
@@ -2218,7 +2231,7 @@ const DELEGATIONS = {
2218
2231
  * cover needs `rls.mode: "database"`, where the `_for` helpers exist; in `jwt`
2219
2232
  * mode only `user()` approvers pass.
2220
2233
  */
2221
- function approvalDelegationsSql(ctx) {
2234
+ function approvalDelegationsSql(ctx, actorMayWrite = false) {
2222
2235
  const table = qualified(ctx, DELEGATIONS.table);
2223
2236
  const fn = qualified(ctx, APPROVAL_STORE.isApprover);
2224
2237
  const covers = qualified(ctx, DELEGATIONS.covers);
@@ -2235,7 +2248,8 @@ function approvalDelegationsSql(ctx) {
2235
2248
  where i.id::text = p_tenant
2236
2249
  )` : "false";
2237
2250
  const policy = (name) => quoteIdent(`${DELEGATIONS.table}_${name}`);
2238
- const own = `delegator::text = ${me} and (tenant is null or ${member("tenant")})`;
2251
+ const mine = `delegator::text = ${me}${actorMayWrite ? ` and (select ${qualified(ctx, ACTOR_MAY_WRITE)}())` : ""}`;
2252
+ const own = `${mine} and (tenant is null or ${member("tenant")})`;
2239
2253
  return `
2240
2254
  -- approval delegations: out-of-office covers a user writes for themselves; tableApprovalDelegationSource and permdock_is_approver read them
2241
2255
  create table if not exists ${table} (
@@ -2266,12 +2280,12 @@ create policy ${policy("insert")} on ${table}
2266
2280
  drop policy if exists ${policy("update")} on ${table};
2267
2281
  create policy ${policy("update")} on ${table}
2268
2282
  for update to authenticated
2269
- using (delegator::text = ${me})
2283
+ using (${mine})
2270
2284
  with check (${own});
2271
2285
  drop policy if exists ${policy("delete")} on ${table};
2272
2286
  create policy ${policy("delete")} on ${table}
2273
2287
  for delete to authenticated
2274
- using (delegator::text = ${me});
2288
+ using (${mine});
2275
2289
 
2276
2290
  -- approval delegations: whether a delegator's own rights match approvers.by; only permdock_is_approver calls it
2277
2291
  create or replace function ${covers}(p_delegator ${user}, p_approvers jsonb, p_tenant text)
@@ -2839,6 +2853,7 @@ function hookParts(scopes, config, overrides) {
2839
2853
  hook,
2840
2854
  roles: hook.roles === false ? void 0 : globalRoleSource(hook.roles ?? config.rls?.roles ?? { table: `${schema}.user_roles` }, "public", "r", config.rls?.customRoleWrites?.roles),
2841
2855
  active: activeFromSql(overrides.activeFrom ?? hook.activeFrom, root),
2856
+ activeFrom: activeSource(overrides.activeFrom ?? hook.activeFrom, root),
2842
2857
  attrs: hook.attrs === void 0 ? void 0 : attrsPlan(hook.attrs),
2843
2858
  extra: extraPlan.claims,
2844
2859
  before: beforePlan(hook.before),
@@ -2857,6 +2872,45 @@ function hookParts(scopes, config, overrides) {
2857
2872
  return parts;
2858
2873
  }
2859
2874
  //#endregion
2875
+ //#region src/cli/supabase-hook/teams.ts
2876
+ /**
2877
+ * The `member_team_ids_of` helper the hook file writes from
2878
+ * `supabase.hook.teams`, or `undefined` when there is no teams table or `rls
2879
+ * generate` already writes one for a `team` or `teams` scope.
2880
+ */
2881
+ function hookTeamsHelper(parts) {
2882
+ if (parts.hook.teams === void 0) return;
2883
+ return parts.helpers.memberFor.some((scope) => isTeamScope(scope)) ? void 0 : memberOfHelper("team");
2884
+ }
2885
+ /**
2886
+ * `member_team_ids_of(p_user uuid)`: the teams `supabase.hook.teams` lists for
2887
+ * the caller, the rows the hook writes to `team_ids`. Any other `p_user`, and a
2888
+ * suspended user, gets no rows, so `authenticated` may execute it. The team
2889
+ * column is a uuid, as the `team_ids` claim is.
2890
+ */
2891
+ function teamIdsOfSql(parts) {
2892
+ const name = hookTeamsHelper(parts);
2893
+ const teams = parts.hook.teams;
2894
+ if (name === void 0 || teams === void 0) return "";
2895
+ const fn = `${quoteIdent(parts.helpers.schema)}.${quoteIdent(name)}`;
2896
+ const active = parts.users === void 0 ? "" : `\n and ${activeRowSql(parts.users, "p_user")}`;
2897
+ return `-- the caller's teams from supabase.hook.teams, for better-supabase's teamIdsOf
2898
+ create or replace function ${fn}(p_user uuid)
2899
+ returns setof uuid
2900
+ language sql
2901
+ stable
2902
+ security definer
2903
+ set search_path = ''
2904
+ as $$
2905
+ select t.${quoteIdent(teams.team)}
2906
+ from ${quoteQualified(teams.table)} t
2907
+ where t.${quoteIdent(teams.user)} = p_user
2908
+ and p_user = (select auth.uid())${active}
2909
+ $$;
2910
+ revoke execute on function ${fn}(uuid) from public, anon;
2911
+ grant execute on function ${fn}(uuid) to authenticated;`;
2912
+ }
2913
+ //#endregion
2860
2914
  //#region src/cli/supabase-hook/version.ts
2861
2915
  const VERSION_TRIGGER = "permdock_authz_version";
2862
2916
  const AUTHZ_VERSION_BUMP = "permdock_bump_authz_version_for";
@@ -3059,9 +3113,8 @@ function roleKeyHolders(parts) {
3059
3113
  holder.userThrough.key
3060
3114
  ],
3061
3115
  tableKey(holder.through.table),
3062
- holder.through.id,
3063
3116
  holder.through.key,
3064
- holder.through.ref
3117
+ holder.through.match
3065
3118
  ]);
3066
3119
  if (seen.has(key)) return false;
3067
3120
  seen.add(key);
@@ -3074,13 +3127,16 @@ function roleKeyHolders(parts) {
3074
3127
  */
3075
3128
  function roleKeysBumpSql(holders, versionTable, indent) {
3076
3129
  return `${indent}if tg_op = 'UPDATE'
3077
- ${indent} and ${[...new Set(holders.flatMap((holder) => [holder.through.key, holder.through.id]))].map((column) => `new.${quoteIdent(column)} is not distinct from old.${quoteIdent(column)}`).join(`\n${indent} and `)} then
3130
+ ${indent} and ${[...new Set(holders.flatMap((holder) => [holder.through.key, ...holder.through.match.map(([, id]) => id)]))].map((column) => `new.${quoteIdent(column)} is not distinct from old.${quoteIdent(column)}`).join(`\n${indent} and `)} then
3078
3131
  ${indent} return null;
3079
3132
  ${indent}end if;
3080
3133
  ${indent}insert into ${versionTable} as v (user_id, version)
3081
3134
  ${indent}select distinct h.user_id, 1
3082
3135
  ${indent}from (
3083
- ${indent} ${holders.map((holder) => holder.userThrough === void 0 ? `select h.${quoteIdent(holder.user)}::uuid as user_id from ${quoteQualified(holder.table)} h where h.${quoteIdent(holder.through.ref)} = old.${quoteIdent(holder.through.id)}` : `select u.${quoteIdent(holder.userThrough.key)}::uuid as user_id from ${quoteQualified(holder.table)} h join ${quoteQualified(holder.userThrough.table)} u on u.${quoteIdent(holder.userThrough.id)} = h.${quoteIdent(holder.user)} where h.${quoteIdent(holder.through.ref)} = old.${quoteIdent(holder.through.id)}`).join(`\n${indent} union\n${indent} `)}
3136
+ ${indent} ${holders.map((holder) => {
3137
+ const held = holder.through.match.map(([ref, id]) => `h.${quoteIdent(ref)} = old.${quoteIdent(id)}`).join(" and ");
3138
+ return holder.userThrough === void 0 ? `select h.${quoteIdent(holder.user)}::uuid as user_id from ${quoteQualified(holder.table)} h where ${held}` : `select u.${quoteIdent(holder.userThrough.key)}::uuid as user_id from ${quoteQualified(holder.table)} h join ${quoteQualified(holder.userThrough.table)} u on u.${quoteIdent(holder.userThrough.id)} = h.${quoteIdent(holder.user)} where ${held}`;
3139
+ }).join(`\n${indent} union\n${indent} `)}
3084
3140
  ${indent}) h
3085
3141
  ${indent}where h.user_id is not null
3086
3142
  ${indent} and exists (select 1 from auth.users au where au.id = h.user_id)
@@ -3139,15 +3195,20 @@ create trigger ${quoteIdent(VERSION_TRIGGER)}
3139
3195
  //#region src/cli/supabase-hook/manifest.ts
3140
3196
  function helperList(parts, types) {
3141
3197
  const client = ["authenticated"];
3142
- return [helperEntry(HELPERS.has, "p_grant text", "boolean", client), ...parts.scopes.flatMap((scope) => {
3143
- const returns = `setof ${types.get(scope.name) ?? "uuid"}`;
3144
- return [
3145
- helperEntry(permittedIdsHelper(scope.name), "p_grant text", returns, client),
3146
- helperEntry(memberIdsHelper(scope.name), "", returns, client),
3147
- ...parts.helpers.memberFor.includes(scope.name) ? [helperEntry(memberForHelper(scope.name), "p_user uuid", returns, parts.extra.length === 0 ? [] : ["supabase_auth_admin"])] : [],
3148
- ...parts.helpers.memberFor.includes(scope.name) && isTeamScope(scope.name) ? [helperEntry(memberOfHelper(scope.name), "p_user uuid", returns, client)] : []
3149
- ];
3150
- })];
3198
+ const teams = hookTeamsHelper(parts);
3199
+ return [
3200
+ helperEntry(HELPERS.has, "p_grant text", "boolean", client),
3201
+ ...parts.scopes.flatMap((scope) => {
3202
+ const returns = `setof ${types.get(scope.name) ?? "uuid"}`;
3203
+ return [
3204
+ helperEntry(permittedIdsHelper(scope.name), "p_grant text", returns, client),
3205
+ helperEntry(memberIdsHelper(scope.name), "", returns, client),
3206
+ ...parts.helpers.memberFor.includes(scope.name) ? [helperEntry(memberForHelper(scope.name), "p_user uuid", returns, parts.extra.length === 0 ? [] : ["supabase_auth_admin"])] : [],
3207
+ ...parts.helpers.memberFor.includes(scope.name) && isTeamScope(scope.name) ? [helperEntry(memberOfHelper(scope.name), "p_user uuid", returns, client)] : []
3208
+ ];
3209
+ }),
3210
+ ...teams === void 0 ? [] : [helperEntry(teams, "p_user uuid", "setof uuid", client)]
3211
+ ];
3151
3212
  }
3152
3213
  function helperEntry(name, args, returns, execute) {
3153
3214
  return {
@@ -3277,7 +3338,8 @@ function manifestOf(parts, out, config, policy) {
3277
3338
  schema: parts.schema,
3278
3339
  function: "custom_access_token_hook",
3279
3340
  out,
3280
- ...parts.before.length === 0 ? {} : { before: parts.before }
3341
+ ...parts.before.length === 0 ? {} : { before: parts.before },
3342
+ activeFrom: parts.activeFrom
3281
3343
  },
3282
3344
  helpers: {
3283
3345
  schema: parts.helpers.schema,
@@ -3421,6 +3483,7 @@ ${toml}${grantsOut === void 0 ? "" : `\n-- what supabase db diff drops from this
3421
3483
  subjectForSql(parts, config),
3422
3484
  authzVersionForSql(parts),
3423
3485
  membersOfSql(parts),
3486
+ teamIdsOfSql(parts),
3424
3487
  apiWrappersSql(parts),
3425
3488
  grantsSql(parts),
3426
3489
  managedSql(parts)
@@ -3622,4 +3685,4 @@ async function runSupabase(input) {
3622
3685
  };
3623
3686
  }
3624
3687
  //#endregion
3625
- export { supabaseConfig as _, supabaseHookManifest as a, resolveAuthorize as b, pd039 as c, schemasRefusal as d, declarativeSql as f, readSupabaseConfig as g, pd074 as h, runSupabase as i, isSupabaseSchemas as l, pd045 as m, hookOut as n, supabaseHookSql as o, attrsPlan as p, loadScopes as r, approvalsSql as s, grantsLabel as t, resolveSchemas as u, parseRbacAuthorize as v, rbacScaffold as y };
3688
+ export { readSupabaseConfig as _, supabaseHookManifest as a, rbacScaffold as b, activeSource as c, resolveSchemas as d, schemasRefusal as f, pd074 as g, pd045 as h, runSupabase as i, pd039 as l, attrsPlan as m, hookOut as n, supabaseHookSql as o, declarativeSql as p, loadScopes as r, approvalsSql as s, grantsLabel as t, isSupabaseSchemas as u, supabaseConfig as v, resolveAuthorize as x, parseRbacAuthorize as y };
@@ -0,0 +1 @@
1
+ export { i as runSupabase } from "./supabase-hook-BT2P9wah.js";
@@ -5,18 +5,18 @@ import { l as policyLevels } from "./policy-CLQ8__GF.js";
5
5
  import { a as describeError, i as configError } from "./errors-Vpu6rKHl.js";
6
6
  import { d as sqlTextArray, i as qualifySqlTable } from "./sql-0WjxIp9g.js";
7
7
  import "./budget-BELja5A9.js";
8
- import { l as roleColumn } from "./sources-CMAM-2A3.js";
8
+ import { l as roleColumn } from "./sources-C4vkzZJV.js";
9
9
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
10
10
  import { c as parseSplit } from "./output-files-BIQ_9pIs.js";
11
- import { b as resolveAuthorize } from "./supabase-hook-CrgU06WH.js";
12
- import { A as quoteQualified, C as parseMembershipsFlag, D as qualified, F as firstScopeType, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, s as signedIn, t as CUSTOM_ROLES } from "./shared-Afctg7B0.js";
13
- import { G as byKey, H as rolesTableScope, O as tokenScopesPlan, Q as graphSqlName, V as raiseSql, W as byCodeUnit, Y as apiKeysPlan, a as closureDepths, bt as checkSuspension, i as tablelessResources, o as graphPlan, r as tableNames, t as resolveVias, z as currentKeyExpr } from "./tables-BqrxBCir.js";
14
- import { o as assignableRoles, r as unsatisfiedKinds, t as ownershipRules, u as roleNames } from "./ownership-DA5YdYTm.js";
11
+ import { x as resolveAuthorize } from "./supabase-hook-BT2P9wah.js";
12
+ import { A as quoteQualified, C as parseMembershipsFlag, D as qualified, F as firstScopeType, O as quoteIdent, R as tenantTypeOf, a as customRolesOn, j as quoteTable, k as quoteLiteral, s as signedIn, t as CUSTOM_ROLES } from "./shared-DrGLwM3s.js";
13
+ import { G as byKey, H as rolesTableScope, O as tokenScopesPlan, Q as graphSqlName, V as raiseSql, W as byCodeUnit, Y as apiKeysPlan, a as closureDepths, bt as checkSuspension, i as tablelessResources, o as graphPlan, r as tableNames, t as resolveVias, z as currentKeyExpr } from "./tables-DimBcVWY.js";
14
+ import { o as assignableRoles, r as unsatisfiedKinds, t as ownershipRules, u as roleNames } from "./ownership-qqBuGJXr.js";
15
15
  import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
16
16
  import { i as group, o as sqlStatements } from "./deciding-columns-NB4wcyBf.js";
17
- import { t as resolveNames } from "./resolve-names-ConCSj1y.js";
18
- import { d as orSql, h as branchClauses } from "./fields-D0vUI6dq.js";
19
- import { m as tableFor } from "./verify-DlUcTDBz.js";
17
+ import { d as orSql, h as branchClauses } from "./fields-DI8s3cPl.js";
18
+ import { t as resolveNames } from "./resolve-names-Y1Cb22cp.js";
19
+ import { m as tableFor } from "./verify-jHrbmn-E.js";
20
20
  //#region src/cli/rls/custom-role-rebuild.ts
21
21
  const PREFIX = "PermDock CLI";
22
22
  /** A column of the roles-table row `r`. */
@@ -8,8 +8,8 @@ import { a as delegatedScopeMap } from "./permdock-BvjivVb9.js";
8
8
  import { i as configError } from "./errors-Vpu6rKHl.js";
9
9
  import { d as sqlTextArray, i as qualifySqlTable, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
10
10
  import { a as scopeMembershipTable, d as restrictedRowsSql, i as scopeColumn, l as relationArmSql } from "./compile-EzEMB-7v.js";
11
- import { d as keptKeys, l as roleColumn, u as roleManifest } from "./sources-CMAM-2A3.js";
12
- import { A as quoteQualified, D as qualified, E as helperSchema, I as scopeTypeOf, O as quoteIdent, R as tenantTypeOf, _ as subjectClaimJsonSql, d as keyTenantSql, f as kindFilterSql, h as roleKindSql, i as allowEntry, j as quoteTable, k as quoteLiteral, m as memberVia, n as GLOBAL_ROLES, o as rootName, r as HELPERS, s as signedIn, t as CUSTOM_ROLES, u as globalKindFilterSql, v as subjectClaimSql, w as CLI, x as userIdHelperSql, y as subjectIdSql } from "./shared-Afctg7B0.js";
11
+ import { d as keptKeys, l as roleColumn, u as roleManifest } from "./sources-C4vkzZJV.js";
12
+ import { A as quoteQualified, D as qualified, E as helperSchema, I as scopeTypeOf, O as quoteIdent, R as tenantTypeOf, _ as subjectClaimJsonSql, d as keyTenantSql, f as kindFilterSql, h as roleKindSql, i as allowEntry, j as quoteTable, k as quoteLiteral, m as memberVia, n as GLOBAL_ROLES, o as rootName, r as HELPERS, s as signedIn, t as CUSTOM_ROLES, u as globalKindFilterSql, v as subjectClaimSql, w as CLI, x as userIdHelperSql, y as subjectIdSql } from "./shared-DrGLwM3s.js";
13
13
  //#region src/cli/sql/active.ts
14
14
  function checkActiveRow(label, row) {
15
15
  quoteTable(row.table);
@@ -1,5 +1,5 @@
1
1
  import { a as CatalogDocument } from "../../types-ZzRGoViD.js";
2
- import { i as SupabaseManifest } from "../../manifest-CzzWtnAb.js";
2
+ import { i as SupabaseManifest } from "../../manifest-B5yF3CIq.js";
3
3
  //#region src/testing/fixtures/index.d.ts
4
4
  /**
5
5
  * The `permissions.catalog.json` of `apps/examples/next-better-supabase`, a
@@ -1,12 +1,12 @@
1
- import { n as parseSupabaseManifest } from "../../manifest-wg8WkkpD.js";
1
+ import { n as parseSupabaseManifest } from "../../manifest-BXTbHNIV.js";
2
2
  import { t as parseCatalog } from "../../parse-1_ZheTW5.js";
3
3
  //#region src/testing/fixtures/better-supabase.catalog.json
4
4
  var better_supabase_catalog_default = {
5
5
  $schema: "https://permdock.com/schemas/catalog-v1.json",
6
6
  version: 1,
7
- generatedAt: "2026-10-21T18:26:20.894Z",
8
- generator: "permdock@0.7.0",
9
- fingerprint: "sha-256:2VY9uDRP6NWXTNcU989MMBZa3-z22VbDWKWkvnXaTFc",
7
+ generatedAt: "2026-10-25T13:10:40.583Z",
8
+ generator: "permdock@0.9.0",
9
+ fingerprint: "sha-256:vWJUJuM8Qg6Cd8ozHqIOkaPdpE4p6cxof-Hypzwe3tg",
10
10
  resources: {
11
11
  "staff": {
12
12
  "id": "id",
@@ -115,29 +115,29 @@ var better_supabase_catalog_default = {
115
115
  },
116
116
  permissions: [
117
117
  {
118
- "key": "audit.revert",
119
- "scope": "audit:revert",
118
+ "key": "audit.read",
119
+ "scope": "audit:read",
120
120
  "resource": "audit",
121
- "action": "revert",
121
+ "action": "read",
122
122
  "arity": "collection",
123
123
  "meta": {},
124
124
  "usages": [{
125
125
  "file": "src/policy.ts",
126
- "line": 29,
126
+ "line": 28,
127
127
  "call": "reference"
128
128
  }],
129
129
  "rowConditions": false
130
130
  },
131
131
  {
132
- "key": "audit.view",
133
- "scope": "audit:view",
132
+ "key": "audit.revert",
133
+ "scope": "audit:revert",
134
134
  "resource": "audit",
135
- "action": "view",
135
+ "action": "revert",
136
136
  "arity": "collection",
137
137
  "meta": {},
138
138
  "usages": [{
139
139
  "file": "src/policy.ts",
140
- "line": 28,
140
+ "line": 29,
141
141
  "call": "reference"
142
142
  }],
143
143
  "rowConditions": false
@@ -334,7 +334,7 @@ var better_supabase_catalog_default = {
334
334
  ],
335
335
  grants: [
336
336
  {
337
- "permission": "audit.revert",
337
+ "permission": "audit.read",
338
338
  "effect": "allow",
339
339
  "role": "owner",
340
340
  "to": {
@@ -345,7 +345,7 @@ var better_supabase_catalog_default = {
345
345
  "scope": "organization"
346
346
  },
347
347
  {
348
- "permission": "audit.view",
348
+ "permission": "audit.revert",
349
349
  "effect": "allow",
350
350
  "role": "owner",
351
351
  "to": {
@@ -512,6 +512,7 @@ var better_supabase_manifest_default = {
512
512
  "schema": "permdock",
513
513
  "function": "custom_access_token_hook",
514
514
  "out": "supabase/schemas/permdock/functions/custom_access_token_hook.sql",
515
+ "activeFrom": { "appMetadata": "active_organization" },
515
516
  "schemas": "pg-delta"
516
517
  },
517
518
  helpers: {
@@ -580,15 +581,14 @@ var better_supabase_manifest_default = {
580
581
  "args": "p_users uuid[]"
581
582
  },
582
583
  memberships: [{
583
- "table": "public.memberships",
584
+ "table": "public.organization_memberships",
584
585
  "user": { "column": "user_id" },
585
- "scope": { "column": "scope" },
586
- "id": { "column": "scope_id" },
586
+ "scope": { "value": "organization" },
587
+ "id": { "column": "organization_id" },
587
588
  "role": { "column": "role" },
588
589
  "columns": [
589
590
  "user_id",
590
- "scope",
591
- "scope_id",
591
+ "organization_id",
592
592
  "role"
593
593
  ]
594
594
  }, {
@@ -722,15 +722,14 @@ var better_supabase_manifest_default = {
722
722
  }
723
723
  ],
724
724
  "memberships": [{
725
- "table": "public.memberships",
725
+ "table": "public.organization_memberships",
726
726
  "user": { "column": "user_id" },
727
- "scope": { "column": "scope" },
728
- "id": { "column": "scope_id" },
727
+ "scope": { "value": "organization" },
728
+ "id": { "column": "organization_id" },
729
729
  "role": { "column": "role" },
730
730
  "columns": [
731
731
  "user_id",
732
- "scope",
733
- "scope_id",
732
+ "organization_id",
734
733
  "role"
735
734
  ]
736
735
  }, {
@@ -758,10 +757,9 @@ var better_supabase_manifest_default = {
758
757
  "public.contacts.customer_id",
759
758
  "public.contacts.organization_id",
760
759
  "public.contacts.user_id",
761
- "public.memberships.role",
762
- "public.memberships.scope",
763
- "public.memberships.scope_id",
764
- "public.memberships.user_id"
760
+ "public.organization_memberships.organization_id",
761
+ "public.organization_memberships.role",
762
+ "public.organization_memberships.user_id"
765
763
  ],
766
764
  markers: {
767
765
  "hook": "v1",
@@ -1,7 +1,7 @@
1
1
  import { G as CustomRoleSource, J as DecisionSink, T as Policy, U as CredentialVerifier, Y as EntitlementSource, Zt as Snapshot, bt as WhereCompiler, ct as SnapshotSource, dt as SubjectResolver, et as LimitStore, fr as Membership, hr as Subject, ht as TokenVerifier, mt as TokenSigner, nt as MembershipSource, ot as RelationSource, pr as Principal, q as DecisionProvider, sn as DeliveryChannel, st as SettingsSource } from "../policy-types-DGIO_gxq.js";
2
2
  import { g as ResourceInit, l as InferPermissionTree, u as Permission } from "../permission-types-CAY-GU7e.js";
3
3
  import { r as Role } from "../vocabulary-DEJ5j4mR.js";
4
- import { Ut as VersionCache, st as LegacyCheck } from "../index-vYjMrXyK.js";
4
+ import { st as LegacyCheck } from "../index-Cay5-Kvx.js";
5
5
  import { D as ApprovalPolicySource, _ as PrincipalSource, a as PermDock, b as Limits, h as PrincipalIdentity } from "../permdock-CprAPN3w.js";
6
6
  import { s as PolicySource } from "../hosted-DVxlLZMe.js";
7
7
  import { a as ApprovalDelegationSource, m as ApprovalStore } from "../types-DLvhVm1r.js";
@@ -11,10 +11,11 @@ import { c as AccessReviewStore } from "../types-B2efzoSX.js";
11
11
  import { R as IdempotencyStore } from "../index-DJwEgYzA.js";
12
12
  import { n as RevocationFeed } from "../revocations-BaUXHM1N.js";
13
13
  import { s as SupportSessionSource } from "../index-CV-7DWeD.js";
14
+ import { r as SupabaseHookManifest } from "../manifest-B5yF3CIq.js";
15
+ import { n as VersionCache } from "../version-cache-Df11C2Qp.js";
16
+ import { t as supabaseMembershipsBudget } from "../budget-hYsPz_yE.js";
14
17
  import { a as AutomationSource, t as Automation } from "../automation-C6Jg75xq.js";
15
18
  import { c as DeliveryTransport, g as TransportMessages } from "../types-CN0LsqbK.js";
16
- import { r as SupabaseHookManifest } from "../manifest-CzzWtnAb.js";
17
- import { t as supabaseMembershipsBudget } from "../budget-hYsPz_yE.js";
18
19
  import { t as CloudApproverOptions } from "../types-BB-zWDcR.js";
19
20
  import { n as ApprovalWaiter } from "../waiter-CqUKX6CY.js";
20
21
  import { g as SetQueue, l as ReplayStore } from "../types-DsHGPtkR.js";
@@ -34,7 +34,7 @@ import { l as sha256Hex, n as scimHandler, t as directoryMembershipSource } from
34
34
  import { c as quoteSqlTable, o as quoteSqlIdent } from "../sql-0WjxIp9g.js";
35
35
  import { i as cloudEndpoints, n as cloud, s as approverHeaders, t as bearerChallenge } from "../challenge-DImNcR7B.js";
36
36
  import { t as supabaseMembershipsBudget } from "../budget-BELja5A9.js";
37
- import { t as supabaseManifestSchema } from "../manifest-schema-2r37XRhD.js";
37
+ import { t as supabaseManifestSchema } from "../manifest-schema-DQkBK2Mr.js";
38
38
  import { t as PUSHED_POLICY_SCHEMA } from "../pushed-policy-CDuOL2de.js";
39
39
  import { i as policyMatrixLayout, n as testRlsParity, r as policyMatrix, t as testOrmParity } from "../core-DzVINFbU.js";
40
40
  import { i as saasPermissions } from "../permissions-CYcHj_w7.js";
@@ -6302,7 +6302,8 @@ const supabaseHookManifestFixture = {
6302
6302
  hook: {
6303
6303
  schema: "permdock",
6304
6304
  function: "custom_access_token_hook",
6305
- out: "supabase/permdock-hook.sql"
6305
+ out: "supabase/permdock-hook.sql",
6306
+ activeFrom: { appMetadata: "active_tenant" }
6306
6307
  },
6307
6308
  helpers: {
6308
6309
  schema: "permdock",
@@ -1,5 +1,4 @@
1
- import { n as RoleMap, r as RoleThrough } from "./types-BMVDHvI0.js";
2
- import { s as SqlMembershipSource } from "./sources-CWG32C0G.js";
1
+ import { h as RoleThrough, m as RoleMap, s as SqlMembershipSource } from "./sources-oB1Hg1Fm.js";
3
2
  //#region src/cli/core/errors.d.ts
4
3
  /**
5
4
  * 0 success, 1 failure, 2 usage, 3 action required, 130 interrupted (SIGINT or
@@ -935,6 +934,28 @@ type PowerSyncConfig = {
935
934
  * `localSnapshot` and `powerSyncSource`; none by default.
936
935
  */
937
936
  readonly manifest?: string;
937
+ /**
938
+ * Tables that are not resources, by `schema.table`, each synced as its own
939
+ * stream: the user's own rows, the rows that point at a resource row the user
940
+ * reads, or both.
941
+ */
942
+ readonly tables?: Readonly<Record<string, PowerSyncTable>>;
943
+ };
944
+ type PowerSyncTable = {
945
+ /** The user id column: the stream holds the rows whose column is the user. */
946
+ readonly user?: string;
947
+ /** The resources a row points at; the stream holds rows of any of them. */
948
+ readonly follow?: readonly PowerSyncFollow[];
949
+ };
950
+ /**
951
+ * A row points at a `resource` row through `field`, which holds its id; `match`
952
+ * keeps the rows whose columns equal the given values, for a table whose rows
953
+ * point at several resources.
954
+ */
955
+ type PowerSyncFollow = {
956
+ readonly resource: string;
957
+ readonly field: string;
958
+ readonly match?: Readonly<Record<string, string>>;
938
959
  };
939
960
  type CliIo = {
940
961
  readonly stdout: (text: string) => void;
@@ -1,4 +1,4 @@
1
- import { s as PermDockPluginOptions } from "../types-CzOeVvcC.js";
1
+ import { s as PermDockPluginOptions } from "../types-Cklw5hJo.js";
2
2
  import { createUnplugin } from "unplugin";
3
3
  //#region src/unplugin/index.d.ts
4
4
  type CreateUnplugin = typeof createUnplugin<PermDockPluginOptions | undefined>;
@@ -1,4 +1,4 @@
1
- import { n as createCollectScheduler, r as report } from "../watch-BFDKqmUa.js";
1
+ import { n as createCollectScheduler, r as report } from "../watch-Bpci3hBY.js";
2
2
  import { r as peerHint } from "../peer-Q0fuZ6hx.js";
3
3
  import { createRequire } from "node:module";
4
4
  //#region src/unplugin/index.ts
@@ -16,7 +16,7 @@ const usage = defineLeaf({
16
16
  }
17
17
  },
18
18
  async run(ctx, { flags }) {
19
- return (await import("./usage-0hjZPIRX.js")).runUsage({
19
+ return (await import("./usage-weohzv2f.js")).runUsage({
20
20
  cwd: ctx.cwd,
21
21
  config: ctx.config,
22
22
  ignore: flags.ignore,
@@ -6,8 +6,8 @@ import { c as jsonSchemaOf } from "./catalog-doc-DjMKzJp9.js";
6
6
  import { a as loadModule, n as asPolicy, s as pickNamed } from "./load-DjSU5KXO.js";
7
7
  import { r as runCollect } from "./collect-WCl8cJQV.js";
8
8
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
9
- import { t as DOCS_BASE } from "./manifest-B2QPh19C.js";
10
- import { r as findingOf } from "./output-DV5dwOTs.js";
9
+ import { t as DOCS_BASE } from "./manifest-B4ENCp2I.js";
10
+ import { r as findingOf } from "./output-LsbLe41I.js";
11
11
  import { existsSync, readFileSync, realpathSync } from "node:fs";
12
12
  import { dirname, resolve } from "node:path";
13
13
  import { fileURLToPath, pathToFileURL } from "node:url";
@@ -0,0 +1 @@
1
+ export { t as runUsage } from "./usage-t_nXnwCW.js";
@@ -20,16 +20,16 @@ import { o as loadPolicyAt } from "./load-DjSU5KXO.js";
20
20
  import { i as qualifySqlTable, n as defaultSqlCommand, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
21
21
  import { a as scopeMembershipTable, i as scopeColumn } from "./compile-EzEMB-7v.js";
22
22
  import "./budget-BELja5A9.js";
23
- import "./sources-CMAM-2A3.js";
23
+ import "./sources-C4vkzZJV.js";
24
24
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
25
- import { t as DOCS_BASE } from "./manifest-B2QPh19C.js";
25
+ import { t as DOCS_BASE } from "./manifest-B4ENCp2I.js";
26
26
  import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-A1_sp_tR.js";
27
- import { A as quoteQualified, N as arrayColumnsOf, O as quoteIdent, P as columnTypesOf, _ as subjectClaimJsonSql, a as customRolesOn, j as quoteTable, k as quoteLiteral, r as HELPERS, v as subjectClaimSql } from "./shared-Afctg7B0.js";
28
- import { C as accessSql, D as tokenScopeAllowsCall, S as requiresSql, ht as scopeTable, k as capabilityAccessSql, n as tableNameOf, o as graphPlan, q as apiKeyAllowsCall, r as tableNames } from "./tables-BqrxBCir.js";
29
- import { c as breakGlassKey, f as compileConditionSql, l as collectGrants, m as sqlFunctionNames, p as contextRefs, s as breakGlassHolder } from "./ownership-DA5YdYTm.js";
27
+ import { A as quoteQualified, N as arrayColumnsOf, O as quoteIdent, P as columnTypesOf, _ as subjectClaimJsonSql, a as customRolesOn, j as quoteTable, k as quoteLiteral, r as HELPERS, v as subjectClaimSql } from "./shared-DrGLwM3s.js";
28
+ import { C as accessSql, D as tokenScopeAllowsCall, S as requiresSql, ht as scopeTable, k as capabilityAccessSql, n as tableNameOf, o as graphPlan, q as apiKeyAllowsCall, r as tableNames } from "./tables-DimBcVWY.js";
29
+ import { c as breakGlassKey, f as compileConditionSql, l as collectGrants, m as sqlFunctionNames, p as contextRefs, s as breakGlassHolder } from "./ownership-qqBuGJXr.js";
30
30
  import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
31
31
  import { n as pgConnector, t as connectPgPool } from "./pg-DQTqRrou.js";
32
- import { _ as wrapSql, g as validitySql, m as andSql, s as viewName, t as FIELD_VIEWS } from "./fields-D0vUI6dq.js";
32
+ import { _ as wrapSql, g as validitySql, m as andSql, s as viewName, t as FIELD_VIEWS } from "./fields-DI8s3cPl.js";
33
33
  import { resolve } from "node:path";
34
34
  import { createHash, randomUUID } from "node:crypto";
35
35
  //#region src/cli/rls/indexes.ts