permdock 0.13.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-oks22j9J.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-BzVfXbhf.js → arazzo-9uhbmKf5.js} +1 -1
  6. package/dist/{arazzo-CBBIhC40.js → arazzo-Bol9OgF-.js} +1 -1
  7. package/dist/better-supabase/index.d.ts +14 -20
  8. package/dist/better-supabase/index.js +4 -16
  9. package/dist/better-supabase-83Gsetrv.js +56 -0
  10. package/dist/{casbin-C8r5trwy.js → casbin-1PVgMHOR.js} +1 -1
  11. package/dist/{casbin-BunKq48W.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-C_Mau1q2.js → cloud-BfJVKpcN.js} +1 -1
  16. package/dist/{codemod-CpMCbp0G.js → codemod-BXLd4K3j.js} +1 -1
  17. package/dist/{codemod-BqYPToUJ.js → codemod-DWfH-KHk.js} +2 -2
  18. package/dist/{collect-D9Tt0Bcx.js → collect-lZgCKMe_.js} +1 -1
  19. package/dist/{completion-Cq4fbT2S.js → completion-fJ19i8Jk.js} +1 -1
  20. package/dist/{config-0xxCmoD8.js → config-BYSk3iKV.js} +1 -1
  21. package/dist/{config-BR23fL8m.js → config-ZZdtyQZy.js} +4 -1
  22. package/dist/{config-report-C1-r59VY.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-Dea6IqRw.js → doctor-NxCr_hba.js} +2 -2
  27. package/dist/{doctor-CDfzrMQB.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-PP7uH8rC.js → import-efm6qPgx.js} +1 -1
  31. package/dist/{init-n1gkKHvc.js → init-BtWY1L0J.js} +3 -3
  32. package/dist/{init-BuUt4bLJ.js → init-D6rpLPwM.js} +1 -1
  33. package/dist/{kernel-qv4cr9w8.js → kernel-BD8QuMnv.js} +9 -2
  34. package/dist/{login-DyQNWJok.js → login-B8s6VI8Z.js} +3 -3
  35. package/dist/{login-YsrgkAQo.js → login-cLflB63Z.js} +1 -1
  36. package/dist/{manifest-Cl6yHiVK.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-BFyBIe9J.js → openapi-CT55v3WD.js} +2 -2
  42. package/dist/{openapi-D8JQtO8k.js → openapi-DDENzRbG.js} +1 -1
  43. package/dist/{output-DpCUAST3.js → output-3iB3_Hfg.js} +1 -1
  44. package/dist/{powersync-Bm3ZjHwD.js → powersync-COjQTHRD.js} +2 -2
  45. package/dist/{powersync-BTLk8GSl.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-iVPQZsnI.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-BItB4vkC.js → rls-DY3Fc18U.js} +5 -5
  52. package/dist/{rls-C8nxX0RV.js → rls-DjjOHlKE.js} +1 -1
  53. package/dist/{run-CjFdAzqE.js → run-BlxXmaDS.js} +3 -3
  54. package/dist/run-DGSLvGty.js +1 -0
  55. package/dist/{scan-COIQvTMg.js → scan-CR_xm71k.js} +1 -1
  56. package/dist/{schema-CeQZY6bO.js → schema-CnrIP94n.js} +1 -1
  57. package/dist/{skills-5XWpNzCi.js → skills-CY-MY_Oj.js} +1 -1
  58. package/dist/{skills-CfkYP7GG.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-PRhfO-bL.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-BfzSfOpD.js → usage-Dm2hn0pS.js} +1 -1
  70. package/dist/{usage-hMYVFsN5.js → usage-WYRc7Kqg.js} +2 -2
  71. package/dist/{verify-CmTiQ-yM.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-CObULVRk.js +0 -1
  78. package/dist/pull-3OQCgxUf.js +0 -1
  79. package/dist/run-BqW8S5TM.js +0 -1
  80. package/dist/supabase-hook-CWvEpdCh.js +0 -1
  81. package/dist/usage-BDiTP763.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
@@ -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-CmTiQ-yM.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-BDiTP763.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-Cl6yHiVK.js";
10
- import { r as findingOf } from "./output-DpCUAST3.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-Cl6yHiVK.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.13.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-BTLk8GSl.js";
@@ -1 +0,0 @@
1
- export { n as runCloudPull } from "./pull-iVPQZsnI.js";
@@ -1 +0,0 @@
1
- export { t as run } from "./run-CjFdAzqE.js";
@@ -1 +0,0 @@
1
- export { i as runSupabase } from "./supabase-hook-CyuD9Wau.js";
@@ -1 +0,0 @@
1
- export { t as runUsage } from "./usage-hMYVFsN5.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