Naming
The PermDock naming convention, the use* and get* duality, reserved words, and what each adapter's createPermDock returns.
PermDock has one naming rule: the brand is the noun. The decision object is a PermDock, the variable is permdock, and the import path, not the identifier, says which framework you are in. Three verbs carry the rest: create* sets something up once at module scope, get* resolves it for one request on the server, and use* reads it on the client. Every package, docs page, skill, error message and example follows this page.
The rest follows from that rule:
- Core and
permdock/pdpbuild an instance withgetPermDock(policy, user), andgetPermDockSyncis its synchronous twin. An adapter'screatePermDockruns once at module scope. - A factory result is
<Entry>PermDock(ServerPermDock,AgentPermDock). It hands out the instance throughgetPermDock(input)ormiddleware(), and mounts its endpoint throughpermdockHandler(); never apermdock()member. - The decisions every app makes are methods on the instance (
can,decide,decideEach,decideIds,decideFor). A feature's own request is a free function that takes the instance first (decideCredential(permdock, request),decideAutomation,decideSupportSession,decideRoleChange,activate,whoCan,simulateArazzo), so an app that does not import the feature does not ship it. - A subject resolver is
subjectFrom<Source>(input, options)and returnsSubject<<Source>Principal>. - An option is named after its interface (
principalsfor aPrincipalSource,approvalPoliciesfor anApprovalPolicySource), andstoremeans onlyApprovalStore. - An in-process default is
memory<Interface>, a runner istest<Interface>, an adapted source is<origin><Interface>and a verifier factory is<thing>Verifier. - A context or prop type puts the adapter first (
ExpressPermDockRequest,HonoPermDockEnv) and spells outContext. - Signed outputs are
vnd.permdock.<format>+jwtand CloudEvents types arecom.permdock.<family>.
Renamed in 0.5.0 lists every name these rules changed; permdock codemod 0.5 applies them.
The core names
| Name | Kind | Meaning |
|---|---|---|
PermDock | type | The immutable, request-scoped decision object returned by getPermDock. Methods: can, decide, canAll, decideAll (each over PermissionChecks), decideEach, decideIds, decideFor, assert, explain, filter, pick, where, simulate, snapshot, on, actions; tenancy: tenant, team (derived instances), derive (the same subject with other customRoles, approvalPolicies, relations or principals), memberships, tenants, heldRoles, audiences, assignableRoles, assignablePermissions (read-only); graph: prefetchRelations (whoCan(permdock, …) is a free function). Vocabulary trees: permissions, roles, plans. |
permdock | variable | The conventional name for a PermDock instance, and the npm package name. Also the CLI binary (permdock collect). |
getPermDock | function | Core and permdock/pdp: the instance for one user once every input (subject mapper, context, sources) has answered. Returns Promise<PermDock>. On an adapter's factory result, the instance for one request. |
getPermDockSync | function | Core and permdock/pdp: getPermDock for inputs that all answer synchronously. Returns PermDock, and throws naming getPermDock when an input answers with a Promise. |
createPermDock | function | Exported by every server, agent and feature adapter. Runs once at module scope and returns a framework-shaped object whose getPermDock, middleware() or hooks hand out instances. |
import { getPermDock, getPermDockSync } from "permdock"; // core: Promise<PermDock>, PermDock
import { createPermDock } from "permdock/next"; // Next.js: { getPermDock, getPermission, getSnapshot, requirePermission, PermDockProvider, permdockHandler }
import { createPermDock } from "permdock/hono"; // Hono: { middleware, protect, permdockHandler }
import { createPermDock } from "permdock/mcp"; // MCP: { protectServer }Never a function that returns PermDock or a Promise depending on its inputs.
There is no NextDock, HonoDock, createNextPermDock or createMcpPermDock. When two adapters are used in one file, alias at the import: import { createPermDock as createHonoPermDock } from 'permdock/hono'. A factory that returns a handler or a store, not an instance, is named after what it returns, without create: evaluationsHandler, nativeStore.
use* on the client, get* on the server
React reads permissions synchronously from a snapshot; servers resolve them asynchronously per request. PermDock follows the duality next-intl uses for useTranslations / getTranslations and useExtracted / getExtracted:
Client (permdock/react) | Server (createPermDock from permdock/next) | Returns |
|---|---|---|
usePermDock() | await getPermDock() | A PermDock (snapshot-backed on the client, full policy on the server) |
usePermission(permission, data?) | await getPermission(permission, data?) | { allowed, status } on the client; the same shape awaited on the server |
<Protected> | await requirePermission(permission, data?, { tenant? }) | Renders children or a fallback on the client; on the server, the granted Decision, or forbidden() / unauthorized() |
usePermissions([...], data?), useFilter(permission, rows) | (await getPermDock()).decide per reference, .filter | One entry per reference; the rows the subject may act on |
useTenant(), useMemberships(), useRoles(), useAssignableRoles(), useAssignablePermissions() | (await getPermDock()).tenants(), .memberships(), .heldRoles(), .assignableRoles(), .assignablePermissions() | The active tenant with switchTo; the membership list; Role[] held in a tenant; Role[] the subject may hand out; Permission[], the custom-role ceiling the subject may hand out |
useApproval(decision), useSubject() | the ApprovalStore and the subject on the server | Client-side request-access flow; the snapshot's principal, actor and delegation |
<PermDockProvider snapshot endpoint tenant> | <PermDockProvider> from the factory result | Client context; the server variant loads the snapshot once per request and serialises it |
requirePermission is the throwing member of the usePermission / getPermission set: same arguments, and a denial becomes the forbidden() or unauthorized() interrupt.
The client hooks and <Protected> are direct exports with no factory: the permission reference carries all the types, so usePermission(permissions.post.update, post) is fully typed without a generic wrapper. Only the server side needs a factory, because only the server holds the policy. describe(decision) is a framework-free core export used by every UI adapter and by Problem Details (UI). Vue keeps the use* composable names. Svelte does not: it exports setPermDock / getPermDock and readable stores (permission, permissions, filter, tenant, …) because Svelte has no React-style hooks. Solid uses accessor functions. The UI parity table lists them.
Definition and policy vocabulary
| Word | Used for | Never used for |
|---|---|---|
definePermissions | Build the reference tree from resources and groups | Rules |
PermissionsOf | The type definePermissions returns for a spec type, for an explicit annotation under isolatedDeclarations | InferPermissions, PermissionTreeOf |
RowOf, RowData, UncheckedData, PERMISSION_ROW | The row type a permission carries, the data a check takes (a partial row or a { current, next } pair), data of no known type, and the type-only key that holds the row | RowType, DataOf, InferRow |
defineOperations, Operation, OperationMap, OperationDefinition, OperationInput | Bind named application actions to permission leaves, with data, results and meta; operations in the catalog and permdock.config.ts | A second permission vocabulary: an operation always names a leaf |
OperationMeta, OperationRisk, OperationEffect, OPERATION_RISKS, isOperationRisk | An operation's { risk?, effects?, title? }; risk low to critical, effects read, write, delete, send, spend, external; OPERATION_RISKS is the frozen risk order, lowest first, and isOperationRisk its guard | A decision input: PermDock never reads meta |
renamed, formerKeys, renamedFrom | The definePermissions option mapping former keys to current keys, the function that lists a leaf's former keys, and the catalog field that carries them | Keeping an old leaf alive; aliases, legacyKeys, deprecated |
defineRoles, definePlans | Build the typed Role and Plan trees (permdock.roles.admin, permdock.plans.pro) | Grants; Postgres roles |
Role, Plan | Frozen vocabulary leaves { key, on?, assignable, meta } and { key, meta }. A role named only by string becomes a synthesised Role leaf with assignable: false | The grant-list type; that is RoleBinding |
RoleMeta, audience | A role's meta: ActionMeta plus audience, the surface its holders use ('staff', 'portal', 'platform'); permdock.audiences() and snapshot.audiences list the distinct values of the roles held in the active tenant | A per-surface role list; a hard-coded role name in a layout |
min, max, transferOnly, assigns, for | Role ownership options: holders kept per scope instance, holders allowed, a holder count that only moves by transfer, the roles a holder may assign and revoke, the membership kinds (via) that may hold the role (ownership) | minHolders, canAssign, allowedVia; activation (reserved for time-boxed roles) |
decideRoleChange, RoleChange, RoleChangeDecision | decideRoleChange(permdock, { kind: 'assign' | 'revoke' | 'transfer', role, scope, id, within?, target, holders? }), or scope: 'global' with no id for a global role, and assignableRoles({ scope: 'global' }): the ownership rules for one change, answered as granted (with the authorising role) or denied with denials; the subject is always the actor | A write; an actor or subject taken from the change |
resource | One resource node: schema, id field, actions, collection, optional parent (which may be the resource itself), optional relations, optional version, optional restricted, optional disclosure | Anything without a schema-or-actions shape |
name (resource option) | The resource name leaves, tables, relations and AuthZEN types use when the last path segment collides | Changing the key; alias, table |
disclosure | The resource() option 'hide' | 'reveal' (default 'reveal'): with 'hide', a denied check on a loaded row answers 404 /not-found, the body a missing row gets, and the reason stays in audit | visibility, secret, a per-grant flag |
restricted, ResourceRestricted, stops | The resource() option naming a boolean column: a row where it is true is reached only by grants on itself, never by relations held on its ancestors or through its links; { field, stops } names the paths it closes (parent and link names) (relationships) | A deny; the reserved role(..., { restricted }) option |
FieldRelation, EdgeRelation, PrincipalRelation (edge, object, subject, expiresAt, principal, period, startsAt) | The three relation shapes on a resource: a row field holding the principal id ({ field, memberOf? } or a string), an edge table ({ edge, object?, subject?, expiresAt? }), and a principal column with an optional validity period ({ principal, period?: { startsAt?, expiresAt? } }) | A tuple store; a relation declared on a grant |
through, depth | relation(resource, name, { through: 'parent', depth }): follow the row's parent chain upward to resource, then its self-parent for up to depth hops (default 16, at most 32) | recursive, levels; walking a memberOf relation |
RelationSource, RelationChain, RelationHolder, memoryRelationSource, relations | The object-graph interface (ancestors, related), its answers, its in-process default over rows and edges, and the createPermDock option that takes it | A module-level cache; a decision |
prefetchRelations, whoCan, WhoCan, Holder, HoldingVia | await permdock.prefetchRelations(permission, rows) fills the instance's relation cache for an async source; await whoCan(permdock, permission, row) lists holders and how (role, relation, share) with complete | A grant; a partial list presented as complete |
related, RelatedCondition, RelationGrantee, RestrictedAncestors, restrictedAncestors, passRestricted | The condition node a graph relation compiles to, and the relation grantee type with through / depth | A hand-written where |
permdock_closure, permitted_<resource>_ids, permdock_closure_<resource>, permdock_restricted_<resource> | The closure table, the per-resource helper keyed by relation name and the trigger-maintained refresh function permdock rls generate emits for graph grants, and the helper listing the rows a closed link does not reach below | A table PermDock writes at runtime; service_role |
actions | The resource() option listing instance-level actions (can(permissions.post.update, post)), and the instance verb permdock.actions(permissions.post, post) returning one result per leaf of a resource | Type-level checks |
collection | Type-level actions (can(permissions.post.create)) | Instance checks |
crud, readable, writable | Option factories for resource(): conventional instance/collection split and default meta | Constructors; grants; a default of resource() |
mergePermissions, listPermissions, findPermission | Registry helpers; functions so they never collide with resource names | Methods on the tree |
parseCatalog, rowConditionKeys, catalogPath | permdock/catalog reads and freezes a permissions.catalog.json and lists its rowConditions: true keys; permdock/cli resolves the file path the way collect does | loadCatalog, readCatalog; a reader that returns null instead of throwing PermDockValidationError |
compileWhere, CompiledWhere | permdock/compile lowers a portable condition, for one subject, to the tree the ORM toWhere compilers render | A policy-time compile with no subject; RLS and PowerSync compile the condition themselves |
ServerPermDock, ServerPermDockOptions, tenantScope, TenantScope, TenantOption | permdock/server: what its createPermDock returns and takes, the kernel an HTTP adapter builds on. tenantScope resolves an adapter's tenant option against its framework context. | A PermDock instance; getPermDock(request) resolves one |
isPermission | The structural guard for a permission leaf (string key, scope, resource, action and an object meta), which also accepts a leaf that crossed JSON and lost its non-enumerable kind | A registry lookup; identity stays by key |
definePolicy | Bind vocabulary, scopes, grants, subject, context, validate to a definition | Defining permissions |
defineApp, AppOptions, AppProfile | Bind an app's sources, features (hostedPolicies, approvalPolicies) and services (sink, store) to a policy; profile is dev or prod | createApp, defineConfig (the CLI's config file), a second factory beside createPermDock |
shadowMode, ShadowOptions, ShadowMismatch, LegacyCheck | A wrap that asks the legacy check and PermDock, returns the legacy answer unless the permission is enforced, and reports each disagreement | dryRun, compareMode, a second decide |
testLegacyParity, LegacyParityCase | The test runner that pins PermDock's answers against the legacy check | testMigration |
role | A RoleBinding: named array of grants with an optional scope ({ on: <declared scope name> | resource reference, assignable }, typed against definePolicy({ scopes })), the ownership options min, max, transferOnly, assigns, for, exclusiveWith and a RoleMeta meta; activation and restricted are reserved; same-named bindings merge; first argument may be a Role leaf | Postgres roles; the only grantee |
to, anyone, authenticated, relation, plan, actor, assurance | Grantee selectors on allow / deny. anyone() is the only selector that evaluates for principal: null; an array in to means every selector must match | A second permission check; hasRole |
scopes | The definePolicy option declaring named scopes in order, each with its row key and an optional parent within ({ organization: { key: 'organization_id' }, customer: { key: 'customer_id', within: 'organization' } }) (named scopes) | Permission scopes (.scope is the colon string form) |
within | A scope's parent in definePolicy({ scopes }), and on a Membership the ids of its ancestor scopes | parent (that is the resource chain) |
scope, id, on | The two shapes of a Membership (an instance of a named scope, a resource role) and the on option of role | Hard-coded tenant and team kinds in core |
tenant, team | Aliases of the first and second declared scope (in role on, memberOf, and the { tenant, team } membership input form); principal.tenant is the active instance of the first scope | Scopes named after a provider's vocabulary when the policy's own names differ |
Membership, CustomRole, CustomRoleGrant | The wire types for a scoped role assignment, a tenant-defined role (includes declared roles, grants of declared permission keys, optional scope and id) and one of its { permission, effect? } entries | Classes; a condition, approval or limit on a custom-role grant; all are plain JSON |
customRoleClaim | Builds the compact memberships[].grants map (key, -key, @role per custom role name) that RLS helpers read in jwt mode with --custom-roles | A claim PermDock trusts without subjectFromJwt; a per-provider helper |
custom_role_permissions, custom_role_includes, permdock_ceiling, permdock_custom_keys | The SQL objects permdock rls generate --custom-roles emits next to role_permissions and the helpers | Tables PermDock writes at runtime; a way around the ceiling |
resolveCustomRole, validateCustomRole | The one resolver of a custom role against the ceiling of assignable declared roles ({ grants, dropped }), and its summary { ok, permissions, dropped } for a save action and permdock doctor PD023 (custom roles) | Widening a role; resolving a name a declared role already uses |
CustomRoleDrop, CustomRoleDropReason | Why a custom-role entry was left out: unknown-permission, outside-ceiling, condition-not-allowed, unknown-level (with level), or { role, reason: 'unknown-role' } for an include | Denial reasons; a drop is never a Decision |
meta.readOnly, meta.destructive, meta.idempotent | Action metadata the MCP adapters turn into readOnlyHint, destructiveHint and idempotentHint for tools whose author set no annotation | A decision input; tags: ['destructive'] |
meta.x, MetaValue | Application-owned JSON on an action's metadata; PermDock carries it and never reads it | A decision input; meta.custom, meta.extra |
x (definition option), AppData, AppDataSchema, PermissionsOptions, VocabularyOptions, PolicyAppDataSchemas | One Standard Schema per kind of app data: definePermissions(…, { x: { permission, resource } }), defineRoles(…, { x }), definePlans(…, { x }), definePolicy(…, { x: { grant, membership } }); AppData is the default plain JSON object | A decision input; declare module augmentation; extensions, custom |
ResourceMeta, GrantMeta | A resource's { title?, description?, x? } and a grant's { description?, x? }; carried to decisions, events, snapshots and the catalog | Policy fingerprint input |
ResourceXTree, RESOURCE_X | The type definePermissions adds to a tree so getResource types meta.x; RESOURCE_X is a type-only key with no runtime value | A runtime property |
Membership.x | Application-owned JSON on a membership, from a trusted source; dropped with an on('auth') schema event when invalid; never in claims | A condition input; metadata, attrs (that is the token claim) |
obligations, AppObligation, ObligationInput | allow(p, { obligations }) and the { kind: 'app', name, detail? } entries it puts on a granted decision | A new kind per app need; obligations on a deny |
DenialDetails | The map from a denial reason to its typed detail (limit, inactive-grant, deny), read through Denial<R> | A free-form detail per reason |
deniedResponse (adapter option), DeniedResponse, DeniedResponseEvent | The HTTP adapter hook that receives { decision, problem, request } for a refusal and returns Problem Details, a Response or nothing; it cannot grant | onForbidden, errorFormatter; a hook that turns a denial into a grant |
deniedText (agent option), DeniedText, DeniedTextEvent | The MCP and agent adapter hook, which may replace only the refusal text | A hook that changes isError or structuredContent |
context (adapter option), RequestContext | The adapter hook that returns server-derived JSON merged into subject.context for the request | A subject, membership, tenant or actor source; locals, extra |
wrap, wrapPermDock, PermDockWrap, PermDockOverrides | The adapter option that wraps every request's instance after otel, and the helper that overrides methods and keeps tenant(), team() and derive() wrapped | A plugin system; middleware, decorate |
field, explain (protect options) | The per-route field check and decision trace passed to decide | A field mask; a trace on the wire |
defaults, PermDockDefaults | Provider-wide content for the <Protected> slots a component leaves out | fallbackComponent; a global mutable default |
useDescribe, getDescribe | describe with the provider's messages; getDescribe in Svelte | A second description format |
meta.manageRoles | On a Role or a permission leaf: holding the role, or being granted the permission, makes the full ceiling assignable instead of only what the subject holds | A grant; a bypass of CustomRoleSource.assignable |
SnapshotAssignable | One { tenant, roles, permissions } entry of a snapshot's assignable list | A second snapshot format |
SnapshotScope | One { name, key, within?, resources? } entry of a snapshot's ordered scopes list | A tenant-and-team pair of keys |
Scope, ScopeDeclaration, PolicyScopesInput, PolicyScopes, ScopeNames | A declared scope { name, key, within? }, one definePolicy({ scopes }) entry { key, within? }, the whole option, Policy.scopes in order, and the names on accepts (declared names plus the tenant / team aliases) (named scopes) | A scope kind enum |
GrantScope, RoleScope | Where a grant applies ('global', a scope name, or { resource }) and what role(..., { on }) accepts | Hard-coded 'tenant' | 'team' |
MembershipSource, CustomRoleSource | The two subject-input interfaces (membershipsFor, rolesFor / assignable) passed as memberships and customRoles to every createPermDock | Stores; PermDock never writes a membership or role |
SubjectResolver | The generic type of every subjectFrom* function: verified input in, Subject out, never throws | A class hierarchy |
memoryCustomRoleSource | The in-process CustomRoleSource over a static CustomRole[] | Production storage |
memoryMembershipSource | The in-process MembershipSource over memberships keyed by principal id | Production storage |
PrincipalSource, PrincipalIdentity, PrincipalIdentityLink, principalByIdentity | The subject input that loads a live principal by id (principal(id, { tenant })) or by an app-owned email or chat identity (principalByIdentity); every reader treats null, a throw or a missing method as no principal | A principal from a request body, a model argument or an unverified address |
memoryPrincipalSource, testPrincipalSource | The in-process PrincipalSource over principals and identity links (frozen copies), and its conformance runner in permdock/testing | Production storage |
memorySnapshotSource | The in-process SnapshotSource over one snapshot; set replaces it and calls each subscriber | Production storage |
customRoleSource, CustomRoleReader, CustomRoleSourceOptions | A CustomRoleSource over rolesFor(tenant), a read of every custom role of the tenant; read: 'held' skips the read when the subject holds only declared roles | A source that returns only the held roles; rolesForUser |
globalRoles, scope: 'global' | The CustomRoleSource method returning platform custom roles, and the custom role scope that marks one | A tenant role without a tenant; platformRoles, systemRoles |
sharedRoles, shared: true, SharedCustomRole | The CustomRoleSource method returning shared custom roles, the flag that marks one, and its type: defined once, held in every tenant, its name winning over a tenant role's | systemRoles, templateRoles, a tenant role with a null tenant |
ApprovalPolicySource, ApprovalPolicy, memoryApprovalPolicySource, approvalPolicies, validateApprovalPolicy, ApprovalPolicyProblem | Approval requirements kept as data, the entry shape, the in-process default, the createPermDock option, and the check that names why an entry does not load (unknown-permission, invalid, where-on-collection, stale-on-without-version); entries only add stages | Granting or relaxing an approval; approvalRules, workflows |
composeMemberships, claimsFirst | One MembershipSource over several (merged, de-duplicated, list and version combined); a source that keeps the verified token's memberships until the token says they were truncated. An array passed as memberships is composed | A store; a cache with its own TTL |
MemberEntry, list, version, claimsFirst | The optional MembershipSource members: every member of one scope instance ({ principal: { id }, membership }), the principal's authorization version, and the claims-first flag | members, epoch, revision |
EntitlementSource, entitlementsFor, entitlements, memoryEntitlementSource, stripeEntitlementSource, testEntitlementSource | The subject-input interface for plan names per tenant, its createPermDock option, the in-process default, the Stripe Entitlements reader over a structural client, and its conformance runner | A permdock/stripe entry; plans as an option name |
fresh, stale, stale-credentials, authzVersion, authz_ver | The definePolicy option listing permissions that need an up-to-date token, the subject flag, the denial reason, the permdock/supabase version reader and the claim it compares | sensitive, strict, stale-token |
onStale, globalRolesFor, refresh | The claimsFirst option for a token whose authorization version is behind: 'deny' (default) denies fresh permissions, 'reread' reads the memberships from the sources instead | A re-read on every request |
managedBy: 'idp', isExternallyManaged, externally-managed | A membership the identity provider owns, its predicate, and the decideRoleChange reason that refuses to change it | readonly, locked, scim: true |
supabasePostgresQuery, SupabasePostgres | ctx.postgres or ctx.postgresAdmin from @supabase/server's withPostgresClient as a SqlQuery, through its queryRaw | A Postgres client; a new connection |
tableMembershipSource, junctionMembershipSource, SqlQuery, SqlMembershipSource, RoleThrough, supabaseMembershipsBudget | The permdock/supabase SQL membership sources, the statement runner they take, their type, a role or user column read through another table, and the default claim budget in bytes | A query builder; an ORM adapter |
postgrestSources, subject_for, authz_version_for, members_of, SupabaseRpcClient, SupabaseRpcCaller, SubjectRecord | The permdock/supabase sources over PostgREST: one subject_for(p_user) call per user, generated next to the hook, gives memberships, customRoles(principal) and subject(userId) for a backend that only has supabase-js, authz_version_for(p_user) gives memberships.version without the full read, and members_of(p_scope, p_id) gives memberships.list; SupabaseRpcCaller is the client parameter, loose enough for a supabase-js client typed with a generated Database | A client-callable function; a subject from a request body |
CustomRoleSourceFactory | (subject) => CustomRoleSource | undefined, the per-subject form of every customRoles option, called once per instance with the resolved subject | A source that remembers the last principal it served |
permittedIds | permdock.permittedIds(permission, scope): the instances of a scope where the subject holds a permission with no row condition, minus denied ones, or with conditioned: true where a conditioned allow applies: the in-process mirror of permitted_<scope>_ids_by_permission; a listing, never a decision | A decision; a check of one row |
countHolders | The live holders of a role in one scope instance, from MembershipSource.list, for decideRoleChange's holders | A holder count from a second, unfiltered query |
operationPermissions, operationPermissionsFromOpenApi | One declaration of each API operation's permission, "METHOD /path/{param}" to a permission, read by an HTTP gate (forRequest) and by permdock/mcp's permissionFor (forOperation) | A regular-expression route table; a second mapping for the MCP tools |
oauthScopes (MCP tool config, protect options, an operation entry, withPermDock config), oauthScopesFor, oauthScopesForRequest, oauthScopesForOperation, operations, ScopeGuard | An operation's own OAuth scopes in place of those derived from its permission, narrowing which coarse scope reaches each MCP tool or REST route that shares a permission, or the only gate of a route that checks no permission (protect(null), ScopeGuard); operations on permdock/server reads them from operationPermissions | A second permission only to tell two tools apart |
supabaseApprovalStore, rls.approvals, approval_requests, permdock_approval_* | The generated approval store (a table and one function per ApprovalStore method, executable by no client role) and the permdock/supabase store over it | An approval table a client role can read or write |
rls.jsonSchema, approval_requests_body_schema | 'auto' | boolean: a pg_jsonschema check constraint that each approval body matches approval-request-v1.json | A remote $ref; format assertions |
APPROVAL_POLICY_UNAVAILABLE | The approval-policy-unavailable denial detail when an ApprovalPolicySource fails, as a constant | A second spelling of the detail |
supabaseClaims, SupabaseClaims, SupabaseMembershipClaim, SupabaseClaimsSchema, extend | The permdock/supabase Standard Schema of the hook's claim contract (loose, no validation library), its output types, and the method that merges an app's own claim schema over it | supabaseClaimsSchema, extendClaims; a strict object that rejects other claims |
oauthScopes, PolicyOAuthScope | Coarse OAuth scopes an authorization server issues (mcp:read), each covering permissions; expanded into the token delegation and named in scope challenges | scopeAliases, aliases, scopeMap |
ClientNames, clients, actor.client, to: { kind, client } | Stable names for OAuth clients whose ids differ per environment or come from dynamic registration: the subject resolver maps a verified client id to a name, and a policy delegation names the client instead of the id | aliases, clientAlias, a client id in the policy |
actorOf, delegationOf, SupabaseActor, SupabaseActorResult | The permdock/supabase rules that turn act / client_id into the acting party (oauth-client, support, impersonation, by act.kind) and scope into delegated scopes; { ok: false, reason: 'invalid-chain' } must deny | getActor, parseActor; returning null for a malformed chain; admin or impersonator as an actor kind |
anonymousSignIns | SupabaseSubjectOptions option: 'deny' maps a token with is_anonymous: true to the anonymous subject, as rls.anonymousSignIns does in RLS | allowAnonymous, a boolean |
liveSession | SupabaseSubjectOptions option and Subject field: true once the caller checked the session against the Auth server for this request; never read from claims | fresh, which fresh permissions already name; sessionValid |
supabaseClaimVectors | permdock/testing export: supabaseClaimFixtures as a supabase/sdk conformance vector file, { feature: "auth.session.get_claims", cases: [{ name, input, expected }] } | supabaseConformance, which names no feature; a JSON file outside the package |
requires | Supabase manifest field: { matrix, capabilities }, the capability-matrix release tag and the feature ids the setup depends on | capabilities at the top level, which reads as what PermDock offers |
pageApprovals, approvalPageSize, encodeApprovalCursor, decodeApprovalCursor, listAllApprovals, ApprovalCursorPosition | The list-paging helpers the built-in approval stores use, exported from permdock/approvals for a custom ApprovalStore (approvals) | A cursor format of the store's own; paginate, listAll |
{ subject: { session: { live: true } } } | The where form for a grant that needs a live session; normalised to { "op": "liveSession" } | A principal.sessionLive ref, which would read a claim |
Actor.readOnly | true narrows every policy delegation to that actor to its read-only permissions (readOnlyHint); a Supabase support session sets it from act.read_only | readonly, writable: false |
ActorKind, AdapterId, MembershipVia, DirectoryEvent.source | Open unions: the values PermDock sets autocomplete, and an application's own id type-checks. Core only compares them for equality, so an unknown value can only fail to match | A closed union for ids an integrator supplies; an open union for anything core interprets |
supabaseTenantClaim | The default claim (tenant_id) for the active tenant, shared by the hook, subjectFromSupabase and the RLS helpers | A per-app tenant name; a column name |
SupabaseHookManifest, SupabaseManifestMembership, SupabaseManifestRls, SupabaseManifestHelper, SupabaseManifestValue, SupabaseManifestColumn, supabaseHookManifestFixture, permdock supabase inspect, permdock.manifest.json | The version: 1 manifest of the generated hook and SQL helpers (helper names and signatures, tenant claim, budget, claims written, membership sources, RLS mode, deciding columns, marker majors), its types in permdock/supabase, its fixture in permdock/testing, and the file inspect --out writes | apiVersion; a second hook generator |
SupabaseManifestRole, SupabaseManifestThrough | A manifest membership's role: a column, fixed roles, or a column with the roles table (table, id, column) it references; a membership's user takes the same through | apiVersion; a second hook generator |
permdock supabase hook generate | The CLI command that compiles the SQL sources into the Custom Access Token Hook | permdock hook, permdock rls hook |
attrs (supabase.hook.attrs, the claim) | Allow-listed server-owned columns and app_metadata.<key> entries the hook writes for attribute conditions (principal.claims.attrs.<key>) | profile, user_metadata, claims as a config key |
supabase.hook.api | The PostgREST wrappers <prefix>subject_for, <prefix>members_of and <prefix>authz_version_for (default schema public, prefix permdock_) that hook generate writes for a backend reaching Postgres through the Data API; postgrestSources({ api }) takes the same setting. The wrappers are security invoker; the one place the hook grants to service_role (usage on the hook schema, execute on the readers), and only when the option is set | A hand-written wrapper per function; a grant to authenticated |
supabase.hook.before | Schema-qualified functions (event jsonb) returns jsonb the generated hook calls first, in order; a result with error is the hook's answer | A second access token hook; a check that writes the claims PermDock owns |
supabase.hook.validate | Check the claims the hook wrote against supabase-claims-v1.json with pg_jsonschema and drop them all on a mismatch | Raising an Auth error on a bad claim; validating claims another package owns |
supabase.schemas, --schemas, 'pg-delta', 'migra', 'migrations', hook.schemas | The schema workflow rls generate --split and supabase hook generate write for: Declarative Schemas 2.0 (supabase db schema declarative sync, the default), 1.0 (supabase db diff) or hand-written migrations; the manifest records it as hook.schemas, and doctor PD068 and PD069 check config.toml and the layout against it (schema workflow) | engine, diff, declarative: boolean; v1/v2 for the Supabase feature versions |
LimitStore, memoryLimitStore, limits | The quota counter for limit grants, its in-process default, and the feature passed as the limits: limits(store) option of core getPermDock and every HTTP and agent adapter | Auto-installing a store; a thenable consume as granted |
GrantLimit, mode, alertAt | The limit grant option { count, per, mode?, alertAt? }: mode is 'hard' (default) or 'soft', alertAt a fraction of count in (0, 1] (limits) | A soft limit that grants when the store is unreachable |
Quota, quota | { remaining, resetsAt } on a granted decision under a limit; resetsAt is RFC 3339 | A snapshot field; a denial |
LimitDetail | { count, per, resetsAt }, the detail of a limit denial: the grant's count, its window in seconds and its reset as RFC 3339; HTTP adapters render it as 429 with Retry-After, RateLimit and RateLimit-Policy | quota on a denied decision; a store read in the renderer |
not-entitled, requiredPlans, SnapshotNotEntitled | The denial reason when a held role's grant fails only on its plan grantee; requiredPlans(decision) lists the plan keys when every denial is not-entitled; describe kind upgrade with plans; 403 /not-entitled with plans; the snapshot's notEntitled entries { permission, role, to } | no-plan, upgrade-required, missing-entitlement; a 402 |
Obligation, obligations, over-limit, near-limit | What a granted decision says the caller owes, as { kind } objects; the kinds so far are over-limit (a soft limit past its count) and near-limit (usage reached alertAt) | A fourth outcome; an obligation on denied or approval-required |
pdp | The HTTP adapter and kernel option taking getPermDock from permdock/pdp, so protect decides delegated permissions remotely | Making the request-scoped instance async |
ProtectOptions, trusted | The third argument of every protect ({ trusted: true } skips validating what the loader returns) | A per-route validate mode |
args (decide option) | The DecideOptions field holding the call's arguments; an approval-required token binds their digest, and agent and MCP adapters pass the tool arguments (approvals) | payload, input, binding the arguments as data |
scope (decide option) | The DecideOptions field naming a declared scope whose memberships alone answer a check (can(permission, undefined, { scope: 'organization' })); global roles still apply (scopes) | scope(...) as a derived instance, tenantOnly, firstScope |
request | The permdock/trpc and permdock/orpc option mapping a context to its Web Request, and the permdock/nest option mapping a non-HTTP ExecutionContext | Reading a subject from it directly |
problemFromError | The permdock/server function turning a thrown PermDock error into its Problem Details Response, undefined for anything else | An error class; a catch-all that maps non-PermDock errors |
policyMatrix, PolicyMatrixReport, permdock/testing/core | The runner-neutral policy matrix describePolicy asserts, { cells, missing }, and the entry that exports it with testRlsParity and testOrmParity without importing a test runner | runMatrix, permdock/testing/node |
testOrmParity, OrmParityScenario | The permdock/testing runner comparing filter() in memory with the rows a database returns for toWhere(where()), and its scenario shape | A database the runner opens itself |
testClientParity, ClientParityCase | The permdock/testing runner asserting that fromSnapshot never grants what the server denies, per membership and tenant, and its case shape | Deriving expectations from the snapshot itself |
testClientStore, ClientStoreFactory | The permdock/testing runner for client snapshot stores and the factory it calls (scenario testing) | A DOM or a framework renderer |
WebMcpToolCall | The { input, token } argument a permdock/webmcp handler receives | Positional input arguments |
listFields, requiredFields | toWhere options: scalar-list fields whose contains is element membership (Prisma, Kysely), and Prisma's non-nullable fields, where a null branch folds away | Inferring either from the Prisma client at runtime |
prismaModelFields, PrismaModelFields, model | The permdock/prisma function reading required and list fields from schema.prisma text or a DMMF datamodel, its result, and the toWhere / toPredicate option taking it | Loading the schema file itself |
toPredicate | The permdock/prisma compiler for Prisma 8 field-proxy predicates | A second toWhere overload |
checkRow, RowCheck | The single-row check of permdock/drizzle, permdock/kysely and permdock/prisma, and its { found: false } | { found: true, granted } result | A not-found outcome on Decision |
resolveRelated | The permdock/prisma step replacing related nodes in a where() result with ids read through a raw query | A compiler; it returns a WhereResult |
relations (compiler option), RelationsMapping | Where the graph tables live for Drizzle and Kysely toWhere and resolveRelated: tables and closure | The createPermDock relations source, which answers facts in process |
match, groups, includes, links | Relationship declarations: an edge table's fixed column filter, its group holders, relations implying this one, and named to-one references walked by through: [...] | Tuple rewrites; through naming a field |
MemberOfParent | A memberOf parents entry: a keyed { field, resource } or a bare field name | Walking a parent chain with a query |
WhereResult.subject | The non-enumerable subject a where() result carries so toWhere compiles memberOf without a second argument | A serialised field; it never reaches JSON |
EVALUATIONS_SEMANTICS, EvaluationsSemantic, evaluationsSemantic, evaluateBatch, mergeEvaluationItem, AuthzenItem, AuthzenEntity | permdock/authzen batch helpers for a PDP with its own evaluator: the AuthZEN options.evaluations_semantic values and reader, the in-order short-circuit loop, and the shared-field merge of one evaluations item (AuthZEN) | mergeItem; AuthZENItem |
parseAuthzenRequest, readAuthzenRequest, AuthzenRequest, AuthzenRequestKind, AuthzenRequestOf, AuthzenEvaluationRequest, AuthzenEvaluationsRequest, AuthzenSearchRequest, AuthzenSearchKind, ParseAuthzenRequestOptions, ParseAuthzenRequestResult | permdock/authzen request checks: the handler's 400 and 413 answers, in its order and wording, as { ok, request } or { ok: false, problem } (AuthZEN) | |
readAuthzenPage, authzenPage, emptyAuthzenPage, AUTHZEN_MAX_PAGE, AuthzenPage, AuthzenPageRequest | permdock/authzen search paging: the offset token, the size capped at 200, and the page object | |
searchActions, searchSubjects, AuthzenSubjectLister, AuthzenSubjectQuery, AuthzenAction, AuthzenSubject, AuthzenSearchOptions, SearchActionsOptions | permdock/authzen search without the handler: every catalog permission of a resource type, and the granted candidates a subject lister answers | |
testAuthzen, AuthzenVectors, authzenTodoPolicy, authzenTodoVectors | The permdock/testing AuthZEN interop runner, its vector layout (the interop harness files unchanged) and the interop Todo domain (authzenTodoPermissions, authzenTodoUsers, authzenTodoData) | Vendoring the official vectors |
testCloudApi, CloudApiKeys, TestCloudApiOptions | The permdock/testing runner for a PermDock Cloud environment: the conformance runners over cloud(), the HTTP contract checks, and every response validated against cloud-api-v1.json | testCloud, cloudConformance |
testHttpAdapter, HttpMounted | The permdock/testing HTTP scenario runner and the value a mount returns (fetch, call, close) | A server the runner starts itself |
ArazzoSimulateInput, ArazzoPlan, arazzoFindings | The simulateArazzo(permdock, { arazzo, openapi }) argument and result, and the resolution-only helper the CLI uses | A permdock/arazzo package; a subject on the call |
webBotAuth, webBotAuthVerifier, discoverViaSignatureAgent | The HTTP createPermDock option for RFC 9421 signatures, the factory of the verifier it takes (webBotAuthVerifier(options), so an app without it bundles no verification) and its Signature-Agent directory lookup | A permdock/web-bot-auth package; trusting a host that is not on allow |
InvalidSignatureError | Thrown by getPermDock(request) when a claimed Web Bot Auth signature fails; protect returns the Problem Details response instead | Downgrading a failed signature to an anonymous actor |
allow, deny | The two grant constructors; both accept one reference or an array and a to grantee, or without a condition a resource, an array of resources or the whole tree | Checking |
isRoleName, RoleNameOf | isRoleName(policy, value) narrows a role read as a string to the roles the policy declares, RoleNameOf<typeof policy> | A guard of its own per app; policy.isRole; an extends between roles |
PermissionOf, ScopeNameOf, PlanNameOf, OperationNameOf, VocabularyOf | Types read from a tree, policy or operation map: the leaf union, the scope, plan and operation names, and the vocabulary for PermDock<V> | PermissionUnion, ScopesOf, InferVocabulary, declare module augmentation |
PermissionCheck | One check of canAll / decideAll: a permission, or a [permission, row] pair | A map keyed by permission string |
principalFromMemberships, BetterSupabaseMembershipRow | permdock/better-supabase: a Principal from rows of the organizations block memberships table, one membership per organization_id | subjectFromMemberships; a hand-written principalOf |
principal | The condition ref builder (principal.id) and the definePolicy option that maps a user to principal values. There is no subject ref builder; subject stays accepted as the definePolicy option name | The RFC 8693 Subject (that stays subject on the instance) |
claim | claim(path) is the condition ref principal.claims.<path>, typed SubjectRef under noUncheckedIndexedAccess and noPropertyAccessFromIndexSignature | A claim reader that verifies tokens; declare module augmentation of claim names |
context | The condition ref builder for values loaded by the definePolicy context function (context.teamIds) | Request-scoped state; the ctx a closure receives |
principal, actor, delegation | The three parts of a subject | Synonyms for user or role |
granted, denied, approval-required | The three Decision.outcome values | not-applicable, allow, deny |
where, check | Conditions on the current row and on the next row | Query building outside conditions |
sqlFunction | Named SQL function plus a portable twin the evaluator, filter, where and snapshots run; rls generate emits the call | A runtime database round-trip; a closure; inlining the function body as the only representation |
opaque | Imported SQL with a fingerprint and no twin; evaluates to false | A portable grant |
fields, pick | Schema keys on a grant and the redaction helper permdock.pick(permission, row) | CASL globs; a permission per field |
validFrom, validUntil, validity | The grant options bounding when a grant applies (RFC 3339 or an Instant), and the normalised { from?, until? } on Grant and, as RFC 3339, on a snapshot grant; an inactive allow denies with inactive-grant | expiresAt (that is a membership's end), notBefore, window, a clock operator in where |
group | The grant option naming a condition group in generated SQL: the grant key is <permission>#<group> instead of a positional #n | A positional key in hand-written SQL; a group per role |
requires | The allow option naming a permission, or a list of them, the subject must also hold through a role, globally or on the row's scope instance, for the grant to count | permission() as a grantee; a where on roles |
inherit(permission, { through }), RelationSource.row | The grantee that holds on a row when the subject holds permission on the row a link list or the parent points to, decided by every grant of that permission; row reads that row by id | from, via, a relation per way the target becomes readable |
key, scope | The dotted (post.update) and colon (post:update) string forms of a permission | Public API arguments |
subjectFrom<Provider> | Turning verified material into a Subject<<Source>Principal>, input first and options second: subjectFromJwt, subjectFromIntrospection, subjectFromSupabase, subjectFromSupabaseSession, subjectFromClerk, subjectFromBetterAuth, subjectFromMcp, subjectFromCapability, subjectFromCiOidc, subjectFromApiKey; each provider mapper takes a schema option (authentication) | Verifying, logging in, or anything that can throw |
ClaimsMap, ClaimPath | Every subject provider's claims option: where id, roles, groups, entitlements, plans, tenant, memberships, kind, assurance and session live in the verified claims, each a dot path or a function | JwtClaimPaths, globalRoles, a top-level roles or tenant path option |
JwtPrincipal | The base principal type permdock/jwt exports (id from sub, issuer from iss, assurance, RFC 9068 roles and groups) | A session type; claims stay on principal.claims |
SupabasePrincipal | The base principal type permdock/supabase exports (id from sub, roles and tenant from hook claims, memberships, assurance.acr from aal) | A session type; user_metadata is never read |
supabaseRls, authorizeSql | RLS compile hints for permdock rls and the authorize() function SQL with an optional tenant parameter | A policy builder; it does not decide |
suspension (RlsSuspension, SupabaseSuspension, RlsSuspendedScope, SupabaseSuspendedScope, RlsSuspendedMembership, SupabaseSuspendedMembership) | The rls config key, supabaseRls and authorizeSql option naming the users and scope-instance tables (RlsActiveRow / SupabaseActiveRow: table, id, disabledAt, status, active) the generated helpers, authorize() and the token hook read to drop suspended rows, and per scope keep, the permissions a suspended instance's members still hold, which a membership carries as Membership.keep; memberships.keep is the same list for a membership whose table's disabledAt column is set (RlsMembershipTable, tableMembershipSource columns.disabledAt, junctionMembershipSource disabledAt) (RLS) | A createPermDock option; in process, suspension is a MembershipSource concern |
permdock_has, permitted_<scope>_ids, member_<scope>_ids, role_permissions | The SQL objects permdock rls generate emits: permdock_has(p_grant) for global roles, one permitted_<scope>_ids(p_grant) per declared scope (permitted_tenant_ids and permitted_team_ids for a policy that declares none), over the seeded role_permissions (role, permission, grant_key, scope, effect), and one membership-only member_<scope>_ids() per declared scope, plus member_<scope>_ids_for(p_user) on Supabase for a scope with a membership source, executable by supabase_auth_admin only, and member_<scope>_ids_of(p_user) for such a scope named team or teams, which answers only for the caller, and in database mode permdock_has_for(p_user, p_grant) and permitted_<scope>_ids_for(p_user, p_grant), executable by no client role, and permitted_<scope>_users(p_permission, p_id) for who holds a permission in one instance, executable by no client role; permdock_has_permission(p_permission), permitted_<scope>_ids_by_permission(p_permission) and grant_keys(p_permission, p_scope, p_effect) take a permission key and answer with its unconditional allows minus any deny; a grant key is the permission key or permission#n (RLS) | Per-row checks; anything a client calls with another user's id; <scope>_ids_for_user or member_<scope>_ids(p_user) for the per-user helper; permitted_<scope>_ids() with no argument or <scope>_ids_for_member for the membership-only helper |
permdock_role_permissions, permdock_permission_keys | The role and catalog readers permdock rls generate emits: permdock_role_permissions(p_role, p_scope, p_tenant, p_scope_id) lists the permission keys a role holds with their effect, permdock_permission_keys() every declared key and permdock_permission_keys(p_scope) those some declared role is allowed on a scope, both executable by authenticated (RLS) | Hand-written joins over role_permissions; role_permission_keys or permission_keys |
permdock_trusted_role_permissions, rls.trustedReaders | The role reader for server code without the caller check, and the Postgres roles granted execute on it | A flag on the member-facing reader; service_role hard-coded |
permitted_<scope>_permission_keys, permitted_<scope>_permission_keys_for | Every permission key the caller (or a named user) holds on one scope instance, as the permission-key helpers answer each key, in one call (RLS) | A loop of permdock_has_permission calls; held_permissions |
permitted_<resource>_rows, permitted_<resource>_rows_for, rowHelpers | The per-resource row helper rls.rowHelpers turns on: the row ids the caller (or a named user) may act on with one permission, as the generated policies decide it (RLS) | permitted_<resource>_ids (that is the graph helper keyed by relation); allowed_rows |
rls.membershipSources | The tableMembershipSource / junctionMembershipSource sources the database-mode helpers read for a scope rls.memberships maps no table for; default supabase.hook.memberships | A second membership mapping per scope |
permdock_can_assign, permdock_can_assign_for, permdock_holders_<scope>, permdock_transfer_only_<scope> | The ownership objects permdock rls generate adds when a role declares a rule: permdock_can_assign(p_role, p_scope_id) for the application's policies on its membership tables (a null p_scope_id for a global role), permdock_can_assign_for(p_user, p_role, p_scope_id) for trusted SQL acting for a stored user in database mode, the deferred holder-count trigger (min, max) and the transfer-only statement triggers on each scope's membership table (ownership) | A trigger that writes; a check that trusts the caller's role claim over the membership table |
<table>_visible, <table>_visible_fields, <table>_mask, permdock_key, --fields views, --fields mask, --revoke-columns, rls.fields, rls.revokeColumns | The field views permdock rls generate --fields views emits: a security_invoker view per table with field-limited read grants whose restricted columns are case when <permitted> then col end, and with --revoke-columns the owner-rights companion it joins on permdock_key while the table keeps only unrestricted columns readable; --fields mask adds <schema>.<table>_mask(p_row), which nulls the restricted columns of one row by the same masks for owner-rights SQL; rls import reads them back as the fieldViews export, testRlsParity({ fieldViews }) and rls verify compare them with pick, doctor PD030 flags columns still readable | Postgres column privileges per app role, a permission per field, or a view that reads past RLS |
secretKeys, SupabaseSecretKey | The permdock/supabase/middleware option mapping a named Supabase secret key (authKeyName from withSupabase) to a service principal with { id, tenant, roles, permissions }, as a service credential | A list of accepted keys; withSupabase's auth: 'secret:<name>' decides which keys verify |
withPermDock | The @supabase/middleware entry permdock/supabase/middleware's createPermDock returns: requires jwtClaims upstream, contributes ctx.permdock; withPermDock({ protect, data }) short-circuits with Problem Details | A PermDock naming pattern; with* is the pipeline's convention and appears elsewhere only as withSubject and withOtel |
jwtSubjectResolver | The cached, reusable form of subjectFromJwt, one per issuer (JWT adapter) | A second createPermDock |
clerkSubjectResolver | The subjectFromClerk resolver that caches each user's memberships: 'all' list for cache.ttl (Clerk adapter) | A token or session cache |
verifyDpopProof | The exported DPoP check permdock/jwt also runs when sender: 'dpop'; replay (a ReplayStore, memoryReplayStore() from permdock/jwt) refuses a reused proof jti | A second verifier; it only checks the proof |
TokenVerifier, TokenSigner | The two JOSE interfaces core declares as types (extension interfaces) | Anything that throws; anything that decides |
joseTokenVerifier, joseTokenSigner | The permdock/jwt implementations of the two interfaces over the optional jose peer | Exports of core |
verifier, signer | The option names for a TokenVerifier (subjectFromJwt, permdock/ssf) and a TokenSigner (permdock.snapshot, approvalsHandler, permdock/cloud) | jwt, jose, crypto as option names |
discovery, accept | The permdock/jwt options for OpenID Connect Discovery (an issuer URL that supplies jwks_uri and issuer) and for which token kind a resolver accepts ('access-token' default, 'id-token') | Guessing the token kind from its claims |
subjectFromIntrospection, IntrospectionPrincipal | An RFC 7662 or RFC 9767 introspection response in, Subject<IntrospectionPrincipal> out (a JwtPrincipal) | An HTTP client; the call is yours |
<provider>CustomRoleSource | A provider's CustomRoleSource implementation (betterAuthCustomRoleSource) | A subject mapper |
accessReviewApplier | permdock/better-supabase: applies an access review's revoked items through the organizations and invitations blocks, then calls markApplied | startAccessReview, which records the decisions |
authorizationProvider | permdock/better-supabase: better-supabase's authorization config value (AuthorizationProvider, apiVersion: 1), built from the manifest and catalog; approvers sets isApprover per request kind, and approver is its 'ai-tool' entry | PermDock's own decision path |
authorizationHooks, AuthorizationHooksOptions | permdock/better-supabase: better-supabase's AuthorizationHooks (createServer's authorization option), deciding automations, delegated scopes, approvers, identities, delivery, support and run tickets with PermDock | PermDock's own decision path |
authorizer | permdock/better-supabase: better-supabase's authorizer server option (Authorizer, apiVersion: 1), deciding each permission of a resource, action, route guard or tool with decide from the verified claims | authorizationProvider, which describes the SQL; toolPolicy, the 0.6 and 0.7 hooks |
bucketPolicy, topicPolicy | permdock/better-supabase: the access policy of defineBucket and defineTopic, mapping operations to Permission references | rls.storage and rls.realtime, which permdock rls generate writes |
apiKeyClaimOptions | permdock/better-supabase: the claim and tenantClaim options of better-supabase's apiKeyClaims() and apiKeyResolver(), from rls.apiKeys | Verifying a key |
subjectFromBetterSupabase | permdock/better-supabase: a Subject from better-supabase's AuthSession, with apiKeys for apiKey sessions and plans for the features claim | Verifying the session; better-supabase did that |
subjectFromShareLink, ShareLinkResolver, ShareLinkRow, ShareLinkTarget, ShareLinkSubjectOptions | permdock/better-supabase: a link Subject<CapabilityPrincipal> from a better-supabase share-link row, keyed by the subject type in links (share links) | A second link principal type; a signed capability |
toolPolicy | permdock/better-supabase: the authorize and visible hooks of better-supabase's createMcp, for tools whose meta is a Permission | Tools on the official MCP SDK (permdock/mcp) |
credentialGuard | permdock/better-supabase: a better-supabase CredentialProvider whose token uses PermDock decides first | Storing or refreshing tokens |
hookCan, handlerCan | permdock/better-supabase: the can options of better-supabase's authorizeHook and protectWebHandler for Workflow SDK hooks and web handlers; hookCan decides in the hook's tenant, handlerCan in the request's active tenant through getPermDock(request) | authorizeHook from permdock/workflow-sdk, which takes the Workflow SDK resumeHook directly |
supportPolicy | permdock/better-supabase: the authorize option of better-supabase's supportSessions, deciding a start with permdock.decideSupportSession; approval-required passes only with a distinct approver | Minting the session; better-supabase signs it |
subscriberPolicy | permdock/better-supabase: the per-subscriber filter for better-supabase webhooks-out, outbox and realtime fan-out, keeping the subscribers decideFor grants the event type's permission, as the sender | Delivering the event |
principalSource | permdock/better-supabase: a PrincipalSource over better-supabase claims, with principalByIdentity following identity links to a user or a contact | memoryPrincipalSource, the in-process source in permdock |
roleOrderFromCatalog, RoleOrderOptions | permdock/better-supabase: the catalog's role keys highest first by assigns, for the SSO block's roleOrder (SSO role order) | A hand-written roleOrder that drifts from the catalog |
describe | describe(decision) returning { kind, title, detail, alternatives } for tooltips and Problem Details | Logging; it is pure |
Snapshot | The JSON type of permdock.snapshot(); format major is the v field | A versioned type name (SnapshotV2); majors live in v |
parseSnapshot | Read snapshot JSON; rejects unknown majors and forbidden keys (__proto__, constructor, prototype) | Evaluating; it is a reader, not getPermDock |
fromSnapshot | Build a client PermDock from a Snapshot so portable grants evaluate locally | A second policy; closures stay on the server |
snapshotFor | The synchronous, deterministic snapshot builder for app-owned 'use cache: private' functions (snapshots) | A function that adds a cache directive, reads headers or awaits a source |
snapshotPromise | PermDockProvider prop on permdock/react: an unawaited Promise<Snapshot> from a Server Component; hooks answer pending until it resolves, or suspend through use() with suspend | Awaiting the snapshot in a layout |
cacheLifeFor | permdock/next: { stale } for cacheLife() from a snapshot's expiresAt and issuedAt, clamped to 30..300 seconds | A cache directive; the app calls cacheLife |
mayAccess | mayAccess(policy, user, permission, { tenant }): optimistic check for a proxy; false only when the declared roles provably lack the permission | A decision; the page still calls can / decide |
mayUse | permdock.mayUse(permission): whether some grant in the instance's snapshot could match for its subject, active tenant and delegation; the listing hint permdock/mcp, permdock/a2a and hosts with their own MCP server (better-supabase createMcp) use to filter tools | A decision; the call still runs can / decide |
approvalHeaders | { 'PermDock-Approval': token } for a retried mutation | Minting a token; it only wraps the one decide returned |
ApprovalStore, memoryApprovalStore, approvalsHandler, cancelApprovals | The pluggable store behind approval-required, its in-process default, the Fetch routes for approvers, and the helper that rejects pending requests for a session (permdock/approvals) | Deciding; a store never influences decide |
consume, consumedAt, consumeApproval, resumeDecision, storedApprovalToken | The atomic single-use step on ApprovalStore, the field it sets, and the helpers that apply a resume token, or find the stored one for a recomputed decision | used, redeemed, a consumed status |
ApprovalError, isApprovalError, assertApprover | The error (with a closed code list), its guard (matches by name and code, so a duplicated module copy still maps) and the approver check (by, escalation once open, no repeat) a custom ApprovalStore applies in resolve | Plain Error from a store, which approvalsHandler maps to 500 |
permdockApproval | The context key the ai-sdk and openai adapters read an explicit resume token from; every agent adapter also recomputes the token and finds the record in its store without it | approval, token (collide with application context) |
APPROVAL_META_KEY | 'dev.permdock/approval', the MCP request _meta key permdock/mcp reads a resume token from | A token in tool arguments (model-controlled) |
mcpResourceGuard, protectedResourceMetadata | permdock/mcp: the bearer-token resource-server check that answers McpAuthInfo or a 401 / 403 challenge, and the RFC 9728 metadata handler its challenges point at | A per-tool scope check (that is protectServer); a token from the query string |
approval: 'human' or { by, distinct, staleOn, quorum, ttl, escalation } | Grant option that yields approval-required; by is a grantee selector; distinct (default true) refuses the principal as approver, and distinct: false is the explicit opt-out doctor PD024 reports; staleOn: 'resource-change' binds the approval to the row's version; quorum (default 1) is the number of distinct approvers; ttl is a duration that caps how long the request stays open; escalation: { after, to } widens the approvers after a duration | A fluent approver builder; allowSelf; approvers on the grant (that is the request's copy); threshold, minApprovals |
holder, anyOf, allOf, PermissionApprover, AnyOfApprover, approverPermissions, permdockFor, verdict.permissions | Approvers who hold a permission in the request tenant (custom roles included), an any-of group, an explicit all-of list, and the verdict facts that holder() is checked through | hasPermission(), oneOf, or() |
mode, stages, user, UserApprover, Approver | The approval mode ('any', 'all', 'sequential'), the ordered approver sets it takes, the approver for one named person, and the union of approver kinds | A workflow engine; steps, chain, levels, person |
approverRelations, approverRelationKey, relations (verdict) | The handler step that reads which relation approvers an approver satisfies, the key each one is stored under, and the verdict field that carries those keys to the store | Facts from a request body |
ApprovalEscalation, ApprovalSignature, approvals | The normalised escalation on a grant, one recorded approval { by, at }, and the request field that lists them oldest first | signatures, votes; a count without who gave it |
applyApprovalVerdict, approvalQuorum, escalationOpenAt | The helpers a custom ApprovalStore uses in resolve: the next request after a verdict (quorum and escalation applied), the approvers a request needs, and the instant its escalation opens | A store re-implementing the quorum rules |
vouchApproval, vouched | A verdict the application's own approval rules decided, recorded with the rule's name: it resolves the request at once without the approvers eligibility checks and keeps the separation checks | A verdict from a request body; a flag that also skips the actor and requester checks |
ApprovalDelegation, ApprovalDelegationSource, memoryApprovalDelegationSource, matchDelegation, parseApprovalDelegation, onBehalfOf, delegation | An out-of-office cover (delegator, delegate, from, until), the source the handler reads, its in-memory default, and the signature fields that record who was covered (permdock/approvals) | A chain of delegations; an open-ended cover |
tableApprovalDelegationSource, rls.approvals.delegations, approval_delegations | permdock/supabase: covers from the table rls.approvals.delegations writes, which the four-argument permdock_is_approver also reads (approval delegation) | Covers configured in better-supabase as well |
AccessReview, AccessReviewItem, AccessReviewStore, AccessReviewError, isAccessReviewError, memoryAccessReviewStore, pageAccessReviewItems, startAccessReview, decideAccessReviewItem, accessReviewerEligible, accessReviewsHandler | A review of who holds a set of permissions, one holding, the store, its default, the population builder, the keep or revoke check, and the Fetch routes (permdock/approvals) | A review that revokes the role itself |
approver-repeated | The ApprovalError code for a principal who already approved the request; approvalsHandler maps it to 409 | duplicate-approval; counting the second approval |
version | The resource() option naming the row field (updatedAt, a revision) that a staleOn: 'resource-change' approval binds to; also on catalog resources | A schema version; the snapshot or catalog format major |
stale-approval | The denial reason for a resume token that approved an earlier version of the row | approval with a detail |
exclusiveWith | Role option listing roles that must not be held together; doctor PD018, separationConflicts and decideRoleChange (conflicting-role) | An evaluation deny |
DecisionSink, memoryDecisionSink | The pluggable destination for on('decision') events and its in-process default; memoryDecisionSink({ signer }) signs each write | Blocking a decision; sinks are fire-and-forget |
signDecisionBatch | Sign a batch of sink events as a vnd.permdock.evidence+jwt JWS | Feeding a signed batch back into decide; evidence only |
signSnapshot, SignSnapshotOptions, snapshotClaims, SnapshotClaims, snapshotFromClaims | Sign a Snapshot as a vnd.permdock.snapshot+jwt with an optional audience, the claims it signs, and read verified claims back into a Snapshot (null when invalid) | A second snapshot envelope |
signPolicyDocument, SignPolicyDocumentOptions | Sign a PolicyDocument as a vnd.permdock.policy+jwt for aud = the environment URL; policyDocumentFromClaims reads it back | Unsigned hosted grants |
signApproval, SignApprovalOptions, approvalSignatureClaims, ApprovalSignatureClaims, ApprovalSignatureEntry | permdock/approvals: sign a resolved request as a vnd.permdock.approval+jwt, and the claims set it carries | Signing a pending request |
parseApprovalRequest, APPROVAL_REQUEST_SCHEMA | permdock/approvals: validate an untrusted approval request record against schemas/approval-request-v1.json (null when invalid), and that schema | A looser request shape |
RUN_TICKET_SCHEMA, SUPPORT_SESSION_SCHEMA | permdock/cli: the claims-set schemas schemas/run-v1.json and schemas/support-session-v1.json | Validating a token instead of verifying it |
Capability, CapabilityInput, CapabilityRedeemer, parseCapability | The v1 share-link object { v, id, holder, on, roles, permissions?, redeemer?, once?, expiresAt }, the signCapability input (permission and resource references, not keys), who may redeem it ('anyone', 'signed-in', { user }, { scope, id }), and the strict own-property parser (link capabilities) | ShareLink, LinkToken, audience (that is the JWT aud) |
signCapability | Sign a capability as a vnd.permdock.capability+jwt | Issuing without a guard; a link that holds a scope or global role |
subjectFromCiOidc, CiOidcSubjectOptions, CiOidcPrincipal, CiOidcProvider | permdock/jwt: verify a CI job's OIDC token (provider: 'github' | 'gitlab' | 'buildkite', required audience, optional issuer and schema) and return a workload principal with repository, ref and environment; on('auth') source ci-oidc | A user principal from a CI token; a long-lived CI secret |
subjectFromCapability, CapabilitySubjectOptions, CapabilityFailureCause | permdock/jwt: verify a capability and return the link subject, never throwing; options issuer, audience, linkPolicy, revoked, replay, viewer; causes redeemer-mismatch, link-policy, capability-revoked, capability-replayed next to the token causes | Accepting a capability in subjectFromJwt; a capability as an access token |
verifySubjectToken, VerifySubjectTokenOptions, VerifySubjectTokenResult, SubjectTokenClaims, SubjectTokenFailureCause | permdock/jwt: an at+jwt naming one subject for one request, from the first of several verifiers, short-lived and used once | Resolving a Subject; subjectFromJwt does that |
verifyIdToken, VerifyIdTokenOptions, VerifyIdTokenResult, IdTokenClaims, IdTokenFailureCause | permdock/jwt: a relying party's OpenID Connect ID token check, nonce included | Authorising an API call with an ID token |
CapabilityPrincipal, kind: 'link', via: 'link' | The principal a capability resolves to (its id is the link id, with the verified capability attached) and the via of its one resource membership | A user id; a principal a model or request body can name |
kind: 'contact', via: 'contact' | A principal outside the tenant who holds only on memberships, each rewritten to via: 'contact'; read-only unless a role with for: ['contact'] grants the write (contact principals) | guest or customer for the kind; a contact that holds tenant roles |
LinkPolicy, LinkPolicyViolation, linkPolicyViolation, linkPolicy | A scope instance's rules for links on its resources (maxLifetime, redeemers, once), the broken rule (lifetime, redeemer, once), the check, and the option on subjectFromCapability and signCapability that applies them | A rule that widens; a policy read from the token |
holder | 'link', or the reserved 'key' for a future stateless key the resolver refuses; API keys are opaque pdk_ keys, not capabilities | A third holder kind |
Credential, CredentialKind, CredentialPermission, parseCredential, isFeedId | The v1 record an API key stands for { v, id, kind, principal, tenant?, roles?, permissions, createdBy, createdAt, expiresAt?, name?, on? }, 'user', 'service' or 'feed', one { permission, ids? } entry, the strict own-property parser, and the feed id check (API keys) | ApiKey for the record; the secret or its hash in the record |
ApiKeyPrincipal, via: 'credential' | A principal resolved from a key, with the verified credential attached; the via of a service key's one tenant membership | A principal a request body can name |
credentialDelegation | The delegation a verified credential narrows its subject to | Copying the owner's rights into the key |
decideCredential, CredentialRequest, CredentialPermissionInput, CredentialDecision, DecideCredentialOptions | decideCredential(permdock, request) decides whether the subject may create a key: granted with the Credential to store, approval-required with a bound token (resume with approved), or denied; options settings, approved, now | Storing the key; a key that mints keys |
CredentialPolicy, CredentialPolicyViolation, credentialPolicyViolation | A tenant's API-key rules (maxTtl, kinds, approval, allowNoExpiry), the broken rule (kind, no-expiry, ttl) and the check | A rule that widens |
SettingsSource, TenantSettings, memorySettingsSource, settings | Per-tenant settings (settingsFor(tenant) returns { credentials? }), its in-process default and the option on decideCredential and subjectFromApiKey | Settings that grant; a module-level settings object |
CredentialVerifier, apiKeyVerifier, memoryCredentialStore, verifier | { verify(key) → Credential | null }, the verifier over an application table (find(id) returns { credential, hash }), the optional touch(id, at) for lastUsedAt, the in-process store (issue, rotate, revoke, list, lastUsedAt) and the option naming a verifier | Verifying keys in core; scanning every row |
subjectFromApiKey, ApiKeySubjectOptions, ApiKeyFailureCause | permdock/server: subjectFromApiKey(key, options) resolves a pdk_ key into Subject<ApiKeyPrincipal>, never throwing; options verifier, permissions, principals, tenant, revoked, settings, sink, sample, kinds; causes malformed, unknown-credential, invalid-claims, expired, credential-policy, credential-revoked, owner-unavailable | An API key in subjectFromJwt; a key as an actor |
signRunTicket, parseRunTicket, RUN_TICKET_CLAIMS, subjectFromRunTicket, RunTicket, RunTicketInput, RunTicketOptions, RunTicketSubjectOptions, RunTicketFailureCause | Sign, validate and resolve a vnd.permdock.run+jwt that lets background work act for a principal inside a delegation (run tickets) | JobToken or RunToken; a ticket without a delegation |
RunKind, RunActClaim, RunAutomation, RunBinding, RunContext, RunPrincipal, RunTicketAutomations | automation, job or caller; the RFC 8693 act claim; { id, version }; { connector?, tools? }; context.run; the principal with runTicket; the live automation reader | trigger as a grant; RunTicketAutomation for the reader |
automation-unavailable, automation-changed | on('auth') causes of subjectFromRunTicket: the automation is missing or revoked, or its version moved | automation-revoked as a separate cause |
generateApiKey, hashApiKey, parseApiKey, generateFeedKey, parseFeedKey, StoredCredential | A fresh pdk_<id>_<secret><checksum>, its base64url SHA-256, the { id, secret } split, the lowercase pdfeed_ key and its parser, and the { credential, hash } row a verifier reads | Storing the key itself |
CredentialEvent, credentialEvent, com.permdock.credential.* | A credential sink event (created, used, rotated, revoked; used carries sample), its builder and CloudEvents type | A per-operation CloudEvents type |
Automation, AutomationMode, AutomationSource, memoryAutomationSource, parseAutomation, automations | The v1 record of a published automation { v, id, version, mode, principal, publishedBy, publishedAt, tenant?, roles?, operations, permissions, run?, revoked?, name? }, 'publisher' or 'service', the live record reader, its in-process default, the strict parser and the option naming a source (automations) | A record that grants from its trigger |
decideAutomation, AutomationRequest, AutomationDecision, DecideAutomationOptions | decideAutomation(permdock, request) decides whether the subject may publish an automation: granted with the Automation to store, or denied | A method on the instance, which every app would ship |
AutomationEvent, automationEvent, AUTOMATION_EVENT_SCHEMA, com.permdock.automation.* | An automation sink event (published, changed, revoked, run; run carries run.id), its builder, its schema and CloudEvents type | Deciding a run |
WorkflowPermDock, WorkflowPermDockOptions, AutomationOptions, StartAutomationResult, AwaitApprovalOptions | permdock/workflow: createPermDock(policy, options) returns { start, getPermDock, awaitApproval, openApproval, resumeApproval } over run tickets | A run that keeps its publisher's rights after a demotion |
ApprovalWaiter, ApprovalWaitOptions, pollingApprovalWaiter, PollingApprovalWaiterOptions, waiter | { wait(token, { expiresAt?, signal? }), wake(token) }, the store-polling default (interval 5,000 ms) and the option on permdock/workflow | Deciding an approval |
workflowSdkWaiter, WorkflowSdkWaiterOptions, approvalHookToken | permdock/workflow-sdk: an ApprovalWaiter over Workflow SDK hooks named permdock:approval:<token>; sleep bounds a wait by expiresAt | A hook payload that carries a verdict |
startAutomation, StartAutomationRunResult | Starts the PermDock run, then the Workflow SDK run with the ticket as its first argument; a denied start starts nothing | A workflow run with no run ticket |
authorizeHook | Resumes a Workflow SDK hook only for a caller granted the permission; a missing hook denies with validation and cause: 'hook-unavailable' | Resuming a hook by token alone |
SupportSession, SupportSessionPolicy, parseSupportSession, supportSessions | The v1 record { v, id, principal, actor, tenant, reason, permissions, startedAt, expiresAt, approvedBy?, reference? }, the tenant setting { disabled?, maxTtl?, readOnly? } that only tightens, and the strict parser (support sessions) | Signing in as the customer |
decideSupportSession, SupportSessionRequest, SupportSessionDecision, DecideSupportSessionOptions, reason-required | decideSupportSession(permdock, request) decides whether a staff member may view as a person: granted, approval-required with a bound token (resume with approved and approvedBy), or denied; reason-required denies an empty reason | A session without a reason |
signSupportSession, subjectFromSupportSession, SupportSessionSubjectOptions, SupportSessionSource, SupportSessionFailureCause, kind: 'support' | permdock/server: sign a vnd.permdock.support-session+jwt and resolve it into a subject with the person as principal and the staff member as a support actor; causes add session-ended, principal-unavailable and actor-unavailable | An approver |
supportSessionEvent, via: 'support-session', subject.supportSession | The access event of a SupportSession, with session and permissions, sent as com.permdock.support-session.*; every decision under the session carries the same id as subject.supportSession: { id } (OTel permdock.support_session.id) | A second support-session schema |
AgentPermDock, AgentPermDockOptions, GatewayOptions, OperationVerdict, decideOperation, allowedOperations, decideModel, permittedModels, filterResults, gatewayOptions, models | permdock/agent: the runtime-neutral agent contract the agent adapters return, the model gate, the results filter and AI Gateway attribution (agents) | A model allow-list outside the policy |
stepUp, StepUp | The permdock/ai-sdk option { at? } that pauses a denial a fresh sign-in or an eligible role activation lifts as user-approval, and the { kind: 'authentication' | 'activation', … } hint on that status and on a denied OperationVerdict (AI SDK) | withStepUp; a wrapper around toolApproval; a step-up that grants |
testAgentRuntime, AgentRuntimeContext, AgentRuntimeDomain, AgentRuntimeMounted, AgentRuntimeOptions, AgentRuntimeScenarioName, AgentRuntimeOperation, AgentRuntimeModel | permdock/testing: the conformance runner for an AgentPermDock and its SaaS domain | An adapter's runtime hooks |
permdock_is_approver | The generated SQL function permdock_is_approver(p_approvers jsonb, p_tenant text default null): whether the signed-in user matches an approval request's approvers, for policies on approval views | Approving in SQL |
exchangeCapability, ExchangeCapabilityOptions | permdock/supabase: a verified link subject in, a short-lived role: 'anon' Supabase access token with a capability claim out | service_role; a sub claim; a security-definer RPC per resource |
rls.anonymousSignIns | 'deny' keeps a Supabase token with is_anonymous: true out of every RLS branch but the anyone() grants' | A boolean; a separate role for anonymous sign-ins |
rls.anonExecute | true grants anon usage on the helper schema and execute on the helpers, for hand-written policies that apply to public or anon | A grant to service_role; a way to let anon read rows |
rls.tenants | 'active' (default) narrows the generated helpers and memberOf checks to the tenant claim when the token carries one; 'all' admits every tenant the subject is a member of, for apps whose tenant comes from the URL | A boolean such as narrowTenant; an organisation-slug header |
permdock_trusted_replace_custom_role_grants, permdock_trusted_rename_custom_role_grants, permdock_trusted_delete_custom_role_grants | The generated custom-role writes for a trusted caller (a migration, a job, a backend role granted execute): the definition checks without the caller checks; no client role may execute them | service_role grants in generated SQL; an admin or bypass flag on the member functions |
permdock_replace_custom_role_grants_by_id, permdock_trusted_replace_custom_role_grants_by_id, permdock_trusted_role_permissions_by_id, rls.customRoleWrites.roles.primaryKey, rls.customRoleWrites.audit | The custom-role functions keyed by the application's role row id: the row supplies tenant, scope and name; the save audits permdock.custom_role.replaced; the reader returns declared keys to rls.trustedReaders only | A tenant or scope argument next to the id; a reader a client role may execute |
permdock_replace_global_roles | The generated rls.roles write that sets one user's global roles in one call, as the invoker so the assignment trigger still judges each row; execute for authenticated only | A security definer variant that skips the ceiling; replace_roles without the scope word |
rls.customRoleWrites.requires, manage-roles | The permissions (or 'manageRoles') a caller must hold before the generated custom-role writes run the hand-out check, and the hint when it holds none | A role name list; a check that only runs on save |
rls.customRoleWrites.roles, permdock_cascade_custom_role | The application's table of custom roles (table, key, tenant, scope, id, skip) and the generated trigger function that carries a role's grants through renames, moves and deletes of its row | A second store of custom role names; a trigger that writes without the write functions' checks for a signed-in caller |
rls.customRoles.from, --backfill-out, -- permdock:backfill v1 | The application's existing custom-role tables (permissions, includes) and the flag that writes the idempotent data migration copying them through the trusted replace function, with its marker line | import, adopt or sync for a one-off copy; a copy that overwrites a role edited since |
rls.customRoles.from.sync, permdock_sync_custom_role | sync: 'trigger' keeps the PermDock custom-role tables current with after-row triggers on the application's permission and include tables, instead of one backfill; the same entries are dropped with a warning. The before-row permdock_sync_custom_role_guard_* triggers hold a signed-in caller to the checks of permdock_replace_custom_role_grants | |
permdock_custom_role_name_guard | The trigger on rls.customRoleWrites.roles that refuses a tenant role named like a declared role (declared-role) or a shared role (name-taken) | |
permdock_custom_role_guard, permdock_custom_role_beyond | Stable SQL checks for an app's own security definer write path: the guard raises unless the caller may change the stored role (not-member, manage-roles, not-assignable-by), and beyond returns the keys of a definition the caller may not hand out; no client role may execute them | |
permdock_custom_role_entry_problem, parseCustomRoleEntry | One stored allow entry, <permission>[@<level>], checked in SQL and in process: unknown-permission, outside-ceiling or unknown-level; parseCustomRoleEntry(policy, entry, { scope }) is exported from permdock | |
RoleMap, map | A role column whose values are not role keys: { column, map: { value: 'role' | null } }, readable in tableMembershipSource, junctionMembershipSource and rls.memberships | |
rls.tables.<resource>.via, permitted_<parent>_ids | via: { table, column, key?, id?, type?, scope? } maps a table that reaches its scope through a parent; the helper is named after the parent table with the plural dropped | |
rls.seeds, seeds: 'function', seeds: 'view', <schema>.seed | 'function' writes the role_permissions rows as <schema>.seed(), a security definer function in the helpers part; call select <schema>.seed(); after each deploy; 'view' writes role_permissions as a security_invoker view over the rows, so nothing needs seeding | |
permdock rls explain | The tables, membership sources, custom roles table, row helpers and triggers a rls generate run binds to, without writing a file | |
supabase.hook.teams, team_ids | The hook option and claim for the uuids of the user's teams (table, user, team, tenant?), counted in the memberships budget | |
PD072, PD073, PD074 | Doctor checks: a membership source reads role keys through a table tenants write, and a role's for that no membership source can hold | |
rls.triggers, rls.audit | Triggers the application owns on generated tables (name, when, events, level, function, args), and one call per generated table to an audit module that registers it by regclass | A permdock_ trigger name for an app trigger; a hand-written migration that has to run after the generated file |
rls.migrate.tables, refresh, --retire-out, -- permdock:retire v1 | The materialised permission tables rls migrate retires, the functions that refresh one, the flag that writes the drop migration once nothing reads them, and its marker line | cascade; drop, remove or cleanup for the flag |
rls.assignments, rls.assignments.ownRole, permdock_assignment_<table>, permdock_can_assign_custom_role, permdock_can_assign_custom_role_for | Assignment triggers on the membership tables, the global-roles table and listed tables such as invitations: a client role may write only the roles it may assign, by assigns or, for a custom role, by what it may hand out, and with ownRole: 'refuse' none on its own rows; other writers are trusted, and the _for form re-checks a stored user | A setting a client could flip to bypass the check; a trigger that trusts the role claim |
rls.ownershipTriggers | false, or { <scope>: false }, leaves out the holder-count and transfer-only triggers of min, max and transferOnly | A way to turn the rules off in decideRoleChange |
permdock_can_assign_any, permdock_can_assign_any_for | One assignment check for a declared or a custom role, (p_role, p_tenant, p_scope, p_scope_id), written when a role declares assigns; p_scope 'global' assigns a platform role, and the _for form takes the stored user first | A caller-side branch on whether a role is declared; a check that trusts the role claim |
rls.readOnlyActors | Restrictive policies, {table}_{op}_read_only_actors, that refuse writes from a token whose act.kind is a listed actor kind (true: support and impersonation) unless act.read_only is false, and permdock_actor_may_write(), the same check for hand-written write policies | A permissive policy that widens access; a session flag a client could set |
rls.realtime.topics, permdock_realtime_<pattern>_<op> | Private Realtime channel policies on realtime.messages: a :-separated topic pattern with one {<scope>} segment, read (select) and write (insert) permission references | A policy keyed on the row's topic column; a public channel |
rls.storage.buckets, permdock_storage_<bucket>_<op> | Storage policies on storage.objects for one bucket: scope, folder (1-based, default 1), read, write (insert and update) and delete permission references | Owner-only policies on owner_id; a bucket-wide grant |
rls.apiKeys, permdock_api_key_allows(p_grant) | An API key passed in a claim (api_key by default) caps every allow at its scopes (permission keys), and a key with a tenant and no subject is a service principal holding roles (or serviceRoles) in that tenant | A wildcard scope; a key that widens its owner's rights; a key set by a client |
rls.tokenScopes, permdock_token_scope_allows(p_grant) | A delegated token (a client_id, or an act that is not a support or impersonation session) reaches a grant only when its scope claim reaches the permission: own scope, former scope or policy oauthScopes, the map better-supabase reads as delegation.scopes | |
permdock_user_id() | The Supabase helper every generated helper, policy, field view and trigger reads the subject through: what auth.uid() returns, and null for an empty sub | auth.uid() in a policy a token with an empty sub reaches; a user id the caller passes |
permdock_session_live() | The Supabase helper a { subject: { session: { live: true } } } condition compiles to: the token's session_id is in auth.sessions for the caller and not past not_after | auth.uid() alone, which a revoked session's token still passes |
permdock_capability_ids, --capabilities, rls.capabilities | The RLS helper that reads the capability claim, and the flag and config key that emit it with one anon policy per resource-scoped grant | A policy that trusts a capability the server did not exchange |
store, sink, directory, reviews, approvalDelegations | Options for an ApprovalStore, a DecisionSink, a DirectoryStore (scimHandler), an AccessReviewStore (startAccessReview) and an ApprovalDelegationSource (approvalsHandler); a SnapshotSource is the source option of permdock/react-native | Anything else; store is never a database handle |
policies | The option every adapter's createPermDock accepts for a PolicySource; read once per instance | A module-level policy the source swaps; a per-check fetch |
hostable | definePolicy option listing the permission subtrees or leaves hosted grants may touch; default none | hosted, editable, remote; a grant option |
PolicySource, memoryPolicySource, testPolicySource | The channel for hosted grants (current(), refresh()), its in-process default and its permdock/testing runner | A decision path; current() is synchronous and never fetches |
PolicyDocument, HostedGrant, parsePolicyDocument, mergeHostedGrants | The v: 1 hosted-grant document, one grant in it, its reader (rejects unknown majors and forbidden keys) and the pure merge getPermDock runs | PolicyDocumentV2; majors live in v |
PushedPolicy, PushedGrant, PUSHED_POLICY_SCHEMA, pushedPolicy, parsePushedPolicy | permdock/catalog and permdock/cli: the v: 1 code-grant document permdock cloud push sends, one grant in it, its JSON Schema (schemas/pushed-policy-v1.json), the builder from a Policy and the strict reader | Hosted grants, which are a PolicyDocument |
manifest, permdockVersion, --manifest | Members of the permdock cloud push body: the supabase inspect --out manifest the flag reads, and the permdock version that pushed | version, the Cloud's catalog version number |
permdock login, permdock logout, --write, --loopback, --no-open | The CLI sign-in at the platform issuer: device flow by default, --loopback for the RFC 8252 browser redirect, --write to add catalog:write, --no-open to print the URL without opening a browser | PERMDOCK_CLOUD_KEY, the environment's secret key |
projects:read, policy:read, catalog:write | The platform issuer's scopes: list and read projects, read a project's pushed policy, publish a catalog with a login | The per-environment sk_ key, which has no scopes |
permdock cloud pull, --project, ProjectPolicy | Write a project's pushed catalog and manifest; --project names the project there and on rls generate; ProjectPolicy is the GET /v1/projects/:id/policy body | policies.refresh, the signed hosted-grant document a running app fetches |
PERMDOCK_CLOUD_TOKEN | A read-only CI key pinned to one Cloud environment, for cloud pull and rls generate --project | PERMDOCK_CLOUD_KEY, which writes; a login, which belongs to a person |
policy-not-published | The Cloud's 404 Problem Details type for a project with no push yet | 404 about:blank for an unknown project |
policyFromCatalog, PolicyFromCatalogOptions, resourceSchemaFromJson | permdock/catalog: rebuild a Policy from catalog-v1 and a PushedPolicy, so a hosted PDP decides as the application does; a closure grant denies; a catalog JSON Schema becomes a Standard Schema | Running application code in the Cloud |
catalogDrift, CatalogDriftInput, hostedGrantFindings | permdock/catalog: the com.permdock.catalog.drifted payload between two catalogs, and the findings for hosted grants the new catalog drops | A second drift format |
HostedGrantRef, matched.hosted | { document, grant } on a grant and a Decision a hosted grant matched: the document fingerprint and the grant id | A role name; hosted grants still name declared roles |
hosted-grant-dropped, HostedGrantDropped | The on('error') value for a hosted grant that failed a merge rule; reason is not-hostable, unknown-permission, unknown-grantee, non-portable, weaker-approval or invalid | A denial reason; a dropped grant never reaches Decision |
CLOUD_EVENT_TYPES, RESERVED_CLOUD_EVENT_TYPES, cloudEventType, CloudEventType, CatalogEventData | The closed CloudEvents type list (com.permdock.decision, com.permdock.<family>.<operation> for approval, directory, membership, credential, catalog, support-session, automation and delivery) and the catalog payload { kind, fingerprint, previous?, findings? } | A new type without a wire-format change |
CatalogFinding, CatalogFindingCode, operationFindings | One drift finding { code, permission, grant?, operation?, previous?, risk? }; code is permission-removed, not-hostable, grantee-removed or approval-tightened for a broken hosted grant, and operation-risk-raised or operation-approval-removed for an operation compared by name; permdock/catalog operationFindings(previous, next) computes the operation-* ones | Free-text finding lines |
coveredByDelegation | permdock: the delegation coverage check (scopes, RAR authorizationDetails, GNAP access) decide uses; returns undefined, no-delegation or not-delegated | isDelegated, checkScopes, a boolean that hides the reason |
agent-tool-not-delegated, tools | The denial reason for a call by an agent actor whose tools list does not name the tool; tools is the actor field, act.tools on a Supabase token | tool-not-allowed, not-delegated with a detail |
delegations, DelegationInput, PolicyDelegation, DelegationTarget | The definePolicy option for standing delegations { from, to, permissions, validFrom?, validUntil? }, its input type, the normalised entry { from, to: { kind, id? }, permissions: string[], validity? } on policy.delegations, and the actor it is for | agents, grantsToActors; a grant with an actor grantee (that gives the actor access of its own) |
delegatedPermissions, delegated | permdock: the ceiling of permission keys the policy's delegations give the subject's actor right now (undefined when none applies), and the snapshot field carrying it sorted | delegationScopes (these are permission keys, not OAuth scopes); a field on the subject |
delegation-removed, delegation-narrowed | permdock diff breaking kinds for a policy delegation that disappeared or lost permission keys or validity | delegation-changed for a narrowing |
catalogFingerprint | permdock: the catalog v1 fingerprint (base64url SHA-256 of canonical JSON without generatedAt, generator, fingerprint and usages) the CLI writes and the Cloud recomputes | A hash of the pretty-printed file; a CLI-only helper |
canonicalJson, sha256Digest | permdock: RFC 8785 canonical JSON of a JSON value, and sha-256:<base64url> of a string; the approval token, the approval ETag and catalogFingerprint are built from them | A second serialiser; a hex digest |
approvalEntityTag, approvalView, ApprovalView | permdock/approvals: the strong ETag approvalsHandler serves for a request, and the request without its token that the tag hashes | An ETag over the stored row including the token |
idempotencyRecord, idempotencyRecordKey, matchesIdempotencyRecord, IdempotencyRecord, IdempotentCall | permdock/approvals: the stored replay of an approve or reject call, its key per principal and Idempotency-Key, and the check that a retry is the same call | A key shared across principals; replaying a different body |
normalizeMembership, normalizeMemberships, resolveScope | permdock: the membership shapes and scope names the core accepts, read the way decide reads them | A second membership parser |
checkHostedGrant, HostedGrantCheck | permdock/catalog: whether one hosted grant would be kept by hostedPolicies, { ok: true } or the drop reason | Saving a grant the endpoint later drops |
hostedGrantOptions, HostedGrantOption, HostedGrantRoleOption, HostedGrantRelationOption | permdock/catalog: per hostable permission, the grantees, effects, approval fields and condition fields a hosted grant may use | A form built from a copy of the rules |
checkRoleChange, RoleRules, RoleChangeCheck, RoleChangeCheckInput | permdock: the subject-free role-change rules (assigns, for, exclusiveWith, min, max, transferOnly) from a catalog role and holder counts; decideRoleChange runs it | Deciding a change for an actor; that is decideRoleChange |
ParseCatalogOptions, CatalogMetaField, requireMeta | permdock/catalog: the parseCatalog option that requires permission meta fields (title, risk, effects) | Requiring meta by default |
catalog_invalid | The CLI problem code for a catalog that breaks a validation rule; issues lists { path, message } | check_failed for a broken catalog |
positionsMoved | collect --check and catalog --check data when only usages[].line differs; the check exits 0 | Failing the build on line churn |
WireDenial, WireDecision | permdock: a denial as it leaves the process ({ role, reason, to?, detail? }, detail a JSON value, never a closure cause or validation error) in decision events, Problem Details, MCP and WebMCP refusals and the decision endpoint; WireDecision is a Decision with those denials | SerializedDenial, PublicDenial; sending Denial as is |
toCsvRow, CSV_COLUMNS | permdock: one RFC 4180 CSV row for a decision event and the pinned header (time, principal, actor, tenant, permission, outcome, matched.role, via, denials.reason, token) | A configurable column list; a Cloud-only exporter |
toOcsf, accessToOcsf, OCSF_VERSION, OcsfAuthorizeSession, OcsfUserManagement | permdock: the pure projections of a decision event onto OCSF Authorize Session and of a support-session event onto User Management, pinned to one OCSF version | A second, Cloud-only projection |
verifyWebhook, parseCloudEvent, PermDockCloudEvent | permdock/cloud: verify a Standard Webhooks Cloud delivery of a CloudEvents batch (never throws, no unsigned mode) and validate one CloudEvent | A shared-secret or unsigned webhook mode |
webhookSigner, webhookVerifier, WebhookFailureCause | permdock/server: sign and verify Standard Webhooks deliveries of any body; the failure field is cause | A PermDock-specific webhook signature |
HonoPermDockEnv | permdock/hono: the Env type the middleware() and protect() middleware declare, so c.var.permdock and c.var.permdockData are typed | A declare module augmentation of ContextVariableMap |
memberships, customRoles, tenant | The three tenancy options every adapter's createPermDock accepts: a MembershipSource, a CustomRoleSource, and how the active tenant is resolved from the request | Reading a tenant from an unsigned header or a model argument |
cloud | cloud({ url, key, environment, verifier }) from permdock/cloud, returning approvals, sink, snapshotsFor(token), policies, the environment URL as issuer and its jwks URL | A factory for a PermDock; there is no decide on it; an app audience option |
approver, CloudApproverOptions | The cloud({ approver: { signer, audience?, permissions?, relations? } }) option: the app's TokenSigner that signs the PermDock-Approver token on approvals.resolve; audience defaults to <issuer>/approvals; permissions and relations read the approver facts the token signs (approver token) | approverSigner, resolver; the environment key through cloudSigner |
cloudEndpoints | cloudEndpoints({ url?, environment? }) from permdock/cloud: the environment URL (issuer) and JWK Set URL (jwks) for a configured environment (environment, then PERMDOCK_CLOUD_ENV), synchronously; throws without one | A network call; discovery |
resolveCloudEndpoints, cloud().endpoints() | The same endpoints, asking GET /v1/environment which environment the key belongs to when none is configured | VERCEL_ENV mapping; discovery |
cloudApprovalWaiter, CloudApprovalWaiter, CloudApprovalWaiterOptions, approvalTokensOf, cloudDeliveryTransport, cloudSigner, CloudSignerOptions, CloudConnectionOptions, CloudCatalog, CloudCatalogPush | permdock/cloud clients: an ApprovalWaiter woken by verified com.permdock.approval.* webhooks (webhook(request)), a DeliveryTransport for the Cloud's hosted sender, a TokenSigner over the environment key, and cloud().catalog.push and its result | A decision; a subject; signing policy, snapshot or evidence types |
cloudOAuth, CloudOAuthClient, CloudOAuthOptions, CloudAuthorization, CloudCredential, CloudProject, CloudProjectPage, CLOUD_BASE_URL, CloudScope | permdock/cloud OAuth client of the platform issuer: authorizeUrl, exchangeCode, refresh and a typed listProjects, with token fields under their RFC 6749 names; CLOUD_BASE_URL is https://permdock.com/api, the default url of every permdock/cloud client | Storing tokens; a decision; access_token renamed to accessToken |
CloudAuthError, isCloudAuthError, CloudAuthErrorCode, CloudAuthErrorDetails | A failed cloudOAuth call, its closed code list (invalid-token and insufficient-scope from the RFC 6750 challenge) and its guard, which matches by name and code | A plain Error; a denial reason |
scimHandler | The RFC 7644 Fetch handler from permdock/scim writing into a DirectoryStore (SCIM adapter) | A PermDock; it decides nothing and reads no tenant from a body |
DirectoryStore, memoryDirectoryStore | The repository interface SCIM provisioning writes to (users, groups, groupsFor), every method tenant-first, and its in-process default | A MembershipSource; the store is the write side, the source below is the read side |
postgresDirectoryStore, PostgresDirectoryStoreOptions | A DirectoryStore over the tables permdock scim generate writes, called through a SqlQuery; schema names their schema | A membership or invitation API; it is written only by scimHandler |
directoryMembershipSource | directoryMembershipSource(store): the MembershipSource that turns synced groups into tenant memberships { tenant, roles, via: 'group:<id>' } and yields nothing for an inactive user | Reading display names; group ids only |
ReplayStore, memoryReplayStore | The pluggable jti replay store for permdock/ssf and its in-process default | A decision input; SETs and logout_tokens never reach decide |
signSet, SignSetOptions, SetEvent, SSF_PUSH_DELIVERY, SSF_POLL_DELIVERY | permdock/ssf: sign one event as an RFC 8417 SET (secevent+jwt, sub_id, one events entry, txn), and the SSF 1.0 delivery method URNs | A SET with several events |
pushSet, PushSetOptions, SetDelivery, SetDeliveryFailureCause | permdock/ssf: the RFC 8935 transmitter push; the cause is the receiver's err in kebab case, or unavailable with retry: true | A throwing push client |
SetQueue, memorySetQueue, setPollHandler, SetPollHandlerOptions, SetError | permdock/ssf: the per-stream SET queue, its in-process default, and the RFC 8936 poll endpoint over it | Long polling |
caepEvents, CaepEvents, CaepCommon, CaepInitiatingEntity, CaepReason, CaepCredentialChange, CaepTokenClaimsChange, CaepAssuranceLevelChange, CaepDeviceComplianceChange | permdock/ssf: CAEP 1.0 event builders (sessionRevoked, credentialChange, tokenClaimsChange, assuranceLevelChange, deviceComplianceChange) and their inputs, camelCase in, snake_case on the wire | Events outside CAEP 1.0 |
riscEvents, RiscEvents, RiscAccountDisabled, RiscCredentialCompromise, streamVerificationEvent | permdock/ssf: RISC 1.0 builders (accountDisabled, accountPurged, credentialCompromise) and the SSF 1.0 stream verification event | Other RISC events |
SsfTransmitterConfiguration, SsfStreamConfiguration, SsfStreamStatus | permdock/ssf: the SSF 1.0 /.well-known/ssf-configuration document, a stream's configuration and its status, with the spec's snake_case fields | Stream status other than enabled, paused and disabled |
SsfStreamStore, SsfStream, memorySsfStreamStore, testSsfStreamStore | permdock/ssf: the streams a transmitter serves, each with the receiver that created it, its in-process default and its conformance suite | Receiver-side stream state |
ssfTransmitter, SsfTransmitterOptions | permdock/ssf: the SSF 1.0 metadata, stream, status, verification and poll endpoints as one Fetch handler | Adding or removing subjects per stream |
fanOutSet, FanOutSetOptions, SsfFanOut | permdock/ssf: one event signed per audience and delivered to every stream that requested it | Retrying a failed push |
pollSets, PollSetsOptions, PollSetsResult, PolledSet | permdock/ssf: one RFC 8936 poll request that answers SETs unverified | Verifying or dispatching SETs, which receiver.poll does |
connection, Connection, ConnectionOptions | The kernel and HTTP adapter method that opens a long-lived connection for a stream or socket, and its frozen result (permdock, signal, check, filter, close) | A mutable instance; stream, socket or subscribe as the kernel method name |
RevocationFeed, RevocationEvent, memoryRevocationFeed | The interface that tells open connections a subject changed (subscribe, revoke; events session-revoked and changed) and its in-process default | A decision input; a feed ends or revalidates, never grants |
revocations | The option carrying a RevocationFeed on the kernel, the HTTP adapters, permdock/ssf and permdock/scim | revocationFeed, feed |
PermDockRevokedError, RevokedCode | The reason of an aborted connection signal; code is session-revoked, expired, denied or subject-changed | A denial reason; a check after the abort is no-grant with detail: 'connection-revoked' |
socket, sse, SseOptions | permdock/hono helpers: socket(conn, events) wraps upgradeWebSocket events, sse(conn, stream, source, options) writes an async iterable to streamSSE | A with* or Dock name; helpers for other adapters |
ElysiaSocket, NestSocket | The structural socket types connection accepts in permdock/elysia and permdock/nest | An import of the framework's socket class |
ApprovalListQuery, ApprovalPage | The ApprovalStore.list argument (ApprovalListFilter plus limit and cursor) and its result (items, next) | An offset, or a page number |
ApprovalHint | { at?, hint? }: the approval option on the server kernel, HTTP adapters and permdock/terminal, emitted as the approval member of approval-required Problem Details | A terminal-only field, a URL built from the token by PermDock |
KeyringEntry, storage.keyring | The Entry shape from @napi-rs/keyring and the permdock/terminal storage option that takes it | A bundled keychain binding, keytar |
remotePdp | permdock/pdp helper that implements DecisionProvider over an AuthZEN evaluation URL | A local decide; unknown or unreachable remote answers deny |
openfga, spicedb, RelationMap | permdock/pdp presets that implement DecisionProvider over OpenFGA check / list-objects and the SpiceDB HTTP gateway CheckPermission / LookupResources, and their one-callback-per-permission tuple map | A tuple store, a model DSL or a per-vendor entry |
DecisionProvider.permitted | The optional listing member: the ids of one resource type a subject may act on, used by the PDP instance's filter and where | A grant; null denies every row |
PermDock-Approval | The HTTP request header carrying an approval token on a retried request, as one RFC 9651 sf-token | Anything else on the wire |
PermDock-Approver | The HTTP request header on a Cloud resolve carrying the approver's RFC 9068 at+jwt: sub the approver's principal id, aud <issuer>/approvals, 60 seconds | An approver named in the resolve body; X-PermDock-Approver |
membershipEvent | Pure builder for a membership sink event | A Decision; it is audit only |
Strings appear only as .key and .scope on the wire, in audit events and in catalogs. The public API takes references.
The subjectFrom<Provider> pattern names the source of the material (a JWT, a Supabase claims object, a Clerk auth object, a Better Auth session, MCP authInfo), always returns a Subject (anonymous when the material cannot be trusted) and never throws, so every provider reads the same way at the call site: createPermDock(policy, subjectFromClerk(await auth())). See Authentication and PermDock.
Reserved words
These never appear as public identifiers, for the reasons given:
| Word | Why it is reserved |
|---|---|
dock | It reads oddly next to PermDock; only permdock is used for the instance. |
ability | CASL's noun; using it would imply CASL semantics (subject detection, manage/all) that PermDock does not have. |
can as a definer | CASL uses can both to define and to check rules, which its own cookbook documents as confusing (less-confusing-can-api). PermDock defines with allow / deny and checks with can. |
$-prefixed members | Kilpi prefixes every instance member with $ to avoid clashing with policy names in a Proxy tree. PermDock keeps methods on the instance and the tree separate, so no prefix is needed. |
Can, Guard, Access | Component names used by CASL and Kilpi; the PermDock gate is <Protected>. The only other component is <PermissionBoundary> in permdock/next/client, permdock/vue, permdock/svelte and permdock/solid: an error boundary for thrown PermDock errors, never a gate. |
org, organization, workspace, account, group as PermDock identifiers | Every provider picks a different noun for the same thing. PermDock uses tenant and team in its own API and lets the subjectFrom* mapper translate (Clerk organization to tenant, SCIM group to team). |
useOrganization, useTeam, TenantProvider | The tenant is a property of the one snapshot, not a second provider; useTenant and useMemberships read it. |
hasRole, isAdmin, roleGuard | Role checks in application code bypass the permission model; check a permission, and read roles only for display (useRoles) or assignment (useAssignableRoles, useAssignablePermissions). |
who | Reserved for a directory-backed "who may X this row" verb; not exported. |
SnapshotV2 | The format major lives in v; the type is Snapshot. |
scope(...) as a derived instance | Derived instances are tenant(id) and team(id), one method per scope kind. |
permdock.with(...) | with* names the Supabase middleware pipeline steps, withSubject and withOtel; an instance with other sources is permdock.derive({ customRoles, approvalPolicies, relations }). |
@permdock/cli, @permdock/testing, any @permdock/* package | permdock is the only published name, owned by the scaledockhq npm organisation. The CLI is its bin plus permdock/cli, permdock/unplugin and permdock/next/plugin; the runners are permdock/testing. One package keeps core, adapters, CLI and runners on the same version. |
permdock/cloud-auth | There is no such entry: PermDock Cloud identity is subjectFromJwt({ discovery, audience }) against the Cloud issuer. |
What each adapter's createPermDock returns
A server adapter's result hands out the instance through getPermDock(input) (permdock/server, permdock/node, permdock/next) or middleware() (Hono, h3, Express, Fastify, Elysia, SvelteKit, Astro, SolidStart, TanStack Start, tRPC, oRPC), and mounts PermDock's endpoint through permdockHandler(), which returns the framework's handler. permdock/terminal, permdock/openai, permdock/claude-agent and permdock/eve also return getPermDock. A result never has a permdock() member.
| Import path | Returns | Notes |
|---|---|---|
permdock | no factory; getPermDock (Promise<PermDock>) and getPermDockSync (PermDock) | getPermDock(policy, user, { tenant?, memberships?, customRoles?, actor?, delegation? }), synchronous; await getPermDock(...) when a source or context is async |
permdock/next | { getPermDock, getPermission, getSnapshot, requirePermission, PermDockProvider, permdockHandler }, plus the standalone cacheLifeFor(snapshot, { min, max, now }), snapshotTag and snapshotHeaders shared with permdock/server | Options: subject, tenant, memberships, customRoles, store, sink, otel, wrap; never a cache directive (getSnapshot sets cacheLife and cacheTag inside the app's 'use cache: private' function, and its tags add to snapshotTag); requirePermission(permission, data?, { tenant?, onDenied? }) takes getPermission's arguments and maps a denial to the forbidden() / unauthorized() interrupts; never authorize |
permdock/next/client | PermissionBoundary (props denied, approval: a node or a PermissionBoundaryFallback function of the state) and usePermissionBoundary() returning { outcome, permission, token?, retry } | A 'use client' entry built on catchError from next/error; the boundary never decides, it renders a fallback for an error a check already threw |
permdock/server | { getPermDock, getSnapshot, protect, protectOn, connection, problem, openapi, permdockHandler } (ServerPermDock), plus the standalone evaluationsHandler, problemFromError(error), snapshotHeaders(snapshot, { tags }), cacheLifeFor and snapshotTag | The Fetch kernel every HTTP adapter wraps. Options: subject, tenant, memberships, customRoles, store, sink, limits, pdp, otel, webBotAuth, actor, and InstanceOptions (approvalPolicies, relations, entitlements, policies) |
permdock/hono | { middleware, protect, connection, socket, sse, permdockHandler } | middleware() sets the instance; protect(permission, data?, options?) guards a route |
permdock/express, permdock/fastify, permdock/elysia, permdock/node | { middleware, protect, permdockHandler } (Express, Fastify, Elysia), plus errorHandler and withPermDock(fn) (Express); Node returns { getPermDock, protect, send, permdockHandler } | Same shape as Hono over the shared kernel; on Fastify, middleware() and permdockHandler() return the plugin |
permdock/h3, permdock/sveltekit, permdock/astro, permdock/solid-start | { middleware, protect, withPermDock, getPermDock, getSnapshot, connection, permdockHandler, openapi } | One shared Fetch core. middleware() is the framework's hook (h3 Middleware, SvelteKit handle, Astro onRequest, the h3 middleware SolidStart's createMiddleware takes); protect(target, data?, options?) is route middleware on h3 and returns a handler wrapper elsewhere. Types are <Adapter>PermDock, <Adapter>PermDockOptions, <Adapter>PermDockLocals (H3PermDockContext on h3) |
permdock/tanstack-start | { middleware, protect, getPermDock, getSnapshot, connection, permdockHandler, openapi } | middleware() and protect are request middleware that add context.permdock and context.permdockData; no withPermDock, because the middleware chain types context. Types are TanStackStartPermDock, TanStackStartPermDockContext, TanStackStartGuardedContext |
permdock/nest | { PermDockModule, PermDockGuard, Protect, InjectPermDock, permdockHandler }, plus decorateMethod | PermDockModule.forRoot({ guard: 'global' }) registers PermDockGuard as APP_GUARD; permdockHandler({ path }) sets the controller path |
permdock/terminal | { getPermDock, protect, filterCommands, format, exitCode }; EX_OK, EX_USAGE, EX_TEMPFAIL, EX_NOPERM, EX_CONFIG; options yes and dryRun (--yes / -y, --dry-run), interactive: { confirm, typed } | For your own CLI; protect wraps a command action, filterCommands hides or annotates denied commands. Not the permdock binary or permdock/cli |
permdock/trpc | { middleware, protect, connection, permdockHandler } | protect is procedure middleware; denials throw TRPCError |
permdock/orpc | { middleware, protect, connection, permdockHandler }, permissionOf | protect is procedure middleware; denials throw ORPCError through the contract's declared constructor when it has one |
permdock/mcp | { protectServer } | protectServer(server).registerTool(name, { permission, data?, longRunning?, ... }, handler), plus registerResource and registerPrompt; protectServer(server, { enforce: 'procedure', permissionFor }) lists by permission and leaves the decision to the procedure; options: subject, actor, delegation, requireAuthInfo, resource (RFC 8707), store, approval ({ at, hint }), stepUp ({ at }), requestState (an SDK createRequestStateCodec); also exports subjectFromMcp, APPROVAL_META_KEY, McpPrincipal |
permdock/ai-sdk | { toolApproval, capabilityMiddleware, needsApproval } | Options: subject, actor, delegation, tenant, operations, store, unmapped, context, otel, wrap, deniedText, stepUp ({ at? }) |
permdock/claude-agent | { canUseTool, permissionRequestHook, getPermDock } | Options: the permdock/ai-sdk options except stepUp, and mcpSources (trusted MCP server sources, default ['sdk']) |
permdock/eve | { approval, approvalFor, getPermDock } | approval is Eve's { request, response } pair for defineTool (EveApprovalPair, contexts EveApprovalContext and EveResponseContext, principals EvePrincipal); options: the permdock/ai-sdk options except stepUp (subject optional) and approvers (EveApprovers); also exports subjectFromEve, actorFromEve, rolesOf |
permdock/openai | { needsApproval, guardTools, resolveInterruptions, getPermDock } | Options: the permdock/ai-sdk options except stepUp |
permdock/authzen | { permdockHandler } | permdockHandler() returns a Fetch handler that serves evaluation, evaluations, search and .well-known |
permdock/ssf | { receiver } | RFC 8935 push and RFC 8936 poll receiver for CAEP events; receiver.logout for OIDC Back-Channel Logout |
permdock/pdp | getPermDock and getPermDockSync over a local policy plus optional remotePdp | Opt-in AuthZEN client; fail-closed on unknown remote decisions |
permdock/convex | { withPermDock, snapshotQuery } | Convex query/mutation wrappers; no Convex SDK peer (structurally typed); options subject, tenant, actor |
permdock/scim | no createPermDock; exports scimHandler, memoryDirectoryStore, postgresDirectoryStore, directoryMembershipSource and the DirectoryStore type | The handler is a Fetch handler you mount; the source is a value you pass as memberships to a factory |
permdock/a2a | { agentCard, extendedAgentCard, protectSkill, sign } | Options: skills |
permdock/otel | no factory; instrument / withOtel | Subscribes to on('decision'); optional @opentelemetry/api |
permdock/delivery | { deliver } (DeliveryPermDock), plus audience, subscribersFor, approvalPrompt, approvalUrlFor, memoryDeliveryTransport, webhookTransport, isDeliveryTarget, isAddrSpec, and the connector-v1 parser parseConnector, CONNECTOR_KINDS, CONNECTOR_SCHEMA, Connector, ConnectorKind, ConnectorIssue, ParseConnectorResult, SiemDestination | Options: transports, principals, sink, from, source; deliver(sender, target, row, recipients, messages, options?) decides target per recipient and returns a DeliveryReport |
permdock/resend | no factory; resendTransport, approvalEmail, resendWebhook | An email transport for permdock/delivery; resend is an optional peer |
permdock/chat | { getPermDock, protect, resolveAction } (ChatPermDock), plus subjectFromChat, isChatAuthor | Options: PermDockOptions, principals, approvals; protect(operation) returns a ChatCommand |
permdock/chat-sdk | no factory; chatSdkAuthor, chatSdkTransport, approvalCard, approvalActions, APPROVE_ACTION, REJECT_ACTION | Chat SDK glue for permdock/chat and permdock/delivery; chat is an optional peer |
These entries deliberately do not export createPermDock:
permdockandpermdock/pdpexportgetPermDockandgetPermDockSync. Core has nothing to set up ahead of a request, so its instance builder is the server getter itself.permdock/reactandpermdock/react-nativeexportPermDockProvider,usePermDock,usePermission,usePermissions,useFilter,useTenant,useMemberships,useRoles,useAssignableRoles,useAssignablePermissions,useApproval,useSubject,useDescribe,useGate,useProtectedAction, therefreshOntriggereventSourceRefreshand<Protected>directly.permdock/react-nativeaddssubjectId(required,nullwhen signed out), the storage wrappersmemorySnapshotStorage,secureStoreStorageandmmkvStorage, the subscriptionsappStateForegroundandnetInfoOnline, the Expo Router guardsusePermissionGuardanduseSnapshotReady, and the snapshot sourceslocalSnapshotandpowerSyncSource.permdock/vueexportspermdockPluginplus the same composable names and<Protected>.permdock/svelteandpermdock/solidkeep the same surface under each framework's idiom.permdock/better-auth,permdock/clerkandpermdock/supabaseexport theirsubjectFrom*mapper and, where the provider stores roles, a<provider>CustomRoleSource; both are values you pass to a factory.permdock/webmcpexportsregisterTools(document.modelContext, group, { permdock })because it consumes a clientPermDockrather than creating one.permdock/drizzle,permdock/prismaandpermdock/kyselyexporttoWhere.permdock/prismaalso exportspermdockExtension,resolveRelated,toPredicateandprismaModelFields. All three also exportwithSubjectandcheckRow.permdock/jwtexportssubjectFromJwt,jwtSubjectResolver,verifyDpopProof,joseTokenVerifierandjoseTokenSignerbecause it produces subjects, verifiers and signers for a factory, not an instance. Structurally typed providers (permdock/supabase,permdock/clerk,permdock/better-auth,permdock/convex,permdock/prisma,permdock/mcp,permdock/react-native) declare no peer dependency: they duck-type the SDK you already installed.permdock/supabase/middlewareis the exception on the Supabase side: it callsdefineMiddleware, so@supabase/middlewareis its optional peer, while@supabase/server'sJWTClaimsis still duck-typed.permdock/approvalsexportsmemoryApprovalStoreandapprovalsHandler, andpermdock/cloudexportscloud; both produce values you pass to a factory (store,sink,policies) or a client provider (source) rather than aPermDock.permdock/testing,permdock/testing/saas,permdock/testing/saas/permissionsandpermdock/testing/fixturesexport the test runners (describePolicy, thetest<Interface>runners,testRlsParity,testOrmParity,testClientParity,testHttpAdapter,testAuthzen) the shared SaaS domain and the example catalog and manifest (betterSupabaseCatalog,betterSupabaseManifest). Test files import them; application entries never do, and Vitest is an optional peer.permdock/cliexportsdefineConfig(forpermdock.config.ts) andrun(thepermdockbinary as a function) plus the config types, andparseHookMarker/parseGrantsMarkerwith their result typesSupabaseHookMarker/SupabaseGrantsMarker. It is a build-time entry: no runtime entry imports it.- Build hooks:
permdock/next/pluginexportscreatePermDockPluginandpermdock/unpluginexportscreatePermDockUnplugin(Vite, Rollup, webpack, Rspack, esbuild through unplugin). Both runcollectat build time and never wire runtime API. Thecreateprefix and thePermDocknoun follow the factory rule; the suffix names the host (Pluginfor Next's config API,Unpluginfor the bundler family).
Names shared on purpose
PermDockmethods and snapshot fields share a name when the field is the method's result serialized:permdock.actions(resource)andsnapshot.actions,permdock.audiences()andsnapshot.audiences,permdock.snapshot()and asnapshotoption or prop,permdock.tenant(id)andprincipal.tenant. The method is on the instance; the field is the wire form a client hydrates from.- One name can be exported by several entries with that entry's meaning, like
createPermDock.getPermDockreturns the instance in every entry that exports it: core takes the policy and the user, an adapter's factory result takes the request or query, andpermdock/sveltereads it from component context.PermDockPluginOptionsis the build plugin's options inpermdock/next/pluginandpermdock/unplugin, and the Vue app plugin's options inpermdock/vue. - Every entry returns
<Entry>PermDockfromcreatePermDockand takes<Entry>PermDockOptions, rather than<Prefix><Thing>, so the entry is the first word wherever both appear (recorded in the repository'sdocs/decisions/0019-adapter-suffix-and-no-dollar-members.md). Context and prop types follow the same order:ExpressPermDockRequest,ConvexPermDockContext,NextPermDockProviderProps.
Spec names
PermDock's subject vocabulary is TypeScript, camelCase and typed; the specifications it consumes are JSON claims with short registered names. subject fixes the rule: where a spec name exists, PermDock either uses it verbatim or maps to it exactly once, in the table below and on subject; PermDock never coins a second spelling for a concept a specification already names.
| Specification name | Source | PermDock name | Rule |
|---|---|---|---|
sub | RFC 7519, OIDC Core | principal.id | Opaque string, compared byte for byte |
iss | RFC 7519, OIDC Core | principal.issuer | Always set by subjectFrom*; identity is issuer + id |
aud | RFC 7519 | audience option | Verified, not stored |
exp | RFC 7519 | subject.expiresAt, Membership.expiresAt, ApprovalRequest.expiresAt, snapshot expiresAt | NumericDate on subject.expiresAt and Membership.expiresAt, RFC 3339 on the approval request and the snapshot; the JWS envelope's exp is NumericDate |
iat, nbf, jti | RFC 7519 | none on the subject; iat, jti on signed outputs | Verified, then dropped |
act | RFC 8693 | actor | Innermost act.sub is actor.id; the nesting is delegation.chain |
client_id, azp | RFC 9068, OIDC Core | actor.id when the client acts under a delegation; verified otherwise | actor.kind 'oauth-client' or 'mcp-client' |
Signature-Agent keyid | Web Bot Auth / RFC 9421 | actor.id when webBotAuth is set | actor.kind 'web-bot-auth' |
scope | RFC 6749, RFC 9068 | delegation.scopes; permission.scope | Space-separated string on the wire, array in TypeScript |
authorization_details | RFC 9396 | delegation.authorizationDetails; permission.authorizationDetails | One RAR type per permission |
access | RFC 9635, RFC 9767 | delegation.access | Objects and reference strings kept verbatim |
cnf (jkt, x5t#S256, jwk, kid) | RFC 7800, RFC 9449, RFC 8705 | binding with the same member names (reshaped) | FAPI's "sender-constrained" gives the field its name; the members are the cnf members so it round-trips |
acr, amr, auth_time | OIDC Core, RFC 8176 | principal.assurance.acr, .amr, .authTime | Provider aal maps into acr; RFC 8176 amr values include pwd, otp, swk, hwk, mfa |
verified_claims, verification, trust_framework, claims | OpenID Connect for Identity Assurance 1.0 | principal.assurance.verified[] with verification and claims kept under the spec's names | The collection is verified because assurance already scopes it; the fields inside keep the spec's snake case |
aal (aal1, aal2) | Supabase Auth JWT | principal.assurance.acr | Verified by getClaims(); aal2 is MFA |
fva / factorVerificationAge | Clerk session token | Recipe into principal.assurance; not mapped by subjectFromClerk | Second element >= 0 means a second factor was verified |
twoFactorEnabled | Better Auth user row | Recipe into principal.assurance; not mapped by subjectFromBetterAuth | A session exists only after the two-factor plugin verifies |
sid | OIDC Front- and Back-Channel Logout | subject.session | The join key for logout_token and CAEP events |
roles, groups, entitlements | RFC 9068 | principal.roles; principal.memberships (team from groups); principal.plans from entitlements | SCIM value only |
userName, externalId, active, displayName (SCIM User) | RFC 7643 | DirectoryUser.userName, .externalId, .active, .displayName verbatim | externalId is the IdP's identifier and id is the store's; active: false yields no memberships; displayName is never an identifier |
members[].value, displayName (SCIM Group) | RFC 7643 | DirectoryGroup.members[].value verbatim; via: 'group:<id>' on the membership | Group id is the group identifier; display and displayName are labels only |
urn:ietf:params:scim:schemas:extension:permdock:2.0:Group (roles) | RFC 7643 section 3.3 extension | The Group extension carrying the declared role names for a group; read by directoryMembershipSource | Unknown or non-assignable role names are dropped, never invented |
type, source, subject (CloudEvents) | CloudEvents 1.0 | com.permdock.decision and com.permdock.<family>.<operation>; an absolute URI naming the emitting service; the permission key, resource id or principal id | The envelope for every webhook and queue sink (wire formats) |
dataschema, traceparent, tracestate (CloudEvents) | CloudEvents 1.0, distributed tracing extension | EVENT_SCHEMA_IDS[family]; CloudEventOptions.traceparent and .tracestate | W3C Trace Context, set only when the caller passes it |
webhook-id, webhook-timestamp, webhook-signature | Standard Webhooks | WebhookMessage.id, the signing time, the v1 / v1a entries | Kept under the spec's names; webhook-id is the replay key |
jwks_uri, issuer (Discovery) | OIDC Discovery, RFC 8414 | discovery option; jwks and issuer options | Discovery supplies both |
typ (at+jwt, JWT, logout+jwt, secevent+jwt) | RFC 9068, RFC 7519, OIDC, RFC 8417 | accept option; vnd.permdock.{snapshot,approval,policy,capability,run,support-session,evidence}+jwt on outputs (RFC 6838 vendor tree) | Explicit typing, RFC 8725 section 3.11 |
invalid_token, insufficient_scope, insufficient_user_authentication | RFC 6750, RFC 9470 | on('auth') reason invalid-token; Decision reasons not-delegated / no-delegation and insufficient-user-authentication | Hyphenated in PermDock, underscored on the wire; the HTTP adapter renders without a second table |
Subject, Resource, Action, Context | AuthZEN 1.0 | principal (+ actor, delegation, tenant under context), resource, action, context | The evaluation mapping on AuthZEN |
reason_admin, reason_user, evaluations_semantic | AuthZEN 1.0 | Response context.reason_admin and context.reason_user; batch options.evaluations_semantic | Kept under the spec's names |
Files and folders
- The server factory lives in
src/permdock/server.tsin every example. The definition issrc/permissions.ts; the policy issrc/policy.ts; generated definitions aresrc/permissions.generated.ts. - Example apps are
apps/examples/<adapter>; the docs page is/docs/adapters/<adapter>; the source folder ispackages/permdock/src/<adapter>. The same short name is used in all three. - Errors are
PermDockDeniedError,PermDockApprovalRequiredError,PermDockValidationErrorandPermDockRevokedError. Any other error class is a domain error with anis<Name>guard:ApprovalErrorandisApprovalError,AccessReviewErrorandisAccessReviewError,DirectoryUniquenessErrorandisDirectoryUniquenessError,DirectoryNotFoundErrorandisDirectoryNotFoundError,CloudAuthErrorandisCloudAuthError, plusInvalidSignatureError. Every guard matches bynameandcode, so an error from another copy of the module still maps. Problem DetailstypeURIs end in/denied,/approval-requiredand/validation. The first two carrydigest(React's name for the property that survives the Server Component boundary):PERMDOCK_DENIED;<permission>andPERMDOCK_APPROVAL_REQUIRED;<permission>;<token>, read withparsePermDockDigest.
Renamed in 0.5.0
permdock codemod 0.5 applies these renames to every file that imports permdock (codemod). Entries are the imports the old name came from. The codemod reports method rows, and option rows outside the calls it knows, for a manual edit. pnpm docs:drift keeps this section equal to packages/permdock/src/cli/codemod/renames-0.5.ts.
| Old | New | Kind | Entries |
|---|---|---|---|
createServerKernel | createPermDock | export | permdock/server |
ServerKernel | ServerPermDock | type | permdock/server |
ServerKernelOptions | ServerPermDockOptions | type | permdock/server |
createEvaluationsHandler | evaluationsHandler | export | permdock/server |
createNativeStore | nativeStore | export | permdock/react-native |
permdock | getPermDock | method | permdock/server, permdock/node, permdock/terminal, permdock/openai, permdock/claude-agent, permdock/eve |
permdock | middleware | method | permdock/hono, permdock/express, permdock/elysia, permdock/trpc, permdock/orpc |
load | data | option | permdock/authzen |
loadData | data | option | permdock/nest |
onDenied | deniedResponse | option | permdock/server, permdock/hono, permdock/express, permdock/fastify, permdock/elysia, permdock/nest, permdock/node, permdock/trpc, permdock/orpc, permdock/supabase/middleware |
onDenied | deniedText | option | permdock/ai-sdk, permdock/mcp |
tools | operations | option | permdock/ai-sdk, permdock/openai, permdock/claude-agent, permdock/eve |
OnDenied | DeniedResponse | type | permdock/server |
OnDeniedEvent | DeniedResponseEvent | type | permdock/server |
OnDeniedText | DeniedText | type | permdock/ai-sdk, permdock/mcp |
PermDockRequest | ExpressPermDockRequest | type | permdock/express |
PermDockRequest | FastifyPermDockRequest | type | permdock/fastify |
PermDockEnv | HonoPermDockEnv | type | permdock/hono |
ElysiaContext | ElysiaPermDockContext | type | permdock/elysia |
ElysiaCtx | ElysiaRequestContext | type | permdock/elysia |
ConvexPermDockCtx | ConvexPermDockContext | type | permdock/convex |
ServerPermDockProviderProps | NextPermDockProviderProps | type | permdock/next |
NativePermDockProviderProps | ReactNativePermDockProviderProps | type | permdock/react-native |
PermDockSvelteOptions | SveltePermDockOptions | type | permdock/svelte |
subjectFromSession | subjectFromEve | export | permdock/eve |
actorFromSession | actorFromEve | export | permdock/eve |
CredentialPrincipal | ApiKeyPrincipal | type | permdock |
LinkPrincipal | CapabilityPrincipal | type | permdock |
SsfSubjectMapper | SsfSubjectResolver | type | permdock/ssf |
memorySettings | memorySettingsSource | export | permdock |
memoryRelations | memoryRelationSource | export | permdock |
memorySink | memoryDecisionSink | export | permdock |
memoryApprovalPolicies | memoryApprovalPolicySource | export | permdock |
memoryApprovalDelegations | memoryApprovalDelegationSource | export | permdock/approvals |
memoryAccessReviews | memoryAccessReviewStore | export | permdock/approvals |
MemoryAccessReviews | MemoryAccessReviewStore | type | permdock/approvals |
MemoryRelationsData | MemoryRelationSourceData | type | permdock |
MemorySink | MemoryDecisionSink | type | permdock |
MemorySinkOptions | MemoryDecisionSinkOptions | type | permdock |
memoryCredentials | memoryCredentialStore | export | permdock/server |
MemoryCredentials | MemoryCredentialStore | type | permdock/server |
memoryStorage | memorySnapshotStorage | export | permdock/react-native |
rlsParity | testRlsParity | export | permdock/testing |
ormParity | testOrmParity | export | permdock/testing |
fromStripeEntitlements | stripeEntitlementSource | export | permdock |
fromTable | tableMembershipSource | export | permdock/supabase |
fromJunction | junctionMembershipSource | export | permdock/supabase |
fromSupabasePostgres | supabasePostgresQuery | export | permdock/supabase |
verifyWebBotAuth | webBotAuthVerifier | export | permdock/server, permdock/hono, permdock/express, permdock/fastify, permdock/elysia, permdock/nest, permdock/node |
RoleSource | CustomRoleSource | type | permdock |
RoleSourceFactory | CustomRoleSourceFactory | type | permdock |
memoryRoleSource | memoryCustomRoleSource | export | permdock |
testRoleSource | testCustomRoleSource | export | permdock/testing |
betterAuthRoleSource | betterAuthCustomRoleSource | export | permdock/better-auth |
BetterAuthRoleSourceOptions | BetterAuthCustomRoleSourceOptions | type | permdock/better-auth |
PermDockStorage | SnapshotStorage | type | permdock/react-native |
store | directory | option | permdock/scim |
store | reviews | option | permdock/approvals |
delegations | approvalDelegations | option | permdock/approvals |
source | call | option | permdock |
testAuthZen | testAuthzen | export | permdock/testing |
AuthZenVectors | AuthzenVectors | type | permdock/testing |
AuthZenEvaluationVector | AuthzenEvaluationVector | type | permdock/testing |
AuthZenEvaluationsVector | AuthzenEvaluationsVector | type | permdock/testing |
AuthZenSearchVector | AuthzenSearchVector | type | permdock/testing |
TestAuthZenOptions | TestAuthzenOptions | type | permdock/testing |
powersyncSource | powerSyncSource | export | permdock/react-native |
summariseSubject | summarizeSubject | export | permdock/approvals |
WebhookFailureReason | WebhookFailureCause | type | permdock/cloud |
ApprovalResumeFailure | ApprovalResumeFailureCause | type | permdock/approvals |
window | per | method | permdock, permdock/server, permdock/hono, permdock/express, permdock/fastify, permdock/elysia, permdock/nest, permdock/node |
DefinePermissionsOptions | PermissionsOptions | type | permdock |
SignCapabilityOptions | CapabilityOptions | type | permdock |
SignRunTicketOptions | RunTicketOptions | type | permdock/server |
StartAccessReviewOptions | AccessReviewOptions | type | permdock/approvals |
StartAutomationOptions | AutomationOptions | type | permdock/workflow, permdock/workflow-sdk |
VerifyWebhookOptions | WebhookOptions | type | permdock/cloud |
UseRolesOptions | RolesOptions | type | permdock/vue, permdock/svelte, permdock/solid |
ConvexCtxLike | ConvexContextLike | type | permdock/convex |
createJwtSubjectResolver | jwtSubjectResolver | export | permdock/jwt |
createClerkSubjectResolver | clerkSubjectResolver | export | permdock/clerk |
fromResponse | sendResponse | export | permdock/node |
fromResponse | send | method | permdock/node |
createPermDock | getPermDockSync | export | permdock |
createPermDock | getPermDock | export | permdock/pdp |
loadRelations | prefetchRelations | method | permdock, permdock/pdp |
These changed their call shape; the codemod lists each call site:
| Before | After |
|---|---|
permittedIds(permdock, permission, scope) | permdock.permittedIds(permission, scope) |
mayUse(permdock, permission) | permdock.mayUse(permission) |
subjectFromApiKey(options)(key) | subjectFromApiKey(key, options) |
subjectFromBetterAuth(auth, session, options) | subjectFromBetterAuth(session, { auth, ...options }) |
capabilitySubject(...) | subjectFromCapability(token, options) |
credentialSubject(...) | subjectFromApiKey(key, options) |
MappedSubject | Subject<JwtPrincipal> |
verifyWebBotAuth(request, options) | webBotAuthVerifier(options)(request) |
verifyWebhook(request, options).reason | verifyWebhook(request, options).cause |
inspectApproval(store, token).detail | inspectApproval(store, token).cause |
consumeApproval(store, token).detail | consumeApproval(store, token).cause |
requireAccess({ permission, data, tenant, onDenied }) | requirePermission(permission, data, { tenant, onDenied }) |
RequireAccessInput | PermissionRequirementOptions |
The CLI changed these commands and flags. An old spelling exits 2 with command_moved or flag_renamed and the new one. permdock codemod 0.5 rewrites them in package.json scripts, CI workflows and shell scripts, and lists them in Markdown:
| CLI before | CLI after | Commands |
|---|---|---|
permdock openapi | permdock openapi emit | |
permdock skills | permdock skills install | |
permdock arazzo | permdock arazzo check | |
--db | --db-url-stdin or DATABASE_URL | rls generate, rls import, rls verify, supabase hook generate, powersync verify |
--db-url | --db-url-stdin or DATABASE_URL | rls generate, rls import, rls verify, supabase hook generate, powersync verify |
--force | --force-rls | rls generate |
--format | --kind | rls verify |
--emit | --kind | rls verify |
--format | --kind, values json to catalog, schema to json-schema, markdown to markdown | catalog |
--format | --kind | openapi emit |
--from | --policy | rls generate, rls verify, rls migrate, powersync generate, powersync verify, openapi emit |
--from | --permissions | catalog, arazzo check |
--schema | --validator | rls import, openapi import |
--strict | --fail-on warning | usage, config, doctor |
--write | --scope catalog:write | login |
--agent | --for | skills install, skills update |
--client | --for | skills install, skills update |
--agent | --integration | init |
--ui | --integration | init |
--src | --out-dir | init |
--rbac-scaffold | --rbac supabase | rls generate, rls verify, rls migrate |
--write | removed: rls migrate writes by default; --dry-run prints the plan without writing | rls migrate |
--environment | --project <id>: a project id is its environment | cloud push |
--legacy | removed: permdock scan lists the checks written without PermDock; drop --legacy | scan |
no --write or --retire-out | --dry-run | rls migrate |
Renamed before 0.1.0
| Old | New |
|---|---|
CreatePermDockOptions | PermDockOptions |
CreatePermDockPluginOptions | PermDockPluginOptions |
ServerPermDock.handler, AuthzenPermDock.handler | permdockHandler, like every other HTTP adapter |
ExpressPermDock.handler(fn) | withPermDock(fn), like permdock/convex |
SsfAdapter, SsfOptions | SsfPermDock, SsfPermDockOptions |
SupabaseMiddlewareOptions | SupabaseMiddlewarePermDockOptions |
A2AAgentCard, A2APermDock and the other A2A* types | A2aAgentCard, A2aPermDock, … (A2a like Ssf and Mcp) |
dock, pd, server, factory for the instance in examples | permdock; a cloud() result is permdockCloud |
Last updated on
Existing apps
Adopt PermDock in an app that already has permission keys, SQL helpers, tokens and stored custom roles, then move to its conventions one step at a time without breaking signed-in users.
Connecting tools
Connect a coding agent to the PermDock docs MCP server, the Markdown pages and the Agent Skills, and point the permdock CLI at PermDock Cloud.