@stratal/framework 0.0.27 → 0.1.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 +596 -0
- package/README.md +166 -24
- package/dist/access-control/index.d.mts +43 -16
- package/dist/access-control/index.d.mts.map +1 -1
- package/dist/access-control/index.mjs +5 -5
- package/dist/access-control/index.mjs.map +1 -1
- package/dist/{access.service-BmDhE-re.mjs → access.service-BjmnWBEo.mjs} +35 -17
- package/dist/access.service-BjmnWBEo.mjs.map +1 -0
- package/dist/auth/index.d.mts +105 -103
- package/dist/auth/index.d.mts.map +1 -1
- package/dist/auth/index.mjs +123 -24
- package/dist/auth/index.mjs.map +1 -1
- package/dist/{auth-context-CGVbiSX3.d.mts → auth-context-C1om3Zsr.d.mts} +1 -2
- package/dist/auth-context-C1om3Zsr.d.mts.map +1 -0
- package/dist/{auth-context-C8NBfiMa.mjs → auth-context-cNSS1rmh.mjs} +2 -2
- package/dist/{auth-context-C8NBfiMa.mjs.map → auth-context-cNSS1rmh.mjs.map} +1 -1
- package/dist/auth.service-Onf3JkyL.d.mts +44 -0
- package/dist/auth.service-Onf3JkyL.d.mts.map +1 -0
- package/dist/context/index.d.mts +4 -5
- package/dist/context/index.d.mts.map +1 -1
- package/dist/context/index.mjs +1 -1
- package/dist/database/index.d.mts +3 -3
- package/dist/database/index.mjs +413 -34
- package/dist/database/index.mjs.map +1 -1
- package/dist/{decorate-B7nr7eBl.mjs → decorate-RQD1h28J.mjs} +1 -1
- package/dist/{decorateParam-DwV9LSPl.mjs → decorateParam-xwTkq9gO.mjs} +2 -2
- package/dist/{decorateParam-DwV9LSPl.mjs.map → decorateParam-xwTkq9gO.mjs.map} +1 -1
- package/dist/factory/index.d.mts +3 -5
- package/dist/factory/index.d.mts.map +1 -1
- package/dist/factory/index.mjs.map +1 -1
- package/dist/guards/index.d.mts +3 -4
- package/dist/guards/index.d.mts.map +1 -1
- package/dist/guards/index.mjs +4 -4
- package/dist/guards/index.mjs.map +1 -1
- package/dist/index-e_u1SRyd.d.mts +921 -0
- package/dist/index-e_u1SRyd.d.mts.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/{types-CWZ9q74G.d.mts → types-B35g-lXi.d.mts} +18 -4
- package/dist/types-B35g-lXi.d.mts.map +1 -0
- package/package.json +31 -27
- package/dist/access.service-BmDhE-re.mjs.map +0 -1
- package/dist/auth-context-CGVbiSX3.d.mts.map +0 -1
- package/dist/index-Dt0YUA7r.d.mts +0 -446
- package/dist/index-Dt0YUA7r.d.mts.map +0 -1
- package/dist/types-CWZ9q74G.d.mts.map +0 -1
- package/dist/types-DabF8LGz.d.mts +0 -11
- package/dist/types-DabF8LGz.d.mts.map +0 -1
package/dist/auth/index.d.mts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { r as AuthUser } from "../auth-context-
|
|
1
|
+
import { n as AccessControlOptions, t as AuthService } from "../auth.service-Onf3JkyL.mjs";
|
|
2
|
+
import { r as AuthUser } from "../auth-context-C1om3Zsr.mjs";
|
|
3
3
|
import { AsyncModuleOptions, DynamicModule } from "stratal/module";
|
|
4
4
|
import { ApplicationError, HttpException } from "stratal/errors";
|
|
5
5
|
import { Middleware, Next, RouteConfigurable, Router, RouterContext } from "stratal/router";
|
|
6
6
|
import { LoggerService } from "stratal/logger";
|
|
7
7
|
import { APIError } from "better-auth/api";
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import { BetterAuthOptions } from "better-auth";
|
|
10
9
|
//#region src/context/router-context.augment.d.ts
|
|
11
10
|
declare module 'stratal/router' {
|
|
12
11
|
interface RouterContext {
|
|
@@ -18,22 +17,26 @@ declare module 'stratal/router' {
|
|
|
18
17
|
*/
|
|
19
18
|
user(): AuthUser;
|
|
20
19
|
}
|
|
21
|
-
}
|
|
20
|
+
}
|
|
22
21
|
//#endregion
|
|
23
22
|
//#region src/auth/auth.module.d.ts
|
|
24
|
-
interface AuthModuleAsyncOptions<TOptions extends BetterAuthOptions = BetterAuthOptions> extends AsyncModuleOptions<TOptions> {
|
|
23
|
+
export interface AuthModuleAsyncOptions<TOptions extends BetterAuthOptions = BetterAuthOptions> extends AsyncModuleOptions<TOptions> {
|
|
25
24
|
/**
|
|
26
25
|
* Optional access control configuration.
|
|
27
26
|
* When provided, registers AccessService and auto-adds the Stratal AC plugin to Better Auth.
|
|
28
27
|
*/
|
|
29
28
|
accessControl?: AccessControlOptions;
|
|
30
29
|
}
|
|
31
|
-
declare class AuthModule implements RouteConfigurable {
|
|
30
|
+
export declare class AuthModule implements RouteConfigurable {
|
|
32
31
|
/**
|
|
33
32
|
* Configure auth middleware globally.
|
|
34
33
|
*
|
|
35
34
|
* SessionVerificationMiddleware verifies the session and populates the
|
|
36
35
|
* request-scoped AuthContext with the authenticated user.
|
|
36
|
+
*
|
|
37
|
+
* AccessShareMiddleware then shares the resulting roles and permissions to
|
|
38
|
+
* Inertia. Order matters: it reads what session verification wrote. Both
|
|
39
|
+
* no-op when their dependencies are absent.
|
|
37
40
|
*/
|
|
38
41
|
configureRoutes(router: Router): void;
|
|
39
42
|
/**
|
|
@@ -49,214 +52,213 @@ declare class AuthModule implements RouteConfigurable {
|
|
|
49
52
|
static forRootAsync<TOptions extends BetterAuthOptions>(options: AuthModuleAsyncOptions<TOptions>): DynamicModule;
|
|
50
53
|
}
|
|
51
54
|
//#endregion
|
|
55
|
+
//#region src/auth/middleware/session-verification.middleware.d.ts
|
|
56
|
+
/**
|
|
57
|
+
* Session Verification Middleware
|
|
58
|
+
*
|
|
59
|
+
* Verifies user session via Better Auth and populates AuthContext with
|
|
60
|
+
* the authenticated user.
|
|
61
|
+
*
|
|
62
|
+
* **Responsibilities:**
|
|
63
|
+
* - Calls Better Auth's getSession() API
|
|
64
|
+
* - Populates AuthContext with the user record if the session is valid
|
|
65
|
+
* - Carries any cookie that read issued through to the response
|
|
66
|
+
* - Continues request chain regardless of session status
|
|
67
|
+
*/
|
|
68
|
+
export declare class SessionVerificationMiddleware implements Middleware {
|
|
69
|
+
private readonly authService;
|
|
70
|
+
private logger;
|
|
71
|
+
constructor(authService: AuthService, logger: LoggerService);
|
|
72
|
+
handle(ctx: RouterContext, next: Next): Promise<Response | void>;
|
|
73
|
+
}
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region src/auth/auth.primers.d.ts
|
|
76
|
+
/**
|
|
77
|
+
* Middleware the response-cache gateway must run before resolving partitions.
|
|
78
|
+
*
|
|
79
|
+
* `ctx.user()` reads the request-scoped `AuthContext`, which
|
|
80
|
+
* `SessionVerificationMiddleware` populates. The gateway runs outside the
|
|
81
|
+
* app's middleware chain, so without this a partition resolver calling
|
|
82
|
+
* `ctx.user()` would throw `UserNotAuthenticatedError` on every request.
|
|
83
|
+
*
|
|
84
|
+
* Pass it alongside `gateway: { entrypoint }` — `primers` without a configured
|
|
85
|
+
* gateway is a boot error, because nothing would ever run the middleware
|
|
86
|
+
* listed here.
|
|
87
|
+
*
|
|
88
|
+
* The cost lands in the primer, not the accessor: `ctx.user()` is a memory
|
|
89
|
+
* read, while `SessionVerificationMiddleware` calls
|
|
90
|
+
* `authService.auth.api.getSession()`. On a cache **miss** that call happens
|
|
91
|
+
* twice — once in the gateway to resolve the partition, once in the app's own
|
|
92
|
+
* chain, since each runs in its own request scope. On a **hit** the app never
|
|
93
|
+
* runs, so only the gateway's single call is paid.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```typescript
|
|
97
|
+
* ResponseCacheModule.forRoot({
|
|
98
|
+
* gateway: { entrypoint: 'Cached' },
|
|
99
|
+
* primers: AUTH_GATEWAY_PRIMERS,
|
|
100
|
+
* partitions: { user: (ctx) => ctx.user().id },
|
|
101
|
+
* })
|
|
102
|
+
* ```
|
|
103
|
+
*/
|
|
104
|
+
export declare const AUTH_GATEWAY_PRIMERS: readonly [typeof SessionVerificationMiddleware];
|
|
105
|
+
//#endregion
|
|
52
106
|
//#region src/auth/auth.tokens.d.ts
|
|
53
107
|
/** Token for AuthService - core authentication service */
|
|
54
|
-
declare const AUTH_SERVICE: unique symbol;
|
|
108
|
+
export declare const AUTH_SERVICE: unique symbol;
|
|
55
109
|
/** Token for Better Auth options configuration */
|
|
56
|
-
declare const AUTH_OPTIONS: unique symbol;
|
|
110
|
+
export declare const AUTH_OPTIONS: unique symbol;
|
|
57
111
|
//#endregion
|
|
58
112
|
//#region src/auth/errors/auth-errors.d.ts
|
|
59
|
-
declare class UserNotFoundError extends HttpException {
|
|
113
|
+
export declare class UserNotFoundError extends HttpException {
|
|
60
114
|
readonly email?: string | undefined;
|
|
61
115
|
constructor(email?: string | undefined);
|
|
62
116
|
}
|
|
63
|
-
declare class InvalidCredentialsError extends HttpException {
|
|
117
|
+
export declare class InvalidCredentialsError extends HttpException {
|
|
64
118
|
constructor();
|
|
65
119
|
}
|
|
66
|
-
declare class InvalidPasswordError extends HttpException {
|
|
120
|
+
export declare class InvalidPasswordError extends HttpException {
|
|
67
121
|
constructor();
|
|
68
122
|
}
|
|
69
|
-
declare class InvalidEmailError extends HttpException {
|
|
123
|
+
export declare class InvalidEmailError extends HttpException {
|
|
70
124
|
readonly email?: string | undefined;
|
|
71
125
|
constructor(email?: string | undefined);
|
|
72
126
|
}
|
|
73
|
-
declare class SessionExpiredError extends HttpException {
|
|
127
|
+
export declare class SessionExpiredError extends HttpException {
|
|
74
128
|
constructor();
|
|
75
129
|
}
|
|
76
|
-
declare class FreshSessionRequiredError extends HttpException {
|
|
130
|
+
export declare class FreshSessionRequiredError extends HttpException {
|
|
77
131
|
constructor();
|
|
78
132
|
}
|
|
79
|
-
declare class EmailNotVerifiedError extends HttpException {
|
|
133
|
+
export declare class EmailNotVerifiedError extends HttpException {
|
|
80
134
|
readonly email?: string | undefined;
|
|
81
135
|
constructor(email?: string | undefined);
|
|
82
136
|
}
|
|
83
|
-
declare class PasswordTooShortError extends HttpException {
|
|
137
|
+
export declare class PasswordTooShortError extends HttpException {
|
|
84
138
|
readonly minLength?: number | undefined;
|
|
85
139
|
constructor(minLength?: number | undefined);
|
|
86
140
|
}
|
|
87
|
-
declare class PasswordTooLongError extends HttpException {
|
|
141
|
+
export declare class PasswordTooLongError extends HttpException {
|
|
88
142
|
readonly maxLength?: number | undefined;
|
|
89
143
|
constructor(maxLength?: number | undefined);
|
|
90
144
|
}
|
|
91
|
-
declare class AccountAlreadyExistsError extends HttpException {
|
|
145
|
+
export declare class AccountAlreadyExistsError extends HttpException {
|
|
92
146
|
readonly email?: string | undefined;
|
|
93
147
|
constructor(email?: string | undefined);
|
|
94
148
|
}
|
|
95
|
-
declare class SocialAccountLinkedError extends HttpException {
|
|
149
|
+
export declare class SocialAccountLinkedError extends HttpException {
|
|
96
150
|
readonly provider?: string | undefined;
|
|
97
151
|
constructor(provider?: string | undefined);
|
|
98
152
|
}
|
|
99
|
-
declare class CannotUnlinkLastAccountError extends HttpException {
|
|
153
|
+
export declare class CannotUnlinkLastAccountError extends HttpException {
|
|
100
154
|
constructor();
|
|
101
155
|
}
|
|
102
|
-
declare class ProviderNotFoundError extends HttpException {
|
|
156
|
+
export declare class ProviderNotFoundError extends HttpException {
|
|
103
157
|
readonly provider?: string | undefined;
|
|
104
158
|
constructor(provider?: string | undefined);
|
|
105
159
|
}
|
|
106
|
-
declare class UserEmailNotFoundError extends HttpException {
|
|
160
|
+
export declare class UserEmailNotFoundError extends HttpException {
|
|
107
161
|
constructor();
|
|
108
162
|
}
|
|
109
|
-
declare class AccountNotFoundError extends HttpException {
|
|
163
|
+
export declare class AccountNotFoundError extends HttpException {
|
|
110
164
|
constructor();
|
|
111
165
|
}
|
|
112
|
-
declare class CredentialAccountNotFoundError extends HttpException {
|
|
166
|
+
export declare class CredentialAccountNotFoundError extends HttpException {
|
|
113
167
|
constructor();
|
|
114
168
|
}
|
|
115
|
-
declare class UserAlreadyHasPasswordError extends HttpException {
|
|
169
|
+
export declare class UserAlreadyHasPasswordError extends HttpException {
|
|
116
170
|
constructor();
|
|
117
171
|
}
|
|
118
|
-
declare class EmailCannotBeUpdatedError extends HttpException {
|
|
172
|
+
export declare class EmailCannotBeUpdatedError extends HttpException {
|
|
119
173
|
readonly reason?: string | undefined;
|
|
120
174
|
constructor(reason?: string | undefined);
|
|
121
175
|
}
|
|
122
|
-
declare class IdTokenNotSupportedError extends HttpException {
|
|
176
|
+
export declare class IdTokenNotSupportedError extends HttpException {
|
|
123
177
|
constructor();
|
|
124
178
|
}
|
|
125
|
-
declare class TokenExpiredError extends HttpException {
|
|
179
|
+
export declare class TokenExpiredError extends HttpException {
|
|
126
180
|
constructor();
|
|
127
181
|
}
|
|
128
|
-
declare class InvalidCallbackUrlError extends HttpException {
|
|
182
|
+
export declare class InvalidCallbackUrlError extends HttpException {
|
|
129
183
|
constructor();
|
|
130
184
|
}
|
|
131
|
-
declare class InvalidOriginError extends HttpException {
|
|
185
|
+
export declare class InvalidOriginError extends HttpException {
|
|
132
186
|
constructor();
|
|
133
187
|
}
|
|
134
|
-
declare class AuthValidationFailedError extends HttpException {
|
|
188
|
+
export declare class AuthValidationFailedError extends HttpException {
|
|
135
189
|
constructor();
|
|
136
190
|
}
|
|
137
|
-
declare class EmailAlreadyVerifiedError extends HttpException {
|
|
191
|
+
export declare class EmailAlreadyVerifiedError extends HttpException {
|
|
138
192
|
constructor();
|
|
139
193
|
}
|
|
140
|
-
declare class EmailMismatchError extends HttpException {
|
|
194
|
+
export declare class EmailMismatchError extends HttpException {
|
|
141
195
|
constructor();
|
|
142
196
|
}
|
|
143
197
|
//#endregion
|
|
144
198
|
//#region src/auth/errors/invalid-token.error.d.ts
|
|
145
|
-
declare class InvalidTokenError extends HttpException {
|
|
199
|
+
export declare class InvalidTokenError extends HttpException {
|
|
146
200
|
constructor();
|
|
147
201
|
}
|
|
148
202
|
//#endregion
|
|
149
203
|
//#region src/auth/errors/organization-errors.d.ts
|
|
150
|
-
declare class OrganizationNotFoundError extends HttpException {
|
|
204
|
+
export declare class OrganizationNotFoundError extends HttpException {
|
|
151
205
|
constructor();
|
|
152
206
|
}
|
|
153
|
-
declare class OrganizationMemberNotFoundError extends HttpException {
|
|
207
|
+
export declare class OrganizationMemberNotFoundError extends HttpException {
|
|
154
208
|
constructor();
|
|
155
209
|
}
|
|
156
|
-
declare class OrganizationInvitationNotFoundError extends HttpException {
|
|
210
|
+
export declare class OrganizationInvitationNotFoundError extends HttpException {
|
|
157
211
|
constructor();
|
|
158
212
|
}
|
|
159
|
-
declare class OrganizationPermissionDeniedError extends HttpException {
|
|
213
|
+
export declare class OrganizationPermissionDeniedError extends HttpException {
|
|
160
214
|
constructor();
|
|
161
215
|
}
|
|
162
|
-
declare class OrganizationInvitationRecipientMismatchError extends HttpException {
|
|
216
|
+
export declare class OrganizationInvitationRecipientMismatchError extends HttpException {
|
|
163
217
|
constructor();
|
|
164
218
|
}
|
|
165
|
-
declare class OrganizationConflictError extends HttpException {
|
|
219
|
+
export declare class OrganizationConflictError extends HttpException {
|
|
166
220
|
constructor();
|
|
167
221
|
}
|
|
168
|
-
declare class OrganizationLimitReachedError extends HttpException {
|
|
222
|
+
export declare class OrganizationLimitReachedError extends HttpException {
|
|
169
223
|
constructor();
|
|
170
224
|
}
|
|
171
|
-
declare class OrganizationMembershipError extends HttpException {
|
|
225
|
+
export declare class OrganizationMembershipError extends HttpException {
|
|
172
226
|
constructor();
|
|
173
227
|
}
|
|
174
|
-
declare class OrganizationTeamNotFoundError extends HttpException {
|
|
228
|
+
export declare class OrganizationTeamNotFoundError extends HttpException {
|
|
175
229
|
constructor();
|
|
176
230
|
}
|
|
177
|
-
declare class OrganizationRoleNotFoundError extends HttpException {
|
|
231
|
+
export declare class OrganizationRoleNotFoundError extends HttpException {
|
|
178
232
|
constructor();
|
|
179
233
|
}
|
|
180
234
|
//#endregion
|
|
181
235
|
//#region src/auth/errors/token-required.error.d.ts
|
|
182
|
-
declare class TokenRequiredError extends HttpException {
|
|
236
|
+
export declare class TokenRequiredError extends HttpException {
|
|
183
237
|
constructor();
|
|
184
238
|
}
|
|
185
239
|
//#endregion
|
|
186
|
-
//#region src/auth/services/auth.service.d.ts
|
|
187
|
-
/**
|
|
188
|
-
* AuthService
|
|
189
|
-
*
|
|
190
|
-
* Base authentication service using Better Auth.
|
|
191
|
-
* Configured via AuthModule.forRootAsync() from the application layer.
|
|
192
|
-
*
|
|
193
|
-
* **Extensibility:**
|
|
194
|
-
* Extend this class to add custom methods. Subclasses inherit
|
|
195
|
-
* `@Request(AUTH_SERVICE)` scope automatically — no decorator needed.
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```typescript
|
|
199
|
-
* @Request(AUTH_SERVICE)
|
|
200
|
-
* export class AppAuthService extends AuthService<AuthOptions> {
|
|
201
|
-
* async signInMagicLink(email: string) {
|
|
202
|
-
* return wrapBetterAuth(async () => {
|
|
203
|
-
* return this.auth.api.signInMagicLink({ body: { email }, headers: new Headers() })
|
|
204
|
-
* })
|
|
205
|
-
* }
|
|
206
|
-
* }
|
|
207
|
-
* ```
|
|
208
|
-
*/
|
|
209
|
-
declare class AuthService<TOptions extends BetterAuthOptions = BetterAuthOptions> {
|
|
210
|
-
protected readonly options: TOptions;
|
|
211
|
-
private _authInstance?;
|
|
212
|
-
constructor(options: TOptions);
|
|
213
|
-
/**
|
|
214
|
-
* Get the Better Auth instance.
|
|
215
|
-
*/
|
|
216
|
-
get auth(): Auth<TOptions>;
|
|
217
|
-
}
|
|
218
|
-
//#endregion
|
|
219
|
-
//#region src/auth/middleware/session-verification.middleware.d.ts
|
|
220
|
-
/**
|
|
221
|
-
* Session Verification Middleware
|
|
222
|
-
*
|
|
223
|
-
* Verifies user session via Better Auth and populates AuthContext with
|
|
224
|
-
* the authenticated user.
|
|
225
|
-
*
|
|
226
|
-
* **Responsibilities:**
|
|
227
|
-
* - Calls Better Auth's getSession() API
|
|
228
|
-
* - Populates AuthContext with the user record if the session is valid
|
|
229
|
-
* - Continues request chain regardless of session status
|
|
230
|
-
*/
|
|
231
|
-
declare class SessionVerificationMiddleware implements Middleware {
|
|
232
|
-
private readonly authService;
|
|
233
|
-
private logger;
|
|
234
|
-
constructor(authService: AuthService, logger: LoggerService);
|
|
235
|
-
handle(ctx: RouterContext, next: Next): Promise<void>;
|
|
236
|
-
}
|
|
237
|
-
//#endregion
|
|
238
240
|
//#region src/auth/utils/auth-helpers.d.ts
|
|
239
241
|
/**
|
|
240
242
|
* Get shared Better Auth error handler configuration.
|
|
241
243
|
* Use this in Better Auth config's onAPIError option.
|
|
242
244
|
*/
|
|
243
|
-
declare function getErrorHandlerConfig(): BetterAuthOptions['onAPIError'];
|
|
245
|
+
export declare function getErrorHandlerConfig(): BetterAuthOptions['onAPIError'];
|
|
244
246
|
/**
|
|
245
247
|
* Wrap a Better Auth function in a try/catch block and map errors to ApplicationError.
|
|
246
248
|
*/
|
|
247
|
-
declare const wrapBetterAuth: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
249
|
+
export declare const wrapBetterAuth: <T>(fn: () => Promise<T>) => Promise<T>;
|
|
248
250
|
//#endregion
|
|
249
251
|
//#region src/auth/utils/better-auth-error-handler.d.ts
|
|
250
252
|
/**
|
|
251
253
|
* Maps Better Auth API error codes to ApplicationError instances.
|
|
252
254
|
*/
|
|
253
|
-
declare function mapBetterAuthError(error: APIError): ApplicationError;
|
|
255
|
+
export declare function mapBetterAuthError(error: APIError): ApplicationError;
|
|
254
256
|
/**
|
|
255
257
|
* Type guard to check if an error is a Better Auth APIError.
|
|
256
258
|
* Uses duck typing to handle bundler environments (e.g. Vite)
|
|
257
259
|
* where instanceof may fail across module boundaries.
|
|
258
260
|
*/
|
|
259
|
-
declare function isAPIError(error: unknown): error is APIError;
|
|
261
|
+
export declare function isAPIError(error: unknown): error is APIError;
|
|
260
262
|
//#endregion
|
|
261
|
-
export {
|
|
263
|
+
export { AuthService };
|
|
262
264
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/context/router-context.augment.ts","../../src/auth/auth.module.ts","../../src/auth/
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/context/router-context.augment.ts","../../src/auth/auth.module.ts","../../src/auth/middleware/session-verification.middleware.ts","../../src/auth/auth.primers.ts","../../src/auth/auth.tokens.ts","../../src/auth/errors/auth-errors.ts","../../src/auth/errors/invalid-token.error.ts","../../src/auth/errors/organization-errors.ts","../../src/auth/errors/token-required.error.ts","../../src/auth/utils/auth-helpers.ts","../../src/auth/utils/better-auth-error-handler.ts"],"mappings":";;;;;;;;;;YAaY;;;;;;;IAOR,QAAQ;;;;;iBCsDK,uBAAuB,iBAAiB,oBAAoB,2BACnE,mBAAmB;;;;;EAK3B,gBAAgB;;qBAML,sBAAsB;;;;;;;;;;;EAWjC,gBAAgB,QAAQ;;;;;;;;;;;SAejB,aAAa,iBAAiB,mBACnC,SAAS,uBAAuB,YAC/B;;;;;;;;;;;;;;;;qBCxFQ,yCAAyC;mBAGjC;UAC4B;EAH/C,YAEmB,aAAa,aACe,QAAQ;EAGjD,OAAO,KAAK,eAAe,MAAM,OAAO,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBCH3C,uCAAoB;;;;qBC7BpB;;qBAGA;;;qBCFA,0BAA0B;WACT;EAA5B,YAA4B;;qBAKjB,gCAAgC;EAC3C;;qBAGW,6BAA6B;EACxC;;qBAGW,0BAA0B;WACT;EAA5B,YAA4B;;qBAKjB,4BAA4B;EACvC;;qBAGW,kCAAkC;EAC7C;;qBAGW,8BAA8B;WACb;EAA5B,YAA4B;;qBAKjB,8BAA8B;WACb;EAA5B,YAA4B;;qBAKjB,6BAA6B;WACZ;EAA5B,YAA4B;;qBAKjB,kCAAkC;WACjB;EAA5B,YAA4B;;qBAKjB,iCAAiC;WAChB;EAA5B,YAA4B;;qBAKjB,qCAAqC;EAChD;;qBAGW,8BAA8B;WACb;EAA5B,YAA4B;;qBAKjB,+BAA+B;EAC1C;;qBAGW,6BAA6B;EACxC;;qBAGW,uCAAuC;EAClD;;qBAGW,oCAAoC;EAC/C;;qBAGW,kCAAkC;WACjB;EAA5B,YAA4B;;qBAKjB,iCAAiC;EAC5C;;qBAGW,0BAA0B;EACrC;;qBAGW,gCAAgC;EAC3C;;qBAGW,2BAA2B;EACtC;;qBAGW,kCAAkC;EAC7C;;qBAGW,kCAAkC;EAC7C;;qBAGW,2BAA2B;EACtC;;;;qBCnHW,0BAA0B;EACrC;;;;qBCDW,kCAAkC;EAC7C;;qBAEW,wCAAwC;EACnD;;qBAEW,4CAA4C;EACvD;;qBAEW,0CAA0C;EACrD;;qBAEW,qDAAqD;EAChE;;qBAEW,kCAAkC;EAC7C;;qBAEW,sCAAsC;EACjD;;qBAEW,oCAAoC;EAC/C;;qBAEW,sCAAsC;EACjD;;qBAEW,sCAAsC;EACjD;;;;qBC5BW,2BAA2B;EACtC;;;;;;;;wBCIc,yBAAyB;;;;qBAe5B,iBAAwB,GAAC,UAAY,QAAQ,OAAK,QAAQ;;;;;;wBCuBvD,mBAAmB,OAAO,WAAW;;;;;;wBAkNrC,WAAW,iBAAiB,SAAS"}
|
package/dist/auth/index.mjs
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import {
|
|
3
|
-
import { t as
|
|
4
|
-
import { t as AuthContext } from "../auth-context-
|
|
1
|
+
import { n as AC_TOKENS, t as __decorateParam } from "../decorateParam-xwTkq9gO.mjs";
|
|
2
|
+
import { t as __decorate } from "../decorate-RQD1h28J.mjs";
|
|
3
|
+
import { a as AccessShareMiddleware, i as createStratalAcPlugin, n as AUTH_OPTIONS, r as AUTH_SERVICE, t as AccessService } from "../access.service-BjmnWBEo.mjs";
|
|
4
|
+
import { t as AuthContext } from "../auth-context-cNSS1rmh.mjs";
|
|
5
5
|
import { CONTAINER_TOKEN, DI_TOKENS, Request, Transient, inject } from "stratal/di";
|
|
6
6
|
import { Module } from "stratal/module";
|
|
7
7
|
import { RATE_LIMITER_TOKENS, RateLimiterRegistry } from "stratal/rate-limiter";
|
|
8
8
|
import { AuthError, HttpException } from "stratal/errors";
|
|
9
9
|
import { RouterContext } from "stratal/router";
|
|
10
|
+
import { parseSetCookieHeader } from "better-auth/cookies";
|
|
10
11
|
import { LOGGER_TOKENS } from "stratal/logger";
|
|
11
12
|
import { betterAuth } from "better-auth/minimal";
|
|
12
13
|
import { APIError } from "better-auth/api";
|
|
@@ -23,13 +24,11 @@ RouterContext.macro("user", function() {
|
|
|
23
24
|
return this.getContainer().resolve(DI_TOKENS.AuthContext).requireUser();
|
|
24
25
|
});
|
|
25
26
|
//#endregion
|
|
26
|
-
//#region src/auth/auth.tokens.ts
|
|
27
|
-
/** Token for AuthService - core authentication service */
|
|
28
|
-
const AUTH_SERVICE = Symbol.for("stratal:auth:service");
|
|
29
|
-
/** Token for Better Auth options configuration */
|
|
30
|
-
const AUTH_OPTIONS = Symbol.for("stratal:auth:options");
|
|
31
|
-
//#endregion
|
|
32
27
|
//#region src/auth/middleware/session-verification.middleware.ts
|
|
28
|
+
/** Every cookie name a `Set-Cookie` value assigns, read with Better Auth's own parser. */
|
|
29
|
+
function namesIn(setCookie) {
|
|
30
|
+
return [...parseSetCookieHeader(setCookie).keys()];
|
|
31
|
+
}
|
|
33
32
|
let SessionVerificationMiddleware = class SessionVerificationMiddleware {
|
|
34
33
|
authService;
|
|
35
34
|
logger;
|
|
@@ -38,13 +37,45 @@ let SessionVerificationMiddleware = class SessionVerificationMiddleware {
|
|
|
38
37
|
this.logger = logger;
|
|
39
38
|
}
|
|
40
39
|
async handle(ctx, next) {
|
|
40
|
+
/**
|
|
41
|
+
* The cookies Better Auth wrote while reading the session.
|
|
42
|
+
*
|
|
43
|
+
* Reading one is not always free of side effects: under `session.cookieCache`
|
|
44
|
+
* it mints the cached-session cookie, and once past `session.updateAge` it
|
|
45
|
+
* reissues the session cookie against the extended expiry. Both are `Set-Cookie`
|
|
46
|
+
* on a response Better Auth builds internally, which is discarded unless asked
|
|
47
|
+
* for — so left unforwarded, the cache is written on every request and read on
|
|
48
|
+
* none, and a sliding expiry never reaches the browser at all.
|
|
49
|
+
*/
|
|
50
|
+
let issued = [];
|
|
41
51
|
try {
|
|
42
|
-
const
|
|
43
|
-
|
|
52
|
+
const { headers, response } = await this.authService.auth.api.getSession({
|
|
53
|
+
headers: ctx.c.req.raw.headers,
|
|
54
|
+
returnHeaders: true
|
|
55
|
+
});
|
|
56
|
+
if (response) ctx.getContainer().resolve(DI_TOKENS.AuthContext).setAuthContext({ user: response.user });
|
|
57
|
+
issued = headers.getSetCookie();
|
|
44
58
|
} catch (error) {
|
|
45
59
|
this.logger.debug("Session validation failed (e.g., invalidated in DB)", { error });
|
|
46
60
|
}
|
|
47
|
-
|
|
61
|
+
await next();
|
|
62
|
+
if (issued.length === 0) return;
|
|
63
|
+
const status = ctx.c.res?.status;
|
|
64
|
+
if (typeof status !== "number" || status < 200 || status > 599) return;
|
|
65
|
+
/**
|
|
66
|
+
* A name the handler has already spoken for, which this must not overwrite.
|
|
67
|
+
*
|
|
68
|
+
* Sign-out is the case that makes this load-bearing rather than tidy. The session
|
|
69
|
+
* is still valid when it is read, so a cached-session cookie can be minted on the
|
|
70
|
+
* way in; the handler then clears that same cookie on the way out. Appending
|
|
71
|
+
* afterwards would put it back — a signed-out browser holding a cached session,
|
|
72
|
+
* which is the one thing the cache must never survive.
|
|
73
|
+
*/
|
|
74
|
+
const spokenFor = new Set(ctx.c.res.headers.getSetCookie().flatMap(namesIn));
|
|
75
|
+
for (const cookie of issued) {
|
|
76
|
+
if (namesIn(cookie).some((name) => spokenFor.has(name))) continue;
|
|
77
|
+
ctx.c.header("set-cookie", cookie, { append: true });
|
|
78
|
+
}
|
|
48
79
|
}
|
|
49
80
|
};
|
|
50
81
|
SessionVerificationMiddleware = __decorate([
|
|
@@ -95,22 +126,54 @@ RateLimiterRegistry.macro("forPath", function(path, resolver) {
|
|
|
95
126
|
RateLimiterRegistry.macro("pathEntries", function() {
|
|
96
127
|
return (pathResolvers.get(this) ?? /* @__PURE__ */ new Map()).entries();
|
|
97
128
|
});
|
|
98
|
-
const BETTER_AUTH_TTL_SECONDS = 86400;
|
|
99
129
|
const BETTER_AUTH_KEY_PREFIX = "ba-rl:";
|
|
100
130
|
/**
|
|
101
131
|
* Adapt Stratal's `IRateLimiterStore` into better-auth's `customStorage` shape.
|
|
102
|
-
*
|
|
103
|
-
*
|
|
132
|
+
*
|
|
133
|
+
* Better-auth requires a single atomic `consume(key, rule)` rather than the
|
|
134
|
+
* separate `get`/`set` pair it used to accept, because a split read and write
|
|
135
|
+
* cannot hold a limit under concurrent requests. `IRateLimiterStore` is a plain
|
|
136
|
+
* typed KV with no compare-and-set, so this is better-auth's documented
|
|
137
|
+
* read-decide-write fallback for backends lacking an atomic primitive, and the
|
|
138
|
+
* decision below mirrors their reference implementation exactly.
|
|
139
|
+
*
|
|
140
|
+
* Accuracy therefore follows the configured store, and matches what Stratal's
|
|
141
|
+
* own throttling already does on the same backend: exact on
|
|
142
|
+
* `InMemoryRateLimiterStore` (read-decide-write is atomic in a single isolate),
|
|
143
|
+
* best-effort on `KvRateLimiterStore`, where concurrent writes from different
|
|
144
|
+
* edge locations may undercount. Register a Durable Object store for strict
|
|
145
|
+
* accuracy across edges — the same escape hatch the KV store documents.
|
|
104
146
|
*/
|
|
105
147
|
function createBetterAuthRateLimitStorage(store) {
|
|
106
|
-
return {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
148
|
+
return { async consume(key, rule) {
|
|
149
|
+
const storageKey = `${BETTER_AUTH_KEY_PREFIX}${key}`;
|
|
150
|
+
const windowMs = rule.window * 1e3;
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
const record = await store.get(storageKey);
|
|
153
|
+
const write = async (count, lastRequest) => {
|
|
154
|
+
await store.set(storageKey, {
|
|
155
|
+
key,
|
|
156
|
+
count,
|
|
157
|
+
lastRequest
|
|
158
|
+
}, rule.window);
|
|
159
|
+
};
|
|
160
|
+
if (!record || now - record.lastRequest >= windowMs) {
|
|
161
|
+
await write(1, now);
|
|
162
|
+
return {
|
|
163
|
+
allowed: true,
|
|
164
|
+
retryAfter: null
|
|
165
|
+
};
|
|
112
166
|
}
|
|
113
|
-
|
|
167
|
+
if (record.count >= rule.max) return {
|
|
168
|
+
allowed: false,
|
|
169
|
+
retryAfter: Math.ceil((record.lastRequest + windowMs - now) / 1e3)
|
|
170
|
+
};
|
|
171
|
+
await write(record.count + 1, now);
|
|
172
|
+
return {
|
|
173
|
+
allowed: true,
|
|
174
|
+
retryAfter: null
|
|
175
|
+
};
|
|
176
|
+
} };
|
|
114
177
|
}
|
|
115
178
|
/**
|
|
116
179
|
* Project every `forPath` entry on the registry into better-auth's
|
|
@@ -471,9 +534,14 @@ let AuthModule = _AuthModule = class AuthModule {
|
|
|
471
534
|
*
|
|
472
535
|
* SessionVerificationMiddleware verifies the session and populates the
|
|
473
536
|
* request-scoped AuthContext with the authenticated user.
|
|
537
|
+
*
|
|
538
|
+
* AccessShareMiddleware then shares the resulting roles and permissions to
|
|
539
|
+
* Inertia. Order matters: it reads what session verification wrote. Both
|
|
540
|
+
* no-op when their dependencies are absent.
|
|
474
541
|
*/
|
|
475
542
|
configureRoutes(router) {
|
|
476
543
|
router.use(SessionVerificationMiddleware);
|
|
544
|
+
router.use(AccessShareMiddleware);
|
|
477
545
|
}
|
|
478
546
|
/**
|
|
479
547
|
* Configure AuthModule with async options factory.
|
|
@@ -538,6 +606,37 @@ let AuthModule = _AuthModule = class AuthModule {
|
|
|
538
606
|
};
|
|
539
607
|
AuthModule = _AuthModule = __decorate([Module({ providers: [AuthContext] })], AuthModule);
|
|
540
608
|
//#endregion
|
|
541
|
-
|
|
609
|
+
//#region src/auth/auth.primers.ts
|
|
610
|
+
/**
|
|
611
|
+
* Middleware the response-cache gateway must run before resolving partitions.
|
|
612
|
+
*
|
|
613
|
+
* `ctx.user()` reads the request-scoped `AuthContext`, which
|
|
614
|
+
* `SessionVerificationMiddleware` populates. The gateway runs outside the
|
|
615
|
+
* app's middleware chain, so without this a partition resolver calling
|
|
616
|
+
* `ctx.user()` would throw `UserNotAuthenticatedError` on every request.
|
|
617
|
+
*
|
|
618
|
+
* Pass it alongside `gateway: { entrypoint }` — `primers` without a configured
|
|
619
|
+
* gateway is a boot error, because nothing would ever run the middleware
|
|
620
|
+
* listed here.
|
|
621
|
+
*
|
|
622
|
+
* The cost lands in the primer, not the accessor: `ctx.user()` is a memory
|
|
623
|
+
* read, while `SessionVerificationMiddleware` calls
|
|
624
|
+
* `authService.auth.api.getSession()`. On a cache **miss** that call happens
|
|
625
|
+
* twice — once in the gateway to resolve the partition, once in the app's own
|
|
626
|
+
* chain, since each runs in its own request scope. On a **hit** the app never
|
|
627
|
+
* runs, so only the gateway's single call is paid.
|
|
628
|
+
*
|
|
629
|
+
* @example
|
|
630
|
+
* ```typescript
|
|
631
|
+
* ResponseCacheModule.forRoot({
|
|
632
|
+
* gateway: { entrypoint: 'Cached' },
|
|
633
|
+
* primers: AUTH_GATEWAY_PRIMERS,
|
|
634
|
+
* partitions: { user: (ctx) => ctx.user().id },
|
|
635
|
+
* })
|
|
636
|
+
* ```
|
|
637
|
+
*/
|
|
638
|
+
const AUTH_GATEWAY_PRIMERS = [SessionVerificationMiddleware];
|
|
639
|
+
//#endregion
|
|
640
|
+
export { AUTH_GATEWAY_PRIMERS, AUTH_OPTIONS, AUTH_SERVICE, AccountAlreadyExistsError, AccountNotFoundError, AuthModule, AuthService, AuthValidationFailedError, CannotUnlinkLastAccountError, CredentialAccountNotFoundError, EmailAlreadyVerifiedError, EmailCannotBeUpdatedError, EmailMismatchError, EmailNotVerifiedError, FreshSessionRequiredError, IdTokenNotSupportedError, InvalidCallbackUrlError, InvalidCredentialsError, InvalidEmailError, InvalidOriginError, InvalidPasswordError, InvalidTokenError, OrganizationConflictError, OrganizationInvitationNotFoundError, OrganizationInvitationRecipientMismatchError, OrganizationLimitReachedError, OrganizationMemberNotFoundError, OrganizationMembershipError, OrganizationNotFoundError, OrganizationPermissionDeniedError, OrganizationRoleNotFoundError, OrganizationTeamNotFoundError, PasswordTooLongError, PasswordTooShortError, ProviderNotFoundError, SessionExpiredError, SessionVerificationMiddleware, SocialAccountLinkedError, TokenExpiredError, TokenRequiredError, UserAlreadyHasPasswordError, UserEmailNotFoundError, UserNotFoundError, getErrorHandlerConfig, isAPIError, mapBetterAuthError, wrapBetterAuth };
|
|
542
641
|
|
|
543
642
|
//# sourceMappingURL=index.mjs.map
|