@warlock.js/access 5.34.1 → 5.34.2

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,12 @@ 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.34.2 - 2026-10-19
8
+
9
+ ### Fixed
10
+
11
+ - Merge package orientation into the grouped skill index and remove the duplicate overview topic; preserve that orientation in generated LLM projections.
12
+
7
13
  ## 5.32.0 - 2026-10-18
8
14
 
9
15
  ### Changed
package/llms-full.txt CHANGED
@@ -4,6 +4,62 @@
4
4
 
5
5
  > Generated artifact. Concatenates every SKILL.md and reference file under `@warlock.js/access/skills/`. Re-run `node scripts/generate-llms.mjs` after any change.
6
6
 
7
+ ## Package orientation
8
+
9
+ ---
10
+ description: 'Authorization (RBAC + ABAC) for Warlock apps: what a signed-in user is allowed to do. Exports `can`, `authorize`, `gate`, `gateAny`, `definePolicy`, `hasRole`, `access`, `DefaultAccessResolver`, `AccessResolver`, `AccessErrorCodes`. Use for: "check a permission", "restrict this route to users who can update orders", "only the owner can edit", "roles and permissions", "per-tenant roles", "custom role storage". Not this package: login, tokens, user-type gating → @warlock.js/auth; request validation → @warlock.js/seal.'
11
+ ---
12
+
13
+ # @warlock.js/access
14
+
15
+ Access is the authorization engine. You supply one adapter, an `AccessResolver`, that reads a user's roles and permissions from your storage; then `can(user, "orders.update")` and `gate("orders.update")` work. Two halves: permissions (RBAC grants) and policies (ABAC conditions). Server-only; reads `request.locals.user`, so it sits beside `@warlock.js/auth`.
16
+
17
+ ## The 80% path
18
+
19
+ 1. Use this index for orientation and choose a task below.
20
+ 2. Configure the required resolver: `configure-access.md` (`DefaultAccessResolver` for a code-defined catalog, or the ejected DB one); custom storage in `implement-resolver.md`.
21
+ 3. Gate routes and check in code: `check-permissions.md`.
22
+ 4. Add "only their own / only while pending" rules: `define-policies.md`.
23
+ 5. Assign and revoke roles: `manage-roles.md`.
24
+
25
+ ## Conventions and pitfalls
26
+
27
+ - Two stages: class-level (`gate`, `can`) asks "can they at all?"; instance-level (`authorize` with a `resource`) runs the policy on the loaded row.
28
+ - Decisions fail closed; a missing resolver is a config error, not a default allow.
29
+ - Stack `gate` after `authMiddleware`; access does not authenticate.
30
+ - After changing a user's roles, flush the cache (`access.flush`) or old grants linger.
31
+ - Only need "is admin"? `authMiddleware("admin")` from auth is enough.
32
+ - Do not value-import from client code; type-only imports are fine.
33
+
34
+ ## The mental model in one paragraph
35
+
36
+ The package owns the **engine** — wildcard matching, caching, ABAC policies, fail-closed decisions. You hand it **one required adapter**, an `AccessResolver`, that reads a user's roles + permissions from however YOUR app stores them (the role→permission catalog lives inside the resolver). Then `can(user, "orders.update")` and `gate("orders.update")` just work. The two concepts inside are **permissions** (RBAC grants) and **policies** (ABAC conditions) — which is why the package is called `access`, not either half.
37
+
38
+ ## When to reach for it
39
+
40
+ - A Warlock app (already on `@warlock.js/auth`) that needs per-action / per-resource authorization beyond auth's user-type gate.
41
+ - **Multi-tenant** role scoping — `editor` in tenant A, `viewer` in tenant B.
42
+ - "Only their own / only in their tenant / only while pending" conditions → ABAC policies.
43
+
44
+ Skip if you only need "is the user an admin" — `authMiddleware("admin")` from `@warlock.js/auth` already covers coarse type gating.
45
+
46
+ ## The two-stage model (important)
47
+
48
+ - **Class-level** (no resource): _"can this user update orders at all?"_ → `gate("orders.update")` in middleware, `can(user, "orders.update")` in code. Cheap, cached, runs before the controller.
49
+ - **Instance-level** (a resource): _"can they update THIS order?"_ → `authorize(user, "orders.update", { resource: order })` in the service, after you load the row. Runs the registered policy on top of the grant.
50
+
51
+ ## What it deliberately doesn't do
52
+
53
+ - **Authentication.** Use `@warlock.js/auth`; `access` reads `request.locals.user`.
54
+ - **Ship a permission admin UI.** The engine reads permission strings; whether the catalog is code-defined (`DefaultAccessResolver`) or DB-managed (the ejected `DatabaseAccessResolver`) is your resolver's choice — the package ships no admin screens.
55
+ - **ReBAC graphs / row-level query scoping.** Use a policy for "own resource"; graph-scale relationships are out of scope.
56
+
57
+ ## See also
58
+
59
+ - The `warlock-js-auth` skill index — authentication, the layer below.
60
+ - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`; stack `gate` after it.
61
+
62
+
7
63
  ## check-permissions `@warlock.js/access/check-permissions/SKILL.md`
8
64
 
9
65
  ---
@@ -431,53 +487,3 @@ If roles live on the user (a `roles` column) or in a token claim, you don't use
431
487
  - The `implement-resolver` topic — non-table role storage.
432
488
 
433
489
 
434
- ## overview `@warlock.js/access/overview/SKILL.md`
435
-
436
- ---
437
- name: overview
438
- description: "@warlock.js/access overview for orientation and choosing the focused skill for the task."
439
- ---
440
-
441
- # `@warlock.js/access` — overview
442
-
443
- Authorization for Warlock apps. `@warlock.js/auth` answers _who you are_; `access` answers _what you can do_.
444
-
445
- Server-only: `package.json` declares `"warlock": { "environment": "server" }`. `@warlock.js/web`'s build refuses app client code that value-imports this package; type-only imports are allowed, and server loaders/controllers/modules are unaffected.
446
-
447
- ## The mental model in one paragraph
448
-
449
- The package owns the **engine** — wildcard matching, caching, ABAC policies, fail-closed decisions. You hand it **one required adapter**, an `AccessResolver`, that reads a user's roles + permissions from however YOUR app stores them (the role→permission catalog lives inside the resolver). Then `can(user, "orders.update")` and `gate("orders.update")` just work. The two concepts inside are **permissions** (RBAC grants) and **policies** (ABAC conditions) — which is why the package is called `access`, not either half.
450
-
451
- ## When to reach for it
452
-
453
- - A Warlock app (already on `@warlock.js/auth`) that needs per-action / per-resource authorization beyond auth's user-type gate.
454
- - **Multi-tenant** role scoping — `editor` in tenant A, `viewer` in tenant B.
455
- - "Only their own / only in their tenant / only while pending" conditions → ABAC policies.
456
-
457
- Skip if you only need "is the user an admin" — `authMiddleware("admin")` from `@warlock.js/auth` already covers coarse type gating.
458
-
459
- ## The two-stage model (important)
460
-
461
- - **Class-level** (no resource): _"can this user update orders at all?"_ → `gate("orders.update")` in middleware, `can(user, "orders.update")` in code. Cheap, cached, runs before the controller.
462
- - **Instance-level** (a resource): _"can they update THIS order?"_ → `authorize(user, "orders.update", { resource: order })` in the service, after you load the row. Runs the registered policy on top of the grant.
463
-
464
- ## Skills index
465
-
466
- - `configure-access` — the required resolver (`DefaultAccessResolver` vs the ejected `DatabaseAccessResolver`), cache + tenant.
467
- - `check-permissions` — `can` / `cannot` / `canAll` / `canAny` / `authorize*` + the `gate*` middleware.
468
- - `define-policies` — `definePolicy` for ownership / tenant / state conditions (ABAC).
469
- - `manage-roles` — assign / revoke via the ejected `UserRole` + `access.flush`, `hasRole` / `hasAnyRole` / `hasAllRoles`.
470
- - `implement-resolver` — connect the engine to your storage (a DB catalog, a column, a pivot, a token claim).
471
-
472
- ## What it deliberately doesn't do
473
-
474
- - **Authentication.** Use `@warlock.js/auth`; `access` reads `request.locals.user`.
475
- - **Ship a permission admin UI.** The engine reads permission strings; whether the catalog is code-defined (`DefaultAccessResolver`) or DB-managed (the ejected `DatabaseAccessResolver`) is your resolver's choice — the package ships no admin screens.
476
- - **ReBAC graphs / row-level query scoping.** Use a policy for "own resource"; graph-scale relationships are out of scope.
477
-
478
- ## See also
479
-
480
- - The `overview` topic of the `warlock-js-auth` skill — authentication, the layer below.
481
- - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`; stack `gate` after it.
482
-
483
-
package/llms.txt CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
  ## Skills
8
8
 
9
+ - [Package orientation](@warlock.js/access/skills/index.md): Authorization (RBAC + ABAC) for Warlock apps: what a signed-in user is allowed to do. Exports `can`, `authorize`, `gate`, `gateAny`, `definePolicy`, `hasRole`, `access`, `DefaultAccessResolver`, `AccessResolver`, `AccessErrorCodes`. Use for: "check a permission", "restrict this route to users who can update orders", "only the owner can edit", "roles and permissions", "per-tenant roles", "custom role storage". Not this package: login, tokens, user-type gating → @warlock.js/auth; request validation → @warlock.js/seal.
9
10
  - [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
11
  - [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
12
  - [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
13
  - [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
14
  - [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
- - [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.34.1",
9
- "@warlock.js/cache": "5.34.1",
10
- "@warlock.js/cascade": "5.34.1",
11
- "@warlock.js/core": "5.34.1",
12
- "@warlock.js/logger": "5.34.1",
13
- "@warlock.js/seal": "5.34.1"
8
+ "@warlock.js/auth": "5.34.2",
9
+ "@warlock.js/cache": "5.34.2",
10
+ "@warlock.js/cascade": "5.34.2",
11
+ "@warlock.js/core": "5.34.2",
12
+ "@warlock.js/logger": "5.34.2",
13
+ "@warlock.js/seal": "5.34.2"
14
14
  },
15
15
  "repository": {
16
16
  "type": "git",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "author": "hassanzohdy",
30
30
  "license": "MIT",
31
- "version": "5.34.1",
31
+ "version": "5.34.2",
32
32
  "main": "./cjs/index.cjs",
33
33
  "module": "./esm/index.mjs",
34
34
  "types": "./esm/index.d.mts",
package/skills/index.md CHANGED
@@ -4,11 +4,11 @@ description: 'Authorization (RBAC + ABAC) for Warlock apps: what a signed-in use
4
4
 
5
5
  # @warlock.js/access
6
6
 
7
- Access is the authorization engine. You supply one adapter, an `AccessResolver`, that reads a user's roles and permissions from your storage; then `can(user, "orders.update")` and `gate("orders.update")` work. Two halves: permissions (RBAC grants) and policies (ABAC conditions). Server-only; reads `request.user`, so it sits beside `@warlock.js/auth`.
7
+ Access is the authorization engine. You supply one adapter, an `AccessResolver`, that reads a user's roles and permissions from your storage; then `can(user, "orders.update")` and `gate("orders.update")` work. Two halves: permissions (RBAC grants) and policies (ABAC conditions). Server-only; reads `request.locals.user`, so it sits beside `@warlock.js/auth`.
8
8
 
9
9
  ## The 80% path
10
10
 
11
- 1. Orient with `overview.md`.
11
+ 1. Use this index for orientation and choose a task below.
12
12
  2. Configure the required resolver: `configure-access.md` (`DefaultAccessResolver` for a code-defined catalog, or the ejected DB one); custom storage in `implement-resolver.md`.
13
13
  3. Gate routes and check in code: `check-permissions.md`.
14
14
  4. Add "only their own / only while pending" rules: `define-policies.md`.
@@ -22,3 +22,31 @@ Access is the authorization engine. You supply one adapter, an `AccessResolver`,
22
22
  - After changing a user's roles, flush the cache (`access.flush`) or old grants linger.
23
23
  - Only need "is admin"? `authMiddleware("admin")` from auth is enough.
24
24
  - Do not value-import from client code; type-only imports are fine.
25
+
26
+ ## The mental model in one paragraph
27
+
28
+ The package owns the **engine** — wildcard matching, caching, ABAC policies, fail-closed decisions. You hand it **one required adapter**, an `AccessResolver`, that reads a user's roles + permissions from however YOUR app stores them (the role→permission catalog lives inside the resolver). Then `can(user, "orders.update")` and `gate("orders.update")` just work. The two concepts inside are **permissions** (RBAC grants) and **policies** (ABAC conditions) — which is why the package is called `access`, not either half.
29
+
30
+ ## When to reach for it
31
+
32
+ - A Warlock app (already on `@warlock.js/auth`) that needs per-action / per-resource authorization beyond auth's user-type gate.
33
+ - **Multi-tenant** role scoping — `editor` in tenant A, `viewer` in tenant B.
34
+ - "Only their own / only in their tenant / only while pending" conditions → ABAC policies.
35
+
36
+ Skip if you only need "is the user an admin" — `authMiddleware("admin")` from `@warlock.js/auth` already covers coarse type gating.
37
+
38
+ ## The two-stage model (important)
39
+
40
+ - **Class-level** (no resource): _"can this user update orders at all?"_ → `gate("orders.update")` in middleware, `can(user, "orders.update")` in code. Cheap, cached, runs before the controller.
41
+ - **Instance-level** (a resource): _"can they update THIS order?"_ → `authorize(user, "orders.update", { resource: order })` in the service, after you load the row. Runs the registered policy on top of the grant.
42
+
43
+ ## What it deliberately doesn't do
44
+
45
+ - **Authentication.** Use `@warlock.js/auth`; `access` reads `request.locals.user`.
46
+ - **Ship a permission admin UI.** The engine reads permission strings; whether the catalog is code-defined (`DefaultAccessResolver`) or DB-managed (the ejected `DatabaseAccessResolver`) is your resolver's choice — the package ships no admin screens.
47
+ - **ReBAC graphs / row-level query scoping.** Use a policy for "own resource"; graph-scale relationships are out of scope.
48
+
49
+ ## See also
50
+
51
+ - The `warlock-js-auth` skill index — authentication, the layer below.
52
+ - The `protect-routes` topic of the `warlock-js-auth` skill — `authMiddleware`; stack `gate` after it.
@@ -1,46 +0,0 @@
1
- ---
2
- name: overview
3
- description: "@warlock.js/access overview for orientation and choosing the focused skill for the task."
4
- ---
5
-
6
- # `@warlock.js/access` — overview
7
-
8
- Authorization for Warlock apps. `@warlock.js/auth` answers _who you are_; `access` answers _what you can do_.
9
-
10
- Server-only: `package.json` declares `"warlock": { "environment": "server" }`. `@warlock.js/web`'s build refuses app client code that value-imports this package; type-only imports are allowed, and server loaders/controllers/modules are unaffected.
11
-
12
- ## The mental model in one paragraph
13
-
14
- The package owns the **engine** — wildcard matching, caching, ABAC policies, fail-closed decisions. You hand it **one required adapter**, an `AccessResolver`, that reads a user's roles + permissions from however YOUR app stores them (the role→permission catalog lives inside the resolver). Then `can(user, "orders.update")` and `gate("orders.update")` just work. The two concepts inside are **permissions** (RBAC grants) and **policies** (ABAC conditions) — which is why the package is called `access`, not either half.
15
-
16
- ## When to reach for it
17
-
18
- - A Warlock app (already on `@warlock.js/auth`) that needs per-action / per-resource authorization beyond auth's user-type gate.
19
- - **Multi-tenant** role scoping — `editor` in tenant A, `viewer` in tenant B.
20
- - "Only their own / only in their tenant / only while pending" conditions → ABAC policies.
21
-
22
- Skip if you only need "is the user an admin" — `authMiddleware("admin")` from `@warlock.js/auth` already covers coarse type gating.
23
-
24
- ## The two-stage model (important)
25
-
26
- - **Class-level** (no resource): _"can this user update orders at all?"_ → `gate("orders.update")` in middleware, `can(user, "orders.update")` in code. Cheap, cached, runs before the controller.
27
- - **Instance-level** (a resource): _"can they update THIS order?"_ → `authorize(user, "orders.update", { resource: order })` in the service, after you load the row. Runs the registered policy on top of the grant.
28
-
29
- ## Skills index
30
-
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
-
37
- ## What it deliberately doesn't do
38
-
39
- - **Authentication.** Use `@warlock.js/auth`; `access` reads `request.locals.user`.
40
- - **Ship a permission admin UI.** The engine reads permission strings; whether the catalog is code-defined (`DefaultAccessResolver`) or DB-managed (the ejected `DatabaseAccessResolver`) is your resolver's choice — the package ships no admin screens.
41
- - **ReBAC graphs / row-level query scoping.** Use a policy for "own resource"; graph-scale relationships are out of scope.
42
-
43
- ## See also
44
-
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.