auth-vir 5.1.0 → 5.2.1

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/README.md CHANGED
@@ -54,7 +54,7 @@ For the easiest usage, construct and use `BackendAuthClient` on your server and
54
54
  Use this on your host / server / backend to authenticate client / frontend requests.
55
55
 
56
56
  1. Expose the [`AuthHeaderName.CsrfToken`](https://electrovir.github.io/auth-vir/variables/AuthHeaderName.html) (or just `'csrf-token'`) header via CORS headers with either of the following options:
57
- 1. Set `customHeaders: [AuthHeaderName.CsrfToken]` in `implementService` from [`@rest-vir/implement-service`](https://www.npmjs.com/package/@rest-vir/implement-service).
57
+ 1. Set `customHeaders: [AuthHeaderName.CsrfToken]` in `implementApi` from [`@rest-vir/host`](https://www.npmjs.com/package/@rest-vir/host).
58
58
  2. Set the header `Access-Control-Allow-Headers` to (at least) `AuthHeaderName.CsrfToken`.
59
59
  2. Set the `Access-Control-Allow-Origin` header (it cannot be `*`) and properly implement CORS headers and responses.
60
60
  3. Generate JWT signing and encryption keys with one of the following:
@@ -156,12 +156,12 @@ export async function createUser(
156
156
  */
157
157
  export async function getAuthenticatedUser(request: ClientRequest) {
158
158
  const userId = (
159
- await extractUserIdFromRequestHeaders<MyUserId>(
160
- request.getHeaders(),
159
+ await extractUserIdFromRequestHeaders<MyUserId>({
160
+ headers: request.getHeaders(),
161
161
  jwtParams,
162
- csrfOption,
163
- AuthCookie.Auth,
164
- )
162
+ csrfHeaderNameOption: csrfOption,
163
+ cookieName: AuthCookie.Auth,
164
+ })
165
165
  )?.userId;
166
166
  const user = userId ? findUserInDatabaseById(userId) : undefined;
167
167
 
@@ -332,7 +332,7 @@ export async function sendAuthenticatedRequest(
332
332
  });
333
333
 
334
334
  if (response.status === HttpStatus.Unauthorized) {
335
- throw new Error(`User no longer logged in.`);
335
+ throw new Error('User no longer logged in.');
336
336
  } else {
337
337
  return response;
338
338
  }
@@ -354,7 +354,7 @@ export async function logout(logoutUrl: string) {
354
354
  All of these configurations must be set for the auth exports in this package to function properly:
355
355
 
356
356
  - Expose the [`AuthHeaderName.CsrfToken`](https://electrovir.github.io/auth-vir/variables/AuthHeaderName.html) (or just `'csrf-token'`) header via CORS headers with either of the following options:
357
- 1. Set `customHeaders: [AuthHeaderName.CsrfToken]` in `implementService` from [`@rest-vir/implement-service`](https://www.npmjs.com/package/@rest-vir/implement-service).
357
+ 1. Set `customHeaders: [AuthHeaderName.CsrfToken]` in `implementApi` from [`@rest-vir/host`](https://www.npmjs.com/package/@rest-vir/host).
358
358
  2. Set the header `Access-Control-Allow-Headers` to (at least) `AuthHeaderName.CsrfToken`.
359
359
  - Set `credentials: include` in all fetch requests on the client that need to use or set the auth cookie.
360
360
  - Server CORS should set `Access-Control-Allow-Origin` (it cannot be `*`).
@@ -1,7 +1,6 @@
1
- import { type AnyObject, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined } from '@augment-vir/common';
1
+ import { type AnyObject, type EmptyObject, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type RequireExactlyOne, type RequireOneOrNone } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
3
  import { type IncomingHttpHeaders, type OutgoingHttpHeaders } from 'node:http';
4
- import { type EmptyObject, type RequireExactlyOne, type RequireOneOrNone } from 'type-fest';
5
4
  import { type UserIdResult } from '../auth.js';
6
5
  import { type CookieParams } from '../cookie.js';
7
6
  import { type CsrfHeaderNameOption } from '../csrf-token.js';
@@ -150,6 +149,12 @@ export type BackendAuthClientConfig<DatabaseUser extends AnyObject, UserId exten
150
149
  * JWT embedded in the `HttpOnly` auth cookie.
151
150
  */
152
151
  csrfCookieOrigin: string;
152
+ /**
153
+ * Optional suffix appended to cookie names (e.g., `'staging'` produces `auth-staging`,
154
+ * `auth-vir-csrf-staging`). When `undefined`, cookie names are unchanged. Useful for
155
+ * running multiple environments on the same domain without cookie collisions.
156
+ */
157
+ cookieNameSuffix: string;
153
158
  }>>;
154
159
  /**
155
160
  * An auth client for creating and validating JWTs embedded in cookies. This should only be used in
@@ -1,7 +1,7 @@
1
1
  import { ensureArray, } from '@augment-vir/common';
2
2
  import { calculateRelativeDate, createUtcFullDate, getNowInUtcTimezone, isDateAfter, } from 'date-vir';
3
3
  import { extractUserIdFromRequestHeaders, generateLogoutHeaders, insecureExtractUserIdFromCookieAlone, } from '../auth.js';
4
- import { AuthCookie, clearCsrfCookie, generateAuthCookie, generateCsrfCookie, } from '../cookie.js';
4
+ import { AuthCookie, clearCsrfCookie, generateAuthCookie, generateCsrfCookie, resolveCookieName, } from '../cookie.js';
5
5
  import { generateCsrfToken } from '../csrf-token.js';
6
6
  import { AuthHeaderName, mergeHeaderValues } from '../headers.js';
7
7
  import { parseJwtKeys } from '../jwt/jwt-keys.js';
@@ -64,6 +64,7 @@ export class BackendAuthClient {
64
64
  jwtParams: await this.getJwtParams(),
65
65
  isDev: this.config.isDev,
66
66
  authCookie: isSignUpCookie ? AuthCookie.SignUp : AuthCookie.Auth,
67
+ cookieNameSuffix: this.config.cookieNameSuffix,
67
68
  };
68
69
  }
69
70
  /** Calls the provided `getUserFromDatabase` config. */
@@ -154,6 +155,7 @@ export class BackendAuthClient {
154
155
  const csrfCookie = generateCsrfCookie(userIdResult.csrfToken, {
155
156
  ...cookieParams,
156
157
  hostOrigin: this.resolveCsrfCookieOrigin(cookieParams.hostOrigin),
158
+ cookieNameSuffix: this.config.cookieNameSuffix,
157
159
  });
158
160
  return {
159
161
  'set-cookie': [
@@ -197,7 +199,13 @@ export class BackendAuthClient {
197
199
  }
198
200
  /** Securely extract a user from their request headers. */
199
201
  async getSecureUser({ requestHeaders, isSignUpCookie, allowUserAuthRefresh, }) {
200
- const userIdResult = await extractUserIdFromRequestHeaders(requestHeaders, await this.getJwtParams(), this.config.csrf, isSignUpCookie ? AuthCookie.SignUp : AuthCookie.Auth);
202
+ const userIdResult = await extractUserIdFromRequestHeaders({
203
+ headers: requestHeaders,
204
+ jwtParams: await this.getJwtParams(),
205
+ csrfHeaderNameOption: this.config.csrf,
206
+ cookieName: isSignUpCookie ? AuthCookie.SignUp : AuthCookie.Auth,
207
+ cookieNameSuffix: this.config.cookieNameSuffix,
208
+ });
201
209
  if (!userIdResult) {
202
210
  this.logForUser({
203
211
  user: undefined,
@@ -244,6 +252,7 @@ export class BackendAuthClient {
244
252
  const csrfCookie = generateCsrfCookie(userIdResult.csrfToken, {
245
253
  hostOrigin: this.resolveCsrfCookieOrigin(authCookieOrigin),
246
254
  isDev: this.config.isDev,
255
+ cookieNameSuffix: this.config.cookieNameSuffix,
247
256
  });
248
257
  return {
249
258
  user: assumedUser || user,
@@ -302,6 +311,7 @@ export class BackendAuthClient {
302
311
  ? clearCsrfCookie({
303
312
  hostOrigin: this.config.csrfCookieOrigin,
304
313
  isDev: this.config.isDev,
314
+ cookieNameSuffix: this.config.cookieNameSuffix,
305
315
  })
306
316
  : undefined;
307
317
  return {
@@ -321,6 +331,7 @@ export class BackendAuthClient {
321
331
  const csrfCookie = generateCsrfCookie(existingUserIdResult.csrfToken, {
322
332
  ...cookieParams,
323
333
  hostOrigin: this.resolveCsrfCookieOrigin(cookieParams.hostOrigin),
334
+ cookieNameSuffix: this.config.cookieNameSuffix,
324
335
  });
325
336
  return {
326
337
  'set-cookie': [
@@ -340,6 +351,7 @@ export class BackendAuthClient {
340
351
  const csrfCookie = generateCsrfCookie(csrfToken, {
341
352
  ...cookieParams,
342
353
  hostOrigin: this.resolveCsrfCookieOrigin(cookieParams.hostOrigin),
354
+ cookieNameSuffix: this.config.cookieNameSuffix,
343
355
  });
344
356
  return {
345
357
  'set-cookie': [
@@ -351,7 +363,8 @@ export class BackendAuthClient {
351
363
  /** Use these headers to log a user in. */
352
364
  async createLoginHeaders({ userId, requestHeaders, isSignUpCookie, }) {
353
365
  const oppositeCookieName = isSignUpCookie ? AuthCookie.Auth : AuthCookie.SignUp;
354
- const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${oppositeCookieName}=`);
366
+ const resolvedOppositeCookieName = resolveCookieName(oppositeCookieName, this.config.cookieNameSuffix);
367
+ const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${resolvedOppositeCookieName}=`);
355
368
  const discardOppositeCookieHeaders = hasExistingOppositeCookie
356
369
  ? generateLogoutHeaders(await this.getCookieParams({
357
370
  isSignUpCookie: !isSignUpCookie,
@@ -360,7 +373,13 @@ export class BackendAuthClient {
360
373
  preserveCsrf: true,
361
374
  })
362
375
  : undefined;
363
- const existingUserIdResult = await extractUserIdFromRequestHeaders(requestHeaders, await this.getJwtParams(), this.config.csrf, isSignUpCookie ? AuthCookie.SignUp : AuthCookie.Auth);
376
+ const existingUserIdResult = await extractUserIdFromRequestHeaders({
377
+ headers: requestHeaders,
378
+ jwtParams: await this.getJwtParams(),
379
+ csrfHeaderNameOption: this.config.csrf,
380
+ cookieName: isSignUpCookie ? AuthCookie.SignUp : AuthCookie.Auth,
381
+ cookieNameSuffix: this.config.cookieNameSuffix,
382
+ });
364
383
  const cookieParams = await this.getCookieParams({
365
384
  isSignUpCookie,
366
385
  requestHeaders,
@@ -405,7 +424,12 @@ export class BackendAuthClient {
405
424
  */
406
425
  async getInsecureUser({ requestHeaders, allowUserAuthRefresh, }) {
407
426
  // eslint-disable-next-line @typescript-eslint/no-deprecated
408
- const userIdResult = await insecureExtractUserIdFromCookieAlone(requestHeaders, await this.getJwtParams(), AuthCookie.Auth);
427
+ const userIdResult = await insecureExtractUserIdFromCookieAlone({
428
+ headers: requestHeaders,
429
+ jwtParams: await this.getJwtParams(),
430
+ cookieName: AuthCookie.Auth,
431
+ cookieNameSuffix: this.config.cookieNameSuffix,
432
+ });
409
433
  if (!userIdResult) {
410
434
  this.logForUser({
411
435
  user: undefined,
@@ -1,6 +1,5 @@
1
- import { type createBlockingInterval, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
1
+ import { type createBlockingInterval, type EmptyObject, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
- import { type EmptyObject } from 'type-fest';
4
3
  import { type CsrfHeaderNameOption } from '../csrf-token.js';
5
4
  /**
6
5
  * Config for {@link FrontendAuthClient}.
@@ -10,6 +9,11 @@ import { type CsrfHeaderNameOption } from '../csrf-token.js';
10
9
  export type FrontendAuthClientConfig = Readonly<{
11
10
  csrf: Readonly<CsrfHeaderNameOption>;
12
11
  }> & PartialWithUndefined<{
12
+ /**
13
+ * Optional suffix appended to cookie names (e.g., `'staging'` produces
14
+ * `auth-vir-csrf-staging`). When `undefined`, cookie names are unchanged.
15
+ */
16
+ cookieNameSuffix: string;
13
17
  /**
14
18
  * Determine if the current user can assume the identity of another user. If this is not
15
19
  * defined, all users will be blocked from assuming other user identities.
@@ -53,11 +53,13 @@ export class FrontendAuthClient {
53
53
  localStorage.removeItem(storageKey);
54
54
  return true;
55
55
  }
56
- else if (!(await this.config.canAssumeUser?.())) {
56
+ else if (await this.config.canAssumeUser?.()) {
57
+ localStorage.setItem(storageKey, JSON.stringify(assumedUserParams));
58
+ return true;
59
+ }
60
+ else {
57
61
  return false;
58
62
  }
59
- localStorage.setItem(storageKey, JSON.stringify(assumedUserParams));
60
- return true;
61
63
  }
62
64
  /** Gets the assumed user params stored in local storage, if any. */
63
65
  getAssumedUser() {
@@ -79,7 +81,7 @@ export class FrontendAuthClient {
79
81
  * combine them with these.
80
82
  */
81
83
  createAuthenticatedRequestInit() {
82
- const csrfToken = getCurrentCsrfToken();
84
+ const csrfToken = getCurrentCsrfToken(this.config.cookieNameSuffix);
83
85
  const assumedUser = this.getAssumedUser();
84
86
  const headers = {
85
87
  ...(csrfToken
package/dist/auth.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { type SelectFrom } from '@augment-vir/common';
1
+ import { type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
2
2
  import { type FullDate, type UtcTimezone } from 'date-vir';
3
- import { AuthCookie, type CookieParams } from './cookie.js';
3
+ import { type AuthCookie, type CookieParams } from './cookie.js';
4
4
  import { type CsrfHeaderNameOption } from './csrf-token.js';
5
5
  import { type ParseJwtParams } from './jwt/jwt.js';
6
6
  import { type JwtUserData } from './jwt/user-jwt.js';
@@ -37,7 +37,13 @@ export type UserIdResult<UserId extends string | number> = {
37
37
  * @category Auth : Host
38
38
  * @returns The extracted user id or `undefined` if no valid auth headers exist.
39
39
  */
40
- export declare function extractUserIdFromRequestHeaders<UserId extends string | number>(headers: HeaderContainer, jwtParams: Readonly<ParseJwtParams>, csrfHeaderNameOption: Readonly<CsrfHeaderNameOption>, cookieName?: AuthCookie): Promise<Readonly<UserIdResult<UserId>> | undefined>;
40
+ export declare function extractUserIdFromRequestHeaders<UserId extends string | number>({ headers, jwtParams, csrfHeaderNameOption, cookieName, cookieNameSuffix, }: Readonly<{
41
+ headers: HeaderContainer;
42
+ jwtParams: Readonly<ParseJwtParams>;
43
+ csrfHeaderNameOption: Readonly<CsrfHeaderNameOption>;
44
+ cookieName: AuthCookie;
45
+ cookieNameSuffix?: string | undefined;
46
+ }>): Promise<Readonly<UserIdResult<UserId>> | undefined>;
41
47
  /**
42
48
  * Extract a user id from just the cookie, without CSRF token validation. This is _less secure_ than
43
49
  * {@link extractUserIdFromRequestHeaders} as a result. This should only be used in rare
@@ -46,7 +52,12 @@ export declare function extractUserIdFromRequestHeaders<UserId extends string |
46
52
  * @deprecated Prefer {@link extractUserIdFromRequestHeaders} instead: it is more secure.
47
53
  * @category Auth : Host
48
54
  */
49
- export declare function insecureExtractUserIdFromCookieAlone<UserId extends string | number>(headers: HeaderContainer, jwtParams: Readonly<ParseJwtParams>, cookieName: AuthCookie): Promise<Readonly<UserIdResult<UserId>> | undefined>;
55
+ export declare function insecureExtractUserIdFromCookieAlone<UserId extends string | number>({ headers, jwtParams, cookieName, cookieNameSuffix, }: Readonly<{
56
+ headers: HeaderContainer;
57
+ jwtParams: Readonly<ParseJwtParams>;
58
+ cookieName: AuthCookie;
59
+ cookieNameSuffix?: string | undefined;
60
+ }>): Promise<Readonly<UserIdResult<UserId>> | undefined>;
50
61
  /**
51
62
  * Used by host (backend) code to set headers on a response object. Sets both the auth JWT cookie
52
63
  * and the CSRF token cookie. The CSRF cookie is not `HttpOnly` so that frontend JavaScript can read
@@ -71,11 +82,13 @@ sessionStartedAt?: number | undefined): Promise<Record<string, string[]>>;
71
82
  export declare function generateLogoutHeaders(cookieConfig: Readonly<SelectFrom<CookieParams, {
72
83
  hostOrigin: true;
73
84
  isDev: true;
74
- }>>, options?: Readonly<{
85
+ }>> & PartialWithUndefined<{
86
+ cookieNameSuffix: string;
87
+ }>, options?: Readonly<PartialWithUndefined<{
75
88
  /**
76
- * When `true`, the CSRF cookie is preserved (not cleared). Use this when clearing only one
77
- * cookie type (e.g., the auth cookie) while keeping the other active session (e.g.,
89
+ * When `true`, the CSRF cookie is preserved (not cleared). Use this when clearing only
90
+ * one cookie type (e.g., the auth cookie) while keeping the other active session (e.g.,
78
91
  * sign-up) that still needs its CSRF token.
79
92
  */
80
- preserveCsrf?: boolean | undefined;
81
- }>): Record<string, string[]>;
93
+ preserveCsrf: boolean;
94
+ }>>): Record<string, string[]>;
package/dist/auth.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AuthCookie, clearAuthCookie, clearCsrfCookie, extractCookieJwt, generateAuthCookie, generateCsrfCookie, } from './cookie.js';
1
+ import { clearAuthCookie, clearCsrfCookie, extractCookieJwt, generateAuthCookie, generateCsrfCookie, } from './cookie.js';
2
2
  import { generateCsrfToken, resolveCsrfHeaderName } from './csrf-token.js';
3
3
  function readHeader(headers, headerName) {
4
4
  if (headers instanceof Headers) {
@@ -28,14 +28,19 @@ function readCsrfTokenHeader(headers, csrfHeaderNameOption) {
28
28
  * @category Auth : Host
29
29
  * @returns The extracted user id or `undefined` if no valid auth headers exist.
30
30
  */
31
- export async function extractUserIdFromRequestHeaders(headers, jwtParams, csrfHeaderNameOption, cookieName = AuthCookie.Auth) {
31
+ export async function extractUserIdFromRequestHeaders({ headers, jwtParams, csrfHeaderNameOption, cookieName, cookieNameSuffix, }) {
32
32
  try {
33
33
  const csrfToken = readCsrfTokenHeader(headers, csrfHeaderNameOption);
34
34
  const cookie = readHeader(headers, 'cookie');
35
35
  if (!cookie || !csrfToken) {
36
36
  return undefined;
37
37
  }
38
- const jwt = await extractCookieJwt(cookie, jwtParams, cookieName);
38
+ const jwt = await extractCookieJwt({
39
+ rawCookie: cookie,
40
+ jwtParams,
41
+ cookieName,
42
+ cookieNameSuffix,
43
+ });
39
44
  if (!jwt || jwt.data.csrfToken !== csrfToken) {
40
45
  return undefined;
41
46
  }
@@ -60,13 +65,18 @@ export async function extractUserIdFromRequestHeaders(headers, jwtParams, csrfHe
60
65
  * @deprecated Prefer {@link extractUserIdFromRequestHeaders} instead: it is more secure.
61
66
  * @category Auth : Host
62
67
  */
63
- export async function insecureExtractUserIdFromCookieAlone(headers, jwtParams, cookieName) {
68
+ export async function insecureExtractUserIdFromCookieAlone({ headers, jwtParams, cookieName, cookieNameSuffix, }) {
64
69
  try {
65
70
  const cookie = readHeader(headers, 'cookie');
66
71
  if (!cookie) {
67
72
  return undefined;
68
73
  }
69
- const jwt = await extractCookieJwt(cookie, jwtParams, cookieName);
74
+ const jwt = await extractCookieJwt({
75
+ rawCookie: cookie,
76
+ jwtParams,
77
+ cookieName,
78
+ cookieNameSuffix,
79
+ });
70
80
  if (!jwt) {
71
81
  return undefined;
72
82
  }
package/dist/cookie.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
1
+ import { type PartialWithUndefined, type Primitive, type SelectFrom } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
- import { type Primitive } from 'type-fest';
4
3
  import { type CreateJwtParams, type ParseJwtParams, type ParsedJwt } from './jwt/jwt.js';
5
4
  import { type JwtUserData } from './jwt/user-jwt.js';
6
5
  /**
@@ -16,6 +15,13 @@ export declare enum AuthCookie {
16
15
  /** Used for storing the CSRF token. Not `HttpOnly` so that frontend JS can read it. */
17
16
  Csrf = "auth-vir-csrf"
18
17
  }
18
+ /**
19
+ * Resolves a cookie name by appending a suffix when provided. When `cookieNameSuffix` is
20
+ * `undefined`, the base name is returned unchanged.
21
+ *
22
+ * @category Internal
23
+ */
24
+ export declare function resolveCookieName(baseCookieName: AuthCookie, cookieNameSuffix?: string | undefined): string;
19
25
  /**
20
26
  * Parameters for {@link generateAuthCookie}.
21
27
  *
@@ -54,6 +60,12 @@ export type CookieParams = {
54
60
  * @default false
55
61
  */
56
62
  isDev: boolean;
63
+ /**
64
+ * Optional suffix appended to cookie names (e.g., `'staging'` produces `auth-staging`). When
65
+ * `undefined`, cookie names are unchanged. Useful for running multiple environments on the same
66
+ * domain without cookie collisions.
67
+ */
68
+ cookieNameSuffix: string;
57
69
  }>;
58
70
  /**
59
71
  * Generate a secure cookie that stores the user JWT data. Used in host (backend) code.
@@ -75,7 +87,9 @@ export declare function generateAuthCookie(userJwtData: Readonly<JwtUserData>, c
75
87
  export declare function generateCsrfCookie(csrfToken: string, cookieConfig: Readonly<SelectFrom<CookieParams, {
76
88
  hostOrigin: true;
77
89
  isDev: true;
78
- }>>): string;
90
+ }>> & PartialWithUndefined<{
91
+ cookieNameSuffix: string;
92
+ }>): string;
79
93
  /**
80
94
  * Generate a cookie value that will clear the previous auth cookie. Use this when signing out.
81
95
  *
@@ -86,6 +100,7 @@ export declare function clearAuthCookie(cookieConfig: Readonly<SelectFrom<Cookie
86
100
  isDev: true;
87
101
  }>> & PartialWithUndefined<{
88
102
  authCookie: AuthCookie;
103
+ cookieNameSuffix: string;
89
104
  }>): string;
90
105
  /**
91
106
  * Generate a cookie value that will clear the CSRF token cookie. Use this when signing out.
@@ -95,7 +110,9 @@ export declare function clearAuthCookie(cookieConfig: Readonly<SelectFrom<Cookie
95
110
  export declare function clearCsrfCookie(cookieConfig: Readonly<SelectFrom<CookieParams, {
96
111
  hostOrigin: true;
97
112
  isDev: true;
98
- }>>): string;
113
+ }>> & PartialWithUndefined<{
114
+ cookieNameSuffix: string;
115
+ }>): string;
99
116
  /**
100
117
  * Generate a cookie string from a raw set of parameters.
101
118
  *
@@ -108,4 +125,10 @@ export declare function generateCookie(params: Readonly<Record<string, Exclude<P
108
125
  * @category Internal
109
126
  * @returns The extracted auth Cookie JWT data or `undefined` if no valid auth JWT data was found.
110
127
  */
111
- export declare function extractCookieJwt(rawCookie: string, jwtParams: Readonly<ParseJwtParams>, cookieName: AuthCookie): Promise<undefined | ParsedJwt<JwtUserData>>;
128
+ export declare function extractCookieJwt({ rawCookie, jwtParams, cookieName, cookieNameSuffix, }: {
129
+ rawCookie: string;
130
+ jwtParams: Readonly<ParseJwtParams>;
131
+ cookieName: AuthCookie;
132
+ } & PartialWithUndefined<{
133
+ cookieNameSuffix: string;
134
+ }>): Promise<undefined | ParsedJwt<JwtUserData>>;
package/dist/cookie.js CHANGED
@@ -17,6 +17,20 @@ export var AuthCookie;
17
17
  /** Used for storing the CSRF token. Not `HttpOnly` so that frontend JS can read it. */
18
18
  AuthCookie["Csrf"] = "auth-vir-csrf";
19
19
  })(AuthCookie || (AuthCookie = {}));
20
+ /**
21
+ * Resolves a cookie name by appending a suffix when provided. When `cookieNameSuffix` is
22
+ * `undefined`, the base name is returned unchanged.
23
+ *
24
+ * @category Internal
25
+ */
26
+ export function resolveCookieName(baseCookieName, cookieNameSuffix) {
27
+ return [
28
+ baseCookieName,
29
+ cookieNameSuffix,
30
+ ]
31
+ .filter(check.isTruthy)
32
+ .join('-');
33
+ }
20
34
  function generateSetCookie({ name, value, httpOnly, cookieConfig, }) {
21
35
  return generateCookie({
22
36
  [name]: value,
@@ -39,7 +53,7 @@ function generateSetCookie({ name, value, httpOnly, cookieConfig, }) {
39
53
  */
40
54
  export async function generateAuthCookie(userJwtData, cookieConfig) {
41
55
  return generateSetCookie({
42
- name: cookieConfig.authCookie || AuthCookie.Auth,
56
+ name: resolveCookieName(cookieConfig.authCookie || AuthCookie.Auth, cookieConfig.cookieNameSuffix),
43
57
  value: await createUserJwt(userJwtData, cookieConfig.jwtParams),
44
58
  httpOnly: true,
45
59
  cookieConfig,
@@ -58,7 +72,7 @@ export async function generateAuthCookie(userJwtData, cookieConfig) {
58
72
  */
59
73
  export function generateCsrfCookie(csrfToken, cookieConfig) {
60
74
  return generateSetCookie({
61
- name: AuthCookie.Csrf,
75
+ name: resolveCookieName(AuthCookie.Csrf, cookieConfig.cookieNameSuffix),
62
76
  value: csrfToken,
63
77
  httpOnly: false,
64
78
  cookieConfig: {
@@ -76,7 +90,7 @@ export function generateCsrfCookie(csrfToken, cookieConfig) {
76
90
  */
77
91
  export function clearAuthCookie(cookieConfig) {
78
92
  return generateSetCookie({
79
- name: cookieConfig.authCookie || AuthCookie.Auth,
93
+ name: resolveCookieName(cookieConfig.authCookie || AuthCookie.Auth, cookieConfig.cookieNameSuffix),
80
94
  value: 'redacted',
81
95
  httpOnly: true,
82
96
  cookieConfig,
@@ -89,7 +103,7 @@ export function clearAuthCookie(cookieConfig) {
89
103
  */
90
104
  export function clearCsrfCookie(cookieConfig) {
91
105
  return generateSetCookie({
92
- name: AuthCookie.Csrf,
106
+ name: resolveCookieName(AuthCookie.Csrf, cookieConfig.cookieNameSuffix),
93
107
  value: 'redacted',
94
108
  httpOnly: false,
95
109
  cookieConfig,
@@ -125,13 +139,14 @@ export function generateCookie(params) {
125
139
  * @category Internal
126
140
  * @returns The extracted auth Cookie JWT data or `undefined` if no valid auth JWT data was found.
127
141
  */
128
- export async function extractCookieJwt(rawCookie, jwtParams, cookieName) {
129
- const cookieRegExp = new RegExp(`${escapeStringForRegExp(cookieName)}=[^;]+(?:;|$)`);
142
+ export async function extractCookieJwt({ rawCookie, jwtParams, cookieName, cookieNameSuffix, }) {
143
+ const resolvedName = resolveCookieName(cookieName, cookieNameSuffix);
144
+ const cookieRegExp = new RegExp(`${escapeStringForRegExp(resolvedName)}=[^;]+(?:;|$)`);
130
145
  const [cookieValue] = safeMatch(rawCookie, cookieRegExp);
131
146
  if (!cookieValue) {
132
147
  return undefined;
133
148
  }
134
- const rawJwt = cookieValue.replace(`${cookieName}=`, '').replace(';', '');
149
+ const rawJwt = cookieValue.replace(`${resolvedName}=`, '').replace(';', '');
135
150
  const jwt = await parseUserJwt(rawJwt, jwtParams);
136
151
  return jwt;
137
152
  }
@@ -1,4 +1,4 @@
1
- import { type RequireExactlyOne } from 'type-fest';
1
+ import { type RequireExactlyOne } from '@augment-vir/common';
2
2
  /**
3
3
  * Generates a random, cryptographically secure CSRF token string.
4
4
  *
@@ -30,4 +30,4 @@ export declare function resolveCsrfHeaderName(options: Readonly<CsrfHeaderNameOp
30
30
  *
31
31
  * @category Auth : Client
32
32
  */
33
- export declare function getCurrentCsrfToken(): string | undefined;
33
+ export declare function getCurrentCsrfToken(cookieNameSuffix?: string | undefined): string | undefined;
@@ -1,6 +1,6 @@
1
1
  import { check } from '@augment-vir/assert';
2
- import { escapeStringForRegExp, randomString, safeMatch } from '@augment-vir/common';
3
- import { AuthCookie } from './cookie.js';
2
+ import { escapeStringForRegExp, randomString, safeMatch, } from '@augment-vir/common';
3
+ import { AuthCookie, resolveCookieName } from './cookie.js';
4
4
  /**
5
5
  * Generates a random, cryptographically secure CSRF token string.
6
6
  *
@@ -35,8 +35,9 @@ export function resolveCsrfHeaderName(options) {
35
35
  *
36
36
  * @category Auth : Client
37
37
  */
38
- export function getCurrentCsrfToken() {
39
- const cookieRegExp = new RegExp(`${escapeStringForRegExp(AuthCookie.Csrf)}=([^;]+)`);
38
+ export function getCurrentCsrfToken(cookieNameSuffix) {
39
+ const resolvedName = resolveCookieName(AuthCookie.Csrf, cookieNameSuffix);
40
+ const cookieRegExp = new RegExp(`${escapeStringForRegExp(resolvedName)}=([^;]+)`);
40
41
  const [, value,] = safeMatch(globalThis.document.cookie, cookieRegExp);
41
42
  return value || undefined;
42
43
  }
@@ -9,12 +9,14 @@ export * from "./enums.js";
9
9
  * Type-safe database client for TypeScript
10
10
  * @example
11
11
  * ```
12
- * const prisma = new PrismaClient()
12
+ * const prisma = new PrismaClient({
13
+ * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
14
+ * })
13
15
  * // Fetch zero or more Users
14
16
  * const users = await prisma.user.findMany()
15
17
  * ```
16
18
  *
17
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
19
+ * Read more in our [docs](https://pris.ly/d/client).
18
20
  */
19
21
  export declare const PrismaClient: $Class.PrismaClientConstructor;
20
22
  export type PrismaClient<LogOpts extends Prisma.LogLevel = never, OmitOpts extends Prisma.PrismaClientOptions["omit"] = Prisma.PrismaClientOptions["omit"], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> = $Class.PrismaClient<LogOpts, OmitOpts, ExtArgs>;
@@ -21,12 +21,14 @@ export * from "./enums.js";
21
21
  * Type-safe database client for TypeScript
22
22
  * @example
23
23
  * ```
24
- * const prisma = new PrismaClient()
24
+ * const prisma = new PrismaClient({
25
+ * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
26
+ * })
25
27
  * // Fetch zero or more Users
26
28
  * const users = await prisma.user.findMany()
27
29
  * ```
28
30
  *
29
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
31
+ * Read more in our [docs](https://pris.ly/d/client).
30
32
  */
31
- export const PrismaClient = $Class.getPrismaClientClass(__dirname);
33
+ export const PrismaClient = $Class.getPrismaClientClass();
32
34
  export { Prisma };
@@ -8,16 +8,18 @@ export interface PrismaClientConstructor {
8
8
  * Type-safe database client for TypeScript
9
9
  * @example
10
10
  * ```
11
- * const prisma = new PrismaClient()
11
+ * const prisma = new PrismaClient({
12
+ * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
13
+ * })
12
14
  * // Fetch zero or more Users
13
15
  * const users = await prisma.user.findMany()
14
16
  * ```
15
17
  *
16
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
18
+ * Read more in our [docs](https://pris.ly/d/client).
17
19
  */
18
20
  new <Options extends Prisma.PrismaClientOptions = Prisma.PrismaClientOptions, LogOpts extends LogOptions<Options> = LogOptions<Options>, OmitOpts extends Prisma.PrismaClientOptions['omit'] = Options extends {
19
21
  omit: infer U;
20
- } ? U : Prisma.PrismaClientOptions['omit'], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs>(options?: Prisma.Subset<Options, Prisma.PrismaClientOptions>): PrismaClient<LogOpts, OmitOpts, ExtArgs>;
22
+ } ? U : Prisma.PrismaClientOptions['omit'], ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs>(options: Prisma.PrismaClientConstructorArgs<Options>): PrismaClient<LogOpts, OmitOpts, ExtArgs>;
21
23
  }
22
24
  /**
23
25
  * ## Prisma Client
@@ -25,12 +27,14 @@ export interface PrismaClientConstructor {
25
27
  * Type-safe database client for TypeScript
26
28
  * @example
27
29
  * ```
28
- * const prisma = new PrismaClient()
30
+ * const prisma = new PrismaClient({
31
+ * adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL })
32
+ * })
29
33
  * // Fetch zero or more Users
30
34
  * const users = await prisma.user.findMany()
31
35
  * ```
32
36
  *
33
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client).
37
+ * Read more in our [docs](https://pris.ly/d/client).
34
38
  */
35
39
  export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out OmitOpts extends Prisma.PrismaClientOptions['omit'] = Prisma.PrismaClientOptions['omit'], in out ExtArgs extends runtime.Types.Extensions.InternalArgs = runtime.Types.Extensions.DefaultArgs> {
36
40
  [K: symbol]: {
@@ -52,7 +56,7 @@ export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out
52
56
  * const result = await prisma.$executeRaw`UPDATE User SET cool = ${true} WHERE email = ${'user@email.com'};`
53
57
  * ```
54
58
  *
55
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access).
59
+ * Read more in our [docs](https://pris.ly/d/raw-queries).
56
60
  */
57
61
  $executeRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<number>;
58
62
  /**
@@ -63,7 +67,7 @@ export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out
63
67
  * const result = await prisma.$executeRawUnsafe('UPDATE User SET cool = $1 WHERE email = $2 ;', true, 'user@email.com')
64
68
  * ```
65
69
  *
66
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access).
70
+ * Read more in our [docs](https://pris.ly/d/raw-queries).
67
71
  */
68
72
  $executeRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<number>;
69
73
  /**
@@ -73,7 +77,7 @@ export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out
73
77
  * const result = await prisma.$queryRaw`SELECT * FROM User WHERE id = ${1} OR email = ${'user@email.com'};`
74
78
  * ```
75
79
  *
76
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access).
80
+ * Read more in our [docs](https://pris.ly/d/raw-queries).
77
81
  */
78
82
  $queryRaw<T = unknown>(query: TemplateStringsArray | Prisma.Sql, ...values: any[]): Prisma.PrismaPromise<T>;
79
83
  /**
@@ -84,7 +88,7 @@ export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out
84
88
  * const result = await prisma.$queryRawUnsafe('SELECT * FROM User WHERE id = $1 OR email = $2;', 1, 'user@email.com')
85
89
  * ```
86
90
  *
87
- * Read more in our [docs](https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/raw-database-access).
91
+ * Read more in our [docs](https://pris.ly/d/raw-queries).
88
92
  */
89
93
  $queryRawUnsafe<T = unknown>(query: string, ...values: any[]): Prisma.PrismaPromise<T>;
90
94
  /**
@@ -98,9 +102,11 @@ export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out
98
102
  * ])
99
103
  * ```
100
104
  *
101
- * Read more in our [docs](https://www.prisma.io/docs/concepts/components/prisma-client/transactions).
105
+ * Read more in our [docs](https://www.prisma.io/docs/orm/prisma-client/queries/transactions).
102
106
  */
103
107
  $transaction<P extends Prisma.PrismaPromise<any>[]>(arg: [...P], options?: {
108
+ maxWait?: number;
109
+ timeout?: number;
104
110
  isolationLevel?: Prisma.TransactionIsolationLevel;
105
111
  }): runtime.Types.Utils.JsPromise<runtime.Types.Utils.UnwrapTuple<P>>;
106
112
  $transaction<R>(fn: (prisma: Omit<PrismaClient, runtime.ITXClientDenyList>) => runtime.Types.Utils.JsPromise<R>, options?: {
@@ -123,4 +129,4 @@ export interface PrismaClient<in LogOpts extends Prisma.LogLevel = never, in out
123
129
  omit: OmitOpts;
124
130
  }>;
125
131
  }
126
- export declare function getPrismaClientClass(dirname: string): PrismaClientConstructor;
132
+ export declare function getPrismaClientClass(): PrismaClientConstructor;