@better-auth/telemetry 1.5.0-beta.18 → 1.5.0-beta.19
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 +17 -0
- package/package.json +21 -7
- package/.turbo/turbo-build.log +0 -16
- package/src/detectors/detect-auth-config.ts +0 -206
- package/src/detectors/detect-database.ts +0 -22
- package/src/detectors/detect-framework.ts +0 -23
- package/src/detectors/detect-project-info.ts +0 -18
- package/src/detectors/detect-runtime.ts +0 -31
- package/src/detectors/detect-system-info.ts +0 -209
- package/src/index.ts +0 -94
- package/src/project-id.ts +0 -27
- package/src/telemetry.test.ts +0 -349
- package/src/types.ts +0 -16
- package/src/utils/hash.ts +0 -9
- package/src/utils/id.ts +0 -5
- package/src/utils/import-util.ts +0 -3
- package/src/utils/package-json.ts +0 -75
- package/tsconfig.json +0 -8
- package/tsdown.config.ts +0 -8
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Better Auth Telemetry
|
|
2
|
+
|
|
3
|
+
Telemetry package for [Better Auth](https://www.better-auth.com) — anonymous usage analytics to help improve the framework.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @better-auth/telemetry
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Documentation
|
|
12
|
+
|
|
13
|
+
For full documentation, visit [better-auth.com](https://www.better-auth.com).
|
|
14
|
+
|
|
15
|
+
## License
|
|
16
|
+
|
|
17
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,13 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-auth/telemetry",
|
|
3
|
-
"version": "1.5.0-beta.
|
|
3
|
+
"version": "1.5.0-beta.19",
|
|
4
4
|
"description": "Telemetry package for Better Auth",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://www.better-auth.com",
|
|
6
8
|
"repository": {
|
|
7
9
|
"type": "git",
|
|
8
10
|
"url": "git+https://github.com/better-auth/better-auth.git",
|
|
9
11
|
"directory": "packages/telemetry"
|
|
10
12
|
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"auth",
|
|
15
|
+
"telemetry",
|
|
16
|
+
"typescript",
|
|
17
|
+
"better-auth"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
11
25
|
"main": "./dist/index.mjs",
|
|
12
26
|
"module": "./dist/index.mjs",
|
|
13
27
|
"types": "./dist/index.d.mts",
|
|
@@ -25,17 +39,17 @@
|
|
|
25
39
|
]
|
|
26
40
|
}
|
|
27
41
|
},
|
|
28
|
-
"devDependencies": {
|
|
29
|
-
"tsdown": "^0.20.3",
|
|
30
|
-
"type-fest": "^5.4.4",
|
|
31
|
-
"@better-auth/core": "1.5.0-beta.18"
|
|
32
|
-
},
|
|
33
42
|
"dependencies": {
|
|
34
43
|
"@better-auth/utils": "0.3.1",
|
|
35
44
|
"@better-fetch/fetch": "1.1.21"
|
|
36
45
|
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"tsdown": "^0.20.3",
|
|
48
|
+
"type-fest": "^5.4.4",
|
|
49
|
+
"@better-auth/core": "1.5.0-beta.19"
|
|
50
|
+
},
|
|
37
51
|
"peerDependencies": {
|
|
38
|
-
"@better-auth/core": "1.5.0-beta.
|
|
52
|
+
"@better-auth/core": "1.5.0-beta.19"
|
|
39
53
|
},
|
|
40
54
|
"scripts": {
|
|
41
55
|
"build": "tsdown",
|
package/.turbo/turbo-build.log
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
> @better-auth/telemetry@1.5.0-beta.18 build /home/runner/work/better-auth/better-auth/packages/telemetry
|
|
3
|
-
> tsdown
|
|
4
|
-
|
|
5
|
-
[34mℹ[39m tsdown [2mv0.20.3[22m powered by rolldown [2mv1.0.0-rc.3[22m
|
|
6
|
-
[34mℹ[39m config file: [4m/home/runner/work/better-auth/better-auth/packages/telemetry/tsdown.config.ts[24m
|
|
7
|
-
[34mℹ[39m entry: [34msrc/index.ts[39m
|
|
8
|
-
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
9
|
-
[34mℹ[39m Build start
|
|
10
|
-
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m18.20 kB[22m [2m│ gzip: 4.84 kB[22m
|
|
11
|
-
[34mℹ[39m [2mdist/[22mindex.mjs.map [2m34.79 kB[22m [2m│ gzip: 8.87 kB[22m
|
|
12
|
-
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 7.70 kB[22m [2m│ gzip: 1.96 kB[22m
|
|
13
|
-
[34mℹ[39m 3 files, total: 60.69 kB
|
|
14
|
-
[33m[PLUGIN_TIMINGS] Warning:[0m Your build spent significant time in plugin `rolldown-plugin-dts:generate`. See https://rolldown.rs/options/checks#plugintimings for more details.
|
|
15
|
-
|
|
16
|
-
[32m✔[39m Build complete in [32m10547ms[39m
|
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import type { BetterAuthOptions } from "@better-auth/core";
|
|
2
|
-
import type { TelemetryContext } from "../types";
|
|
3
|
-
|
|
4
|
-
export async function getTelemetryAuthConfig(
|
|
5
|
-
options: BetterAuthOptions,
|
|
6
|
-
context?: TelemetryContext | undefined,
|
|
7
|
-
) {
|
|
8
|
-
return {
|
|
9
|
-
database: context?.database,
|
|
10
|
-
adapter: context?.adapter,
|
|
11
|
-
emailVerification: {
|
|
12
|
-
sendVerificationEmail: !!options.emailVerification?.sendVerificationEmail,
|
|
13
|
-
sendOnSignUp: !!options.emailVerification?.sendOnSignUp,
|
|
14
|
-
sendOnSignIn: !!options.emailVerification?.sendOnSignIn,
|
|
15
|
-
autoSignInAfterVerification:
|
|
16
|
-
!!options.emailVerification?.autoSignInAfterVerification,
|
|
17
|
-
expiresIn: options.emailVerification?.expiresIn,
|
|
18
|
-
beforeEmailVerification:
|
|
19
|
-
!!options.emailVerification?.beforeEmailVerification,
|
|
20
|
-
afterEmailVerification:
|
|
21
|
-
!!options.emailVerification?.afterEmailVerification,
|
|
22
|
-
},
|
|
23
|
-
emailAndPassword: {
|
|
24
|
-
enabled: !!options.emailAndPassword?.enabled,
|
|
25
|
-
disableSignUp: !!options.emailAndPassword?.disableSignUp,
|
|
26
|
-
requireEmailVerification:
|
|
27
|
-
!!options.emailAndPassword?.requireEmailVerification,
|
|
28
|
-
maxPasswordLength: options.emailAndPassword?.maxPasswordLength,
|
|
29
|
-
minPasswordLength: options.emailAndPassword?.minPasswordLength,
|
|
30
|
-
sendResetPassword: !!options.emailAndPassword?.sendResetPassword,
|
|
31
|
-
resetPasswordTokenExpiresIn:
|
|
32
|
-
options.emailAndPassword?.resetPasswordTokenExpiresIn,
|
|
33
|
-
onPasswordReset: !!options.emailAndPassword?.onPasswordReset,
|
|
34
|
-
password: {
|
|
35
|
-
hash: !!options.emailAndPassword?.password?.hash,
|
|
36
|
-
verify: !!options.emailAndPassword?.password?.verify,
|
|
37
|
-
},
|
|
38
|
-
autoSignIn: !!options.emailAndPassword?.autoSignIn,
|
|
39
|
-
revokeSessionsOnPasswordReset:
|
|
40
|
-
!!options.emailAndPassword?.revokeSessionsOnPasswordReset,
|
|
41
|
-
},
|
|
42
|
-
socialProviders: await Promise.all(
|
|
43
|
-
Object.keys(options.socialProviders || {}).map(async (key) => {
|
|
44
|
-
const p =
|
|
45
|
-
options.socialProviders?.[
|
|
46
|
-
key as keyof typeof options.socialProviders
|
|
47
|
-
];
|
|
48
|
-
if (!p) return {};
|
|
49
|
-
const provider = typeof p === "function" ? await p() : p;
|
|
50
|
-
return {
|
|
51
|
-
id: key,
|
|
52
|
-
mapProfileToUser: !!provider.mapProfileToUser,
|
|
53
|
-
disableDefaultScope: !!provider.disableDefaultScope,
|
|
54
|
-
disableIdTokenSignIn: !!provider.disableIdTokenSignIn,
|
|
55
|
-
disableImplicitSignUp: provider.disableImplicitSignUp,
|
|
56
|
-
disableSignUp: provider.disableSignUp,
|
|
57
|
-
getUserInfo: !!provider.getUserInfo,
|
|
58
|
-
overrideUserInfoOnSignIn: !!provider.overrideUserInfoOnSignIn,
|
|
59
|
-
prompt: provider.prompt,
|
|
60
|
-
verifyIdToken: !!provider.verifyIdToken,
|
|
61
|
-
scope: provider.scope,
|
|
62
|
-
refreshAccessToken: !!provider.refreshAccessToken,
|
|
63
|
-
};
|
|
64
|
-
}),
|
|
65
|
-
),
|
|
66
|
-
plugins: options.plugins?.map((p) => p.id.toString()),
|
|
67
|
-
user: {
|
|
68
|
-
modelName: options.user?.modelName,
|
|
69
|
-
fields: options.user?.fields,
|
|
70
|
-
additionalFields: options.user?.additionalFields,
|
|
71
|
-
changeEmail: {
|
|
72
|
-
enabled: options.user?.changeEmail?.enabled,
|
|
73
|
-
sendChangeEmailConfirmation:
|
|
74
|
-
!!options.user?.changeEmail?.sendChangeEmailConfirmation,
|
|
75
|
-
},
|
|
76
|
-
},
|
|
77
|
-
verification: {
|
|
78
|
-
modelName: options.verification?.modelName,
|
|
79
|
-
disableCleanup: options.verification?.disableCleanup,
|
|
80
|
-
fields: options.verification?.fields,
|
|
81
|
-
},
|
|
82
|
-
session: {
|
|
83
|
-
modelName: options.session?.modelName,
|
|
84
|
-
additionalFields: options.session?.additionalFields,
|
|
85
|
-
cookieCache: {
|
|
86
|
-
enabled: options.session?.cookieCache?.enabled,
|
|
87
|
-
maxAge: options.session?.cookieCache?.maxAge,
|
|
88
|
-
strategy: options.session?.cookieCache?.strategy,
|
|
89
|
-
},
|
|
90
|
-
disableSessionRefresh: options.session?.disableSessionRefresh,
|
|
91
|
-
expiresIn: options.session?.expiresIn,
|
|
92
|
-
fields: options.session?.fields,
|
|
93
|
-
freshAge: options.session?.freshAge,
|
|
94
|
-
preserveSessionInDatabase: options.session?.preserveSessionInDatabase,
|
|
95
|
-
storeSessionInDatabase: options.session?.storeSessionInDatabase,
|
|
96
|
-
updateAge: options.session?.updateAge,
|
|
97
|
-
},
|
|
98
|
-
account: {
|
|
99
|
-
modelName: options.account?.modelName,
|
|
100
|
-
fields: options.account?.fields,
|
|
101
|
-
encryptOAuthTokens: options.account?.encryptOAuthTokens,
|
|
102
|
-
updateAccountOnSignIn: options.account?.updateAccountOnSignIn,
|
|
103
|
-
accountLinking: {
|
|
104
|
-
enabled: options.account?.accountLinking?.enabled,
|
|
105
|
-
trustedProviders: options.account?.accountLinking?.trustedProviders,
|
|
106
|
-
updateUserInfoOnLink:
|
|
107
|
-
options.account?.accountLinking?.updateUserInfoOnLink,
|
|
108
|
-
allowUnlinkingAll: options.account?.accountLinking?.allowUnlinkingAll,
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
hooks: {
|
|
112
|
-
after: !!options.hooks?.after,
|
|
113
|
-
before: !!options.hooks?.before,
|
|
114
|
-
},
|
|
115
|
-
secondaryStorage: !!options.secondaryStorage,
|
|
116
|
-
advanced: {
|
|
117
|
-
cookiePrefix: !!options.advanced?.cookiePrefix, //this shouldn't be tracked
|
|
118
|
-
cookies: !!options.advanced?.cookies,
|
|
119
|
-
crossSubDomainCookies: {
|
|
120
|
-
domain: !!options.advanced?.crossSubDomainCookies?.domain,
|
|
121
|
-
enabled: options.advanced?.crossSubDomainCookies?.enabled,
|
|
122
|
-
additionalCookies:
|
|
123
|
-
options.advanced?.crossSubDomainCookies?.additionalCookies,
|
|
124
|
-
},
|
|
125
|
-
database: {
|
|
126
|
-
generateId: options.advanced?.database?.generateId,
|
|
127
|
-
defaultFindManyLimit: options.advanced?.database?.defaultFindManyLimit,
|
|
128
|
-
},
|
|
129
|
-
useSecureCookies: options.advanced?.useSecureCookies,
|
|
130
|
-
ipAddress: {
|
|
131
|
-
disableIpTracking: options.advanced?.ipAddress?.disableIpTracking,
|
|
132
|
-
ipAddressHeaders: options.advanced?.ipAddress?.ipAddressHeaders,
|
|
133
|
-
},
|
|
134
|
-
disableCSRFCheck: options.advanced?.disableCSRFCheck,
|
|
135
|
-
cookieAttributes: {
|
|
136
|
-
expires: options.advanced?.defaultCookieAttributes?.expires,
|
|
137
|
-
secure: options.advanced?.defaultCookieAttributes?.secure,
|
|
138
|
-
sameSite: options.advanced?.defaultCookieAttributes?.sameSite,
|
|
139
|
-
domain: !!options.advanced?.defaultCookieAttributes?.domain,
|
|
140
|
-
path: options.advanced?.defaultCookieAttributes?.path,
|
|
141
|
-
httpOnly: options.advanced?.defaultCookieAttributes?.httpOnly,
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
trustedOrigins: options.trustedOrigins?.length,
|
|
145
|
-
rateLimit: {
|
|
146
|
-
storage: options.rateLimit?.storage,
|
|
147
|
-
modelName: options.rateLimit?.modelName,
|
|
148
|
-
window: options.rateLimit?.window,
|
|
149
|
-
customStorage: !!options.rateLimit?.customStorage,
|
|
150
|
-
enabled: options.rateLimit?.enabled,
|
|
151
|
-
max: options.rateLimit?.max,
|
|
152
|
-
},
|
|
153
|
-
onAPIError: {
|
|
154
|
-
errorURL: options.onAPIError?.errorURL,
|
|
155
|
-
onError: !!options.onAPIError?.onError,
|
|
156
|
-
throw: options.onAPIError?.throw,
|
|
157
|
-
},
|
|
158
|
-
logger: {
|
|
159
|
-
disabled: options.logger?.disabled,
|
|
160
|
-
level: options.logger?.level,
|
|
161
|
-
log: !!options.logger?.log,
|
|
162
|
-
},
|
|
163
|
-
databaseHooks: {
|
|
164
|
-
user: {
|
|
165
|
-
create: {
|
|
166
|
-
after: !!options.databaseHooks?.user?.create?.after,
|
|
167
|
-
before: !!options.databaseHooks?.user?.create?.before,
|
|
168
|
-
},
|
|
169
|
-
update: {
|
|
170
|
-
after: !!options.databaseHooks?.user?.update?.after,
|
|
171
|
-
before: !!options.databaseHooks?.user?.update?.before,
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
session: {
|
|
175
|
-
create: {
|
|
176
|
-
after: !!options.databaseHooks?.session?.create?.after,
|
|
177
|
-
before: !!options.databaseHooks?.session?.create?.before,
|
|
178
|
-
},
|
|
179
|
-
update: {
|
|
180
|
-
after: !!options.databaseHooks?.session?.update?.after,
|
|
181
|
-
before: !!options.databaseHooks?.session?.update?.before,
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
account: {
|
|
185
|
-
create: {
|
|
186
|
-
after: !!options.databaseHooks?.account?.create?.after,
|
|
187
|
-
before: !!options.databaseHooks?.account?.create?.before,
|
|
188
|
-
},
|
|
189
|
-
update: {
|
|
190
|
-
after: !!options.databaseHooks?.account?.update?.after,
|
|
191
|
-
before: !!options.databaseHooks?.account?.update?.before,
|
|
192
|
-
},
|
|
193
|
-
},
|
|
194
|
-
verification: {
|
|
195
|
-
create: {
|
|
196
|
-
after: !!options.databaseHooks?.verification?.create?.after,
|
|
197
|
-
before: !!options.databaseHooks?.verification?.create?.before,
|
|
198
|
-
},
|
|
199
|
-
update: {
|
|
200
|
-
after: !!options.databaseHooks?.verification?.update?.after,
|
|
201
|
-
before: !!options.databaseHooks?.verification?.update?.before,
|
|
202
|
-
},
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
};
|
|
206
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { DetectionInfo } from "../types";
|
|
2
|
-
import { getPackageVersion } from "../utils/package-json";
|
|
3
|
-
|
|
4
|
-
const DATABASES: Record<string, string> = {
|
|
5
|
-
pg: "postgresql",
|
|
6
|
-
mysql: "mysql",
|
|
7
|
-
mariadb: "mariadb",
|
|
8
|
-
sqlite3: "sqlite",
|
|
9
|
-
"better-sqlite3": "sqlite",
|
|
10
|
-
"@prisma/client": "prisma",
|
|
11
|
-
mongoose: "mongodb",
|
|
12
|
-
mongodb: "mongodb",
|
|
13
|
-
"drizzle-orm": "drizzle",
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export async function detectDatabase(): Promise<DetectionInfo | undefined> {
|
|
17
|
-
for (const [pkg, name] of Object.entries(DATABASES)) {
|
|
18
|
-
const version = await getPackageVersion(pkg);
|
|
19
|
-
if (version) return { name, version };
|
|
20
|
-
}
|
|
21
|
-
return undefined;
|
|
22
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { getPackageVersion } from "../utils/package-json";
|
|
2
|
-
|
|
3
|
-
const FRAMEWORKS: Record<string, string> = {
|
|
4
|
-
next: "next",
|
|
5
|
-
nuxt: "nuxt",
|
|
6
|
-
"react-router": "react-router",
|
|
7
|
-
astro: "astro",
|
|
8
|
-
"@sveltejs/kit": "sveltekit",
|
|
9
|
-
"solid-start": "solid-start",
|
|
10
|
-
"tanstack-start": "tanstack-start",
|
|
11
|
-
hono: "hono",
|
|
12
|
-
express: "express",
|
|
13
|
-
elysia: "elysia",
|
|
14
|
-
expo: "expo",
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
export async function detectFramework() {
|
|
18
|
-
for (const [pkg, name] of Object.entries(FRAMEWORKS)) {
|
|
19
|
-
const version = await getPackageVersion(pkg);
|
|
20
|
-
if (version) return { name, version };
|
|
21
|
-
}
|
|
22
|
-
return undefined;
|
|
23
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
// https://github.com/zkochan/packages/blob/main/which-pm-runs/index.js
|
|
2
|
-
import { env } from "@better-auth/core/env";
|
|
3
|
-
|
|
4
|
-
export function detectPackageManager() {
|
|
5
|
-
const userAgent = env.npm_config_user_agent;
|
|
6
|
-
if (!userAgent) {
|
|
7
|
-
return undefined;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const pmSpec = userAgent.split(" ")[0]!;
|
|
11
|
-
const separatorPos = pmSpec.lastIndexOf("/");
|
|
12
|
-
const name = pmSpec.substring(0, separatorPos);
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
name: name === "npminstall" ? "cnpm" : name,
|
|
16
|
-
version: pmSpec.substring(separatorPos + 1),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { getEnvVar, isTest } from "@better-auth/core/env";
|
|
2
|
-
import { isCI } from "./detect-system-info";
|
|
3
|
-
|
|
4
|
-
export function detectRuntime() {
|
|
5
|
-
// @ts-expect-error: TS doesn't know about Deno global
|
|
6
|
-
if (typeof Deno !== "undefined") {
|
|
7
|
-
// @ts-expect-error: TS doesn't know about Deno global
|
|
8
|
-
const denoVersion = Deno?.version?.deno ?? null;
|
|
9
|
-
return { name: "deno", version: denoVersion };
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
if (typeof Bun !== "undefined") {
|
|
13
|
-
const bunVersion = Bun?.version ?? null;
|
|
14
|
-
return { name: "bun", version: bunVersion };
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
if (typeof process !== "undefined" && process?.versions?.node) {
|
|
18
|
-
return { name: "node", version: process.versions.node ?? null };
|
|
19
|
-
}
|
|
20
|
-
return { name: "edge", version: null };
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function detectEnvironment() {
|
|
24
|
-
return getEnvVar("NODE_ENV") === "production"
|
|
25
|
-
? "production"
|
|
26
|
-
: isCI()
|
|
27
|
-
? "ci"
|
|
28
|
-
: isTest()
|
|
29
|
-
? "test"
|
|
30
|
-
: "development";
|
|
31
|
-
}
|
|
@@ -1,209 +0,0 @@
|
|
|
1
|
-
import { env } from "@better-auth/core/env";
|
|
2
|
-
import { importRuntime } from "../utils/import-util";
|
|
3
|
-
|
|
4
|
-
function getVendor() {
|
|
5
|
-
const hasAny = (...keys: string[]) =>
|
|
6
|
-
keys.some((k) => Boolean((env as any)[k]));
|
|
7
|
-
|
|
8
|
-
if (
|
|
9
|
-
hasAny("CF_PAGES", "CF_PAGES_URL", "CF_ACCOUNT_ID") ||
|
|
10
|
-
(typeof navigator !== "undefined" &&
|
|
11
|
-
navigator.userAgent === "Cloudflare-Workers")
|
|
12
|
-
) {
|
|
13
|
-
return "cloudflare";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
if (hasAny("VERCEL", "VERCEL_URL", "VERCEL_ENV")) return "vercel";
|
|
17
|
-
|
|
18
|
-
if (hasAny("NETLIFY", "NETLIFY_URL")) return "netlify";
|
|
19
|
-
|
|
20
|
-
if (
|
|
21
|
-
hasAny(
|
|
22
|
-
"RENDER",
|
|
23
|
-
"RENDER_URL",
|
|
24
|
-
"RENDER_INTERNAL_HOSTNAME",
|
|
25
|
-
"RENDER_SERVICE_ID",
|
|
26
|
-
)
|
|
27
|
-
) {
|
|
28
|
-
return "render";
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
hasAny("AWS_LAMBDA_FUNCTION_NAME", "AWS_EXECUTION_ENV", "LAMBDA_TASK_ROOT")
|
|
33
|
-
) {
|
|
34
|
-
return "aws";
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
hasAny(
|
|
39
|
-
"GOOGLE_CLOUD_FUNCTION_NAME",
|
|
40
|
-
"GOOGLE_CLOUD_PROJECT",
|
|
41
|
-
"GCP_PROJECT",
|
|
42
|
-
"K_SERVICE",
|
|
43
|
-
)
|
|
44
|
-
) {
|
|
45
|
-
return "gcp";
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
hasAny(
|
|
50
|
-
"AZURE_FUNCTION_NAME",
|
|
51
|
-
"FUNCTIONS_WORKER_RUNTIME",
|
|
52
|
-
"WEBSITE_INSTANCE_ID",
|
|
53
|
-
"WEBSITE_SITE_NAME",
|
|
54
|
-
)
|
|
55
|
-
) {
|
|
56
|
-
return "azure";
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if (hasAny("DENO_DEPLOYMENT_ID", "DENO_REGION")) return "deno-deploy";
|
|
60
|
-
|
|
61
|
-
if (hasAny("FLY_APP_NAME", "FLY_REGION", "FLY_ALLOC_ID")) return "fly-io";
|
|
62
|
-
|
|
63
|
-
if (hasAny("RAILWAY_STATIC_URL", "RAILWAY_ENVIRONMENT_NAME"))
|
|
64
|
-
return "railway";
|
|
65
|
-
|
|
66
|
-
if (hasAny("DYNO", "HEROKU_APP_NAME")) return "heroku";
|
|
67
|
-
|
|
68
|
-
if (hasAny("DO_DEPLOYMENT_ID", "DO_APP_NAME", "DIGITALOCEAN"))
|
|
69
|
-
return "digitalocean";
|
|
70
|
-
|
|
71
|
-
if (hasAny("KOYEB", "KOYEB_DEPLOYMENT_ID", "KOYEB_APP_NAME")) return "koyeb";
|
|
72
|
-
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export async function detectSystemInfo() {
|
|
77
|
-
try {
|
|
78
|
-
//check if it's cloudflare
|
|
79
|
-
if (getVendor() === "cloudflare") return "cloudflare";
|
|
80
|
-
const os = await importRuntime<typeof import("os")>("os");
|
|
81
|
-
const cpus = os.cpus();
|
|
82
|
-
return {
|
|
83
|
-
deploymentVendor: getVendor(),
|
|
84
|
-
systemPlatform: os.platform(),
|
|
85
|
-
systemRelease: os.release(),
|
|
86
|
-
systemArchitecture: os.arch(),
|
|
87
|
-
cpuCount: cpus.length,
|
|
88
|
-
cpuModel: cpus.length ? cpus[0]!.model : null,
|
|
89
|
-
cpuSpeed: cpus.length ? cpus[0]!.speed : null,
|
|
90
|
-
memory: os.totalmem(),
|
|
91
|
-
isWSL: await isWsl(),
|
|
92
|
-
isDocker: await isDocker(),
|
|
93
|
-
isTTY:
|
|
94
|
-
typeof process !== "undefined" && (process as any).stdout
|
|
95
|
-
? (process as any).stdout.isTTY
|
|
96
|
-
: null,
|
|
97
|
-
};
|
|
98
|
-
} catch {
|
|
99
|
-
return {
|
|
100
|
-
systemPlatform: null,
|
|
101
|
-
systemRelease: null,
|
|
102
|
-
systemArchitecture: null,
|
|
103
|
-
cpuCount: null,
|
|
104
|
-
cpuModel: null,
|
|
105
|
-
cpuSpeed: null,
|
|
106
|
-
memory: null,
|
|
107
|
-
isWSL: null,
|
|
108
|
-
isDocker: null,
|
|
109
|
-
isTTY: null,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
let isDockerCached: boolean | undefined;
|
|
115
|
-
|
|
116
|
-
async function hasDockerEnv() {
|
|
117
|
-
if (getVendor() === "cloudflare") return false;
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
const fs = await importRuntime<typeof import("fs")>("fs");
|
|
121
|
-
fs.statSync("/.dockerenv");
|
|
122
|
-
return true;
|
|
123
|
-
} catch {
|
|
124
|
-
return false;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
async function hasDockerCGroup() {
|
|
129
|
-
if (getVendor() === "cloudflare") return false;
|
|
130
|
-
try {
|
|
131
|
-
const fs = await importRuntime<typeof import("fs")>("fs");
|
|
132
|
-
return fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
|
133
|
-
} catch {
|
|
134
|
-
return false;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function isDocker() {
|
|
139
|
-
if (getVendor() === "cloudflare") return false;
|
|
140
|
-
|
|
141
|
-
if (isDockerCached === undefined) {
|
|
142
|
-
isDockerCached = (await hasDockerEnv()) || (await hasDockerCGroup());
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return isDockerCached;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
async function isWsl() {
|
|
149
|
-
try {
|
|
150
|
-
if (getVendor() === "cloudflare") return false;
|
|
151
|
-
if (typeof process === "undefined" || process?.platform !== "linux") {
|
|
152
|
-
return false;
|
|
153
|
-
}
|
|
154
|
-
const fs = await importRuntime<typeof import("fs")>("fs");
|
|
155
|
-
const os = await importRuntime<typeof import("os")>("os");
|
|
156
|
-
if (os.release().toLowerCase().includes("microsoft")) {
|
|
157
|
-
if (await isInsideContainer()) {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return true;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return fs
|
|
165
|
-
.readFileSync("/proc/version", "utf8")
|
|
166
|
-
.toLowerCase()
|
|
167
|
-
.includes("microsoft")
|
|
168
|
-
? !(await isInsideContainer())
|
|
169
|
-
: false;
|
|
170
|
-
} catch {
|
|
171
|
-
return false;
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
let isInsideContainerCached: boolean | undefined;
|
|
176
|
-
|
|
177
|
-
const hasContainerEnv = async () => {
|
|
178
|
-
if (getVendor() === "cloudflare") return false;
|
|
179
|
-
try {
|
|
180
|
-
const fs = await importRuntime<typeof import("fs")>("fs");
|
|
181
|
-
fs.statSync("/run/.containerenv");
|
|
182
|
-
return true;
|
|
183
|
-
} catch {
|
|
184
|
-
return false;
|
|
185
|
-
}
|
|
186
|
-
};
|
|
187
|
-
|
|
188
|
-
async function isInsideContainer() {
|
|
189
|
-
if (isInsideContainerCached === undefined) {
|
|
190
|
-
isInsideContainerCached = (await hasContainerEnv()) || (await isDocker());
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
return isInsideContainerCached;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
export function isCI() {
|
|
197
|
-
return (
|
|
198
|
-
env.CI !== "false" &&
|
|
199
|
-
("BUILD_ID" in env || // Jenkins, Cloudbees
|
|
200
|
-
"BUILD_NUMBER" in env || // Jenkins, TeamCity (fixed typo: extra space removed)
|
|
201
|
-
"CI" in env || // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari, Cloudflare
|
|
202
|
-
"CI_APP_ID" in env || // Appflow
|
|
203
|
-
"CI_BUILD_ID" in env || // Appflow
|
|
204
|
-
"CI_BUILD_NUMBER" in env || // Appflow
|
|
205
|
-
"CI_NAME" in env || // Codeship and others
|
|
206
|
-
"CONTINUOUS_INTEGRATION" in env || // Travis CI, Cirrus CI
|
|
207
|
-
"RUN_ID" in env) // TaskCluster, dsari
|
|
208
|
-
);
|
|
209
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
import type { BetterAuthOptions } from "@better-auth/core";
|
|
2
|
-
import { ENV, getBooleanEnvVar, isTest, logger } from "@better-auth/core/env";
|
|
3
|
-
import { betterFetch } from "@better-fetch/fetch";
|
|
4
|
-
import { getTelemetryAuthConfig } from "./detectors/detect-auth-config";
|
|
5
|
-
import { detectDatabase } from "./detectors/detect-database";
|
|
6
|
-
import { detectFramework } from "./detectors/detect-framework";
|
|
7
|
-
import { detectPackageManager } from "./detectors/detect-project-info";
|
|
8
|
-
import { detectEnvironment, detectRuntime } from "./detectors/detect-runtime";
|
|
9
|
-
import { detectSystemInfo } from "./detectors/detect-system-info";
|
|
10
|
-
import { getProjectId } from "./project-id";
|
|
11
|
-
import type { TelemetryContext, TelemetryEvent } from "./types";
|
|
12
|
-
export { getTelemetryAuthConfig };
|
|
13
|
-
export type { TelemetryEvent } from "./types";
|
|
14
|
-
|
|
15
|
-
const noop: (event: TelemetryEvent) => Promise<void> = async function noop() {};
|
|
16
|
-
|
|
17
|
-
export async function createTelemetry(
|
|
18
|
-
options: BetterAuthOptions,
|
|
19
|
-
context?: TelemetryContext | undefined,
|
|
20
|
-
) {
|
|
21
|
-
const debugEnabled =
|
|
22
|
-
options.telemetry?.debug ||
|
|
23
|
-
getBooleanEnvVar("BETTER_AUTH_TELEMETRY_DEBUG", false);
|
|
24
|
-
|
|
25
|
-
const telemetryEndpoint = ENV.BETTER_AUTH_TELEMETRY_ENDPOINT;
|
|
26
|
-
// Return noop if no endpoint and no custom track function
|
|
27
|
-
if (!telemetryEndpoint && !context?.customTrack) {
|
|
28
|
-
return {
|
|
29
|
-
publish: noop,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
const track = async (event: TelemetryEvent) => {
|
|
33
|
-
if (context?.customTrack) {
|
|
34
|
-
await context.customTrack(event).catch(logger.error);
|
|
35
|
-
} else if (telemetryEndpoint) {
|
|
36
|
-
if (debugEnabled) {
|
|
37
|
-
logger.info("telemetry event", JSON.stringify(event, null, 2));
|
|
38
|
-
} else {
|
|
39
|
-
await betterFetch(telemetryEndpoint, {
|
|
40
|
-
method: "POST",
|
|
41
|
-
body: event,
|
|
42
|
-
}).catch(logger.error);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const isEnabled = async () => {
|
|
48
|
-
const telemetryEnabled =
|
|
49
|
-
options.telemetry?.enabled !== undefined
|
|
50
|
-
? options.telemetry.enabled
|
|
51
|
-
: false;
|
|
52
|
-
const envEnabled = getBooleanEnvVar("BETTER_AUTH_TELEMETRY", false);
|
|
53
|
-
return (
|
|
54
|
-
(envEnabled || telemetryEnabled) && (context?.skipTestCheck || !isTest())
|
|
55
|
-
);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const enabled = await isEnabled();
|
|
59
|
-
let anonymousId: string | undefined;
|
|
60
|
-
|
|
61
|
-
if (enabled) {
|
|
62
|
-
anonymousId = await getProjectId(
|
|
63
|
-
typeof options.baseURL === "string" ? options.baseURL : undefined,
|
|
64
|
-
);
|
|
65
|
-
|
|
66
|
-
const payload = {
|
|
67
|
-
config: await getTelemetryAuthConfig(options, context),
|
|
68
|
-
runtime: detectRuntime(),
|
|
69
|
-
database: await detectDatabase(),
|
|
70
|
-
framework: await detectFramework(),
|
|
71
|
-
environment: detectEnvironment(),
|
|
72
|
-
systemInfo: await detectSystemInfo(),
|
|
73
|
-
packageManager: detectPackageManager(),
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
void track({ type: "init", payload, anonymousId });
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return {
|
|
80
|
-
publish: async (event: TelemetryEvent) => {
|
|
81
|
-
if (!enabled) return;
|
|
82
|
-
if (!anonymousId) {
|
|
83
|
-
anonymousId = await getProjectId(
|
|
84
|
-
typeof options.baseURL === "string" ? options.baseURL : undefined,
|
|
85
|
-
);
|
|
86
|
-
}
|
|
87
|
-
await track({
|
|
88
|
-
type: event.type,
|
|
89
|
-
payload: event.payload,
|
|
90
|
-
anonymousId,
|
|
91
|
-
});
|
|
92
|
-
},
|
|
93
|
-
};
|
|
94
|
-
}
|
package/src/project-id.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { hashToBase64 } from "./utils/hash";
|
|
2
|
-
import { generateId } from "./utils/id";
|
|
3
|
-
import { getNameFromLocalPackageJson } from "./utils/package-json";
|
|
4
|
-
|
|
5
|
-
let projectIdCached: string | null = null;
|
|
6
|
-
|
|
7
|
-
export async function getProjectId(
|
|
8
|
-
baseUrl: string | undefined,
|
|
9
|
-
): Promise<string> {
|
|
10
|
-
if (projectIdCached) return projectIdCached;
|
|
11
|
-
|
|
12
|
-
const projectName = await getNameFromLocalPackageJson();
|
|
13
|
-
if (projectName) {
|
|
14
|
-
projectIdCached = await hashToBase64(
|
|
15
|
-
baseUrl ? baseUrl + projectName : projectName,
|
|
16
|
-
);
|
|
17
|
-
return projectIdCached;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
if (baseUrl) {
|
|
21
|
-
projectIdCached = await hashToBase64(baseUrl);
|
|
22
|
-
return projectIdCached;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
projectIdCached = generateId(32);
|
|
26
|
-
return projectIdCached;
|
|
27
|
-
}
|
package/src/telemetry.test.ts
DELETED
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { createTelemetry } from "./index";
|
|
3
|
-
import type { TelemetryEvent } from "./types";
|
|
4
|
-
|
|
5
|
-
vi.mock("@better-fetch/fetch", () => ({
|
|
6
|
-
betterFetch: vi.fn(async () => ({ status: 200 })),
|
|
7
|
-
}));
|
|
8
|
-
|
|
9
|
-
vi.mock("./project-id", () => ({
|
|
10
|
-
getProjectId: vi.fn(async () => "anon-123"),
|
|
11
|
-
}));
|
|
12
|
-
|
|
13
|
-
vi.mock("./detectors/detect-runtime", () => ({
|
|
14
|
-
detectRuntime: vi.fn(() => ({ name: "node", version: "test" })),
|
|
15
|
-
detectEnvironment: vi.fn(() => "test"),
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
vi.mock("./detectors/detect-database", () => ({
|
|
19
|
-
detectDatabase: vi.fn(async () => ({ name: "postgresql", version: "1.0.0" })),
|
|
20
|
-
}));
|
|
21
|
-
|
|
22
|
-
vi.mock("./detectors/detect-framework", () => ({
|
|
23
|
-
detectFramework: vi.fn(async () => ({ name: "next", version: "15.0.0" })),
|
|
24
|
-
}));
|
|
25
|
-
|
|
26
|
-
vi.mock("./detectors/detect-system-info", () => ({
|
|
27
|
-
detectSystemInfo: vi.fn(() => ({
|
|
28
|
-
systemPlatform: "darwin",
|
|
29
|
-
systemRelease: "24.6.0",
|
|
30
|
-
systemArchitecture: "arm64",
|
|
31
|
-
cpuCount: 8,
|
|
32
|
-
cpuModel: "Apple M3",
|
|
33
|
-
cpuSpeed: 3200,
|
|
34
|
-
memory: 16 * 1024 * 1024 * 1024,
|
|
35
|
-
isDocker: false,
|
|
36
|
-
isTTY: true,
|
|
37
|
-
isWSL: false,
|
|
38
|
-
isCI: false,
|
|
39
|
-
})),
|
|
40
|
-
isCI: vi.fn(() => false),
|
|
41
|
-
}));
|
|
42
|
-
|
|
43
|
-
vi.mock("./detectors/detect-project-info", () => ({
|
|
44
|
-
detectPackageManager: vi.fn(() => ({ name: "pnpm", version: "9.0.0" })),
|
|
45
|
-
}));
|
|
46
|
-
|
|
47
|
-
beforeEach(() => {
|
|
48
|
-
vi.resetModules();
|
|
49
|
-
process.env.BETTER_AUTH_TELEMETRY = "";
|
|
50
|
-
process.env.BETTER_AUTH_TELEMETRY_DEBUG = "";
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
describe("telemetry", () => {
|
|
54
|
-
it("publishes events when enabled", async () => {
|
|
55
|
-
let event: TelemetryEvent | undefined;
|
|
56
|
-
const track = vi.fn().mockImplementation(async (e) => {
|
|
57
|
-
event = e;
|
|
58
|
-
});
|
|
59
|
-
await createTelemetry(
|
|
60
|
-
{
|
|
61
|
-
baseURL: "http://localhost.com", //this shouldn't be tracked
|
|
62
|
-
appName: "test", //this shouldn't be tracked
|
|
63
|
-
advanced: {
|
|
64
|
-
cookiePrefix: "test", //this shouldn't be tracked - should set to true
|
|
65
|
-
crossSubDomainCookies: {
|
|
66
|
-
domain: ".test.com", //this shouldn't be tracked - should set to true
|
|
67
|
-
enabled: true,
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
telemetry: { enabled: true },
|
|
71
|
-
},
|
|
72
|
-
{ customTrack: track, skipTestCheck: true },
|
|
73
|
-
);
|
|
74
|
-
expect(event).toMatchObject({
|
|
75
|
-
type: "init",
|
|
76
|
-
payload: {
|
|
77
|
-
config: {
|
|
78
|
-
emailVerification: {
|
|
79
|
-
sendVerificationEmail: false,
|
|
80
|
-
sendOnSignUp: false,
|
|
81
|
-
sendOnSignIn: false,
|
|
82
|
-
autoSignInAfterVerification: false,
|
|
83
|
-
expiresIn: undefined,
|
|
84
|
-
onEmailVerification: false,
|
|
85
|
-
afterEmailVerification: false,
|
|
86
|
-
},
|
|
87
|
-
emailAndPassword: {
|
|
88
|
-
enabled: false,
|
|
89
|
-
disableSignUp: false,
|
|
90
|
-
requireEmailVerification: false,
|
|
91
|
-
maxPasswordLength: undefined,
|
|
92
|
-
minPasswordLength: undefined,
|
|
93
|
-
sendResetPassword: false,
|
|
94
|
-
resetPasswordTokenExpiresIn: undefined,
|
|
95
|
-
onPasswordReset: false,
|
|
96
|
-
password: { hash: false, verify: false },
|
|
97
|
-
autoSignIn: false,
|
|
98
|
-
revokeSessionsOnPasswordReset: false,
|
|
99
|
-
},
|
|
100
|
-
socialProviders: [],
|
|
101
|
-
plugins: undefined,
|
|
102
|
-
user: {
|
|
103
|
-
modelName: undefined,
|
|
104
|
-
fields: undefined,
|
|
105
|
-
additionalFields: undefined,
|
|
106
|
-
changeEmail: {
|
|
107
|
-
enabled: undefined,
|
|
108
|
-
sendChangeEmailVerification: false,
|
|
109
|
-
},
|
|
110
|
-
},
|
|
111
|
-
verification: {
|
|
112
|
-
modelName: undefined,
|
|
113
|
-
disableCleanup: undefined,
|
|
114
|
-
fields: undefined,
|
|
115
|
-
},
|
|
116
|
-
session: {
|
|
117
|
-
modelName: undefined,
|
|
118
|
-
additionalFields: undefined,
|
|
119
|
-
cookieCache: { enabled: undefined, maxAge: undefined },
|
|
120
|
-
disableSessionRefresh: undefined,
|
|
121
|
-
expiresIn: undefined,
|
|
122
|
-
fields: undefined,
|
|
123
|
-
freshAge: undefined,
|
|
124
|
-
preserveSessionInDatabase: undefined,
|
|
125
|
-
storeSessionInDatabase: undefined,
|
|
126
|
-
updateAge: undefined,
|
|
127
|
-
},
|
|
128
|
-
account: {
|
|
129
|
-
modelName: undefined,
|
|
130
|
-
fields: undefined,
|
|
131
|
-
encryptOAuthTokens: undefined,
|
|
132
|
-
updateAccountOnSignIn: undefined,
|
|
133
|
-
accountLinking: {
|
|
134
|
-
enabled: undefined,
|
|
135
|
-
trustedProviders: undefined,
|
|
136
|
-
updateUserInfoOnLink: undefined,
|
|
137
|
-
allowUnlinkingAll: undefined,
|
|
138
|
-
},
|
|
139
|
-
},
|
|
140
|
-
hooks: { after: false, before: false },
|
|
141
|
-
secondaryStorage: false,
|
|
142
|
-
advanced: {
|
|
143
|
-
cookiePrefix: true,
|
|
144
|
-
cookies: false,
|
|
145
|
-
crossSubDomainCookies: {
|
|
146
|
-
domain: true,
|
|
147
|
-
enabled: true,
|
|
148
|
-
additionalCookies: undefined,
|
|
149
|
-
},
|
|
150
|
-
database: {
|
|
151
|
-
useNumberId: false,
|
|
152
|
-
generateId: undefined,
|
|
153
|
-
defaultFindManyLimit: undefined,
|
|
154
|
-
},
|
|
155
|
-
useSecureCookies: undefined,
|
|
156
|
-
ipAddress: {
|
|
157
|
-
disableIpTracking: undefined,
|
|
158
|
-
ipAddressHeaders: undefined,
|
|
159
|
-
},
|
|
160
|
-
disableCSRFCheck: undefined,
|
|
161
|
-
cookieAttributes: {
|
|
162
|
-
expires: undefined,
|
|
163
|
-
secure: undefined,
|
|
164
|
-
sameSite: undefined,
|
|
165
|
-
domain: false,
|
|
166
|
-
path: undefined,
|
|
167
|
-
httpOnly: undefined,
|
|
168
|
-
},
|
|
169
|
-
},
|
|
170
|
-
trustedOrigins: undefined,
|
|
171
|
-
rateLimit: {
|
|
172
|
-
storage: undefined,
|
|
173
|
-
modelName: undefined,
|
|
174
|
-
window: undefined,
|
|
175
|
-
customStorage: false,
|
|
176
|
-
enabled: undefined,
|
|
177
|
-
max: undefined,
|
|
178
|
-
},
|
|
179
|
-
onAPIError: {
|
|
180
|
-
errorURL: undefined,
|
|
181
|
-
onError: false,
|
|
182
|
-
throw: undefined,
|
|
183
|
-
},
|
|
184
|
-
logger: { disabled: undefined, level: undefined, log: false },
|
|
185
|
-
databaseHooks: {
|
|
186
|
-
user: {
|
|
187
|
-
create: {
|
|
188
|
-
after: false,
|
|
189
|
-
before: false,
|
|
190
|
-
},
|
|
191
|
-
update: {
|
|
192
|
-
after: false,
|
|
193
|
-
before: false,
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
session: {
|
|
197
|
-
create: {
|
|
198
|
-
after: false,
|
|
199
|
-
before: false,
|
|
200
|
-
},
|
|
201
|
-
update: {
|
|
202
|
-
after: false,
|
|
203
|
-
before: false,
|
|
204
|
-
},
|
|
205
|
-
},
|
|
206
|
-
account: {
|
|
207
|
-
create: {
|
|
208
|
-
after: false,
|
|
209
|
-
before: false,
|
|
210
|
-
},
|
|
211
|
-
update: {
|
|
212
|
-
after: false,
|
|
213
|
-
before: false,
|
|
214
|
-
},
|
|
215
|
-
},
|
|
216
|
-
verification: {
|
|
217
|
-
create: {
|
|
218
|
-
after: false,
|
|
219
|
-
before: false,
|
|
220
|
-
},
|
|
221
|
-
update: {
|
|
222
|
-
after: false,
|
|
223
|
-
before: false,
|
|
224
|
-
},
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
},
|
|
228
|
-
runtime: { name: "node", version: "test" },
|
|
229
|
-
database: { name: "postgresql", version: "1.0.0" },
|
|
230
|
-
framework: { name: "next", version: "15.0.0" },
|
|
231
|
-
environment: "test",
|
|
232
|
-
systemInfo: {
|
|
233
|
-
systemPlatform: "darwin",
|
|
234
|
-
systemRelease: "24.6.0",
|
|
235
|
-
systemArchitecture: "arm64",
|
|
236
|
-
cpuCount: 8,
|
|
237
|
-
cpuModel: "Apple M3",
|
|
238
|
-
cpuSpeed: 3200,
|
|
239
|
-
memory: 17179869184,
|
|
240
|
-
isDocker: false,
|
|
241
|
-
isTTY: true,
|
|
242
|
-
isWSL: false,
|
|
243
|
-
isCI: false,
|
|
244
|
-
},
|
|
245
|
-
packageManager: { name: "pnpm", version: "9.0.0" },
|
|
246
|
-
},
|
|
247
|
-
anonymousId: "anon-123",
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
it("does not publish when disabled via env", async () => {
|
|
252
|
-
process.env.BETTER_AUTH_TELEMETRY = "false";
|
|
253
|
-
let event: TelemetryEvent | undefined;
|
|
254
|
-
const track = vi.fn().mockImplementation(async (e) => {
|
|
255
|
-
event = e;
|
|
256
|
-
});
|
|
257
|
-
await createTelemetry(
|
|
258
|
-
{
|
|
259
|
-
baseURL: "http://localhost",
|
|
260
|
-
},
|
|
261
|
-
{ customTrack: track, skipTestCheck: true },
|
|
262
|
-
);
|
|
263
|
-
expect(event).toBeUndefined();
|
|
264
|
-
expect(track).not.toBeCalled();
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
it("does not publish when disabled via option", async () => {
|
|
268
|
-
let event: TelemetryEvent | undefined;
|
|
269
|
-
const track = vi.fn().mockImplementation(async (e) => {
|
|
270
|
-
event = e;
|
|
271
|
-
});
|
|
272
|
-
await createTelemetry(
|
|
273
|
-
{
|
|
274
|
-
baseURL: "http://localhost",
|
|
275
|
-
telemetry: { enabled: false },
|
|
276
|
-
},
|
|
277
|
-
{ customTrack: track, skipTestCheck: true },
|
|
278
|
-
);
|
|
279
|
-
expect(event).toBeUndefined();
|
|
280
|
-
expect(track).not.toBeCalled();
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
it("shouldn't fail cause track isn't being reached", async () => {
|
|
284
|
-
await expect(
|
|
285
|
-
createTelemetry(
|
|
286
|
-
{
|
|
287
|
-
baseURL: "http://localhost",
|
|
288
|
-
telemetry: { enabled: true },
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
customTrack() {
|
|
292
|
-
throw new Error("test");
|
|
293
|
-
},
|
|
294
|
-
skipTestCheck: true,
|
|
295
|
-
},
|
|
296
|
-
),
|
|
297
|
-
).resolves.not.throw(Error);
|
|
298
|
-
});
|
|
299
|
-
|
|
300
|
-
it("initializes without Node built-ins in edge-like env (no process.cwd)", async () => {
|
|
301
|
-
const originalProcess = globalThis.process;
|
|
302
|
-
try {
|
|
303
|
-
// Simulate an edge runtime where process exists minimally but has no cwd
|
|
304
|
-
// so utils/package-json won't try to import fs/path
|
|
305
|
-
(globalThis as any).process = { env: {} } as any;
|
|
306
|
-
const track = vi.fn();
|
|
307
|
-
await expect(
|
|
308
|
-
createTelemetry(
|
|
309
|
-
{ baseURL: "https://example.com", telemetry: { enabled: true } },
|
|
310
|
-
{ customTrack: track, skipTestCheck: true },
|
|
311
|
-
),
|
|
312
|
-
).resolves.not.toThrow();
|
|
313
|
-
// Should still attempt to publish init event
|
|
314
|
-
expect(track).toHaveBeenCalled();
|
|
315
|
-
} finally {
|
|
316
|
-
// restore
|
|
317
|
-
(globalThis as any).process = originalProcess as any;
|
|
318
|
-
}
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
it("returns noop publisher when BETTER_AUTH_TELEMETRY_ENDPOINT is undefined", async () => {
|
|
322
|
-
// Import betterFetch mock to check it's not called
|
|
323
|
-
const { betterFetch } = await import("@better-fetch/fetch");
|
|
324
|
-
|
|
325
|
-
// Clear any previous calls to the mock
|
|
326
|
-
vi.mocked(betterFetch).mockClear();
|
|
327
|
-
|
|
328
|
-
// Ensure the environment variable is not set
|
|
329
|
-
vi.stubEnv("BETTER_AUTH_TELEMETRY_ENDPOINT", undefined);
|
|
330
|
-
|
|
331
|
-
// Create telemetry without customTrack to test actual endpoint logic
|
|
332
|
-
const telemetry = await createTelemetry(
|
|
333
|
-
{
|
|
334
|
-
baseURL: "http://localhost",
|
|
335
|
-
telemetry: { enabled: true },
|
|
336
|
-
},
|
|
337
|
-
{ skipTestCheck: true },
|
|
338
|
-
);
|
|
339
|
-
|
|
340
|
-
// The publish function should be a noop and not make any HTTP requests
|
|
341
|
-
await telemetry.publish({
|
|
342
|
-
type: "test-event",
|
|
343
|
-
payload: { test: "data" },
|
|
344
|
-
} as any);
|
|
345
|
-
|
|
346
|
-
// Verify that betterFetch was never called since endpoint is undefined
|
|
347
|
-
expect(betterFetch).not.toHaveBeenCalled();
|
|
348
|
-
});
|
|
349
|
-
});
|
package/src/types.ts
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export interface DetectionInfo {
|
|
2
|
-
name: string;
|
|
3
|
-
version: string | null;
|
|
4
|
-
}
|
|
5
|
-
export interface TelemetryEvent {
|
|
6
|
-
type: string;
|
|
7
|
-
anonymousId?: string | undefined;
|
|
8
|
-
payload: Record<string, any>;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export interface TelemetryContext {
|
|
12
|
-
customTrack?: ((event: TelemetryEvent) => Promise<void>) | undefined;
|
|
13
|
-
database?: string | undefined;
|
|
14
|
-
adapter?: string | undefined;
|
|
15
|
-
skipTestCheck?: boolean | undefined;
|
|
16
|
-
}
|
package/src/utils/hash.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { base64 } from "@better-auth/utils/base64";
|
|
2
|
-
import { createHash } from "@better-auth/utils/hash";
|
|
3
|
-
|
|
4
|
-
export async function hashToBase64(
|
|
5
|
-
data: string | ArrayBuffer,
|
|
6
|
-
): Promise<string> {
|
|
7
|
-
const buffer = await createHash("SHA-256").digest(data);
|
|
8
|
-
return base64.encode(buffer);
|
|
9
|
-
}
|
package/src/utils/id.ts
DELETED
package/src/utils/import-util.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { PackageJson } from "type-fest";
|
|
2
|
-
|
|
3
|
-
let packageJSONCache: PackageJson | undefined;
|
|
4
|
-
|
|
5
|
-
async function readRootPackageJson() {
|
|
6
|
-
if (packageJSONCache) return packageJSONCache;
|
|
7
|
-
try {
|
|
8
|
-
const cwd =
|
|
9
|
-
typeof process !== "undefined" && typeof process.cwd === "function"
|
|
10
|
-
? process.cwd()
|
|
11
|
-
: "";
|
|
12
|
-
if (!cwd) return undefined;
|
|
13
|
-
// Lazily import Node built-ins only when available (Node/Bun/Deno) and
|
|
14
|
-
// avoid static analyzer/bundler resolution by obfuscating module names
|
|
15
|
-
const importRuntime = (m: string) =>
|
|
16
|
-
(Function("mm", "return import(mm)") as any)(m);
|
|
17
|
-
const [{ default: fs }, { default: path }] = await Promise.all([
|
|
18
|
-
importRuntime("fs/promises"),
|
|
19
|
-
importRuntime("path"),
|
|
20
|
-
]);
|
|
21
|
-
const raw = await fs.readFile(path.join(cwd, "package.json"), "utf-8");
|
|
22
|
-
packageJSONCache = JSON.parse(raw);
|
|
23
|
-
return packageJSONCache as PackageJson;
|
|
24
|
-
} catch {}
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function getPackageVersion(pkg: string) {
|
|
29
|
-
if (packageJSONCache) {
|
|
30
|
-
return (packageJSONCache.dependencies?.[pkg] ||
|
|
31
|
-
packageJSONCache.devDependencies?.[pkg] ||
|
|
32
|
-
packageJSONCache.peerDependencies?.[pkg]) as string | undefined;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
try {
|
|
36
|
-
const cwd =
|
|
37
|
-
typeof process !== "undefined" && typeof process.cwd === "function"
|
|
38
|
-
? process.cwd()
|
|
39
|
-
: "";
|
|
40
|
-
if (!cwd) throw new Error("no-cwd");
|
|
41
|
-
const importRuntime = (m: string) =>
|
|
42
|
-
(Function("mm", "return import(mm)") as any)(m);
|
|
43
|
-
const [{ default: fs }, { default: path }] = await Promise.all([
|
|
44
|
-
importRuntime("fs/promises"),
|
|
45
|
-
importRuntime("path"),
|
|
46
|
-
]);
|
|
47
|
-
const pkgJsonPath = path.join(cwd, "node_modules", pkg, "package.json");
|
|
48
|
-
const raw = await fs.readFile(pkgJsonPath, "utf-8");
|
|
49
|
-
const json = JSON.parse(raw);
|
|
50
|
-
const resolved =
|
|
51
|
-
(json.version as string) ||
|
|
52
|
-
(await getVersionFromLocalPackageJson(pkg)) ||
|
|
53
|
-
undefined;
|
|
54
|
-
return resolved;
|
|
55
|
-
} catch {}
|
|
56
|
-
|
|
57
|
-
const fromRoot = await getVersionFromLocalPackageJson(pkg);
|
|
58
|
-
return fromRoot;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
async function getVersionFromLocalPackageJson(pkg: string) {
|
|
62
|
-
const json = await readRootPackageJson();
|
|
63
|
-
if (!json) return undefined;
|
|
64
|
-
const allDeps = {
|
|
65
|
-
...json.dependencies,
|
|
66
|
-
...json.devDependencies,
|
|
67
|
-
...json.peerDependencies,
|
|
68
|
-
} as Record<string, string | undefined>;
|
|
69
|
-
return allDeps[pkg];
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
export async function getNameFromLocalPackageJson() {
|
|
73
|
-
const json = await readRootPackageJson();
|
|
74
|
-
return json?.name as string | undefined;
|
|
75
|
-
}
|
package/tsconfig.json
DELETED