@warlock.js/access 5.27.0 → 5.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,18 @@ All notable changes to `@warlock.js/access` are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/). `@warlock.js/*` packages are released in lockstep — every package shares the same version number, so a version below may list only the changes that affected this package.
6
6
 
7
+ ## 5.29.0 - 2026-10-01
8
+
9
+ ### Changed
10
+
11
+ - Lockstep release; package APIs are unchanged. Skills refer to other topics by name instead of file paths, so cross-references keep working after `agent-kit` copies them into an app.
12
+
13
+ ## 5.28.0 - 2026-10-01
14
+
15
+ ### Changed
16
+
17
+ - Lockstep release; package APIs are unchanged. `llms.txt` now lists every skill topic with its description (frontmatter in CRLF files was skipped).
18
+
7
19
  ## 5.27.0 - 2026-10-01
8
20
 
9
21
  ### Changed
package/llms-full.txt CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ---
10
10
  name: check-permissions
11
- description: 'Check permissions in `@warlock.js/access` — `can` / `cannot` / `canAll` / `canAny` (boolean), `authorize` / `authorizeAll` / `authorizeAny` (throw 403), and the `gate` / `gateAny` / `gateAll` route middleware. Class-level vs instance-level (pass a `resource` to run its policy). TRIGGER: `can(`, `authorize(`, `canAll`, `canAny`, `gate`, `gateAny`, `gateAll`, "check a permission", "protect route by permission", "403 forbidden", "any vs all permissions". Skip: ownership / tenant conditions — `@warlock.js/access/define-policies/SKILL.md`; role checks — `@warlock.js/access/manage-roles/SKILL.md`.'
11
+ description: 'Check permissions in `@warlock.js/access` — `can` / `cannot` / `canAll` / `canAny` (boolean), `authorize` / `authorizeAll` / `authorizeAny` (throw 403), and the `gate` / `gateAny` / `gateAll` route middleware. Class-level vs instance-level (pass a `resource` to run its policy). TRIGGER: `can(`, `authorize(`, `canAll`, `canAny`, `gate`, `gateAny`, `gateAll`, "check a permission", "protect route by permission", "403 forbidden", "any vs all permissions". Skip: ownership / tenant conditions — the `define-policies` topic; role checks — the `manage-roles` topic.'
12
12
  ---
13
13
 
14
14
  # Check permissions
@@ -52,7 +52,7 @@ await authorizeAll(user, ["orders.update", "orders.viewCost"]);
52
52
 
53
53
  ## Instance-level — "this resource"
54
54
 
55
- Pass a `resource` and the permission's policy runs on top of the grant (see [`define-policies`](@warlock.js/access/define-policies/SKILL.md)):
55
+ Pass a `resource` and the permission's policy runs on top of the grant (see the `define-policies` topic):
56
56
 
57
57
  ```ts
58
58
  const order = await Order.find(orderId);
@@ -75,15 +75,15 @@ await authorize(user, "orders.update", { resource: order, tenant }); // grant AN
75
75
 
76
76
  ## See also
77
77
 
78
- - [`@warlock.js/access/define-policies/SKILL.md`](@warlock.js/access/define-policies/SKILL.md) — the `{ resource }` conditions.
79
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — `authMiddleware`, which runs first.
78
+ - The `define-policies` topic — the `{ resource }` conditions.
79
+ - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`, which runs first.
80
80
 
81
81
 
82
82
  ## configure-access `@warlock.js/access/configure-access/SKILL.md`
83
83
 
84
84
  ---
85
85
  name: configure-access
86
- description: 'Configure `@warlock.js/access` — the REQUIRED `resolver` (the quickstart `DefaultAccessResolver` over a fixed code map vs the ejected, DB-backed `DatabaseAccessResolver`), `cache: { ttl }`, and the ambient tenant via the resolver''s optional `resolveTenant()`. TRIGGER: `AccessConfigurations`, `config.access`, `src/config/access.ts`, "set up permissions", "DefaultAccessResolver", "DatabaseAccessResolver", "access cache ttl", "access tenant". Skip: checking permissions — `@warlock.js/access/check-permissions/SKILL.md`; custom storage — `@warlock.js/access/implement-resolver/SKILL.md`.'
86
+ description: 'Configure `@warlock.js/access` — the REQUIRED `resolver` (the quickstart `DefaultAccessResolver` over a fixed code map vs the ejected, DB-backed `DatabaseAccessResolver`), `cache: { ttl }`, and the ambient tenant via the resolver''s optional `resolveTenant()`. TRIGGER: `AccessConfigurations`, `config.access`, `src/config/access.ts`, "set up permissions", "DefaultAccessResolver", "DatabaseAccessResolver", "access cache ttl", "access tenant". Skip: checking permissions — the `check-permissions` topic; custom storage — the `implement-resolver` topic.'
87
87
  ---
88
88
 
89
89
  # Configure access
@@ -127,7 +127,7 @@ const access: AccessConfigurations = {
127
127
  export default access;
128
128
  ```
129
129
 
130
- Assign roles via the ejected `UserRole.assign(user, "editor", tenant)` — it flushes that user's cached set for you (see [`manage-roles`](@warlock.js/access/manage-roles/SKILL.md)).
130
+ Assign roles via the ejected `UserRole.assign(user, "editor", tenant)` — it flushes that user's cached set for you (see the `manage-roles` topic).
131
131
 
132
132
  ## The full shape
133
133
 
@@ -145,7 +145,7 @@ type AccessConfigurations = {
145
145
 
146
146
  An instance check (`{ resource }`) for a permission with no registered ABAC policy **denies by default** (`strictPolicies: true`) — a forgotten policy must never fail open. The miss is logged once per permission (`log.warn`) either way.
147
147
 
148
- Set `strictPolicies: false` to explicitly restore the pre-5.13 behavior: fall back to the RBAC grant alone (ALLOWS — any holder of the permission can act on ANY resource, a plausible IDOR). See [`define-policies`](@warlock.js/access/define-policies/SKILL.md) for the full decision table.
148
+ Set `strictPolicies: false` to explicitly restore the pre-5.13 behavior: fall back to the RBAC grant alone (ALLOWS — any holder of the permission can act on ANY resource, a plausible IDOR). See the `define-policies` topic for the full decision table.
149
149
 
150
150
  > **Breaking in 5.13:** `strictPolicies` now defaults to `true` and DENIES (it used to default to `false` and ALLOW). Set `strictPolicies: false` to keep the old fail-open fallback.
151
151
 
@@ -167,8 +167,8 @@ The engine caches each user's resolved set (`cache.ttl`, default `10m`). Roles c
167
167
 
168
168
  ## See also
169
169
 
170
- - [`@warlock.js/access/implement-resolver/SKILL.md`](@warlock.js/access/implement-resolver/SKILL.md) — write a resolver for your own storage.
171
- - [`@warlock.js/access/manage-roles/SKILL.md`](@warlock.js/access/manage-roles/SKILL.md) — assign / revoke with the ejected table.
170
+ - The `implement-resolver` topic — write a resolver for your own storage.
171
+ - The `manage-roles` topic — assign / revoke with the ejected table.
172
172
  ```
173
173
 
174
174
 
@@ -176,7 +176,7 @@ The engine caches each user's resolved set (`cache.ttl`, default `10m`). Roles c
176
176
 
177
177
  ---
178
178
  name: define-policies
179
- description: 'ABAC conditions in `@warlock.js/access` — `definePolicy(permission, (user, resource, ctx) => boolean)` adds an instance-level rule (ownership / tenant / state) on top of the RBAC grant, evaluated when an authorization check carries a `resource`. TRIGGER: `definePolicy`, "ownership check", "only their own", "can edit this specific record", "ABAC", "policy", "resource-level permission", `authorize(user, perm, { resource })`. Skip: plain grant checks — `@warlock.js/access/check-permissions/SKILL.md`.'
179
+ description: 'ABAC conditions in `@warlock.js/access` — `definePolicy(permission, (user, resource, ctx) => boolean)` adds an instance-level rule (ownership / tenant / state) on top of the RBAC grant, evaluated when an authorization check carries a `resource`. TRIGGER: `definePolicy`, "ownership check", "only their own", "can edit this specific record", "ABAC", "policy", "resource-level permission", `authorize(user, perm, { resource })`. Skip: plain grant checks — the `check-permissions` topic.'
180
180
  ---
181
181
 
182
182
  # Define policies (ABAC)
@@ -212,7 +212,7 @@ So `gate("orders.update")` (a route gate, no resource) checks the grant; the per
212
212
  ## The decision = grant AND policy
213
213
 
214
214
  - No grant → denied (the policy never runs).
215
- - Grant + no policy registered → **denied by default** (`strictPolicies: true`, the 5.13+ default) — a typo'd permission or a forgotten `import "./policies"` must never silently degrade an instance check to a class-level one. Logs a one-time `log.warn` naming the permission either way. Set `strictPolicies: false` in the access config (see [`configure-access`](@warlock.js/access/configure-access/SKILL.md)) to explicitly restore the pre-5.13 RBAC-only fallback (allowed).
215
+ - Grant + no policy registered → **denied by default** (`strictPolicies: true`, the 5.13+ default) — a typo'd permission or a forgotten `import "./policies"` must never silently degrade an instance check to a class-level one. Logs a one-time `log.warn` naming the permission either way. Set `strictPolicies: false` in the access config (see the `configure-access` topic) to explicitly restore the pre-5.13 RBAC-only fallback (allowed).
216
216
  - Grant + policy → the policy decides.
217
217
 
218
218
  Policies **deny**, they don't grant — a policy can't let a user past a permission they don't hold.
@@ -241,14 +241,14 @@ definePolicy("orders.refund", (user, order, ctx) =>
241
241
 
242
242
  ## See also
243
243
 
244
- - [`@warlock.js/access/check-permissions/SKILL.md`](@warlock.js/access/check-permissions/SKILL.md) — `authorize(…, { resource })`.
244
+ - The `check-permissions` topic — `authorize(…, { resource })`.
245
245
 
246
246
 
247
247
  ## implement-resolver `@warlock.js/access/implement-resolver/SKILL.md`
248
248
 
249
249
  ---
250
250
  name: implement-resolver
251
- description: 'Connect `@warlock.js/access` to your role/permission storage by implementing the `AccessResolver` contract (`resolveRoles` / `resolvePermissions`, optional `resolveTenant`) — for a DB-backed catalog, a user column, a pivot table, a token claim, or an external directory. The engine owns matching / caching / policies; the resolver only fetches. TRIGGER: `AccessResolver`, `DatabaseAccessResolver`, `resolveTenant`, "custom resolver", "where do roles come from", "roles in a token claim", "permissions from an external API", "implement resolver". Skip: the quickstart `DefaultAccessResolver` — `@warlock.js/access/configure-access/SKILL.md`.'
251
+ description: 'Connect `@warlock.js/access` to your role/permission storage by implementing the `AccessResolver` contract (`resolveRoles` / `resolvePermissions`, optional `resolveTenant`) — for a DB-backed catalog, a user column, a pivot table, a token claim, or an external directory. The engine owns matching / caching / policies; the resolver only fetches. TRIGGER: `AccessResolver`, `DatabaseAccessResolver`, `resolveTenant`, "custom resolver", "where do roles come from", "roles in a token claim", "permissions from an external API", "implement resolver". Skip: the quickstart `DefaultAccessResolver` — the `configure-access` topic.'
252
252
  ---
253
253
 
254
254
  # Implement a resolver
@@ -350,7 +350,7 @@ class DirectResolver implements AccessResolver {
350
350
 
351
351
  ## See also
352
352
 
353
- - [`@warlock.js/access/configure-access/SKILL.md`](@warlock.js/access/configure-access/SKILL.md) — the quickstart `DefaultAccessResolver`.
353
+ - The `configure-access` topic — the quickstart `DefaultAccessResolver`.
354
354
  ```
355
355
 
356
356
 
@@ -358,7 +358,7 @@ class DirectResolver implements AccessResolver {
358
358
 
359
359
  ---
360
360
  name: manage-roles
361
- description: 'Assign and read roles in `@warlock.js/access` — the ejected `UserRole.assign` / `UserRole.revoke` (the `user_roles` table) followed by `access.flush`, plus `hasRole` / `hasAnyRole` / `hasAllRoles`. The role→permission catalog is the ejected `Role` table (dynamic). TRIGGER: `UserRole.assign`, `UserRole.revoke`, `access.flush`, `hasRole`, `hasAnyRole`, `hasAllRoles`, `Role` table, "give a user a role", "assign role", "check a user role", "roles per tenant". Skip: permission checks — `@warlock.js/access/check-permissions/SKILL.md`; resolver choice — `@warlock.js/access/configure-access/SKILL.md`.'
361
+ description: 'Assign and read roles in `@warlock.js/access` — the ejected `UserRole.assign` / `UserRole.revoke` (the `user_roles` table) followed by `access.flush`, plus `hasRole` / `hasAnyRole` / `hasAllRoles`. The role→permission catalog is the ejected `Role` table (dynamic). TRIGGER: `UserRole.assign`, `UserRole.revoke`, `access.flush`, `hasRole`, `hasAnyRole`, `hasAllRoles`, `Role` table, "give a user a role", "assign role", "check a user role", "roles per tenant". Skip: permission checks — the `check-permissions` topic; resolver choice — the `configure-access` topic.'
362
362
  ---
363
363
 
364
364
  # Manage roles
@@ -420,12 +420,12 @@ The ejected `UserRole` is a thin cascade model — `{ user_id, user_type, role,
420
420
 
421
421
  ## Roles stored elsewhere?
422
422
 
423
- If roles live on the user (a `roles` column) or in a token claim, you don't use `UserRole` — you manage assignment your way and a resolver reads them. See [`implement-resolver`](@warlock.js/access/implement-resolver/SKILL.md).
423
+ If roles live on the user (a `roles` column) or in a token claim, you don't use `UserRole` — you manage assignment your way and a resolver reads them. See the `implement-resolver` topic.
424
424
 
425
425
  ## See also
426
426
 
427
- - [`@warlock.js/access/configure-access/SKILL.md`](@warlock.js/access/configure-access/SKILL.md) — choosing the resolver.
428
- - [`@warlock.js/access/implement-resolver/SKILL.md`](@warlock.js/access/implement-resolver/SKILL.md) — non-table role storage.
427
+ - The `configure-access` topic — choosing the resolver.
428
+ - The `implement-resolver` topic — non-table role storage.
429
429
  ```
430
430
 
431
431
 
@@ -461,11 +461,11 @@ Skip if you only need "is the user an admin" — `authMiddleware("admin")` from
461
461
 
462
462
  ## Skills index
463
463
 
464
- - [`configure-access`](@warlock.js/access/configure-access/SKILL.md) — the required resolver (`DefaultAccessResolver` vs the ejected `DatabaseAccessResolver`), cache + tenant.
465
- - [`check-permissions`](@warlock.js/access/check-permissions/SKILL.md) — `can` / `cannot` / `canAll` / `canAny` / `authorize*` + the `gate*` middleware.
466
- - [`define-policies`](@warlock.js/access/define-policies/SKILL.md) — `definePolicy` for ownership / tenant / state conditions (ABAC).
467
- - [`manage-roles`](@warlock.js/access/manage-roles/SKILL.md) — assign / revoke via the ejected `UserRole` + `access.flush`, `hasRole` / `hasAnyRole` / `hasAllRoles`.
468
- - [`implement-resolver`](@warlock.js/access/implement-resolver/SKILL.md) — connect the engine to your storage (a DB catalog, a column, a pivot, a token claim).
464
+ - `configure-access` — the required resolver (`DefaultAccessResolver` vs the ejected `DatabaseAccessResolver`), cache + tenant.
465
+ - `check-permissions` — `can` / `cannot` / `canAll` / `canAny` / `authorize*` + the `gate*` middleware.
466
+ - `define-policies` — `definePolicy` for ownership / tenant / state conditions (ABAC).
467
+ - `manage-roles` — assign / revoke via the ejected `UserRole` + `access.flush`, `hasRole` / `hasAnyRole` / `hasAllRoles`.
468
+ - `implement-resolver` — connect the engine to your storage (a DB catalog, a column, a pivot, a token claim).
469
469
 
470
470
  ## What it deliberately doesn't do
471
471
 
@@ -475,7 +475,7 @@ Skip if you only need "is the user an admin" — `authMiddleware("admin")` from
475
475
 
476
476
  ## See also
477
477
 
478
- - [`@warlock.js/auth/overview/SKILL.md`](@warlock.js/auth/overview/SKILL.md) — authentication, the layer below.
479
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — `authMiddleware`; stack `gate` after it.
478
+ - The `overview` topic of the `warlock-js-auth` skill — authentication, the layer below.
479
+ - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`; stack `gate` after it.
480
480
 
481
481
 
package/llms.txt CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
  ## Skills
8
8
 
9
- - [check-permissions](@warlock.js/access/check-permissions/SKILL.md): (no description)
10
- - [configure-access](@warlock.js/access/configure-access/SKILL.md): (no description)
11
- - [define-policies](@warlock.js/access/define-policies/SKILL.md): (no description)
12
- - [implement-resolver](@warlock.js/access/implement-resolver/SKILL.md): (no description)
13
- - [manage-roles](@warlock.js/access/manage-roles/SKILL.md): (no description)
9
+ - [check-permissions](@warlock.js/access/check-permissions/SKILL.md): Check permissions in `@warlock.js/access` — `can` / `cannot` / `canAll` / `canAny` (boolean), `authorize` / `authorizeAll` / `authorizeAny` (throw 403), and the `gate` / `gateAny` / `gateAll` route middleware. Class-level vs instance-level (pass a `resource` to run its policy). TRIGGER: `can(`, `authorize(`, `canAll`, `canAny`, `gate`, `gateAny`, `gateAll`, "check a permission", "protect route by permission", "403 forbidden", "any vs all permissions". Skip: ownership / tenant conditions — the `define-policies` topic; role checks — the `manage-roles` topic.
10
+ - [configure-access](@warlock.js/access/configure-access/SKILL.md): Configure `@warlock.js/access` — the REQUIRED `resolver` (the quickstart `DefaultAccessResolver` over a fixed code map vs the ejected, DB-backed `DatabaseAccessResolver`), `cache: { ttl }`, and the ambient tenant via the resolver's optional `resolveTenant()`. TRIGGER: `AccessConfigurations`, `config.access`, `src/config/access.ts`, "set up permissions", "DefaultAccessResolver", "DatabaseAccessResolver", "access cache ttl", "access tenant". Skip: checking permissions — the `check-permissions` topic; custom storage — the `implement-resolver` topic.
11
+ - [define-policies](@warlock.js/access/define-policies/SKILL.md): ABAC conditions in `@warlock.js/access` — `definePolicy(permission, (user, resource, ctx) => boolean)` adds an instance-level rule (ownership / tenant / state) on top of the RBAC grant, evaluated when an authorization check carries a `resource`. TRIGGER: `definePolicy`, "ownership check", "only their own", "can edit this specific record", "ABAC", "policy", "resource-level permission", `authorize(user, perm, { resource })`. Skip: plain grant checks — the `check-permissions` topic.
12
+ - [implement-resolver](@warlock.js/access/implement-resolver/SKILL.md): Connect `@warlock.js/access` to your role/permission storage by implementing the `AccessResolver` contract (`resolveRoles` / `resolvePermissions`, optional `resolveTenant`) — for a DB-backed catalog, a user column, a pivot table, a token claim, or an external directory. The engine owns matching / caching / policies; the resolver only fetches. TRIGGER: `AccessResolver`, `DatabaseAccessResolver`, `resolveTenant`, "custom resolver", "where do roles come from", "roles in a token claim", "permissions from an external API", "implement resolver". Skip: the quickstart `DefaultAccessResolver` — the `configure-access` topic.
13
+ - [manage-roles](@warlock.js/access/manage-roles/SKILL.md): Assign and read roles in `@warlock.js/access` — the ejected `UserRole.assign` / `UserRole.revoke` (the `user_roles` table) followed by `access.flush`, plus `hasRole` / `hasAnyRole` / `hasAllRoles`. The role→permission catalog is the ejected `Role` table (dynamic). TRIGGER: `UserRole.assign`, `UserRole.revoke`, `access.flush`, `hasRole`, `hasAnyRole`, `hasAllRoles`, `Role` table, "give a user a role", "assign role", "check a user role", "roles per tenant". Skip: permission checks — the `check-permissions` topic; resolver choice — the `configure-access` topic.
14
14
  - [overview](@warlock.js/access/overview/SKILL.md): @warlock.js/access overview for orientation and choosing the focused skill for the task.
package/package.json CHANGED
@@ -5,12 +5,12 @@
5
5
  "environment": "server"
6
6
  },
7
7
  "peerDependencies": {
8
- "@warlock.js/auth": "5.27.0",
9
- "@warlock.js/cache": "5.27.0",
10
- "@warlock.js/cascade": "5.27.0",
11
- "@warlock.js/core": "5.27.0",
12
- "@warlock.js/logger": "5.27.0",
13
- "@warlock.js/seal": "5.27.0"
8
+ "@warlock.js/auth": "5.29.0",
9
+ "@warlock.js/cache": "5.29.0",
10
+ "@warlock.js/cascade": "5.29.0",
11
+ "@warlock.js/core": "5.29.0",
12
+ "@warlock.js/logger": "5.29.0",
13
+ "@warlock.js/seal": "5.29.0"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "author": "hassanzohdy",
29
29
  "license": "MIT",
30
- "version": "5.27.0",
30
+ "version": "5.29.0",
31
31
  "main": "./cjs/index.cjs",
32
32
  "module": "./esm/index.mjs",
33
33
  "types": "./esm/index.d.mts",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: check-permissions
3
- description: 'Check permissions in `@warlock.js/access` — `can` / `cannot` / `canAll` / `canAny` (boolean), `authorize` / `authorizeAll` / `authorizeAny` (throw 403), and the `gate` / `gateAny` / `gateAll` route middleware. Class-level vs instance-level (pass a `resource` to run its policy). TRIGGER: `can(`, `authorize(`, `canAll`, `canAny`, `gate`, `gateAny`, `gateAll`, "check a permission", "protect route by permission", "403 forbidden", "any vs all permissions". Skip: ownership / tenant conditions — `@warlock.js/access/define-policies/SKILL.md`; role checks — `@warlock.js/access/manage-roles/SKILL.md`.'
3
+ description: 'Check permissions in `@warlock.js/access` — `can` / `cannot` / `canAll` / `canAny` (boolean), `authorize` / `authorizeAll` / `authorizeAny` (throw 403), and the `gate` / `gateAny` / `gateAll` route middleware. Class-level vs instance-level (pass a `resource` to run its policy). TRIGGER: `can(`, `authorize(`, `canAll`, `canAny`, `gate`, `gateAny`, `gateAll`, "check a permission", "protect route by permission", "403 forbidden", "any vs all permissions". Skip: ownership / tenant conditions — the `define-policies` topic; role checks — the `manage-roles` topic.'
4
4
  ---
5
5
 
6
6
  # Check permissions
@@ -44,7 +44,7 @@ await authorizeAll(user, ["orders.update", "orders.viewCost"]);
44
44
 
45
45
  ## Instance-level — "this resource"
46
46
 
47
- Pass a `resource` and the permission's policy runs on top of the grant (see [`define-policies`](@warlock.js/access/define-policies/SKILL.md)):
47
+ Pass a `resource` and the permission's policy runs on top of the grant (see the `define-policies` topic):
48
48
 
49
49
  ```ts
50
50
  const order = await Order.find(orderId);
@@ -67,5 +67,5 @@ await authorize(user, "orders.update", { resource: order, tenant }); // grant AN
67
67
 
68
68
  ## See also
69
69
 
70
- - [`@warlock.js/access/define-policies/SKILL.md`](@warlock.js/access/define-policies/SKILL.md) — the `{ resource }` conditions.
71
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — `authMiddleware`, which runs first.
70
+ - The `define-policies` topic — the `{ resource }` conditions.
71
+ - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`, which runs first.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: configure-access
3
- description: 'Configure `@warlock.js/access` — the REQUIRED `resolver` (the quickstart `DefaultAccessResolver` over a fixed code map vs the ejected, DB-backed `DatabaseAccessResolver`), `cache: { ttl }`, and the ambient tenant via the resolver''s optional `resolveTenant()`. TRIGGER: `AccessConfigurations`, `config.access`, `src/config/access.ts`, "set up permissions", "DefaultAccessResolver", "DatabaseAccessResolver", "access cache ttl", "access tenant". Skip: checking permissions — `@warlock.js/access/check-permissions/SKILL.md`; custom storage — `@warlock.js/access/implement-resolver/SKILL.md`.'
3
+ description: 'Configure `@warlock.js/access` — the REQUIRED `resolver` (the quickstart `DefaultAccessResolver` over a fixed code map vs the ejected, DB-backed `DatabaseAccessResolver`), `cache: { ttl }`, and the ambient tenant via the resolver''s optional `resolveTenant()`. TRIGGER: `AccessConfigurations`, `config.access`, `src/config/access.ts`, "set up permissions", "DefaultAccessResolver", "DatabaseAccessResolver", "access cache ttl", "access tenant". Skip: checking permissions — the `check-permissions` topic; custom storage — the `implement-resolver` topic.'
4
4
  ---
5
5
 
6
6
  # Configure access
@@ -44,7 +44,7 @@ const access: AccessConfigurations = {
44
44
  export default access;
45
45
  ```
46
46
 
47
- Assign roles via the ejected `UserRole.assign(user, "editor", tenant)` — it flushes that user's cached set for you (see [`manage-roles`](@warlock.js/access/manage-roles/SKILL.md)).
47
+ Assign roles via the ejected `UserRole.assign(user, "editor", tenant)` — it flushes that user's cached set for you (see the `manage-roles` topic).
48
48
 
49
49
  ## The full shape
50
50
 
@@ -62,7 +62,7 @@ type AccessConfigurations = {
62
62
 
63
63
  An instance check (`{ resource }`) for a permission with no registered ABAC policy **denies by default** (`strictPolicies: true`) — a forgotten policy must never fail open. The miss is logged once per permission (`log.warn`) either way.
64
64
 
65
- Set `strictPolicies: false` to explicitly restore the pre-5.13 behavior: fall back to the RBAC grant alone (ALLOWS — any holder of the permission can act on ANY resource, a plausible IDOR). See [`define-policies`](@warlock.js/access/define-policies/SKILL.md) for the full decision table.
65
+ Set `strictPolicies: false` to explicitly restore the pre-5.13 behavior: fall back to the RBAC grant alone (ALLOWS — any holder of the permission can act on ANY resource, a plausible IDOR). See the `define-policies` topic for the full decision table.
66
66
 
67
67
  > **Breaking in 5.13:** `strictPolicies` now defaults to `true` and DENIES (it used to default to `false` and ALLOW). Set `strictPolicies: false` to keep the old fail-open fallback.
68
68
 
@@ -84,6 +84,6 @@ The engine caches each user's resolved set (`cache.ttl`, default `10m`). Roles c
84
84
 
85
85
  ## See also
86
86
 
87
- - [`@warlock.js/access/implement-resolver/SKILL.md`](@warlock.js/access/implement-resolver/SKILL.md) — write a resolver for your own storage.
88
- - [`@warlock.js/access/manage-roles/SKILL.md`](@warlock.js/access/manage-roles/SKILL.md) — assign / revoke with the ejected table.
87
+ - The `implement-resolver` topic — write a resolver for your own storage.
88
+ - The `manage-roles` topic — assign / revoke with the ejected table.
89
89
  ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: define-policies
3
- description: 'ABAC conditions in `@warlock.js/access` — `definePolicy(permission, (user, resource, ctx) => boolean)` adds an instance-level rule (ownership / tenant / state) on top of the RBAC grant, evaluated when an authorization check carries a `resource`. TRIGGER: `definePolicy`, "ownership check", "only their own", "can edit this specific record", "ABAC", "policy", "resource-level permission", `authorize(user, perm, { resource })`. Skip: plain grant checks — `@warlock.js/access/check-permissions/SKILL.md`.'
3
+ description: 'ABAC conditions in `@warlock.js/access` — `definePolicy(permission, (user, resource, ctx) => boolean)` adds an instance-level rule (ownership / tenant / state) on top of the RBAC grant, evaluated when an authorization check carries a `resource`. TRIGGER: `definePolicy`, "ownership check", "only their own", "can edit this specific record", "ABAC", "policy", "resource-level permission", `authorize(user, perm, { resource })`. Skip: plain grant checks — the `check-permissions` topic.'
4
4
  ---
5
5
 
6
6
  # Define policies (ABAC)
@@ -36,7 +36,7 @@ So `gate("orders.update")` (a route gate, no resource) checks the grant; the per
36
36
  ## The decision = grant AND policy
37
37
 
38
38
  - No grant → denied (the policy never runs).
39
- - Grant + no policy registered → **denied by default** (`strictPolicies: true`, the 5.13+ default) — a typo'd permission or a forgotten `import "./policies"` must never silently degrade an instance check to a class-level one. Logs a one-time `log.warn` naming the permission either way. Set `strictPolicies: false` in the access config (see [`configure-access`](@warlock.js/access/configure-access/SKILL.md)) to explicitly restore the pre-5.13 RBAC-only fallback (allowed).
39
+ - Grant + no policy registered → **denied by default** (`strictPolicies: true`, the 5.13+ default) — a typo'd permission or a forgotten `import "./policies"` must never silently degrade an instance check to a class-level one. Logs a one-time `log.warn` naming the permission either way. Set `strictPolicies: false` in the access config (see the `configure-access` topic) to explicitly restore the pre-5.13 RBAC-only fallback (allowed).
40
40
  - Grant + policy → the policy decides.
41
41
 
42
42
  Policies **deny**, they don't grant — a policy can't let a user past a permission they don't hold.
@@ -65,4 +65,4 @@ definePolicy("orders.refund", (user, order, ctx) =>
65
65
 
66
66
  ## See also
67
67
 
68
- - [`@warlock.js/access/check-permissions/SKILL.md`](@warlock.js/access/check-permissions/SKILL.md) — `authorize(…, { resource })`.
68
+ - The `check-permissions` topic — `authorize(…, { resource })`.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: implement-resolver
3
- description: 'Connect `@warlock.js/access` to your role/permission storage by implementing the `AccessResolver` contract (`resolveRoles` / `resolvePermissions`, optional `resolveTenant`) — for a DB-backed catalog, a user column, a pivot table, a token claim, or an external directory. The engine owns matching / caching / policies; the resolver only fetches. TRIGGER: `AccessResolver`, `DatabaseAccessResolver`, `resolveTenant`, "custom resolver", "where do roles come from", "roles in a token claim", "permissions from an external API", "implement resolver". Skip: the quickstart `DefaultAccessResolver` — `@warlock.js/access/configure-access/SKILL.md`.'
3
+ description: 'Connect `@warlock.js/access` to your role/permission storage by implementing the `AccessResolver` contract (`resolveRoles` / `resolvePermissions`, optional `resolveTenant`) — for a DB-backed catalog, a user column, a pivot table, a token claim, or an external directory. The engine owns matching / caching / policies; the resolver only fetches. TRIGGER: `AccessResolver`, `DatabaseAccessResolver`, `resolveTenant`, "custom resolver", "where do roles come from", "roles in a token claim", "permissions from an external API", "implement resolver". Skip: the quickstart `DefaultAccessResolver` — the `configure-access` topic.'
4
4
  ---
5
5
 
6
6
  # Implement a resolver
@@ -102,5 +102,5 @@ class DirectResolver implements AccessResolver {
102
102
 
103
103
  ## See also
104
104
 
105
- - [`@warlock.js/access/configure-access/SKILL.md`](@warlock.js/access/configure-access/SKILL.md) — the quickstart `DefaultAccessResolver`.
105
+ - The `configure-access` topic — the quickstart `DefaultAccessResolver`.
106
106
  ```
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: manage-roles
3
- description: 'Assign and read roles in `@warlock.js/access` — the ejected `UserRole.assign` / `UserRole.revoke` (the `user_roles` table) followed by `access.flush`, plus `hasRole` / `hasAnyRole` / `hasAllRoles`. The role→permission catalog is the ejected `Role` table (dynamic). TRIGGER: `UserRole.assign`, `UserRole.revoke`, `access.flush`, `hasRole`, `hasAnyRole`, `hasAllRoles`, `Role` table, "give a user a role", "assign role", "check a user role", "roles per tenant". Skip: permission checks — `@warlock.js/access/check-permissions/SKILL.md`; resolver choice — `@warlock.js/access/configure-access/SKILL.md`.'
3
+ description: 'Assign and read roles in `@warlock.js/access` — the ejected `UserRole.assign` / `UserRole.revoke` (the `user_roles` table) followed by `access.flush`, plus `hasRole` / `hasAnyRole` / `hasAllRoles`. The role→permission catalog is the ejected `Role` table (dynamic). TRIGGER: `UserRole.assign`, `UserRole.revoke`, `access.flush`, `hasRole`, `hasAnyRole`, `hasAllRoles`, `Role` table, "give a user a role", "assign role", "check a user role", "roles per tenant". Skip: permission checks — the `check-permissions` topic; resolver choice — the `configure-access` topic.'
4
4
  ---
5
5
 
6
6
  # Manage roles
@@ -62,10 +62,10 @@ The ejected `UserRole` is a thin cascade model — `{ user_id, user_type, role,
62
62
 
63
63
  ## Roles stored elsewhere?
64
64
 
65
- If roles live on the user (a `roles` column) or in a token claim, you don't use `UserRole` — you manage assignment your way and a resolver reads them. See [`implement-resolver`](@warlock.js/access/implement-resolver/SKILL.md).
65
+ If roles live on the user (a `roles` column) or in a token claim, you don't use `UserRole` — you manage assignment your way and a resolver reads them. See the `implement-resolver` topic.
66
66
 
67
67
  ## See also
68
68
 
69
- - [`@warlock.js/access/configure-access/SKILL.md`](@warlock.js/access/configure-access/SKILL.md) — choosing the resolver.
70
- - [`@warlock.js/access/implement-resolver/SKILL.md`](@warlock.js/access/implement-resolver/SKILL.md) — non-table role storage.
69
+ - The `configure-access` topic — choosing the resolver.
70
+ - The `implement-resolver` topic — non-table role storage.
71
71
  ```
@@ -28,11 +28,11 @@ Skip if you only need "is the user an admin" — `authMiddleware("admin")` from
28
28
 
29
29
  ## Skills index
30
30
 
31
- - [`configure-access`](@warlock.js/access/configure-access/SKILL.md) — the required resolver (`DefaultAccessResolver` vs the ejected `DatabaseAccessResolver`), cache + tenant.
32
- - [`check-permissions`](@warlock.js/access/check-permissions/SKILL.md) — `can` / `cannot` / `canAll` / `canAny` / `authorize*` + the `gate*` middleware.
33
- - [`define-policies`](@warlock.js/access/define-policies/SKILL.md) — `definePolicy` for ownership / tenant / state conditions (ABAC).
34
- - [`manage-roles`](@warlock.js/access/manage-roles/SKILL.md) — assign / revoke via the ejected `UserRole` + `access.flush`, `hasRole` / `hasAnyRole` / `hasAllRoles`.
35
- - [`implement-resolver`](@warlock.js/access/implement-resolver/SKILL.md) — connect the engine to your storage (a DB catalog, a column, a pivot, a token claim).
31
+ - `configure-access` — the required resolver (`DefaultAccessResolver` vs the ejected `DatabaseAccessResolver`), cache + tenant.
32
+ - `check-permissions` — `can` / `cannot` / `canAll` / `canAny` / `authorize*` + the `gate*` middleware.
33
+ - `define-policies` — `definePolicy` for ownership / tenant / state conditions (ABAC).
34
+ - `manage-roles` — assign / revoke via the ejected `UserRole` + `access.flush`, `hasRole` / `hasAnyRole` / `hasAllRoles`.
35
+ - `implement-resolver` — connect the engine to your storage (a DB catalog, a column, a pivot, a token claim).
36
36
 
37
37
  ## What it deliberately doesn't do
38
38
 
@@ -42,5 +42,5 @@ Skip if you only need "is the user an admin" — `authMiddleware("admin")` from
42
42
 
43
43
  ## See also
44
44
 
45
- - [`@warlock.js/auth/overview/SKILL.md`](@warlock.js/auth/overview/SKILL.md) — authentication, the layer below.
46
- - [`@warlock.js/auth/protect-routes/SKILL.md`](@warlock.js/auth/protect-routes/SKILL.md) — `authMiddleware`; stack `gate` after it.
45
+ - The `overview` topic of the `warlock-js-auth` skill — authentication, the layer below.
46
+ - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`; stack `gate` after it.