@stacksjs/auth 0.70.86 → 0.70.88

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/dist/rbac.d.ts DELETED
@@ -1,265 +0,0 @@
1
- import type { UserModel as OrmUserModel } from '@stacksjs/orm';
2
- /**
3
- * Set the RBAC store implementation
4
- */
5
- export declare function setRbacStore(rbacStore: RbacStore): void;
6
- /**
7
- * Flush the RBAC cache
8
- */
9
- export declare function flushRbacCache(): void;
10
- /**
11
- * Create a new role
12
- */
13
- export declare function createRole(name: string, guardName?: string, description?: string): Promise<RoleRecord>;
14
- /**
15
- * Find a role by name
16
- */
17
- export declare function findRole(name: string, guardName?: string): Promise<RoleRecord | null>;
18
- /**
19
- * Delete a role
20
- */
21
- export declare function deleteRole(name: string, guardName?: string): Promise<void>;
22
- /**
23
- * Get all roles
24
- */
25
- export declare function getAllRoles(guardName?: string): Promise<RoleRecord[]>;
26
- /**
27
- * Create a new permission
28
- */
29
- export declare function createPermission(name: string, guardName?: string, description?: string): Promise<PermissionRecord>;
30
- /**
31
- * Find a permission by name
32
- */
33
- export declare function findPermission(name: string, guardName?: string): Promise<PermissionRecord | null>;
34
- /**
35
- * Delete a permission
36
- */
37
- export declare function deletePermission(name: string, guardName?: string): Promise<void>;
38
- /**
39
- * Get all permissions
40
- */
41
- export declare function getAllPermissions(guardName?: string): Promise<PermissionRecord[]>;
42
- /**
43
- * Get all roles for a user
44
- */
45
- export declare function getUserRoles(user: UserModel | { id: number } | number): Promise<RoleRecord[]>;
46
- /**
47
- * Assign a role to a user
48
- */
49
- export declare function assignRole(user: UserModel | { id: number } | number, roleName: string, guardName?: string): Promise<void>;
50
- /**
51
- * Remove a role from a user
52
- */
53
- export declare function removeRole(user: UserModel | { id: number } | number, roleName: string, guardName?: string): Promise<void>;
54
- /**
55
- * Remove all roles from a user
56
- */
57
- export declare function removeAllRoles(user: UserModel | { id: number } | number): Promise<void>;
58
- /**
59
- * Sync roles for a user (replaces all current roles)
60
- */
61
- export declare function syncRoles(user: UserModel | { id: number } | number, roleNames: string[], guardName?: string): Promise<void>;
62
- /**
63
- * Check if a user has a specific role
64
- */
65
- export declare function hasRole(user: UserModel | { id: number } | number, roleName: string, guardName?: string): Promise<boolean>;
66
- /**
67
- * Check if a user has any of the given roles
68
- */
69
- export declare function hasAnyRole(user: UserModel | { id: number } | number, roleNames: string[], guardName?: string): Promise<boolean>;
70
- /**
71
- * Check if a user has all of the given roles
72
- */
73
- export declare function hasAllRoles(user: UserModel | { id: number } | number, roleNames: string[], guardName?: string): Promise<boolean>;
74
- /**
75
- * Get all permissions for a user (direct + via roles)
76
- */
77
- export declare function getUserPermissions(user: UserModel | { id: number } | number): Promise<PermissionRecord[]>;
78
- /**
79
- * Give a direct permission to a user
80
- */
81
- export declare function givePermission(user: UserModel | { id: number } | number, permissionName: string, guardName?: string): Promise<void>;
82
- /**
83
- * Revoke a direct permission from a user
84
- */
85
- export declare function revokePermission(user: UserModel | { id: number } | number, permissionName: string, guardName?: string): Promise<void>;
86
- /**
87
- * Revoke all direct permissions from a user
88
- */
89
- export declare function revokeAllPermissions(user: UserModel | { id: number } | number): Promise<void>;
90
- /**
91
- * Sync direct permissions for a user
92
- */
93
- export declare function syncPermissions(user: UserModel | { id: number } | number, permissionNames: string[], guardName?: string): Promise<void>;
94
- /**
95
- * Check if a user has a specific permission (direct or via role)
96
- */
97
- export declare function hasPermission(user: UserModel | { id: number } | number, permissionName: string, guardName?: string): Promise<boolean>;
98
- /**
99
- * Check if a user has any of the given permissions
100
- */
101
- export declare function hasAnyPermission(user: UserModel | { id: number } | number, permissionNames: string[], guardName?: string): Promise<boolean>;
102
- /**
103
- * Check if a user has all of the given permissions
104
- */
105
- export declare function hasAllPermissions(user: UserModel | { id: number } | number, permissionNames: string[], guardName?: string): Promise<boolean>;
106
- /**
107
- * Get all permissions for a role
108
- */
109
- export declare function getRolePermissions(roleId: number): Promise<PermissionRecord[]>;
110
- /**
111
- * Assign a permission to a role
112
- */
113
- export declare function givePermissionToRole(roleName: string, permissionName: string, guardName?: string): Promise<void>;
114
- /**
115
- * Remove a permission from a role
116
- */
117
- export declare function revokePermissionFromRole(roleName: string, permissionName: string, guardName?: string): Promise<void>;
118
- /**
119
- * Sync permissions for a role
120
- */
121
- export declare function syncRolePermissions(roleName: string, permissionNames: string[], guardName?: string): Promise<void>;
122
- /**
123
- * Add RBAC methods to a user object
124
- *
125
- * @example
126
- * const user = withRbac(authenticatedUser)
127
- * if (await user.hasRole('admin')) { ... }
128
- * await user.assignRole('editor')
129
- */
130
- export declare function withRbac<T extends UserModel | { id: number }>(user: T): T & RbacMethods;
131
- /**
132
- * RBAC facade for convenient access
133
- */
134
- export declare const Rbac: {
135
- setStore: unknown;
136
- flushCache: unknown;
137
- createRole: typeof createRole;
138
- findRole: typeof findRole;
139
- deleteRole: typeof deleteRole;
140
- getAllRoles: typeof getAllRoles;
141
- createPermission: typeof createPermission;
142
- findPermission: typeof findPermission;
143
- deletePermission: typeof deletePermission;
144
- getAllPermissions: typeof getAllPermissions;
145
- getUserRoles: typeof getUserRoles;
146
- assignRole: typeof assignRole;
147
- removeRole: typeof removeRole;
148
- removeAllRoles: typeof removeAllRoles;
149
- syncRoles: typeof syncRoles;
150
- hasRole: typeof hasRole;
151
- hasAnyRole: typeof hasAnyRole;
152
- hasAllRoles: typeof hasAllRoles;
153
- getUserPermissions: typeof getUserPermissions;
154
- givePermission: typeof givePermission;
155
- revokePermission: typeof revokePermission;
156
- revokeAllPermissions: typeof revokeAllPermissions;
157
- syncPermissions: typeof syncPermissions;
158
- hasPermission: typeof hasPermission;
159
- hasAnyPermission: typeof hasAnyPermission;
160
- hasAllPermissions: typeof hasAllPermissions;
161
- getRolePermissions: typeof getRolePermissions;
162
- givePermissionToRole: typeof givePermissionToRole;
163
- revokePermissionFromRole: typeof revokePermissionFromRole;
164
- syncRolePermissions: typeof syncRolePermissions;
165
- withRbac: typeof withRbac
166
- };
167
- export declare interface RoleRecord {
168
- id: number
169
- name: string
170
- guard_name: string
171
- description?: string
172
- created_at?: string
173
- updated_at?: string
174
- }
175
- export declare interface PermissionRecord {
176
- id: number
177
- name: string
178
- guard_name: string
179
- description?: string
180
- created_at?: string
181
- updated_at?: string
182
- }
183
- export declare interface RolePermissionPivot {
184
- role_id: number
185
- permission_id: number
186
- created_at?: string
187
- }
188
- export declare interface UserRolePivot {
189
- user_id: number
190
- role_id: number
191
- created_at?: string
192
- }
193
- export declare interface UserPermissionPivot {
194
- user_id: number
195
- permission_id: number
196
- created_at?: string
197
- }
198
- /**
199
- * RBAC database adapter interface.
200
- * Implement this to connect RBAC to your database layer.
201
- */
202
- export declare interface RbacStore {
203
- findRoleByName(name: string, guardName?: string): Promise<RoleRecord | null>
204
- findRoleById(id: number): Promise<RoleRecord | null>
205
- createRole(name: string, guardName?: string, description?: string): Promise<RoleRecord>
206
- deleteRole(id: number): Promise<void>
207
- getAllRoles(guardName?: string): Promise<RoleRecord[]>
208
- findPermissionByName(name: string, guardName?: string): Promise<PermissionRecord | null>
209
- findPermissionById(id: number): Promise<PermissionRecord | null>
210
- createPermission(name: string, guardName?: string, description?: string): Promise<PermissionRecord>
211
- deletePermission(id: number): Promise<void>
212
- getAllPermissions(guardName?: string): Promise<PermissionRecord[]>
213
- getUserRoles(userId: number): Promise<RoleRecord[]>
214
- assignRoleToUser(userId: number, roleId: number): Promise<void>
215
- removeRoleFromUser(userId: number, roleId: number): Promise<void>
216
- removeAllRolesFromUser(userId: number): Promise<void>
217
- syncUserRoles(userId: number, roleIds: number[]): Promise<void>
218
- getUserDirectPermissions(userId: number): Promise<PermissionRecord[]>
219
- assignPermissionToUser(userId: number, permissionId: number): Promise<void>
220
- removePermissionFromUser(userId: number, permissionId: number): Promise<void>
221
- removeAllPermissionsFromUser(userId: number): Promise<void>
222
- syncUserPermissions(userId: number, permissionIds: number[]): Promise<void>
223
- getRolePermissions(roleId: number): Promise<PermissionRecord[]>
224
- assignPermissionToRole(roleId: number, permissionId: number): Promise<void>
225
- removePermissionFromRole(roleId: number, permissionId: number): Promise<void>
226
- syncRolePermissions(roleId: number, permissionIds: number[]): Promise<void>
227
- }
228
- // ─── Authorizable Mixin (add to user objects) ───────────────────
229
- export declare interface RbacMethods {
230
- hasRole(roleName: string, guardName?: string): Promise<boolean>
231
- hasAnyRole(roleNames: string[], guardName?: string): Promise<boolean>
232
- hasAllRoles(roleNames: string[], guardName?: string): Promise<boolean>
233
- hasPermission(permissionName: string, guardName?: string): Promise<boolean>
234
- hasAnyPermission(permissionNames: string[], guardName?: string): Promise<boolean>
235
- hasAllPermissions(permissionNames: string[], guardName?: string): Promise<boolean>
236
- getRoles(): Promise<RoleRecord[]>
237
- getPermissions(): Promise<PermissionRecord[]>
238
- assignRole(roleName: string, guardName?: string): Promise<void>
239
- removeRole(roleName: string, guardName?: string): Promise<void>
240
- syncRoles(roleNames: string[], guardName?: string): Promise<void>
241
- givePermission(permissionName: string, guardName?: string): Promise<void>
242
- revokePermission(permissionName: string, guardName?: string): Promise<void>
243
- syncPermissions(permissionNames: string[], guardName?: string): Promise<void>
244
- }
245
- // Use the row/instance shape from orm so role helpers operate on the
246
- // authenticated user object, not the User class constructor.
247
- declare type UserModel = OrmUserModel;
248
- /**
249
- * FIFO-bounded Map. Wraps Map with a hard size cap; on overflow, the
250
- * oldest entry (Map insertion order) is evicted. Used for the RBAC
251
- * per-user caches because the previous unbounded `Map<number, ...>`
252
- * grew without limit across the process lifetime — a long-running
253
- * server serving many distinct users would OOM eventually
254
- * (stacksjs/stacks#1860 M-5). Same shape as `BoundedMap` in
255
- * `@stacksjs/router/stacks-router.ts`.
256
- */
257
- declare class BoundedMap<K, V> {
258
- constructor(max: number);
259
- get(key: K): V | undefined;
260
- has(key: K): boolean;
261
- set(key: K, value: V): this;
262
- delete(key: K): boolean;
263
- clear(): void;
264
- }
265
- export default Rbac;
@@ -1,3 +0,0 @@
1
- import type { AuthToken } from './token';
2
- import type { NewUser } from '@stacksjs/orm';
3
- export declare function register(credentials: NewUser): Promise<{ token: AuthToken }>;
@@ -1,49 +0,0 @@
1
- import { User } from '@stacksjs/orm';
2
- /**
3
- * Authenticate a user via email and password, creating a session.
4
- * Sessions are persisted to the database so they survive server restarts.
5
- *
6
- * The `fingerprint` override is mainly for tests; in normal HTTP
7
- * handling the active request's IP + UA are captured automatically.
8
- */
9
- export declare function sessionLogin(email: string, password: string, fingerprint?: { ip?: string | null, userAgent?: string | null }): Promise<{ user: UserModel, sessionId: string }>;
10
- /**
11
- * Destroy the session for the given session ID.
12
- */
13
- export declare function sessionLogout(sessionId: string): Promise<void>;
14
- /**
15
- * Destroy every session for a user — the credential-change sweep.
16
- * Sessions are validated purely on row existence + `expires_at`, never
17
- * re-checked against the password hash, so without this a stolen
18
- * session cookie survives a password reset for up to 24h
19
- * (stacksjs/stacks#1947).
20
- *
21
- * Unlike `sessionLogout`, real failures propagate (fail loud): a reset
22
- * that reports success while the attacker's session lives would be a
23
- * lie. A missing `sessions` table alone is a benign no-op — no
24
- * framework migration creates it (only userland adopting session-auth
25
- * does), and without the table `sessionCheck` can never validate a
26
- * session, so there is no credential left to revoke.
27
- */
28
- export declare function sessionDestroyAll(userId: number): Promise<void>;
29
- /**
30
- * Get the authenticated user from a session ID.
31
- */
32
- export declare function sessionUser(sessionId: string): Promise<UserModel | undefined>;
33
- /**
34
- * Check if a session is authenticated.
35
- */
36
- export declare function sessionCheck(sessionId: string): Promise<boolean>;
37
- /**
38
- * Refresh a session's expiry time.
39
- */
40
- export declare function sessionRefresh(sessionId: string, ttlMs?: unknown): Promise<boolean>;
41
- export declare const SessionAuth: {
42
- login: unknown;
43
- logout: unknown;
44
- destroyAll: unknown;
45
- user: unknown;
46
- check: unknown;
47
- refresh: unknown
48
- };
49
- declare type UserModel = NonNullable<Awaited<ReturnType<typeof User.find>>>;
package/dist/team.d.ts DELETED
@@ -1,121 +0,0 @@
1
- /**
2
- * Pure resolver — no I/O — that decides which team is "active" for a user
3
- * given their memberships and an optional switch preference. Reusable across
4
- * apps: it encodes the whole workspace-switching precedence in one place.
5
- *
6
- * - Honors `activeTeamId` only when the user may access it: a member always
7
- * may; a privileged operator may access any team when `allowAnyTeam` is set
8
- * (the app decides who is privileged — e.g. a super-admin flag).
9
- * - Otherwise falls back to the highest-priority membership (owner > admin >
10
- * anything else), matching what dashboard pages have always shown, so the
11
- * "current team" never differs between a rendered form and the action it
12
- * posts to.
13
- */
14
- export declare function selectActiveTeam(opts: {
15
- memberships: Array<{ team_id: number | string, role?: string | null }>
16
- activeTeamId?: number | null
17
- allowAnyTeam?: boolean
18
- rolePriority?: Record<string, number>
19
- }): { teamId: number | null, role: string | null };
20
- /** Read the active-team switch preference from a request's cookie. */
21
- export declare function getActiveTeamPreference(request: TeamAuthRequest): number | null;
22
- /**
23
- * Build the `Set-Cookie` that pins the active team (workspace switcher). A
24
- * year-long HttpOnly cookie: only the server needs it (SSR reads it, the
25
- * switch action writes it), and it carries no privilege of its own.
26
- */
27
- export declare function buildActiveTeamCookie(teamId: number, opts?: { maxAgeSeconds?: number, secure?: boolean }): string;
28
- /** Clear the active-team cookie {@link buildActiveTeamCookie} sets. */
29
- export declare function clearActiveTeamCookie(): string;
30
- /**
31
- * Resolve the requesting user's active team membership (team id + role)
32
- * from their auth credential. Driver-aware: reads config/auth.ts's
33
- * configured guard driver rather than hardcoding a validation scheme.
34
- *
35
- * Dashboard forms are plain HTML POSTs (no client JS, no Authorization
36
- * header) — the browser only ever sends the auth cookie set on login,
37
- * so that's checked for the 'token' driver alongside a bearer-header
38
- * fallback for JS/API callers.
39
- *
40
- * Owner membership wins over admin, which wins over any other active
41
- * membership, when a user belongs to more than one team — the same
42
- * precedence server-rendered dashboard pages use, so a user never sees
43
- * a different "current team" between the page that rendered a form and
44
- * the action that form posts to.
45
- *
46
- * Returns `null` when unauthenticated or without an active team
47
- * membership — callers must treat that as "reject the request," not
48
- * "fall back to a default team."
49
- */
50
- export declare function resolveAuthenticatedMembership(request: TeamAuthRequest): Promise<TeamMembershipResult | null>;
51
- /**
52
- * Full team context for a server-rendered dashboard: the authenticated user,
53
- * the resolved active team (honoring the workspace switcher), and the list of
54
- * teams the user can switch between. One call replaces the per-page auth+team
55
- * boilerplate every dashboard view used to copy, and centralizes the
56
- * switch-aware scoping so pages and the actions they post to never disagree.
57
- *
58
- * `opts.allowAnyTeam(user)` lets an app grant an operator (e.g. a super-admin)
59
- * access to every team — they can switch to, and see, teams they aren't a
60
- * member of. The full user row is returned so the app can read its own
61
- * columns (like a super-admin flag) without a second query.
62
- */
63
- export declare function resolveTeamContext(request: TeamAuthRequest, opts?: { allowAnyTeam?: (user: any) => boolean }): Promise<TeamContext>;
64
- /**
65
- * Team id only — the common case for actions that just need to scope a
66
- * write to the requester's team. See {@link resolveAuthenticatedMembership}
67
- * when the caller also needs the role (e.g. owner/admin-only settings).
68
- */
69
- export declare function resolveAuthenticatedTeamId(request: TeamAuthRequest): Promise<number | null>;
70
- /**
71
- * The authenticated USER (not team) from a request's real auth
72
- * credential — bearer header first, then the login cookie, driver-aware
73
- * like {@link resolveAuthenticatedMembership} (which builds on this).
74
- * For dashboard form actions that operate on the requester themselves
75
- * (security settings, profile) rather than on team-scoped rows: plain
76
- * HTML POSTs carry no Authorization header, so `request.user()` (stamped
77
- * by the auth middleware from a bearer/session) is undefined there and
78
- * the login cookie is the only credential available.
79
- */
80
- export declare function resolveAuthenticatedUser(request: TeamAuthRequest): Promise<{ id: number, email?: string } | undefined>;
81
- /**
82
- * Name of the cookie that remembers which team the user last switched the
83
- * dashboard to (a workspace switcher). It is NOT a security credential: the
84
- * server re-validates membership against `selectActiveTeam` on every request,
85
- * so a tampered value can only ever resolve to a team the user already
86
- * belongs to (or, for operators, any team when `allowAnyTeam` is set).
87
- */
88
- export declare const ACTIVE_TEAM_COOKIE: 'active_team';
89
- /**
90
- * Team resolution from a request's real auth credential (bearer token or
91
- * session cookie) — never from a client-supplied form field. Extracted
92
- * from app-land (stacksjs/status config/auth-team.ts) because every app
93
- * with team-scoped dashboard forms needs exactly this, and `config/` is
94
- * for autoloaded config files, not shared helpers.
95
- *
96
- * Structural request type on purpose: callers pass whatever request
97
- * object their action received. Partial objects (tests, non-HTTP
98
- * callers) resolve to "unauthenticated" rather than crashing.
99
- */
100
- export declare interface TeamAuthRequest {
101
- bearerToken?: () => string | null | undefined
102
- cookies?: { get: (name: string) => string | null | undefined }
103
- }
104
- export declare interface TeamMembershipResult {
105
- teamId: number
106
- role: string
107
- }
108
- /** A team the authenticated user may switch the dashboard to. */
109
- export declare interface SwitchableTeam {
110
- id: number
111
- name: string
112
- role: string
113
- }
114
- /** Full dashboard team context — see {@link resolveTeamContext}. */
115
- export declare interface TeamContext {
116
- user: any | null
117
- teamId: number | null
118
- role: string | null
119
- teams: SwitchableTeam[]
120
- activeTeamId: number | null
121
- }
package/dist/token.d.ts DELETED
@@ -1,16 +0,0 @@
1
- export type { AuthToken } from '@stacksjs/types';
2
- /**
3
- * `TokenManager` used to expose `createAccessToken` / `validateToken` /
4
- * `rotateToken` / `revokeToken` static methods that hardcoded a 30-day
5
- * `expires_at`, bypassed `config.auth.tokenExpiry`, and compared raw
6
- * tokens against DB-stored hashes (i.e. broken). They had no callers —
7
- * the real path lives on `Auth` (see authentication.ts) and respects
8
- * the configured 1-hour expiry plus the refresh-token rotation
9
- * landed for #1839. Removed entirely so the trap can't fire.
10
- *
11
- * `generateJWT` is the one piece worth keeping — `Auth.createTokenForUser`
12
- * and `Auth.rotateToken` both use it to mint the JWT body.
13
- */
14
- export declare class TokenManager {
15
- static generateJWT(userId: number, expiresInSeconds?: number): string;
16
- }