@better-auth/infra 0.2.13 → 0.3.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/dist/native.mjs CHANGED
@@ -1,6 +1,5 @@
1
- import "./constants-CvriWQVc.mjs";
2
- import { n as createKV } from "./fetch-DiAhoiKA.mjs";
3
- import { a as resolveSentinelClientIdentifyUrl, c as bytesToHex, i as solvePoWChallenge, n as decodePoWChallenge, r as encodePoWSolution, s as identify, t as createPowRetryTimeout, u as dashClient } from "./pow-retry-D2RRftJr.mjs";
1
+ import { o as createKV, t as bytesToHex } from "./crypto-DjtrPUlP.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-24lSgXId.mjs";
4
3
  import { env } from "@better-auth/core/env";
5
4
  import { Dimensions, InteractionManager, PixelRatio, Platform } from "react-native";
6
5
  //#region src/sentinel/native/components.ts
@@ -100,9 +99,19 @@ const NATIVE_IDENTIFY_CONTEXT_URL = "react-native://identify";
100
99
  function createNativeFingerprintRuntime(deps) {
101
100
  let cached = null;
102
101
  let pending = null;
103
- let identifySent = false;
104
- let identifyComplete = null;
105
- let identifyCompleteResolve = null;
102
+ let identifySucceeded = false;
103
+ let identifyExpiresAt = null;
104
+ let identifyInFlight = null;
105
+ async function expireIdentifySessionIfStale() {
106
+ if (!identifySucceeded || identifyExpiresAt === null) return;
107
+ if (Date.now() < identifyExpiresAt) return;
108
+ identifySucceeded = false;
109
+ identifyExpiresAt = null;
110
+ if (cached) cached = {
111
+ ...cached,
112
+ requestId: await generateRequestId()
113
+ };
114
+ }
106
115
  async function getFingerprint() {
107
116
  if (cached != null) return cached;
108
117
  if (pending != null) return pending;
@@ -127,39 +136,42 @@ function createNativeFingerprintRuntime(deps) {
127
136
  return pending;
128
137
  }
129
138
  async function sendIdentify() {
130
- if (identifySent) return;
131
- const fingerprint = await getFingerprint();
132
- if (!fingerprint) return;
133
- identifySent = true;
134
- identifyComplete = new Promise((resolve) => {
135
- identifyCompleteResolve = resolve;
136
- });
137
- const payload = {
138
- visitorId: fingerprint.visitorId,
139
- requestId: fingerprint.requestId,
140
- confidence: fingerprint.confidence,
141
- components: fingerprint.components,
142
- url: NATIVE_IDENTIFY_CONTEXT_URL,
143
- incognito: false
144
- };
145
- try {
146
- await identify(deps.$kv, payload);
147
- } catch (error) {
148
- console.warn("[Sentinel native] Identify request failed:", error);
149
- } finally {
150
- identifyCompleteResolve?.();
151
- identifyCompleteResolve = null;
152
- }
139
+ await expireIdentifySessionIfStale();
140
+ if (identifySucceeded) return true;
141
+ if (identifyInFlight !== null) return identifyInFlight;
142
+ identifyInFlight = (async () => {
143
+ const fingerprint = await getFingerprint();
144
+ if (!fingerprint) return false;
145
+ const payload = {
146
+ visitorId: fingerprint.visitorId,
147
+ requestId: fingerprint.requestId,
148
+ confidence: fingerprint.confidence,
149
+ components: fingerprint.components,
150
+ url: NATIVE_IDENTIFY_CONTEXT_URL,
151
+ incognito: false
152
+ };
153
+ try {
154
+ const result = await identify(deps.$kv, payload);
155
+ identifySucceeded = true;
156
+ identifyExpiresAt = result.expiresAt ?? null;
157
+ return true;
158
+ } catch (error) {
159
+ console.warn("[Sentinel native] Identify request failed:", error);
160
+ return false;
161
+ } finally {
162
+ identifyInFlight = null;
163
+ }
164
+ })();
165
+ return identifyInFlight;
153
166
  }
154
- async function waitForIdentify(timeoutMs) {
155
- if (!identifyComplete) return;
156
- const ms = timeoutMs ?? 1e3;
157
- await Promise.race([identifyComplete, new Promise((resolve) => setTimeout(resolve, ms))]);
167
+ function appendIdentification(headers, fingerprint) {
168
+ headers.set("X-Visitor-Id", fingerprint.visitorId);
169
+ if (identifySucceeded) headers.set("X-Request-Id", fingerprint.requestId);
158
170
  }
159
171
  return {
160
172
  getFingerprint,
161
173
  sendIdentify,
162
- waitForIdentify
174
+ appendIdentification
163
175
  };
164
176
  }
165
177
  const VISITOR_STORAGE_KEY = "better-auth.infra.sentinel.visitorId";
@@ -219,6 +231,19 @@ const sentinelNativeClient = (options) => {
219
231
  envKvUrl: env.BETTER_AUTH_KV_URL
220
232
  }),
221
233
  kvTimeout: options?.kvTimeout
234
+ }, {
235
+ throw: true,
236
+ retry: {
237
+ type: "exponential",
238
+ attempts: 2,
239
+ baseDelay: 400,
240
+ maxDelay: 600,
241
+ shouldRetry(response) {
242
+ if (response === null) return true;
243
+ if (response.status === 429) return true;
244
+ return response.status >= 500;
245
+ }
246
+ }
222
247
  }),
223
248
  getOrCreateVisitorId: () => getOrCreateVisitorId(options?.storage)
224
249
  });
@@ -231,14 +256,11 @@ const sentinelNativeClient = (options) => {
231
256
  id: "sentinel-fingerprint",
232
257
  name: "sentinel-fingerprint",
233
258
  hooks: { async onRequest(context) {
234
- await runtime.waitForIdentify(options?.kvTimeout);
259
+ await runtime.sendIdentify();
235
260
  const fingerprint = await runtime.getFingerprint();
236
261
  if (!fingerprint) return context;
237
262
  const headers = context.headers || new Headers();
238
- if (headers instanceof Headers) {
239
- headers.set("X-Visitor-Id", fingerprint.visitorId);
240
- headers.set("X-Request-Id", fingerprint.requestId);
241
- }
263
+ if (headers instanceof Headers) runtime.appendIdentification(headers, fingerprint);
242
264
  return {
243
265
  ...context,
244
266
  headers
@@ -270,10 +292,7 @@ const sentinelNativeClient = (options) => {
270
292
  const fingerprint = await runtime.getFingerprint();
271
293
  const retryHeaders = new Headers();
272
294
  retryHeaders.set("X-PoW-Solution", encodePoWSolution(solution));
273
- if (fingerprint) {
274
- retryHeaders.set("X-Visitor-Id", fingerprint.visitorId);
275
- retryHeaders.set("X-Request-Id", fingerprint.requestId);
276
- }
295
+ if (fingerprint) runtime.appendIdentification(retryHeaders, fingerprint);
277
296
  retryHeaders.set("Content-Type", "application/json");
278
297
  const powRetry = createPowRetryTimeout(req.timeout);
279
298
  try {
@@ -1,3 +1,4 @@
1
+ import { i as randomBytes, n as hash, t as bytesToHex } from "./crypto-DjtrPUlP.mjs";
1
2
  //#region src/dash-client.ts
2
3
  function resolveDashUserId(input, options) {
3
4
  return input.userId || options?.resolveUserId?.({
@@ -45,28 +46,13 @@ const dashClient = (options) => {
45
46
  };
46
47
  };
47
48
  //#endregion
48
- //#region src/crypto.ts
49
- function randomBytes(length) {
50
- const bytes = new Uint8Array(length);
51
- crypto.getRandomValues(bytes);
52
- return bytes;
53
- }
54
- function bytesToHex(bytes) {
55
- return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
56
- }
57
- async function hash(message) {
58
- const msgBuffer = new TextEncoder().encode(message);
59
- const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
60
- return bytesToHex(new Uint8Array(hashBuffer));
61
- }
62
- //#endregion
63
49
  //#region src/identification-client.ts
64
50
  function generateRequestId() {
65
51
  const hex = bytesToHex(randomBytes(16));
66
52
  return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20, 32)}`;
67
53
  }
68
54
  async function identify($kv, payload) {
69
- await $kv("/identify", {
55
+ return await $kv("/identify", {
70
56
  method: "POST",
71
57
  body: payload
72
58
  });
@@ -181,4 +167,4 @@ function createPowRetryTimeout(timeoutMs) {
181
167
  };
182
168
  }
183
169
  //#endregion
184
- export { resolveSentinelClientIdentifyUrl as a, bytesToHex as c, solvePoWChallenge as i, hash as l, decodePoWChallenge as n, generateRequestId as o, encodePoWSolution as r, identify as s, createPowRetryTimeout as t, dashClient as u };
170
+ export { resolveSentinelClientIdentifyUrl as a, dashClient as c, solvePoWChallenge as i, decodePoWChallenge as n, generateRequestId as o, encodePoWSolution as r, identify as s, createPowRetryTimeout as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/infra",
3
- "version": "0.2.13",
3
+ "version": "0.3.0",
4
4
  "description": "Dashboard and analytics plugin for Better Auth",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -39,7 +39,8 @@
39
39
  },
40
40
  "files": [
41
41
  "dist",
42
- "README.md"
42
+ "README.md",
43
+ "CHANGELOG.md"
43
44
  ],
44
45
  "keywords": [
45
46
  "better-auth",
@@ -53,21 +54,21 @@
53
54
  "license": "MIT",
54
55
  "repository": {
55
56
  "type": "git",
56
- "url": "git+https://github.com/better-auth/better-auth-infra.git",
57
+ "url": "git+https://github.com/better-auth/infrastructure.git",
57
58
  "directory": "packages/infra"
58
59
  },
59
60
  "bugs": {
60
- "url": "https://github.com/better-auth/better-auth-infra/issues"
61
+ "url": "https://github.com/better-auth/infrastructure/issues"
61
62
  },
62
63
  "homepage": "https://better-auth.com",
63
64
  "devDependencies": {
64
- "@better-auth/scim": "1.6.14",
65
- "@better-auth/sso": "1.6.14",
65
+ "@better-auth/scim": "1.7.0-beta.8",
66
+ "@better-auth/sso": "1.7.0-beta.8",
66
67
  "@infra/mocks": "0.0.0",
67
68
  "@infra/utils": "0.0.0",
68
69
  "@types/bun": "latest",
69
70
  "@types/node": "^24.12.0",
70
- "better-auth": "1.6.14",
71
+ "better-auth": "1.7.0-beta.8",
71
72
  "expo-crypto": "^14.0.2",
72
73
  "happy-dom": "^20.9.0",
73
74
  "msw": "^2.14.6",
@@ -76,7 +77,8 @@
76
77
  "zod": "^4.3.6"
77
78
  },
78
79
  "dependencies": {
79
- "@better-fetch/fetch": "^1.1.21",
80
+ "@better-auth/utils": "^0.4.2",
81
+ "@better-fetch/fetch": "1.3.1",
80
82
  "better-call": "^1.3.2",
81
83
  "jose": "^6.1.0",
82
84
  "libphonenumber-js": "^1.13.3"
@@ -85,7 +87,6 @@
85
87
  "better-auth": ">=1.4.0",
86
88
  "zod": ">=4.1.12",
87
89
  "@better-auth/core": ">=1.4.0",
88
- "@better-auth/sso": ">=1.4.0",
89
90
  "react-native": ">=0.74.0",
90
91
  "@react-native-async-storage/async-storage": ">=1.21.0",
91
92
  "expo-constants": ">=16.0.0",
@@ -1,26 +0,0 @@
1
- import "./constants-CvriWQVc.mjs";
2
- import { createFetch } from "@better-fetch/fetch";
3
- //#region src/fetch.ts
4
- function createAPI(options, fetchOptions) {
5
- return createFetch({
6
- baseURL: options.apiUrl,
7
- headers: {
8
- "user-agent": "better-auth",
9
- "x-api-key": options.apiKey
10
- },
11
- timeout: options.apiTimeout,
12
- ...fetchOptions
13
- });
14
- }
15
- function createKV(options, fetchOptions) {
16
- const headers = { "user-agent": "better-auth" };
17
- if (options.apiKey) headers["x-api-key"] = options.apiKey;
18
- return createFetch({
19
- baseURL: options.kvUrl,
20
- headers,
21
- timeout: options.kvTimeout ?? 1e3,
22
- ...fetchOptions
23
- });
24
- }
25
- //#endregion
26
- export { createKV as n, createAPI as t };