permdock 0.11.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.
Files changed (84) hide show
  1. package/dist/a2a/index.js +1 -1
  2. package/dist/{adoption-scan-DKCOsfcF.js → adoption-scan-BGtwGfoH.js} +1 -1
  3. package/dist/agent/index.js +1 -1
  4. package/dist/ai-sdk/index.js +2 -2
  5. package/dist/{arazzo-CTH5iN--.js → arazzo-9uhbmKf5.js} +1 -1
  6. package/dist/{arazzo-BXaEhGHM.js → arazzo-Bol9OgF-.js} +1 -1
  7. package/dist/better-supabase/index.d.ts +19 -17
  8. package/dist/better-supabase/index.js +31 -16
  9. package/dist/better-supabase-83Gsetrv.js +56 -0
  10. package/dist/{casbin-BuTZnSPv.js → casbin-1PVgMHOR.js} +1 -1
  11. package/dist/{casbin-DTi6HSsl.js → casbin-CBXD5rFx.js} +1 -1
  12. package/dist/claude-agent/index.js +1 -1
  13. package/dist/cli/bin.js +1 -1
  14. package/dist/cli/index.js +2 -2
  15. package/dist/{cloud-DiAiYFRo.js → cloud-BfJVKpcN.js} +1 -1
  16. package/dist/{codemod-C1U8_Zu3.js → codemod-BXLd4K3j.js} +1 -1
  17. package/dist/{codemod-_q_ZI01S.js → codemod-DWfH-KHk.js} +2 -2
  18. package/dist/{collect-D9Tt0Bcx.js → collect-lZgCKMe_.js} +1 -1
  19. package/dist/{completion-DLTuCf53.js → completion-fJ19i8Jk.js} +1 -1
  20. package/dist/{config-CmydKZr2.js → config-BYSk3iKV.js} +1 -1
  21. package/dist/{config-BR23fL8m.js → config-ZZdtyQZy.js} +4 -1
  22. package/dist/{config-report-5AwptLr2.js → config-report-BpztJ3HP.js} +1 -1
  23. package/dist/{create-6EwRQlig.js → create-Coq5fIrq.js} +1 -1
  24. package/dist/{diff-BwR1JdP2.js → diff-CxtbOi2l.js} +1 -1
  25. package/dist/{diff-CQegtBAo.js → diff-DfmYaIhB.js} +1 -1
  26. package/dist/{doctor-DxyVeUEE.js → doctor-NxCr_hba.js} +2 -2
  27. package/dist/{doctor-ktitU5Dl.js → doctor-eNc7A_7I.js} +13 -47
  28. package/dist/eve/index.js +1 -1
  29. package/dist/{fixtures-A1_sp_tR.js → fixtures-Bm4_K1ke.js} +7 -9
  30. package/dist/{import-t1yqnCyG.js → import-efm6qPgx.js} +1 -1
  31. package/dist/{init-CY7THM2v.js → init-BtWY1L0J.js} +3 -3
  32. package/dist/{init-DFwylmiN.js → init-D6rpLPwM.js} +1 -1
  33. package/dist/{kernel-qv4cr9w8.js → kernel-BD8QuMnv.js} +9 -2
  34. package/dist/{login-C5XLYZSF.js → login-B8s6VI8Z.js} +3 -3
  35. package/dist/{login-B92-dZMK.js → login-cLflB63Z.js} +1 -1
  36. package/dist/{manifest-Cav1rjNQ.js → manifest-BWIR_EEB.js} +33 -33
  37. package/dist/mcp/index.d.ts +12 -3
  38. package/dist/mcp/index.js +60 -16
  39. package/dist/next/plugin.js +1 -1
  40. package/dist/openai/index.js +2 -2
  41. package/dist/{openapi-gMQQSzNn.js → openapi-CT55v3WD.js} +2 -2
  42. package/dist/{openapi-CuePQL4z.js → openapi-DDENzRbG.js} +1 -1
  43. package/dist/{output-CtyBwTNB.js → output-3iB3_Hfg.js} +1 -1
  44. package/dist/{powersync-CBcsEvdr.js → powersync-COjQTHRD.js} +2 -2
  45. package/dist/{powersync-CD8-Ypao.js → powersync-DVbskWD9.js} +126 -39
  46. package/dist/powersync-k8lUeC37.js +1 -0
  47. package/dist/pull-BY1METGf.js +1 -0
  48. package/dist/{pull-CAeaAioC.js → pull-Er4aBHlL.js} +1 -1
  49. package/dist/react-native/index.d.ts +7 -7
  50. package/dist/react-native/index.js +57 -16
  51. package/dist/{rls-CtRaRrn3.js → rls-DY3Fc18U.js} +30 -15
  52. package/dist/{rls-BYHN5bcJ.js → rls-DjjOHlKE.js} +1 -1
  53. package/dist/{run-B5nyNKe8.js → run-BlxXmaDS.js} +3 -3
  54. package/dist/run-DGSLvGty.js +1 -0
  55. package/dist/{scan-CvFWW_fU.js → scan-CR_xm71k.js} +1 -1
  56. package/dist/{schema-CQzIJdEd.js → schema-CnrIP94n.js} +1 -1
  57. package/dist/{skills-Bar7ZqwM.js → skills-CY-MY_Oj.js} +1 -1
  58. package/dist/{skills-BZc81VLt.js → skills-uzsVqEi9.js} +1 -1
  59. package/dist/supabase/index.js +1 -1
  60. package/dist/{supabase-CBEK6KEo.js → supabase-DYWnT800.js} +2 -2
  61. package/dist/{supabase-hook-CyuD9Wau.js → supabase-hook-HPgwYb9V.js} +2 -2
  62. package/dist/supabase-hook-qsewAVZY.js +1 -0
  63. package/dist/{supautils-C-_jqylY.js → supautils-DZ95xxW-.js} +3 -3
  64. package/dist/testing/core.js +1 -1
  65. package/dist/testing/fixtures/index.js +1 -1
  66. package/dist/testing/index.js +2 -2
  67. package/dist/unplugin/index.js +1 -1
  68. package/dist/usage-CH7oISI6.js +1 -0
  69. package/dist/{usage-heV5KOiU.js → usage-Dm2hn0pS.js} +1 -1
  70. package/dist/{usage-Y6xZUfE-.js → usage-WYRc7Kqg.js} +2 -2
  71. package/dist/{verify-6EauWrkP.js → verify-CHQgLrtS.js} +3 -3
  72. package/dist/watch-C44FtM79.js +1 -0
  73. package/dist/{watch-Bpci3hBY.js → watch-CTfSlIGD.js} +1 -1
  74. package/package.json +16 -16
  75. package/skills/permdock-credentials/references/tokens-keys-links.md +1 -1
  76. package/skills/permdock-wire/references/adapters.md +1 -1
  77. package/dist/powersync-6vgKevSi.js +0 -1
  78. package/dist/pull-DfJALUbS.js +0 -1
  79. package/dist/run-0vOholnN.js +0 -1
  80. package/dist/supabase-hook-CWvEpdCh.js +0 -1
  81. package/dist/usage-CNca1i1W.js +0 -1
  82. package/dist/watch-COuvly20.js +0 -1
  83. package/dist/{core-DzVINFbU.js → core-lxoANyai.js} +1 -1
  84. package/dist/{supabase-CC6rIri4.js → supabase-CDHMsDD0.js} +1 -1
@@ -11,13 +11,13 @@ import "./sources-C4vkzZJV.js";
11
11
  import { t as policyFromCatalog } from "./policy-from-catalog-CU3An8uP.js";
12
12
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
13
13
  import { i as INDEXES_MARKER, n as GRANTS_MARKER, o as SEEDS_MARKER, t as BACKFILL_MARKER } from "./markers-BeHZ4x9Q.js";
14
- import { a as nonEmptyOr } from "./output-CtyBwTNB.js";
14
+ import { a as nonEmptyOr } from "./output-3iB3_Hfg.js";
15
15
  import { i as requirePeer, n as packageManagerOf, t as addLine } from "./peer-Q0fuZ6hx.js";
16
16
  import { t as POLICY_NOT_PUBLISHED } from "./problem-types-DSsRfONQ.js";
17
- import { t as fetchProjectPolicy } from "./pull-CAeaAioC.js";
17
+ import { t as fetchProjectPolicy } from "./pull-Er4aBHlL.js";
18
18
  import { n as MIGRATION_DIRS } from "./constants-DcJABbLW.js";
19
19
  import { a as isSeedsDirectory, c as parseSplit, d as seedsMigration, f as writeOutputFiles, l as partPath, n as dataMigrationFile, r as driftOf, u as pgDeltaPath } from "./output-files-BIQ_9pIs.js";
20
- import { b as rbacScaffold, d as resolveSchemas, f as schemasRefusal, o as supabaseHookSql, p as declarativeSql, s as approvalsSql, t as grantsLabel, u as isSupabaseSchemas, y as parseRbacAuthorize } from "./supabase-hook-CyuD9Wau.js";
20
+ import { b as rbacScaffold, d as resolveSchemas, f as schemasRefusal, o as supabaseHookSql, p as declarativeSql, s as approvalsSql, t as grantsLabel, u as isSupabaseSchemas, y as parseRbacAuthorize } from "./supabase-hook-HPgwYb9V.js";
21
21
  import { A as quoteQualified, D as qualified$1, I as scopeTypeOf, O as quoteIdent$1, _ as subjectClaimJsonSql, c as SESSION_LIVE_HELPER, g as sessionLiveHelperSql, j as quoteTable, k as quoteLiteral, r as HELPERS, t as CUSTOM_ROLES, y as subjectIdSql } from "./shared-DrGLwM3s.js";
22
22
  import { C as accessSql, G as byKey, T as seedSql, Z as graphHelper, ct as memberIdsHelper, ft as permittedIdsHelper, ht as scopeTable, mt as scopeSources, r as tableNames, s as graphSql, w as helpersSql, x as permittedByPermissionHelper, y as permissionHelpersSql } from "./tables-DimBcVWY.js";
23
23
  import { c as breakGlassKey, i as assignmentSql, l as collectGrants, n as ownershipSql, s as breakGlassHolder } from "./ownership-qqBuGJXr.js";
@@ -25,8 +25,8 @@ import { a as splitUndiffed } from "./deciding-columns-NB4wcyBf.js";
25
25
  import { t as connectPgPool } from "./pg-DQTqRrou.js";
26
26
  import { a as fieldViewsSql, c as ACTOR_MAY_WRITE, f as readOnlyActorKinds, i as fieldViews, l as actorMayWriteSql, n as columnGrantSql, o as rowBranches, p as readOnlyActorPolicies, r as columnRevokeSql, u as assemblePolicies } from "./fields-DI8s3cPl.js";
27
27
  import { n as permissionHoldersSql } from "./resolve-names-Y1Cb22cp.js";
28
- import { _ as indexTargets, a as verifyResult, b as readTableIndexFacts, c as callsHelper, g as INDEX_COLUMNS_SQL, h as COLUMNS_SQL, i as verifyIgnores, l as helperCallKeys, m as tableFor, n as runRlsVerify, o as HELPER_TABLES, p as compileGrants, r as rlsFinding, v as indexesSql, y as pruneIndexTargets } from "./verify-6EauWrkP.js";
29
- import { a as buildContext, c as levelKeys, d as rebuildPlan, i as splitsPart, l as rowHelpersSql, n as generateOptions, o as CANDIDATES, r as isRefusal, s as inheritTargets, t as supautilsRejections, u as DROPPED_LIST } from "./supautils-C-_jqylY.js";
28
+ import { _ as indexTargets, a as verifyResult, b as readTableIndexFacts, c as callsHelper, g as INDEX_COLUMNS_SQL, h as COLUMNS_SQL, i as verifyIgnores, l as helperCallKeys, m as tableFor, n as runRlsVerify, o as HELPER_TABLES, p as compileGrants, r as rlsFinding, v as indexesSql, y as pruneIndexTargets } from "./verify-CHQgLrtS.js";
29
+ import { a as buildContext, c as levelKeys, d as rebuildPlan, i as splitsPart, l as rowHelpersSql, n as generateOptions, o as CANDIDATES, r as isRefusal, s as inheritTargets, t as supautilsRejections, u as DROPPED_LIST } from "./supautils-DZ95xxW-.js";
30
30
  import { readFileSync } from "node:fs";
31
31
  import { basename, delimiter, join } from "node:path";
32
32
  import { spawn } from "node:child_process";
@@ -1027,11 +1027,13 @@ function realtimeStoragePolicies(ctx, facts, config, warnings = []) {
1027
1027
  }
1028
1028
  //#endregion
1029
1029
  //#region src/cli/rls/generate-policies.ts
1030
+ const ACTOR_GUARDS_HEADER = "-- rls.readOnlyActors with --helpers-only: restrictive policies on the write commands, which narrow the hand-written policies and grant nothing. A table that does not exist yet is skipped.";
1030
1031
  const SERVICE_TABLES_HEADER = "-- Supabase Realtime and Storage: rls.realtime and rls.storage. RLS on both tables is Supabase's.";
1031
1032
  /**
1032
- * A `realtime.messages` or `storage.objects` policy that applies only where the
1033
- * table exists. The Realtime and Storage services create those tables, so a
1034
- * local stack with the service off, and pg-delta's shadow database, have none.
1033
+ * A policy that applies only where its table exists. The Realtime and Storage
1034
+ * services create `realtime.messages` and `storage.objects`, so a local stack
1035
+ * with the service off, and pg-delta's shadow database, have none; under
1036
+ * `--helpers-only` the app's own migrations create its tables.
1035
1037
  */
1036
1038
  function guardedPolicySql(item) {
1037
1039
  const body = policySql(item).trimEnd().split("\n").map((line) => ` ${line}`).join("\n");
@@ -1053,6 +1055,18 @@ function withHelperTables(sql, helperTables) {
1053
1055
  const tables = `${helperTables.trimEnd()}\n`;
1054
1056
  return sql.trim() === "" ? tables : `${sql.trimEnd()}\n\n${tables}`;
1055
1057
  }
1058
+ /**
1059
+ * The read-only actor policies `--helpers-only` writes: those on a table
1060
+ * `rls.tables` names. A resource it does not name has no known table, so its
1061
+ * write commands get a warning instead.
1062
+ */
1063
+ function helpersOnlyActorGuards(guards, tables, actorMayWrite, warnings) {
1064
+ const named = new Set(Object.values(tableNames(tables) ?? {}).map((table) => qualifySqlTable(table)));
1065
+ const kept = guards.filter((guard) => named.has(qualifySqlTable(guard.table)));
1066
+ const unmapped = [...new Set(guards.filter((guard) => !named.has(qualifySqlTable(guard.table))).map((guard) => qualifySqlTable(guard.table)))].toSorted();
1067
+ if (unmapped.length > 0) warnings.push(`rls.readOnlyActors with --helpers-only writes read-only actor policies only on tables rls.tables names; for ${unmapped.join(", ")}, name the table in rls.tables, or add \`and (select ${actorMayWrite}())\` to each hand-written insert, update and delete policy`);
1068
+ return kept;
1069
+ }
1056
1070
  function databaseModeWarnings(policy, { ctx }, warnings) {
1057
1071
  if (ctx.authorize !== "database") return;
1058
1072
  for (const { name } of ctx.scopes) if (policy.grants.some((grant) => grant.scope === name) && scopeTable(ctx, name) === void 0 && scopeSources(ctx, name).length === 0) warnings.push(`${name}-scoped grants read the ${name} memberships table in database mode: set rls.memberships.scopes.${name}, rls.membershipSources or supabase.hook.memberships (or --memberships for the first scope), otherwise they deny`);
@@ -1077,12 +1091,12 @@ function generatePolicies(input, policy, options, built, warnings) {
1077
1091
  const force = input.force === true || rls?.force === true;
1078
1092
  if (force && views.some((view) => view.companion !== void 0)) warnings.push("--force with --revoke-columns: each <table>_visible_fields companion reads as its owner, so its owner needs BYPASSRLS or the restricted columns read as null");
1079
1093
  const policyName = input.policyName ?? rls?.policyName;
1080
- const assembled = helpersOnly ? [] : assemblePolicies(fieldsMode === void 0 ? compiled.branches : rowBranches(compiled.branches), {
1094
+ const assembled = assemblePolicies(fieldsMode === void 0 ? compiled.branches : rowBranches(compiled.branches), {
1081
1095
  perRole: input.policyPerRole === true || rls?.policyPerRole === true,
1082
1096
  ...policyName === void 0 ? {} : { name: policyName }
1083
1097
  });
1084
1098
  const actorKinds = readOnlyActorKinds(rls?.readOnlyActors);
1085
- if (actorKinds !== void 0 && helpersOnly) warnings.push(`rls.readOnlyActors with --helpers-only writes no policies: add \`and (select ${qualified$1(ctx, ACTOR_MAY_WRITE)}())\` to each hand-written insert, update and delete policy, or a restrictive policy that calls it`);
1099
+ const actorGuards = actorKinds === void 0 || !helpersOnly ? [] : helpersOnlyActorGuards(readOnlyActorPolicies(assembled, subjectClaimJsonSql(ctx, "act"), actorKinds), rls?.tables, qualified$1(ctx, ACTOR_MAY_WRITE), warnings);
1086
1100
  const withActors = (items) => actorKinds === void 0 ? items : [...items, ...readOnlyActorPolicies(items, subjectClaimJsonSql(ctx, "act"), actorKinds)];
1087
1101
  let tablePolicies;
1088
1102
  try {
@@ -1104,7 +1118,8 @@ function generatePolicies(input, policy, options, built, warnings) {
1104
1118
  helpersOnly,
1105
1119
  force,
1106
1120
  views,
1107
- policies: withActors(assembled)
1121
+ policies: helpersOnly ? [] : withActors(assembled),
1122
+ ...actorGuards.length === 0 ? {} : { actorGuards: [ACTOR_GUARDS_HEADER, ...actorGuards.map(guardedPolicySql)].join("\n") }
1108
1123
  };
1109
1124
  if (servicePolicies.length === 0) return generated;
1110
1125
  return {
@@ -1543,7 +1558,7 @@ function tableColumns(rowColumns, tables, helpersOnly, warnings) {
1543
1558
  function emitTarget(input, built, generated, preamble) {
1544
1559
  const rls = input.config.rls;
1545
1560
  const { ctx } = built;
1546
- const { policies, force, views, helperTables } = generated;
1561
+ const { policies, force, views, helperTables, actorGuards } = generated;
1547
1562
  const outRel = input.out ?? rls?.out ?? defaultOut(input.target);
1548
1563
  const migration = input.target === "sql" ? "" : dialectRoles(migrationSql(policies, withHelperTables(preamble, helperTables), force, views), ctx.dialect);
1549
1564
  const migrationRel = migration === "" ? void 0 : migrationOut(outRel);
@@ -1551,7 +1566,7 @@ function emitTarget(input, built, generated, preamble) {
1551
1566
  let text;
1552
1567
  switch (input.target) {
1553
1568
  case "sql":
1554
- text = dialectRoles(withHelperTables(emitSql(policies, preamble, force, views), helperTables), ctx.dialect);
1569
+ text = dialectRoles(withHelperTables(withHelperTables(emitSql(policies, preamble, force, views), helperTables), actorGuards), ctx.dialect);
1555
1570
  break;
1556
1571
  case "drizzle":
1557
1572
  text = emitDrizzle(policies, compact({
@@ -1594,7 +1609,7 @@ function generateSql(input, policy, options, built, warnings) {
1594
1609
  const { preamble, audit } = assembled;
1595
1610
  if (generated.force) forceWarnings(built, warnings);
1596
1611
  const emitted = emitTarget(input, built, generated, preamble);
1597
- const { policies, force, views, helperTables, guardedTables, helpersOnly } = generated;
1612
+ const { policies, force, views, helperTables, guardedTables, helpersOnly, actorGuards } = generated;
1598
1613
  const seedsSplit = splitsPart(input.split, "seeds");
1599
1614
  return {
1600
1615
  ...generated,
@@ -1605,7 +1620,7 @@ function generateSql(input, policy, options, built, warnings) {
1605
1620
  policies: dialectRoles(withHelperTables(emitSql(policies, "", force, views), helperTables), ctx.dialect),
1606
1621
  declarativePolicies: dialectRoles(emitSql(policies, "", force, views), ctx.dialect),
1607
1622
  ...guardedTables === void 0 ? {} : { servicePolicies: dialectRoles(guardedTables, ctx.dialect) },
1608
- helpers: dialectRoles(emitSql([], preamble, false, helpersOnly ? views : []), ctx.dialect),
1623
+ helpers: dialectRoles(withHelperTables(emitSql([], preamble, false, helpersOnly ? views : []), actorGuards), ctx.dialect),
1609
1624
  seeds: `${SEEDS_MARKER} schema=${built.schema}\n${seedsBody(ctx, built.schema, generated.compiled.rolePermissions)}\n${seedsSplit ? audit : ""}`,
1610
1625
  indexes: `${INDEXES_MARKER}\n${indexesSql(indexes)}\n`
1611
1626
  })
@@ -192,7 +192,7 @@ async function rlsInput(ctx, verb, shape, options) {
192
192
  };
193
193
  }
194
194
  async function runRls(input) {
195
- return (await import("./rls-CtRaRrn3.js")).runRls(input);
195
+ return (await import("./rls-DY3Fc18U.js")).runRls(input);
196
196
  }
197
197
  const generate = defineLeaf({
198
198
  flags: {
@@ -1,13 +1,13 @@
1
1
  import { i as dateAt } from "./time-nR1JesoH.js";
2
2
  import { a as describeError, l as problemOf, n as CliError, r as cliProblem, s as kindOfCode } from "./errors-Vpu6rKHl.js";
3
3
  import { s as cliVersion } from "./version-DMQ0dnN5.js";
4
- import { a as resolveCwd, i as readConfig } from "./config-BR23fL8m.js";
4
+ import { a as resolveCwd, i as readConfig } from "./config-ZZdtyQZy.js";
5
5
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
6
6
  import { a as suggestion, i as parseLeaf, n as flagSpellings, o as GLOBAL_FLAGS, r as parseFlags } from "./args-0FrVs5EH.js";
7
7
  import { r as progressReporter, t as redact } from "./credentials-CdDxp7jN.js";
8
- import { a as resolve, i as leaves, n as ROOT, r as SECTIONS, t as DOCS_BASE } from "./manifest-Cav1rjNQ.js";
8
+ import { a as resolve, i as leaves, n as ROOT, r as SECTIONS, t as DOCS_BASE } from "./manifest-BWIR_EEB.js";
9
9
  import { t as createStyle } from "./style-Ds11Hmk4.js";
10
- import { i as githubAnnotations, n as envelope, o as sarifLog, t as dataOf } from "./output-CtyBwTNB.js";
10
+ import { i as githubAnnotations, n as envelope, o as sarifLog, t as dataOf } from "./output-3iB3_Hfg.js";
11
11
  import { i as renameMessage, r as flagRename, t as COMMAND_MOVES } from "./renames-CGj7YwcQ.js";
12
12
  import { stripVTControlCharacters } from "node:util";
13
13
  import { existsSync, statSync } from "node:fs";
@@ -0,0 +1 @@
1
+ export { t as run } from "./run-BlxXmaDS.js";
@@ -16,7 +16,7 @@ const scan = defineLeaf({
16
16
  }
17
17
  },
18
18
  async run(ctx, { flags }) {
19
- const { runAdoptionScan } = await import("./adoption-scan-DKCOsfcF.js");
19
+ const { runAdoptionScan } = await import("./adoption-scan-BGtwGfoH.js");
20
20
  return runAdoptionScan({
21
21
  cwd: ctx.cwd,
22
22
  srcPath: flags.src.length > 0 ? flags.src : ctx.config.collect?.srcPath ?? ["src"],
@@ -1,7 +1,7 @@
1
1
  import { r as isRecord } from "./compact-CAf557ZB.js";
2
2
  import { l as packageRoot } from "./version-DMQ0dnN5.js";
3
3
  import { t as DRAFT_PINS } from "./pins-nqarl3oE.js";
4
- import { a as nonEmptyOr } from "./output-CtyBwTNB.js";
4
+ import { a as nonEmptyOr } from "./output-3iB3_Hfg.js";
5
5
  import { t as require__2020 } from "./2020-CJbO8Bvz.js";
6
6
  import { readFileSync } from "node:fs";
7
7
  import { join } from "node:path";
@@ -2,7 +2,7 @@ import { t as byCodePoint } from "./compare-DTfyUunF.js";
2
2
  import { i as readJsonFile } from "./files-BSjrtIHw.js";
3
3
  import { l as packageRoot } from "./version-DMQ0dnN5.js";
4
4
  import { t as didYouMean } from "./args-0FrVs5EH.js";
5
- import { a as nonEmptyOr } from "./output-CtyBwTNB.js";
5
+ import { a as nonEmptyOr } from "./output-3iB3_Hfg.js";
6
6
  import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, realpathSync, writeFileSync } from "node:fs";
7
7
  import { basename, dirname, join, relative, resolve } from "node:path";
8
8
  import { pathToFileURL } from "node:url";
@@ -1,7 +1,7 @@
1
1
  import { t as defineLeaf } from "./command-L8EstFNm.js";
2
2
  import { t as checkFlag } from "./flags-DXjoTVbS.js";
3
3
  import { r as pick, t as CANCELLED } from "./prompt-BYc6drYW.js";
4
- import { n as detectedAgents, r as runSkills, t as SKILL_AGENTS } from "./skills-Bar7ZqwM.js";
4
+ import { n as detectedAgents, r as runSkills, t as SKILL_AGENTS } from "./skills-CY-MY_Oj.js";
5
5
  //#region src/cli/commands/skills.ts
6
6
  const forFlag = { for: {
7
7
  type: "string",
@@ -1,5 +1,5 @@
1
- import { a as supabaseClaims, i as supabaseApprovalStore, n as supabaseRls, o as exchangeCapability, r as tableApprovalDelegationSource, t as authorizeSql } from "../supabase-CC6rIri4.js";
2
1
  import { n as supabaseTenantClaim, t as supabaseMembershipsBudget } from "../budget-BELja5A9.js";
2
+ import { a as supabaseClaims, i as supabaseApprovalStore, n as supabaseRls, o as exchangeCapability, r as tableApprovalDelegationSource, t as authorizeSql } from "../supabase-CDHMsDD0.js";
3
3
  import { c as tableMembershipSource, i as authzVersion, o as junctionMembershipSource, s as supabasePostgresQuery, t as AUTHZ_VERSION_TABLE } from "../sources-C4vkzZJV.js";
4
4
  import { a as delegationOf, c as subjectFromSupabaseSession, i as actorOf, n as postgrestSources, r as readSubjectRecord, s as subjectFromSupabase } from "../postgrest-DAxFltvO.js";
5
5
  import { n as parseSupabaseManifest, t as hasTokenHook } from "../manifest-BXTbHNIV.js";
@@ -47,7 +47,7 @@ const hookGenerate = defineLeaf({
47
47
  const budget = given(flags.budget);
48
48
  const schema = given(flags.schema);
49
49
  const grantsOut = given(flags["grants-out"]);
50
- const { runSupabase } = await import("./supabase-hook-CWvEpdCh.js");
50
+ const { runSupabase } = await import("./supabase-hook-qsewAVZY.js");
51
51
  return runSupabase({
52
52
  cwd: ctx.cwd,
53
53
  config: ctx.config,
@@ -76,7 +76,7 @@ const inspect = defineLeaf({
76
76
  },
77
77
  async run(ctx, { flags }) {
78
78
  const out = flags.out === "" ? true : flags.out === "-" ? void 0 : flags.out;
79
- const { runSupabase } = await import("./supabase-hook-CWvEpdCh.js");
79
+ const { runSupabase } = await import("./supabase-hook-qsewAVZY.js");
80
80
  return runSupabase({
81
81
  cwd: ctx.cwd,
82
82
  config: ctx.config,
@@ -6,10 +6,10 @@ import { a as describeError, i as configError } from "./errors-Vpu6rKHl.js";
6
6
  import { i as readJsonFile, o as sqlFiles, s as writeFileEnsuringDir } from "./files-BSjrtIHw.js";
7
7
  import { a as SUPABASE_MANIFEST_SCHEMA } from "./version-DMQ0dnN5.js";
8
8
  import { c as requirePolicy } from "./load-DjSU5KXO.js";
9
+ import "./budget-BELja5A9.js";
9
10
  import { i as qualifySqlTable } from "./sql-0WjxIp9g.js";
10
11
  import { i as scopeColumn } from "./compile-EzEMB-7v.js";
11
- import { t as authorizeSql } from "./supabase-CC6rIri4.js";
12
- import "./budget-BELja5A9.js";
12
+ import { t as authorizeSql } from "./supabase-CDHMsDD0.js";
13
13
  import { a as hookApiNames, d as keptKeys, t as AUTHZ_VERSION_TABLE, u as roleManifest } from "./sources-C4vkzZJV.js";
14
14
  import { o as readMemberships } from "./postgrest-DAxFltvO.js";
15
15
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
@@ -0,0 +1 @@
1
+ export { i as runSupabase } from "./supabase-hook-HPgwYb9V.js";
@@ -3,12 +3,12 @@ import { f as scopeList, s as resolveScope } from "./scopes-0Up_UA2t.js";
3
3
  import { o as flattenGrantee } from "./grantee-Dke-9rd1.js";
4
4
  import { l as policyLevels } from "./policy-CLQ8__GF.js";
5
5
  import { a as describeError, i as configError } from "./errors-Vpu6rKHl.js";
6
- import { d as sqlTextArray, i as qualifySqlTable } from "./sql-0WjxIp9g.js";
7
6
  import "./budget-BELja5A9.js";
7
+ import { d as sqlTextArray, i as qualifySqlTable } from "./sql-0WjxIp9g.js";
8
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 { x as resolveAuthorize } from "./supabase-hook-CyuD9Wau.js";
11
+ import { x as resolveAuthorize } from "./supabase-hook-HPgwYb9V.js";
12
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
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
14
  import { o as assignableRoles, r as unsatisfiedKinds, t as ownershipRules, u as roleNames } from "./ownership-qqBuGJXr.js";
@@ -16,7 +16,7 @@ import { t as membershipSourcesOf } from "./sources-qoIJQrJv.js";
16
16
  import { i as group, o as sqlStatements } from "./deciding-columns-NB4wcyBf.js";
17
17
  import { d as orSql, h as branchClauses } from "./fields-DI8s3cPl.js";
18
18
  import { t as resolveNames } from "./resolve-names-Y1Cb22cp.js";
19
- import { m as tableFor } from "./verify-6EauWrkP.js";
19
+ import { m as tableFor } from "./verify-CHQgLrtS.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`. */
@@ -1 +1 @@
1
- export { r as policyMatrix, t as testOrmParity, n as testRlsParity } from "../core-DzVINFbU.js";
1
+ export { r as policyMatrix, t as testOrmParity, n as testRlsParity } from "../core-lxoANyai.js";
@@ -512,7 +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
+ "activeFrom": { "appMetadata": "tenant_id" },
516
516
  "schemas": "pg-delta"
517
517
  },
518
518
  helpers: {
@@ -27,16 +27,16 @@ import { c as problemFromDecision } from "../problem-BVLHFK33.js";
27
27
  import { o as resolveApproval } from "../helpers-DJicaG6f.js";
28
28
  import { t as APPROVAL_REQUEST_SCHEMA } from "../request-schema-DhX7UbfQ.js";
29
29
  import { t as catalogSchema } from "../schema-BOJjqlWL.js";
30
+ import { t as supabaseMembershipsBudget } from "../budget-BELja5A9.js";
30
31
  import { c as parseApiKey } from "../server-3cVlTLde.js";
31
32
  import { n as discoverAuthorizationServer } from "../device-BwbJNmb2.js";
32
33
  import { t as CONNECTOR_SCHEMA } from "../connector-schema-CYLQNMYq.js";
33
34
  import { l as sha256Hex, n as scimHandler, t as directoryMembershipSource } from "../scim-jJBJ7g1Z.js";
34
35
  import { c as quoteSqlTable, o as quoteSqlIdent } from "../sql-0WjxIp9g.js";
35
36
  import { i as cloudEndpoints, n as cloud, s as approverHeaders, t as bearerChallenge } from "../challenge-DImNcR7B.js";
36
- import { t as supabaseMembershipsBudget } from "../budget-BELja5A9.js";
37
37
  import { t as supabaseManifestSchema } from "../manifest-schema-DQkBK2Mr.js";
38
38
  import { t as PUSHED_POLICY_SCHEMA } from "../pushed-policy-CDuOL2de.js";
39
- import { i as policyMatrixLayout, n as testRlsParity, r as policyMatrix, t as testOrmParity } from "../core-DzVINFbU.js";
39
+ import { i as policyMatrixLayout, n as testRlsParity, r as policyMatrix, t as testOrmParity } from "../core-lxoANyai.js";
40
40
  import { i as saasPermissions } from "../permissions-CYcHj_w7.js";
41
41
  import { C as saasOrg, E as saasSeed, S as saasMemberships, a as saasProject, g as verifySaasSession, h as signSaasToken, k as saasPolicy, t as saasDoc, w as saasPrincipal, x as saasCustomRoles } from "../saas-DK4V-3Is.js";
42
42
  import { t as POLICY_NOT_PUBLISHED } from "../problem-types-DSsRfONQ.js";
@@ -1,4 +1,4 @@
1
- import { n as createCollectScheduler, r as report } from "../watch-Bpci3hBY.js";
1
+ import { n as createCollectScheduler, r as report } from "../watch-CTfSlIGD.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
@@ -0,0 +1 @@
1
+ export { t as runUsage } from "./usage-WYRc7Kqg.js";
@@ -16,7 +16,7 @@ const usage = defineLeaf({
16
16
  }
17
17
  },
18
18
  async run(ctx, { flags }) {
19
- return (await import("./usage-CNca1i1W.js")).runUsage({
19
+ return (await import("./usage-CH7oISI6.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-Cav1rjNQ.js";
10
- import { r as findingOf } from "./output-CtyBwTNB.js";
9
+ import { t as DOCS_BASE } from "./manifest-BWIR_EEB.js";
10
+ import { r as findingOf } from "./output-3iB3_Hfg.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";
@@ -17,13 +17,13 @@ import { t as policyRowConditionKeys } from "./row-conditions-BAGHOmVq.js";
17
17
  import { s as writeFileEnsuringDir } from "./files-BSjrtIHw.js";
18
18
  import { c as jsonSchemaOf } from "./catalog-doc-DjMKzJp9.js";
19
19
  import { o as loadPolicyAt } from "./load-DjSU5KXO.js";
20
+ import "./budget-BELja5A9.js";
20
21
  import { i as qualifySqlTable, n as defaultSqlCommand, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
21
22
  import { a as scopeMembershipTable, i as scopeColumn } from "./compile-EzEMB-7v.js";
22
- import "./budget-BELja5A9.js";
23
23
  import "./sources-C4vkzZJV.js";
24
24
  import { t as beforeFirst } from "./text-BMFRfBqc.js";
25
- import { t as DOCS_BASE } from "./manifest-Cav1rjNQ.js";
26
- import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-A1_sp_tR.js";
25
+ import { t as DOCS_BASE } from "./manifest-BWIR_EEB.js";
26
+ import { n as fixtureSubject, r as loadFixtures, t as fixtureRow } from "./fixtures-Bm4_K1ke.js";
27
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
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
29
  import { c as breakGlassKey, f as compileConditionSql, l as collectGrants, m as sqlFunctionNames, p as contextRefs, s as breakGlassHolder } from "./ownership-qqBuGJXr.js";
@@ -0,0 +1 @@
1
+ export { i as watchCollect } from "./watch-CTfSlIGD.js";
@@ -2,7 +2,7 @@ import { i as dateAt } from "./time-nR1JesoH.js";
2
2
  import { a as describeError } from "./errors-Vpu6rKHl.js";
3
3
  import { t as defaultSrcPath } from "./files-BSjrtIHw.js";
4
4
  import { r as runCollect } from "./collect-WCl8cJQV.js";
5
- import { n as isConfigFile, r as loadConfig } from "./config-BR23fL8m.js";
5
+ import { n as isConfigFile, r as loadConfig } from "./config-ZZdtyQZy.js";
6
6
  import { watch } from "node:fs";
7
7
  import { basename, dirname, relative, resolve, sep } from "node:path";
8
8
  //#region src/cli/watch.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "permdock",
3
- "version": "0.11.0",
3
+ "version": "0.14.0",
4
4
  "description": "Typed permissions for TypeScript apps, APIs, databases, and AI agents, with the permdock CLI and test runners.",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -320,7 +320,7 @@
320
320
  "oxc-parser": "0.154.0"
321
321
  },
322
322
  "devDependencies": {
323
- "@anthropic-ai/claude-agent-sdk": "0.3.301",
323
+ "@anthropic-ai/claude-agent-sdk": "0.3.303",
324
324
  "@arethetypeswrong/cli": "0.18.5",
325
325
  "@babel/core": "8.0.7",
326
326
  "@clack/prompts": "1.8.1",
@@ -330,9 +330,9 @@
330
330
  "@nestjs/core": "12.1.3",
331
331
  "@nestjs/platform-express": "12.1.3",
332
332
  "@openai/agents": "0.20.0",
333
- "@orpc/contract": "2.0.0-beta.42",
334
- "@orpc/openapi": "2.0.0-beta.42",
335
- "@orpc/server": "2.0.0-beta.42",
333
+ "@orpc/contract": "2.0.0-beta.44",
334
+ "@orpc/openapi": "2.0.0-beta.44",
335
+ "@orpc/server": "2.0.0-beta.44",
336
336
  "@permdock/ox-config": "0.0.0",
337
337
  "@permdock/typescript-config": "0.0.0",
338
338
  "@solidjs/start": "2.0.6",
@@ -340,35 +340,35 @@
340
340
  "@supabase/supabase-js": "2.118.0",
341
341
  "@sveltejs/kit": "3.1.0",
342
342
  "@sveltejs/vite-plugin-svelte": "7.3.1",
343
- "@tanstack/react-start": "1.169.2",
343
+ "@tanstack/react-start": "1.169.3",
344
344
  "@trpc/server": "11.19.0",
345
345
  "@types/express": "5.0.6",
346
- "@types/node": "24.19.2",
346
+ "@types/node": "26.6.5",
347
347
  "@types/pg": "8.23.1",
348
348
  "@types/react": "19.3.0",
349
349
  "@types/react-dom": "19.3.0",
350
350
  "@vercel/detect-agent": "1.2.5",
351
351
  "@vitest/coverage-v8": "5.0.5",
352
- "ai": "7.0.141",
352
+ "ai": "7.0.143",
353
353
  "ajv": "8.20.0",
354
354
  "astro": "7.4.0",
355
355
  "babel-plugin-react-compiler": "1.0.0",
356
- "better-supabase": "0.18.0",
357
- "better-supabase-floor": "npm:better-supabase@0.13.0",
356
+ "better-supabase": "0.29.0",
357
+ "better-supabase-floor": "npm:better-supabase@0.29.0",
358
358
  "chat": "4.42.0",
359
359
  "diff": "9.0.0",
360
360
  "drizzle-orm": "1.0.0-rc.5-5935859",
361
361
  "elysia": "1.4.30",
362
- "eve": "0.79.2",
362
+ "eve": "0.80.1",
363
363
  "express": "5.3.0",
364
364
  "fastest-levenshtein": "1.0.16",
365
365
  "fastify": "5.12.7",
366
- "h3": "2.0.2",
366
+ "h3": "2.0.5",
367
367
  "happy-dom": "21.0.4",
368
368
  "hono": "4.13.13",
369
369
  "jose": "6.2.12",
370
- "kysely": "0.29.6",
371
- "next": "16.4.1",
370
+ "kysely": "0.29.7",
371
+ "next": "16.4.2",
372
372
  "oxlint": "1.89.0",
373
373
  "oxlint-tsgolint": "7.0.2004",
374
374
  "package-manager-detector": "1.9.0",
@@ -378,7 +378,7 @@
378
378
  "react": "19.3.1",
379
379
  "react-dom": "19.3.1",
380
380
  "reflect-metadata": "0.2.2",
381
- "resend": "6.33.0",
381
+ "resend": "6.34.1",
382
382
  "rxjs": "7.8.2",
383
383
  "smol-toml": "1.9.1",
384
384
  "solid-js": "1.9.17",
@@ -411,7 +411,7 @@
411
411
  "@trpc/server": ">=11",
412
412
  "ai": ">=5",
413
413
  "astro": ">=5",
414
- "better-supabase": ">=0.13.0",
414
+ "better-supabase": ">=0.29.0",
415
415
  "chat": ">=4",
416
416
  "drizzle-orm": ">=0.40 || >=1.0.0-rc.0",
417
417
  "elysia": ">=1",
@@ -125,7 +125,7 @@ const subject = await subjectFromCapability(token, {
125
125
  - The result is a `kind: 'link'` principal with one `{ on, roles, via: 'link' }` membership. It never holds a scope or global role.
126
126
  - `linkPolicy` returns the tenant's `LinkPolicy` (`maxLifetime`, `redeemers`, `once`). Passing the same policy to `signCapability` refuses to mint a link the resolver would refuse.
127
127
  - Never an unguessable id without expiry, and never a security-definer RPC that reads the guest page's rows.
128
- - The one exception is resolving a stored link. When links live in better-supabase's share-links block, its `resolve_share_link` is `security definer` and reads only the link table. `subjectFromShareLink(token, { shareLinks, links, ttl })` from `permdock/better-supabase` turns the row into the same link subject. The page's rows are then read through `exchangeCapability` and RLS, as for a signed link. `links` maps each subject type (`subject.type` from better-supabase 0.14, `subjectType` before it) to a resource and maps the row's role to PermDock roles. An unmapped type or role, and a revoked or expired row, are anonymous. A link pinned to a version is refused, because a capability reads the current rows; read it through better-supabase's `versions.getShared(token)`. See [row-backed links](https://permdock.com/docs/concepts/capabilities#row-backed-links).
128
+ - The one exception is resolving a stored link. When links live in better-supabase's share-links block, its `resolve_share_link` is `security definer` and reads only the link table. `subjectFromShareLink(token, { shareLinks, links, ttl })` from `permdock/better-supabase` turns the row into the same link subject. The page's rows are then read through `exchangeCapability` and RLS, as for a signed link. `links` maps each subject type (the row's `subject.type`) to a resource and maps the row's role to PermDock roles. An unmapped type or role, and a revoked or expired row, are anonymous. A link pinned to a version is refused, because a capability reads the current rows; read it through better-supabase's `versions.getShared(token)`. See [row-backed links](https://permdock.com/docs/concepts/capabilities#row-backed-links).
129
129
 
130
130
  With Supabase, let RLS serve the link through an exchange, never the link token itself:
131
131
 
@@ -501,7 +501,7 @@ const subject = subjectFromSupabase(claims, {
501
501
 
502
502
  Write the claims with `permdock supabase hook generate`; `permdock supabase inspect --out` writes the manifest (helper names, tenant claim, budget, claims written) that `authorizationProvider` from `permdock/better-supabase` turns into better-supabase's `authorization` config. No `@supabase/supabase-js` peer. Pair with `permdock rls generate`, or keep SQL as authority and run `permdock rls verify --db-url-stdin` against `sqlFunction` twins ([database-first](https://permdock.com/docs/adapters/rls)); the generic RLS workflow is in the `permdock-data` skill.
503
503
 
504
- With better-supabase, set `auth.authorization: authorizationProvider({ manifest, catalog })` in `better-supabase.config.ts` (top-level `authorization` before 0.15) (with `rls.customRoles` its `canAssign` and `canAssignFor` call `permdock_can_assign_any` and its `_for` form, so custom roles are assignable through better-supabase; regenerate the manifest after turning custom roles on), pass `authorizer({ policy })` to the server (`createNext`, `createHono`, `createMcp`) so every `permission` a resource, action, route guard or tool declares is decided by PermDock from the verified claims (`operations` maps tables for `permissions: true`; a missing or anonymous claim denies), build bucket and topic `access` policies with `bucketPolicy` and `topicPolicy`, and map its session with `subjectFromBetterSupabase(session)` (all from `permdock/better-supabase`): the active tenant's `features` become `principal.plans`. Pass `plans: { keys }` when better-supabase's `entitlements.claim.keys` shortens feature keys, and `apiKeys: { permissions, manifest }` so an `apiKey` session maps to the key's credential subject instead of the anonymous one. For `createMcp` tools, put the permission in `meta` and spread `toolPolicy({ permdock })` into the options: tools without one are hidden and refused, and approval-required calls are refused because `createMcp` collects no approvals. Wrap a `CredentialProvider` with `credentialGuard(provider, { permdock, use, revoke? })` so PermDock decides each token use. `authorizationProvider({ ..., approver })` lets holders of that permission approve AI tool calls, never their own. `approvers: { 'ai-tool': holder(p), 'support-session': ..., 'invoice.send': ... }` fills `isApprover` through `permdock_is_approver` (needs `rls.approvals`); only `user()`, `holder()` and `anyOf()` approvers, and a kind it does not name has no approver. `accessReviewApplier({ client, reviews, policy, demoteTo?, email?, permdockFor? })` applies a review's revoked items: `update_member_role` to the `demoteTo` role when that role lacks the permission, else `remove_member`, plus `revoke_invitation` for the member's matching invitations, then `markApplied`; pass the reviewer's client so the blocks' own checks run. better-supabase's `createAgentRuntime({ toolApproval })` takes `toolApproval` from `permdock/ai-sdk` as it is. Validate its claims with `betterSupabase.claims(supabaseClaims().extend(appSchema))` (`supabaseClaims` from `permdock/supabase`, any Standard Schema as `appSchema`) instead of a hand-written copy of the claim shape. A `supabase.hook.claims` function that needs the user's organizations calls `<schema>.member_organization_ids_for(user_id)` (generated by `rls generate`, executable by `supabase_auth_admin` only) instead of querying the membership tables itself. With a scope named `team` or `teams`, `authorizationProvider` fills better-supabase's `teamIdsOf` with `<schema>.member_team_ids_of(user)`, which answers only for the caller, so with `blocks.permissions.model: 'provider'` (`blocks.access` before 0.15) better-supabase's `team_ids_of()` and team-sharing policies read PermDock's memberships. A token Supabase's OAuth server issued to a third-party app (`client_id`) becomes an `oauth-client` actor limited to its `scope`; `deny(permission, { to: actor('oauth-client') })` keeps such apps out, in the app and, through `rls generate`, in Postgres. A better-supabase support session (`act.kind: 'support'`) is actor kind `support` with `sessionId` and `readOnly`, and `actingAs` (`act.kind: 'impersonation'`) is kind `impersonation`; neither has a delegation, so they reach nothing until a policy delegation names `actor('support')` or `actor('impersonation')`, and `readOnly: true` (also when `read_only` is absent) narrows that to read-only permissions. Generated RLS reads memberships, not `act`, so a support token sent to the Data API writes as the user: add a restrictive `for update` (and `insert` / `delete`) policy per writable table that requires `act ->> 'read_only' = 'false'` when `act` is a support or session level ([support access](https://permdock.com/docs/guides/support-access)). With `rls.anonymousSignIns: 'deny'`, pass `anonymousSignIns: 'deny'` to the subject mapper too (doctor PD057). Check a deployed database against the generated policies with `permdock rls verify --introspect`.
504
+ With better-supabase, set `auth.authorization: authorizationProvider({ manifest, catalog })` in `better-supabase.config.ts` (with `rls.customRoles` its `canAssign` and `canAssignFor` call `permdock_can_assign_any` and its `_for` form, so custom roles are assignable through better-supabase; regenerate the manifest after turning custom roles on), pass `authorizer({ policy })` to the server (`createNext`, `createHono`, `createMcp`) so every `permission` a resource, action, route guard or tool declares is decided by PermDock from the verified claims (`operations` maps tables for `permissions: true`; a missing or anonymous claim denies), build bucket and topic `access` policies with `bucketPolicy` and `topicPolicy`, and map its session with `subjectFromBetterSupabase(session)` (all from `permdock/better-supabase`): the active tenant's `features` become `principal.plans`. Pass `plans: { keys }` when better-supabase's `entitlements.claim.keys` shortens feature keys, and `apiKeys: { permissions, manifest }` so an `apiKey` session maps to the key's credential subject instead of the anonymous one. For `createMcp` tools, put the permission in `meta` and spread `toolPolicy({ permdock })` into the options: tools without one are hidden and refused, and approval-required calls are refused because `createMcp` collects no approvals. Wrap a `CredentialProvider` with `credentialGuard(provider, { permdock, use, revoke? })` so PermDock decides each token use. `authorizationProvider({ ..., approver })` lets holders of that permission approve AI tool calls, never their own. `approvers: { 'ai-tool': holder(p), 'support-session': ..., 'invoice.send': ... }` fills `isApprover` through `permdock_is_approver` (needs `rls.approvals`); only `user()`, `holder()` and `anyOf()` approvers, and a kind it does not name has no approver. `accessReviewApplier({ client, reviews, policy, demoteTo?, email?, permdockFor? })` applies a review's revoked items: `update_member_role` to the `demoteTo` role when that role lacks the permission, else `remove_member`, plus `revoke_invitation` for the member's matching invitations, then `markApplied`; pass the reviewer's client so the blocks' own checks run. better-supabase's `createAgentRuntime({ toolApproval })` takes `toolApproval` from `permdock/ai-sdk` as it is. Validate its claims with `betterSupabase.claims(supabaseClaims().extend(appSchema))` (`supabaseClaims` from `permdock/supabase`, any Standard Schema as `appSchema`) instead of a hand-written copy of the claim shape. A `supabase.hook.claims` function that needs the user's organizations calls `<schema>.member_organization_ids_for(user_id)` (generated by `rls generate`, executable by `supabase_auth_admin` only) instead of querying the membership tables itself. With a scope named `team` or `teams`, `authorizationProvider` fills better-supabase's `teamIdsOf` with `<schema>.member_team_ids_of(user)`, which answers only for the caller, so with `blocks.permissions.model: 'provider'` better-supabase's `team_ids_of()` and team-sharing policies read PermDock's memberships. A token Supabase's OAuth server issued to a third-party app (`client_id`) becomes an `oauth-client` actor limited to its `scope`; `deny(permission, { to: actor('oauth-client') })` keeps such apps out, in the app and, through `rls generate`, in Postgres. A better-supabase support session (`act.kind: 'support'`) is actor kind `support` with `sessionId` and `readOnly`, and `actingAs` (`act.kind: 'impersonation'`) is kind `impersonation`; neither has a delegation, so they reach nothing until a policy delegation names `actor('support')` or `actor('impersonation')`, and `readOnly: true` (also when `read_only` is absent) narrows that to read-only permissions. Generated RLS reads memberships, not `act`, so a support token sent to the Data API writes as the user: add a restrictive `for update` (and `insert` / `delete`) policy per writable table that requires `act ->> 'read_only' = 'false'` when `act` is a support or session level ([support access](https://permdock.com/docs/guides/support-access)). With `rls.anonymousSignIns: 'deny'`, pass `anonymousSignIns: 'deny'` to the subject mapper too (doctor PD057). Check a deployed database against the generated policies with `permdock rls verify --introspect`.
505
505
 
506
506
  The other better-supabase slots, all from `permdock/better-supabase` ([better-supabase](https://permdock.com/docs/adapters/better-supabase)): `hookCan(permdock)` and `handlerCan({ getPermDock })` are the `can` options of `authorizeHook` and `protectWebHandler` in `better-supabase/workflow-sdk`; they decide with no row unless the `data` option loads one (`hookCan(permdock, { data: (tenant, key) => row })`, `handlerCan(source, { data: (request, key) => row })`), so without it a permission with a row condition denies, and `handlerCan` answers `undefined` (401) without a signed-in principal. `supportPolicy({ policy, options?, writable?, approval?, approved? })` is the `authorize` option of `supportSessions`; it decides each start with `decideSupportSession` as the admin, and an `approval-required` start passes only once `approved(input, pending)` returns `{ approvedBy }` for an approver other than the admin. `subscriberPolicy({ policy, principals, events, row?, sender? })` filters outbox, webhook or realtime subscribers to those who may read the event (exact type, then the longest `prefix.*`, then `*`; a type with no entry reaches no one). `principalSource({ claims, identities? })` is a `PrincipalSource` over the claims better-supabase mints, for `decideFor`, `subscribersFor` and delivery; only links the app created through a signed-in flow or a verified address go in `identities`. `authorizationHooks({ policy, claims, service?, principals?, events?, approvers?, support?, tickets? })` is the `authorization` option of `createServer`: it answers automation publish and run-as, delegated OAuth scopes, `approverOf`, identities, delivery audiences, support sessions and run tickets from the claims better-supabase mints now, never from the request.
507
507
 
@@ -1 +0,0 @@
1
- export { n as runPowerSync } from "./powersync-CD8-Ypao.js";
@@ -1 +0,0 @@
1
- export { n as runCloudPull } from "./pull-CAeaAioC.js";
@@ -1 +0,0 @@
1
- export { t as run } from "./run-B5nyNKe8.js";
@@ -1 +0,0 @@
1
- export { i as runSupabase } from "./supabase-hook-CyuD9Wau.js";
@@ -1 +0,0 @@
1
- export { t as runUsage } from "./usage-Y6xZUfE-.js";
@@ -1 +0,0 @@
1
- export { i as watchCollect } from "./watch-Bpci3hBY.js";
@@ -5,8 +5,8 @@ import { y as membershipsClaim } from "./evaluate-BAmf_AQd.js";
5
5
  import { n as parseSnapshot } from "./snapshot-CXlzi69u.js";
6
6
  import { n as fromSnapshot } from "./from-snapshot-DCakWRsr.js";
7
7
  import { t as getPermDock } from "./permdock-BvjivVb9.js";
8
- import { c as quoteSqlTable, n as defaultSqlCommand, o as quoteSqlIdent, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
9
8
  import "./budget-BELja5A9.js";
9
+ import { c as quoteSqlTable, n as defaultSqlCommand, o as quoteSqlIdent, t as SQL_IDENT } from "./sql-0WjxIp9g.js";
10
10
  //#region src/testing/policy-matrix.ts
11
11
  function isOutcomeCell(value) {
12
12
  return value === "granted" || value === "denied" || value === "approval-required" || value !== null && typeof value === "object" && ("denials" in value || "outcome" in value || "alternatives" in value || "obligations" in value || "deniedBy" in value);
@@ -5,8 +5,8 @@ import { s as ApprovalError } from "./types-CcUXciSj.js";
5
5
  import { c as decodeApprovalCursor, l as encodeApprovalCursor, s as approvalPageSize, t as applyApprovalVerdict } from "./store-RNFvaJJv.js";
6
6
  import { a as parseCapability } from "./capability-BqX94r07.js";
7
7
  import { t as loadJose } from "./load-jose-DZ4dnjri.js";
8
- import { a as quoteQualifiedTable, c as quoteSqlTable, d as sqlTextArray, i as qualifySqlTable, o as quoteSqlIdent, s as quoteSqlLiteral } from "./sql-0WjxIp9g.js";
9
8
  import "./budget-BELja5A9.js";
9
+ import { a as quoteQualifiedTable, c as quoteSqlTable, d as sqlTextArray, i as qualifySqlTable, o as quoteSqlIdent, s as quoteSqlLiteral } from "./sql-0WjxIp9g.js";
10
10
  import { d as keptKeys, l as roleColumn } from "./sources-C4vkzZJV.js";
11
11
  import { t as callRpc } from "./postgrest-DAxFltvO.js";
12
12
  //#region src/supabase/capability.ts