auth-vir 2.3.3 → 2.3.5

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 { createBlockingInterval, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom, type SetOptionalWithUndefined } from '@augment-vir/common';
1
+ import { createBlockingInterval, type JsonCompatibleObject, type MaybePromise, type PartialWithUndefined, type SelectFrom } from '@augment-vir/common';
2
2
  import { type AnyDuration } from 'date-vir';
3
3
  import { type EmptyObject } from 'type-fest';
4
4
  /**
@@ -23,10 +23,13 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
23
23
  * Get a response from the backend to see if the user is still authenticated. If the
24
24
  * response returns a non-authorized status, the user is wiped. Any other status is
25
25
  * ignored.
26
+ *
27
+ * If the user is not currently authorized, this should return `undefined` to prevent
28
+ * unnecessary network traffic.
26
29
  */
27
30
  performCheck: () => MaybePromise<SelectFrom<Response, {
28
31
  status: true;
29
- }>>;
32
+ }> | undefined>;
30
33
  /** @default {minutes: 1} */
31
34
  interval?: AnyDuration | undefined;
32
35
  };
@@ -84,9 +87,11 @@ export declare class FrontendAuthClient<AssumedUserParams extends JsonCompatible
84
87
  /**
85
88
  * Use to verify _all_ responses received from the backend. Immediately logs the user out once
86
89
  * an unauthorized response is detected.
90
+ *
91
+ * @returns `true` if the auth is okay, `false` otherwise.
87
92
  */
88
- verifyResponseAuth(response: Readonly<SetOptionalWithUndefined<SelectFrom<Response, {
93
+ verifyResponseAuth(response: Readonly<PartialWithUndefined<SelectFrom<Response, {
89
94
  status: true;
90
95
  headers: true;
91
- }>, 'headers'>>): Promise<void>;
96
+ }>>>): Promise<boolean>;
92
97
  }
@@ -126,11 +126,20 @@ export class FrontendAuthClient {
126
126
  /**
127
127
  * Use to verify _all_ responses received from the backend. Immediately logs the user out once
128
128
  * an unauthorized response is detected.
129
+ *
130
+ * @returns `true` if the auth is okay, `false` otherwise.
129
131
  */
130
132
  async verifyResponseAuth(response) {
131
133
  if (response.status === HttpStatus.Unauthorized &&
132
134
  !response.headers?.get(AuthHeaderName.IsSignUpAuth)) {
133
135
  await this.logout();
136
+ return false;
134
137
  }
138
+ /** If the response has a new CSRF token, store it. */
139
+ const { csrfToken } = extractCsrfTokenHeader(response, this.config.overrides);
140
+ if (csrfToken) {
141
+ storeCsrfToken(csrfToken, this.config.overrides);
142
+ }
143
+ return true;
135
144
  }
136
145
  }
@@ -62,9 +62,9 @@ export type GetCsrfTokenResult = RequireExactlyOne<{
62
62
  *
63
63
  * @category Auth : Client
64
64
  */
65
- export declare function extractCsrfTokenHeader(response: Readonly<SelectFrom<Response, {
65
+ export declare function extractCsrfTokenHeader(response: Readonly<PartialWithUndefined<SelectFrom<Response, {
66
66
  headers: true;
67
- }>>, overrides?: PartialWithUndefined<{
67
+ }>>>, overrides?: PartialWithUndefined<{
68
68
  csrfHeaderName: string;
69
69
  }>): Readonly<GetCsrfTokenResult>;
70
70
  /**
@@ -45,7 +45,7 @@ export var CsrfTokenFailureReason;
45
45
  */
46
46
  export function extractCsrfTokenHeader(response, overrides = {}) {
47
47
  const csrfTokenHeaderName = overrides.csrfHeaderName || AuthHeaderName.CsrfToken;
48
- const rawCsrfToken = response.headers.get(csrfTokenHeaderName);
48
+ const rawCsrfToken = response.headers?.get(csrfTokenHeaderName);
49
49
  return parseCsrfToken(rawCsrfToken);
50
50
  }
51
51
  /**
@@ -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.3",
3
+ "version": "2.3.5",
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.47.0",
46
+ "@augment-vir/common": "^31.47.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.47.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.1.0",
66
66
  "typedoc": "^0.28.14"
67
67
  },
68
68
  "engines": {
@@ -5,7 +5,6 @@ import {
5
5
  type MaybePromise,
6
6
  type PartialWithUndefined,
7
7
  type SelectFrom,
8
- type SetOptionalWithUndefined,
9
8
  } from '@augment-vir/common';
10
9
  import {type AnyDuration} from 'date-vir';
11
10
  import {type EmptyObject} from 'type-fest';
@@ -41,14 +40,18 @@ export type FrontendAuthClientConfig = PartialWithUndefined<{
41
40
  * Get a response from the backend to see if the user is still authenticated. If the
42
41
  * response returns a non-authorized status, the user is wiped. Any other status is
43
42
  * ignored.
43
+ *
44
+ * If the user is not currently authorized, this should return `undefined` to prevent
45
+ * unnecessary network traffic.
44
46
  */
45
47
  performCheck: () => MaybePromise<
46
- SelectFrom<
47
- Response,
48
- {
49
- status: true;
50
- }
51
- >
48
+ | SelectFrom<
49
+ Response,
50
+ {
51
+ status: true;
52
+ }
53
+ >
54
+ | undefined
52
55
  >;
53
56
  /** @default {minutes: 1} */
54
57
  interval?: AnyDuration | undefined;
@@ -76,6 +79,7 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
76
79
  this.userCheckInterval = createBlockingInterval(
77
80
  async () => {
78
81
  const response = await config.checkUser?.performCheck();
82
+
79
83
  if (response) {
80
84
  await this.verifyResponseAuth({
81
85
  status: response.status,
@@ -223,26 +227,36 @@ export class FrontendAuthClient<AssumedUserParams extends JsonCompatibleObject =
223
227
  /**
224
228
  * Use to verify _all_ responses received from the backend. Immediately logs the user out once
225
229
  * an unauthorized response is detected.
230
+ *
231
+ * @returns `true` if the auth is okay, `false` otherwise.
226
232
  */
227
233
  public async verifyResponseAuth(
228
234
  response: Readonly<
229
- SetOptionalWithUndefined<
235
+ PartialWithUndefined<
230
236
  SelectFrom<
231
237
  Response,
232
238
  {
233
239
  status: true;
234
240
  headers: true;
235
241
  }
236
- >,
237
- 'headers'
242
+ >
238
243
  >
239
244
  >,
240
- ): Promise<void> {
245
+ ): Promise<boolean> {
241
246
  if (
242
247
  response.status === HttpStatus.Unauthorized &&
243
248
  !response.headers?.get(AuthHeaderName.IsSignUpAuth)
244
249
  ) {
245
250
  await this.logout();
251
+ return false;
252
+ }
253
+
254
+ /** If the response has a new CSRF token, store it. */
255
+ const {csrfToken} = extractCsrfTokenHeader(response, this.config.overrides);
256
+ if (csrfToken) {
257
+ storeCsrfToken(csrfToken, this.config.overrides);
246
258
  }
259
+
260
+ return true;
247
261
  }
248
262
  }
package/src/csrf-token.ts CHANGED
@@ -77,14 +77,14 @@ export type GetCsrfTokenResult = RequireExactlyOne<{
77
77
  * @category Auth : Client
78
78
  */
79
79
  export function extractCsrfTokenHeader(
80
- response: Readonly<SelectFrom<Response, {headers: true}>>,
80
+ response: Readonly<PartialWithUndefined<SelectFrom<Response, {headers: true}>>>,
81
81
  overrides: PartialWithUndefined<{
82
82
  csrfHeaderName: string;
83
83
  }> = {},
84
84
  ): Readonly<GetCsrfTokenResult> {
85
85
  const csrfTokenHeaderName = overrides.csrfHeaderName || AuthHeaderName.CsrfToken;
86
86
 
87
- const rawCsrfToken = response.headers.get(csrfTokenHeaderName);
87
+ const rawCsrfToken = response.headers?.get(csrfTokenHeaderName);
88
88
 
89
89
  return parseCsrfToken(rawCsrfToken);
90
90
  }
@@ -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';