@palbase/backend 14.0.0 → 14.2.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.
@@ -1,4 +1,4 @@
1
- import { D as DBClient, P as PBRequest, a as PalbaseModuleClients, L as Logger, C as CacheClient, U as User } from '../endpoint-CAWdScEH.cjs';
1
+ import { D as DBClient, P as PBRequest, a as PalbaseModuleClients, L as Logger, C as CacheClient, U as User } from '../endpoint-D2yR2RD1.cjs';
2
2
  import 'zod';
3
3
 
4
4
  /** Mock DB client with tracking and seed data support. */
@@ -1,4 +1,4 @@
1
- import { D as DBClient, P as PBRequest, a as PalbaseModuleClients, L as Logger, C as CacheClient, U as User } from '../endpoint-CAWdScEH.js';
1
+ import { D as DBClient, P as PBRequest, a as PalbaseModuleClients, L as Logger, C as CacheClient, U as User } from '../endpoint-D2yR2RD1.js';
2
2
  import 'zod';
3
3
 
4
4
  /** Mock DB client with tracking and seed data support. */
package/docs/auth.md CHANGED
@@ -36,11 +36,38 @@ interface User {
36
36
  }
37
37
  ```
38
38
 
39
- Every field is **server-resolved** from the verified token — nothing here is
40
- client-settable. `emailVerified` in particular is read from the user's verified
41
- profile, not from a JWT claim: a claim is only true as of when the token was
42
- minted, so a user who verifies mid-session would keep reporting `false` until
43
- their token expired.
39
+ Every field is **server-resolved** from the verified profile — nothing here is
40
+ client-settable. `metadata` is your own `auth.users.metadata` (set through the
41
+ admin users API); `role` is the **database** role RLS reads and is always
42
+ `"authenticated"` for a signed-in user, so application roles belong in
43
+ `metadata`, not there.
44
+
45
+ `emailVerified` is likewise read from the verified profile rather than a JWT
46
+ claim: a claim is only true as of when the token was minted, so a user who
47
+ verifies mid-session would keep reporting `false` until their token expired.
48
+ Profile reads are cached for ~30 seconds, so a change shows up within that
49
+ window, not on the very next request.
50
+
51
+ ## Roles
52
+
53
+ `auth: { role: "admin" }` gates on the caller's `metadata.role`:
54
+
55
+ ```ts
56
+ @Controller("/admin", { auth: { role: "admin" } })
57
+ export default class AdminController {
58
+ @Get("/stats")
59
+ stats(): Promise<Stats> { … } // only metadata.role === "admin" reaches here
60
+ }
61
+ ```
62
+
63
+ Not signed in → `401`. Signed in with a different (or missing) role → `403`. A
64
+ role gate implies authentication, so the caller is resolved even on a route with
65
+ no `@User()` parameter.
66
+
67
+ The role is read from the verified profile, not from a claim baked into the
68
+ token, so revoking it takes effect **within ~30 seconds** — the runtime caches a
69
+ verified identity for that long — rather than whenever the token happens to
70
+ expire.
44
71
 
45
72
  ## Email verification
46
73
 
@@ -92,10 +119,14 @@ publish(@User() user: UserT) {
92
119
  }
93
120
  ```
94
121
 
95
- > There is no per-route `requireVerifiedEmail` option. A route-level flag would
96
- > have to be enforced by the runtime, and the one-line check above is enforced by
97
- > your own code — visible where it applies, and impossible to declare on a route
98
- > and have quietly do nothing.
122
+ Or declare it on the route and let the runtime enforce it:
123
+
124
+ ```ts
125
+ @Controller("/posts", { auth: { verifiedEmail: true } })
126
+ ```
127
+
128
+ Unverified callers get `403 email_not_verified`. Use the route flag to fence a
129
+ whole controller, and the inline check when only part of a handler cares.
99
130
 
100
131
  ## Password reset and magic links
101
132
 
@@ -680,11 +680,38 @@ interface User {
680
680
  }
681
681
  ```
682
682
 
683
- Every field is **server-resolved** from the verified token — nothing here is
684
- client-settable. `emailVerified` in particular is read from the user's verified
685
- profile, not from a JWT claim: a claim is only true as of when the token was
686
- minted, so a user who verifies mid-session would keep reporting `false` until
687
- their token expired.
683
+ Every field is **server-resolved** from the verified profile — nothing here is
684
+ client-settable. `metadata` is your own `auth.users.metadata` (set through the
685
+ admin users API); `role` is the **database** role RLS reads and is always
686
+ `"authenticated"` for a signed-in user, so application roles belong in
687
+ `metadata`, not there.
688
+
689
+ `emailVerified` is likewise read from the verified profile rather than a JWT
690
+ claim: a claim is only true as of when the token was minted, so a user who
691
+ verifies mid-session would keep reporting `false` until their token expired.
692
+ Profile reads are cached for ~30 seconds, so a change shows up within that
693
+ window, not on the very next request.
694
+
695
+ ## Roles
696
+
697
+ `auth: { role: "admin" }` gates on the caller's `metadata.role`:
698
+
699
+ ```ts
700
+ @Controller("/admin", { auth: { role: "admin" } })
701
+ export default class AdminController {
702
+ @Get("/stats")
703
+ stats(): Promise<Stats> { … } // only metadata.role === "admin" reaches here
704
+ }
705
+ ```
706
+
707
+ Not signed in → `401`. Signed in with a different (or missing) role → `403`. A
708
+ role gate implies authentication, so the caller is resolved even on a route with
709
+ no `@User()` parameter.
710
+
711
+ The role is read from the verified profile, not from a claim baked into the
712
+ token, so revoking it takes effect **within ~30 seconds** — the runtime caches a
713
+ verified identity for that long — rather than whenever the token happens to
714
+ expire.
688
715
 
689
716
  ## Email verification
690
717
 
@@ -736,10 +763,14 @@ publish(@User() user: UserT) {
736
763
  }
737
764
  ```
738
765
 
739
- > There is no per-route `requireVerifiedEmail` option. A route-level flag would
740
- > have to be enforced by the runtime, and the one-line check above is enforced by
741
- > your own code — visible where it applies, and impossible to declare on a route
742
- > and have quietly do nothing.
766
+ Or declare it on the route and let the runtime enforce it:
767
+
768
+ ```ts
769
+ @Controller("/posts", { auth: { verifiedEmail: true } })
770
+ ```
771
+
772
+ Unverified callers get `403 email_not_verified`. Use the route flag to fence a
773
+ whole controller, and the inline check when only part of a handler cares.
743
774
 
744
775
  ## Password reset and magic links
745
776
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@palbase/backend",
3
- "version": "14.0.0",
3
+ "version": "14.2.0",
4
4
  "description": "Palbase Backend SDK — class controllers (@Controller/@Get/@Post + @Body/@QueryParams/@Param), error classes, schema DSL",
5
5
  "license": "MIT",
6
6
  "repository": {