@better-auth/infra 0.3.5 → 0.3.7

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 CHANGED
@@ -5,8 +5,21 @@ All notable changes to `@better-auth/infra` are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.3.7] - 2026-07-20
9
+
10
+ ### Added
11
+
12
+ - **`GET /dash/config` error URL insight** — Config insights now include `hasErrorURLConfigured`, reflecting whether `onAPIError.errorURL` is set.
13
+
14
+ ## [0.3.6] - 2026-07-09
15
+
16
+ ### Changed
17
+
18
+ - **Activity tracking writes** — `lastActiveAt` updates now run through Better Auth background tasks (`runInBackgroundOrAwait`) instead of blocking the request or using fire-and-forget promises, so activity tracking no longer delays responses when a background runner is available.
19
+
8
20
  ## [0.3.5] - 2026-07-06
9
21
 
22
+
10
23
  ### Added
11
24
 
12
25
  - **`GET /dash/users` partial fetches** — Endpoint was optimized to load only the requested fields (sessions or accounts) instead of all fields.
@@ -129,6 +142,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
129
142
 
130
143
  - Fixed impossible travel security challenges.
131
144
 
145
+ [0.3.7]: https://github.com/better-auth/infrastructure/compare/infra@v0.3.6...infra@v0.3.7
146
+ [0.3.6]: https://github.com/better-auth/infrastructure/compare/infra@v0.3.5...infra@v0.3.6
132
147
  [0.3.5]: https://github.com/better-auth/infrastructure/compare/infra@v0.3.4...infra@v0.3.5
133
148
  [0.3.4]: https://github.com/better-auth/infrastructure/compare/infra@v0.3.3...infra@v0.3.4
134
149
  [0.3.3]: https://github.com/better-auth/infrastructure/compare/infra@v0.3.2...infra@v0.3.3
package/dist/client.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { n as hash, o as createKV } from "./crypto-DvC9lT5e.mjs";
2
- import { a as resolveSentinelClientIdentifyUrl, c as dashClient, i as solvePoWChallenge, n as decodePoWChallenge, o as generateRequestId, r as encodePoWSolution, s as identify, t as createPowRetryTimeout } from "./pow-retry-DEaL-FIC.mjs";
1
+ import { n as hash, o as createKV } from "./crypto--3ycICW4.mjs";
2
+ import { a as resolveSentinelClientIdentifyUrl, c as dashClient, i as solvePoWChallenge, n as decodePoWChallenge, o as generateRequestId, r as encodePoWSolution, s as identify, t as createPowRetryTimeout } from "./pow-retry-Dy1D-TKx.mjs";
3
3
  import { env } from "@better-auth/core/env";
4
4
  //#region src/sentinel/fingerprint.ts
5
5
  function murmurhash3(str, seed = 0) {
@@ -1,7 +1,7 @@
1
1
  import { env } from "@better-auth/core/env";
2
2
  //#endregion
3
3
  //#region src/version.ts
4
- const PLUGIN_VERSION = "0.3.5";
4
+ const PLUGIN_VERSION = "0.3.7";
5
5
  //#endregion
6
6
  //#region src/constants.ts
7
7
  /**
@@ -1,4 +1,4 @@
1
- import { i as INFRA_USER_AGENT } from "./constants-COVOGExF.mjs";
1
+ import { i as INFRA_USER_AGENT } from "./constants-AfApXLhx.mjs";
2
2
  import { createFetch } from "@better-fetch/fetch";
3
3
  //#region src/fetch.ts
4
4
  function createAPI(options, fetchOptions) {
package/dist/email.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { i as INFRA_USER_AGENT, n as INFRA_API_URL } from "./constants-COVOGExF.mjs";
1
+ import { i as INFRA_USER_AGENT, n as INFRA_API_URL } from "./constants-AfApXLhx.mjs";
2
2
  import { logger } from "better-auth";
3
3
  import { env } from "@better-auth/core/env";
4
4
  import { createFetch } from "@better-fetch/fetch";
package/dist/index.d.mts CHANGED
@@ -1245,7 +1245,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1245
1245
  emailVerified: boolean;
1246
1246
  name: string;
1247
1247
  image?: string | null | undefined;
1248
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1248
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1249
1249
  };
1250
1250
  update: {
1251
1251
  after(user: {
@@ -1256,7 +1256,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1256
1256
  emailVerified: boolean;
1257
1257
  name: string;
1258
1258
  image?: string | null | undefined;
1259
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1259
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1260
1260
  };
1261
1261
  delete: {
1262
1262
  after(user: {
@@ -1267,7 +1267,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1267
1267
  emailVerified: boolean;
1268
1268
  name: string;
1269
1269
  image?: string | null | undefined;
1270
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1270
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1271
1271
  };
1272
1272
  };
1273
1273
  session: {
@@ -1281,7 +1281,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1281
1281
  token: string;
1282
1282
  ipAddress?: string | null | undefined;
1283
1283
  userAgent?: string | null | undefined;
1284
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<{
1284
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<{
1285
1285
  data: {
1286
1286
  loginMethod: string | null;
1287
1287
  };
@@ -1295,7 +1295,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1295
1295
  token: string;
1296
1296
  ipAddress?: string | null | undefined;
1297
1297
  userAgent?: string | null | undefined;
1298
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1298
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1299
1299
  };
1300
1300
  delete: {
1301
1301
  after(session: {
@@ -1307,7 +1307,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1307
1307
  token: string;
1308
1308
  ipAddress?: string | null | undefined;
1309
1309
  userAgent?: string | null | undefined;
1310
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1310
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1311
1311
  };
1312
1312
  };
1313
1313
  account: {
@@ -1326,7 +1326,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1326
1326
  refreshTokenExpiresAt?: Date | null | undefined;
1327
1327
  scope?: string | null | undefined;
1328
1328
  password?: string | null | undefined;
1329
- }, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1329
+ }, _ctx: GenericEndpointContext | null): Promise<void>;
1330
1330
  };
1331
1331
  update: {
1332
1332
  after(account: {
@@ -1343,7 +1343,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1343
1343
  refreshTokenExpiresAt?: Date | null | undefined;
1344
1344
  scope?: string | null | undefined;
1345
1345
  password?: string | null | undefined;
1346
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1346
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1347
1347
  };
1348
1348
  delete: {
1349
1349
  after(account: {
@@ -1360,7 +1360,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1360
1360
  refreshTokenExpiresAt?: Date | null | undefined;
1361
1361
  scope?: string | null | undefined;
1362
1362
  password?: string | null | undefined;
1363
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1363
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1364
1364
  };
1365
1365
  };
1366
1366
  verification: {
@@ -1372,7 +1372,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1372
1372
  value: string;
1373
1373
  expiresAt: Date;
1374
1374
  identifier: string;
1375
- } & Record<string, unknown>, _ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1375
+ } & Record<string, unknown>, _ctx: GenericEndpointContext | null): Promise<void>;
1376
1376
  };
1377
1377
  delete: {
1378
1378
  after(verification: {
@@ -1382,7 +1382,7 @@ declare const dash: <O extends DashOptions>(options?: O) => {
1382
1382
  value: string;
1383
1383
  expiresAt: Date;
1384
1384
  identifier: string;
1385
- } & Record<string, unknown>, ctx: import("better-auth").GenericEndpointContext | null): Promise<void>;
1385
+ } & Record<string, unknown>, ctx: GenericEndpointContext | null): Promise<void>;
1386
1386
  };
1387
1387
  };
1388
1388
  };
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { i as INFRA_USER_AGENT, n as INFRA_API_URL, o as PLUGIN_VERSION, r as INFRA_KV_URL } from "./constants-COVOGExF.mjs";
2
- import { a as createAPI, o as createKV, r as hmacSha256Hex } from "./crypto-DvC9lT5e.mjs";
1
+ import { i as INFRA_USER_AGENT, n as INFRA_API_URL, o as PLUGIN_VERSION, r as INFRA_KV_URL } from "./constants-AfApXLhx.mjs";
2
+ import { a as createAPI, o as createKV, r as hmacSha256Hex } from "./crypto--3ycICW4.mjs";
3
3
  import { EMAIL_TEMPLATES, createEmailSender, sendBulkEmails, sendEmail } from "./email.mjs";
4
4
  import { getCurrentAuthContext } from "@better-auth/core/context";
5
5
  import { APIError, generateId, getAuthTables, logger } from "better-auth";
@@ -3262,7 +3262,8 @@ const getConfig = (options) => {
3262
3262
  secure: typeof ctx.context.options.advanced?.defaultCookieAttributes?.secure !== "undefined" ? ctx.context.options.advanced?.defaultCookieAttributes?.secure : null
3263
3263
  } : null,
3264
3264
  appName: ctx.context.options.appName || null,
3265
- hasJoinsEnabled: ctx.context.options.experimental?.joins === true
3265
+ hasJoinsEnabled: ctx.context.options.experimental?.joins === true,
3266
+ hasErrorURLConfigured: !!ctx.context.options.onAPIError?.errorURL
3266
3267
  }
3267
3268
  };
3268
3269
  });
@@ -7585,19 +7586,12 @@ const getUserDetails = (options) => {
7585
7586
  shouldUpdateLastActiveAt = true;
7586
7587
  }
7587
7588
  }
7588
- if (shouldUpdateLastActiveAt && lastActiveAt) {
7589
- const updateActivity = async () => {
7590
- try {
7591
- await ctx.context.internalAdapter.updateUser(userId, {
7592
- lastActiveAt,
7593
- updatedAt: /* @__PURE__ */ new Date()
7594
- });
7595
- } catch (error) {
7596
- ctx.context.logger.error("[Dash] Failed to update user lastActiveAt:", error);
7597
- }
7598
- };
7599
- updateActivity();
7600
- }
7589
+ if (shouldUpdateLastActiveAt && lastActiveAt) await ctx.context.runInBackgroundOrAwait(ctx.context.internalAdapter.updateUser(userId, {
7590
+ lastActiveAt,
7591
+ updatedAt: /* @__PURE__ */ new Date()
7592
+ }).catch((error) => {
7593
+ ctx.context.logger.error("[Dash] Failed to update user lastActiveAt:", error);
7594
+ }));
7601
7595
  }
7602
7596
  const { session: _joinedSessions, ...userWithoutSessions } = user;
7603
7597
  return {
@@ -8514,6 +8508,18 @@ const dash = (options) => {
8514
8508
  };
8515
8509
  const $kv = createKV(opts);
8516
8510
  const activityUpdateInterval = opts.activityTracking?.updateInterval ?? 3e5;
8511
+ const scheduleLastActiveUpdate = async (ctx, userId) => {
8512
+ await ctx.context.runInBackgroundOrAwait(ctx.context.adapter.updateMany({
8513
+ model: "user",
8514
+ where: [{
8515
+ field: "id",
8516
+ value: userId
8517
+ }],
8518
+ update: { lastActiveAt: /* @__PURE__ */ new Date() }
8519
+ }).catch((error) => {
8520
+ logger.warn("[Dash] Failed to update user activity", error);
8521
+ }));
8522
+ };
8517
8523
  const { tracker } = initTrackEvents($api);
8518
8524
  const { trackUserSignedUp, trackUserProfileUpdated, trackUserProfileImageUpdated, trackUserEmailVerified, trackUserBanned, trackUserUnBanned, trackUserDeleted } = initUserEvents(tracker);
8519
8525
  const { trackEmailVerificationSent, trackEmailSignInAttempt, trackUserSignedIn, trackUserSignedOut, trackSessionCreated, trackSocialSignInAttempt, trackSocialSignInRedirectionAttempt, trackUserImpersonated, trackUserImpersonationStop, trackSessionRevoked, trackSessionRevokedAll } = initSessionEvents(tracker);
@@ -8700,18 +8706,7 @@ const dash = (options) => {
8700
8706
  const knownImpersonator = resolveUserFromContext(session.impersonatedBy, ctx);
8701
8707
  trackUserImpersonated(enrichedSession, trigger, ctx, location, eventUser, knownImpersonator);
8702
8708
  }
8703
- if (opts.activityTracking?.enabled) try {
8704
- await ctx.context.adapter.updateMany({
8705
- model: "user",
8706
- where: [{
8707
- field: "id",
8708
- value: session.userId
8709
- }],
8710
- update: { lastActiveAt: /* @__PURE__ */ new Date() }
8711
- });
8712
- } catch (error) {
8713
- logger.warn("[Dash] Failed to update user activity", error);
8714
- }
8709
+ if (opts.activityTracking?.enabled) await scheduleLastActiveUpdate(ctx, session.userId);
8715
8710
  }
8716
8711
  },
8717
8712
  delete: { async after(session, _ctx) {
@@ -8852,16 +8847,7 @@ const dash = (options) => {
8852
8847
  if (lastUpdate) {
8853
8848
  if (now - new Date(lastUpdate).getTime() < activityUpdateInterval) return;
8854
8849
  }
8855
- ctx.context.adapter.updateMany({
8856
- model: "user",
8857
- where: [{
8858
- field: "id",
8859
- value: userId
8860
- }],
8861
- update: { lastActiveAt: /* @__PURE__ */ new Date() }
8862
- }).catch((error) => {
8863
- logger.warn("[Dash] Failed to update user activity", error);
8864
- });
8850
+ await scheduleLastActiveUpdate(ctx, userId);
8865
8851
  }),
8866
8852
  matcher: (ctx) => ctx.request?.method !== "GET"
8867
8853
  }]
package/dist/native.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { o as createKV, t as bytesToHex } from "./crypto-DvC9lT5e.mjs";
2
- import { a as resolveSentinelClientIdentifyUrl, c as dashClient, i as solvePoWChallenge, n as decodePoWChallenge, r as encodePoWSolution, s as identify, t as createPowRetryTimeout } from "./pow-retry-DEaL-FIC.mjs";
1
+ import { o as createKV, t as bytesToHex } from "./crypto--3ycICW4.mjs";
2
+ import { a as resolveSentinelClientIdentifyUrl, c as dashClient, i as solvePoWChallenge, n as decodePoWChallenge, r as encodePoWSolution, s as identify, t as createPowRetryTimeout } from "./pow-retry-Dy1D-TKx.mjs";
3
3
  import { env } from "@better-auth/core/env";
4
4
  import { Dimensions, InteractionManager, PixelRatio, Platform } from "react-native";
5
5
  //#region src/sentinel/native/components.ts
@@ -1,4 +1,4 @@
1
- import { i as randomBytes, n as hash, t as bytesToHex } from "./crypto-DvC9lT5e.mjs";
1
+ import { i as randomBytes, n as hash, t as bytesToHex } from "./crypto--3ycICW4.mjs";
2
2
  //#region src/dash-client.ts
3
3
  function resolveDashUserId(input, options) {
4
4
  return input.userId || options?.resolveUserId?.({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/infra",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "Dashboard and analytics plugin for Better Auth",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -62,13 +62,13 @@
62
62
  },
63
63
  "homepage": "https://better-auth.com",
64
64
  "devDependencies": {
65
- "@better-auth/scim": "1.7.0-rc.0",
66
- "@better-auth/sso": "1.7.0-rc.0",
65
+ "@better-auth/scim": "1.7.0-rc.1",
66
+ "@better-auth/sso": "1.7.0-rc.1",
67
67
  "@infra/mocks": "0.0.0",
68
68
  "@infra/utils": "0.0.0",
69
69
  "@types/bun": "latest",
70
70
  "@types/node": "^24.12.0",
71
- "better-auth": "1.7.0-rc.0",
71
+ "better-auth": "1.7.0-rc.1",
72
72
  "expo-crypto": "^14.0.2",
73
73
  "happy-dom": "^20.9.0",
74
74
  "msw": "^2.14.6",