auth-vir 2.3.2 → 2.3.4

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 { type AnyObject, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type RequiredAndNotNull } from '@augment-vir/common';
1
+ import { type AnyObject, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
3
  import { type IncomingHttpHeaders, type OutgoingHttpHeaders } from 'node:http';
4
4
  import { type EmptyObject, type RequireExactlyOne, type RequireOneOrNone } from 'type-fest';
@@ -165,7 +165,7 @@ export declare class BackendAuthClient<DatabaseUser extends AnyObject, UserId ex
165
165
  userId: UserId;
166
166
  requestHeaders: IncomingHttpHeaders;
167
167
  isSignUpCookie: boolean;
168
- }): Promise<Pick<RequiredAndNotNull<OutgoingHttpHeaders>, 'set-cookie'> & Record<CsrfHeaderName, string>>;
168
+ }): Promise<OutgoingHttpHeaders>;
169
169
  /** Combines `.getInsecureUser()` and `.getSecureUser()` into one method. */
170
170
  getInsecureOrSecureUser(params: {
171
171
  requestHeaders: IncomingHttpHeaders;
@@ -46,6 +46,11 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
46
46
  export declare class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject = EmptyObject> {
47
47
  protected readonly config: FrontendAuthClientConfig;
48
48
  protected userCheckInterval: undefined | ReturnType<typeof createBlockingInterval>;
49
+ /**
50
+ * Keeps track of whether the latest state of auth is logged in (`true`) or not (`false`). This
51
+ * is used for determining if the check user interval should keep running.
52
+ */
53
+ protected isLatestAuthorized: boolean;
49
54
  constructor(config?: FrontendAuthClientConfig);
50
55
  /**
51
56
  * Destroys the client and performs all necessary cleanup (like clearing the user check
@@ -84,9 +89,11 @@ export declare class FrontendAuthClient<AssumedUserParams extends JsonCompatible
84
89
  /**
85
90
  * Use to verify _all_ responses received from the backend. Immediately logs the user out once
86
91
  * an unauthorized response is detected.
92
+ *
93
+ * @returns `true` if the auth is okay, `false` otherwise.
87
94
  */
88
95
  verifyResponseAuth(response: Readonly<SetOptionalWithUndefined<SelectFrom<Response, {
89
96
  status: true;
90
97
  headers: true;
91
- }>, 'headers'>>): Promise<void>;
98
+ }>, 'headers'>>): Promise<boolean>;
92
99
  }
@@ -11,13 +11,22 @@ import { AuthHeaderName } from '../headers.js';
11
11
  export class FrontendAuthClient {
12
12
  config;
13
13
  userCheckInterval;
14
+ /**
15
+ * Keeps track of whether the latest state of auth is logged in (`true`) or not (`false`). This
16
+ * is used for determining if the check user interval should keep running.
17
+ */
18
+ isLatestAuthorized = false;
14
19
  constructor(config = {}) {
15
20
  this.config = config;
16
21
  if (config.checkUser) {
17
22
  this.userCheckInterval = createBlockingInterval(async () => {
23
+ /** No need to check current user status when there is no user. */
24
+ if (!this.isLatestAuthorized) {
25
+ return;
26
+ }
18
27
  const response = await config.checkUser?.performCheck();
19
28
  if (response) {
20
- await this.verifyResponseAuth({
29
+ this.isLatestAuthorized = await this.verifyResponseAuth({
21
30
  status: response.status,
22
31
  });
23
32
  }
@@ -102,6 +111,7 @@ export class FrontendAuthClient {
102
111
  }
103
112
  /** Wipes the current user auth. */
104
113
  async logout() {
114
+ this.isLatestAuthorized = false;
105
115
  await this.config.authClearedCallback?.();
106
116
  wipeCurrentCsrfToken(this.config.overrides);
107
117
  }
@@ -122,15 +132,20 @@ export class FrontendAuthClient {
122
132
  throw new Error('Did not receive any CSRF token.');
123
133
  }
124
134
  storeCsrfToken(csrfToken, this.config.overrides);
135
+ this.isLatestAuthorized = true;
125
136
  }
126
137
  /**
127
138
  * Use to verify _all_ responses received from the backend. Immediately logs the user out once
128
139
  * an unauthorized response is detected.
140
+ *
141
+ * @returns `true` if the auth is okay, `false` otherwise.
129
142
  */
130
143
  async verifyResponseAuth(response) {
131
144
  if (response.status === HttpStatus.Unauthorized &&
132
145
  !response.headers?.get(AuthHeaderName.IsSignUpAuth)) {
133
146
  await this.logout();
147
+ return false;
134
148
  }
149
+ return true;
135
150
  }
136
151
  }
@@ -21,8 +21,8 @@ const config = {
21
21
  "fromEnvVar": null
22
22
  },
23
23
  "config": {
24
- "engineType": "client",
25
- "moduleFormat": "esm"
24
+ "moduleFormat": "esm",
25
+ "engineType": "client"
26
26
  },
27
27
  "binaryTargets": [
28
28
  {
@@ -39,8 +39,8 @@ const config = {
39
39
  "isCustomOutput": true
40
40
  },
41
41
  "relativePath": "../../test-files",
42
- "clientVersion": "6.17.1",
43
- "engineVersion": "272a37d34178c2894197e17273bf937f25acdeac",
42
+ "clientVersion": "6.18.0",
43
+ "engineVersion": "34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
44
44
  "datasourceNames": [
45
45
  "db"
46
46
  ],
@@ -54,8 +54,8 @@ const config = {
54
54
  }
55
55
  }
56
56
  },
57
- "inlineSchema": "generator jsClient {\n provider = \"prisma-client\"\n previewFeatures = [\"strictUndefinedChecks\", \"relationJoins\"]\n output = \"../src/generated\"\n engineType = \"client\"\n moduleFormat = \"esm\"\n}\n\ngenerator shapes {\n provider = \"prisma-shapes\"\n output = \"../src/generated\"\n}\n\ngenerator stringDates {\n provider = \"prisma-string-dates\"\n output = \"../src/generated\"\n}\n\ngenerator taggedIds {\n provider = \"prisma-tagged-ids\"\n output = \"../src/generated\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id String @id @default(cuid(2))\n createdAt DateTime @default(now())\n updatedAt DateTime @default(now()) @updatedAt\n\n name String\n}\n",
58
- "inlineSchemaHash": "7d1ca802697687a0d28701b345324b445a425e1f524d6377a89cbc48895f7110",
57
+ "inlineSchema": "generator jsClient {\n provider = \"prisma-client\"\n previewFeatures = [\"strictUndefinedChecks\", \"relationJoins\"]\n output = \"../src/generated\"\n engineType = \"client\"\n moduleFormat = \"esm\"\n}\n\ngenerator shapes {\n provider = \"prisma-shapes\"\n output = \"../src/generated\"\n}\n\ngenerator stringDates {\n provider = \"prisma-string-dates\"\n output = \"../src/generated\"\n}\n\ngenerator brandedFields {\n provider = \"prisma-branded-fields\"\n output = \"../src/generated\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id String @id @default(cuid(2))\n createdAt DateTime @default(now())\n updatedAt DateTime @default(now()) @updatedAt\n\n name String\n}\n",
58
+ "inlineSchemaHash": "23208c8e58615c00e5101cfaaa5341ce46c109a1169d3aea10dae8caa3594dcc",
59
59
  "copyEngine": true,
60
60
  "runtimeDataModel": {
61
61
  "models": {},
@@ -58,13 +58,14 @@ export type PrismaVersion = {
58
58
  engine: string;
59
59
  };
60
60
  /**
61
- * Prisma Client JS version: 6.17.1
62
- * Query Engine version: 272a37d34178c2894197e17273bf937f25acdeac
61
+ * Prisma Client JS version: 6.18.0
62
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
63
63
  */
64
64
  export declare const prismaVersion: PrismaVersion;
65
65
  /**
66
66
  * Utility Types
67
67
  */
68
+ export type Bytes = runtime.Bytes;
68
69
  export type JsonObject = runtime.JsonObject;
69
70
  export type JsonArray = runtime.JsonArray;
70
71
  export type JsonValue = runtime.JsonValue;
@@ -38,12 +38,12 @@ export const skip = runtime.skip;
38
38
  export const Decimal = runtime.Decimal;
39
39
  export const getExtensionContext = runtime.Extensions.getExtensionContext;
40
40
  /**
41
- * Prisma Client JS version: 6.17.1
42
- * Query Engine version: 272a37d34178c2894197e17273bf937f25acdeac
41
+ * Prisma Client JS version: 6.18.0
42
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
43
43
  */
44
44
  export const prismaVersion = {
45
- client: "6.17.1",
46
- engine: "272a37d34178c2894197e17273bf937f25acdeac"
45
+ client: "6.18.0",
46
+ engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
47
47
  };
48
48
  export const NullTypes = {
49
49
  DbNull: runtime.objectEnumValues.classes.DbNull,
@@ -1,8 +1,5 @@
1
- import { type Tagged } from 'type-fest';
2
- export type UserId = Tagged<string, 'model-User-field-id', {
3
- model: 'User';
4
- field: 'id';
5
- }>;
1
+ import { type Branded } from '@augment-vir/common';
2
+ export type UserId = Branded<string, 'model-User-field-id'>;
6
3
  import { type UtcIsoString } from 'date-vir';
7
4
  import type * as runtime from "@prisma/client/runtime/client";
8
5
  import type * as Prisma from "../internal/prismaNamespace.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auth-vir",
3
- "version": "2.3.2",
3
+ "version": "2.3.4",
4
4
  "description": "Auth made easy and secure via JWT cookies, CSRF tokens, and password hashing helpers.",
5
5
  "keywords": [
6
6
  "auth",
@@ -42,18 +42,18 @@
42
42
  "test:web": "virmator test web"
43
43
  },
44
44
  "dependencies": {
45
- "@augment-vir/assert": "^31.42.0",
46
- "@augment-vir/common": "^31.42.0",
45
+ "@augment-vir/assert": "^31.45.0",
46
+ "@augment-vir/common": "^31.45.0",
47
47
  "date-vir": "^8.0.0",
48
48
  "hash-wasm": "^4.12.0",
49
49
  "jose": "^6.1.0",
50
- "object-shape-tester": "^6.9.2",
50
+ "object-shape-tester": "^6.9.3",
51
51
  "type-fest": "^5.1.0",
52
52
  "url-vir": "^2.1.6"
53
53
  },
54
54
  "devDependencies": {
55
- "@augment-vir/test": "^31.42.0",
56
- "@prisma/client": "^6.17.1",
55
+ "@augment-vir/test": "^31.45.0",
56
+ "@prisma/client": "^6.18.0",
57
57
  "@types/node": "^24.9.1",
58
58
  "@web/dev-server-esbuild": "^1.0.4",
59
59
  "@web/test-runner": "^0.20.2",
@@ -62,7 +62,7 @@
62
62
  "@web/test-runner-visual-regression": "^0.10.0",
63
63
  "istanbul-smart-text-reporter": "^1.1.5",
64
64
  "markdown-code-example-inserter": "^3.0.3",
65
- "prisma-vir": "^1.2.2",
65
+ "prisma-vir": "^2.0.0",
66
66
  "typedoc": "^0.28.14"
67
67
  },
68
68
  "engines": {
@@ -4,7 +4,6 @@ import {
4
4
  type JsonCompatibleObject,
5
5
  type MaybePromise,
6
6
  type PartialWithUndefined,
7
- type RequiredAndNotNull,
8
7
  } from '@augment-vir/common';
9
8
  import {calculateRelativeDate, getNowInUtcTimezone, isDateAfter, type AnyDuration} from 'date-vir';
10
9
  import {type IncomingHttpHeaders, type OutgoingHttpHeaders} from 'node:http';
@@ -426,9 +425,7 @@ export class BackendAuthClient<
426
425
  userId: UserId;
427
426
  requestHeaders: IncomingHttpHeaders;
428
427
  isSignUpCookie: boolean;
429
- }): Promise<
430
- Pick<RequiredAndNotNull<OutgoingHttpHeaders>, 'set-cookie'> & Record<CsrfHeaderName, string>
431
- > {
428
+ }): Promise<OutgoingHttpHeaders> {
432
429
  const oppositeCookieName = isSignUpCookie ? AuthCookieName.Auth : AuthCookieName.SignUp;
433
430
  const hasExistingOppositeCookie = requestHeaders.cookie?.includes(`${oppositeCookieName}=`);
434
431
 
@@ -70,14 +70,24 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
70
70
  */
71
71
  export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject = EmptyObject> {
72
72
  protected userCheckInterval: undefined | ReturnType<typeof createBlockingInterval>;
73
+ /**
74
+ * Keeps track of whether the latest state of auth is logged in (`true`) or not (`false`). This
75
+ * is used for determining if the check user interval should keep running.
76
+ */
77
+ protected isLatestAuthorized = false;
73
78
 
74
79
  constructor(protected readonly config: FrontendAuthClientConfig = {}) {
75
80
  if (config.checkUser) {
76
81
  this.userCheckInterval = createBlockingInterval(
77
82
  async () => {
83
+ /** No need to check current user status when there is no user. */
84
+ if (!this.isLatestAuthorized) {
85
+ return;
86
+ }
87
+
78
88
  const response = await config.checkUser?.performCheck();
79
89
  if (response) {
80
- await this.verifyResponseAuth({
90
+ this.isLatestAuthorized = await this.verifyResponseAuth({
81
91
  status: response.status,
82
92
  });
83
93
  }
@@ -184,6 +194,7 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
184
194
 
185
195
  /** Wipes the current user auth. */
186
196
  public async logout() {
197
+ this.isLatestAuthorized = false;
187
198
  await this.config.authClearedCallback?.();
188
199
  wipeCurrentCsrfToken(this.config.overrides);
189
200
  }
@@ -218,11 +229,14 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
218
229
  }
219
230
 
220
231
  storeCsrfToken(csrfToken, this.config.overrides);
232
+ this.isLatestAuthorized = true;
221
233
  }
222
234
 
223
235
  /**
224
236
  * Use to verify _all_ responses received from the backend. Immediately logs the user out once
225
237
  * an unauthorized response is detected.
238
+ *
239
+ * @returns `true` if the auth is okay, `false` otherwise.
226
240
  */
227
241
  public async verifyResponseAuth(
228
242
  response: Readonly<
@@ -237,12 +251,15 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
237
251
  'headers'
238
252
  >
239
253
  >,
240
- ): Promise<void> {
254
+ ): Promise<boolean> {
241
255
  if (
242
256
  response.status === HttpStatus.Unauthorized &&
243
257
  !response.headers?.get(AuthHeaderName.IsSignUpAuth)
244
258
  ) {
245
259
  await this.logout();
260
+ return false;
246
261
  }
262
+
263
+ return true;
247
264
  }
248
265
  }
@@ -26,8 +26,8 @@ const config: runtime.GetPrismaClientConfig = {
26
26
  "fromEnvVar": null
27
27
  },
28
28
  "config": {
29
- "engineType": "client",
30
- "moduleFormat": "esm"
29
+ "moduleFormat": "esm",
30
+ "engineType": "client"
31
31
  },
32
32
  "binaryTargets": [
33
33
  {
@@ -44,8 +44,8 @@ const config: runtime.GetPrismaClientConfig = {
44
44
  "isCustomOutput": true
45
45
  },
46
46
  "relativePath": "../../test-files",
47
- "clientVersion": "6.17.1",
48
- "engineVersion": "272a37d34178c2894197e17273bf937f25acdeac",
47
+ "clientVersion": "6.18.0",
48
+ "engineVersion": "34b5a692b7bd79939a9a2c3ef97d816e749cda2f",
49
49
  "datasourceNames": [
50
50
  "db"
51
51
  ],
@@ -59,8 +59,8 @@ const config: runtime.GetPrismaClientConfig = {
59
59
  }
60
60
  }
61
61
  },
62
- "inlineSchema": "generator jsClient {\n provider = \"prisma-client\"\n previewFeatures = [\"strictUndefinedChecks\", \"relationJoins\"]\n output = \"../src/generated\"\n engineType = \"client\"\n moduleFormat = \"esm\"\n}\n\ngenerator shapes {\n provider = \"prisma-shapes\"\n output = \"../src/generated\"\n}\n\ngenerator stringDates {\n provider = \"prisma-string-dates\"\n output = \"../src/generated\"\n}\n\ngenerator taggedIds {\n provider = \"prisma-tagged-ids\"\n output = \"../src/generated\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id String @id @default(cuid(2))\n createdAt DateTime @default(now())\n updatedAt DateTime @default(now()) @updatedAt\n\n name String\n}\n",
63
- "inlineSchemaHash": "7d1ca802697687a0d28701b345324b445a425e1f524d6377a89cbc48895f7110",
62
+ "inlineSchema": "generator jsClient {\n provider = \"prisma-client\"\n previewFeatures = [\"strictUndefinedChecks\", \"relationJoins\"]\n output = \"../src/generated\"\n engineType = \"client\"\n moduleFormat = \"esm\"\n}\n\ngenerator shapes {\n provider = \"prisma-shapes\"\n output = \"../src/generated\"\n}\n\ngenerator stringDates {\n provider = \"prisma-string-dates\"\n output = \"../src/generated\"\n}\n\ngenerator brandedFields {\n provider = \"prisma-branded-fields\"\n output = \"../src/generated\"\n}\n\ndatasource db {\n provider = \"postgresql\"\n url = env(\"DATABASE_URL\")\n}\n\nmodel User {\n id String @id @default(cuid(2))\n createdAt DateTime @default(now())\n updatedAt DateTime @default(now()) @updatedAt\n\n name String\n}\n",
63
+ "inlineSchemaHash": "23208c8e58615c00e5101cfaaa5341ce46c109a1169d3aea10dae8caa3594dcc",
64
64
  "copyEngine": true,
65
65
  "runtimeDataModel": {
66
66
  "models": {},
@@ -93,18 +93,19 @@ export type PrismaVersion = {
93
93
  }
94
94
 
95
95
  /**
96
- * Prisma Client JS version: 6.17.1
97
- * Query Engine version: 272a37d34178c2894197e17273bf937f25acdeac
96
+ * Prisma Client JS version: 6.18.0
97
+ * Query Engine version: 34b5a692b7bd79939a9a2c3ef97d816e749cda2f
98
98
  */
99
99
  export const prismaVersion: PrismaVersion = {
100
- client: "6.17.1",
101
- engine: "272a37d34178c2894197e17273bf937f25acdeac"
100
+ client: "6.18.0",
101
+ engine: "34b5a692b7bd79939a9a2c3ef97d816e749cda2f"
102
102
  }
103
103
 
104
104
  /**
105
105
  * Utility Types
106
106
  */
107
107
 
108
+ export type Bytes = runtime.Bytes
108
109
  export type JsonObject = runtime.JsonObject
109
110
  export type JsonArray = runtime.JsonArray
110
111
  export type JsonValue = runtime.JsonValue
@@ -1,6 +1,6 @@
1
- import {type Tagged} from 'type-fest';
1
+ import {type Branded} from '@augment-vir/common';
2
2
 
3
- export type UserId = Tagged<string, 'model-User-field-id', {model: 'User', field: 'id'}>;
3
+ export type UserId = Branded<string, 'model-User-field-id'>;
4
4
 
5
5
  // @ts-nocheck
6
6
  import {type UtcIsoString} from 'date-vir';