Feat/telemetry (#372)

This commit is contained in:
Théo LAGACHE
2026-07-13 15:38:36 +02:00
committed by GitHub
parent 1971ff69e3
commit 435879a562
16 changed files with 545 additions and 55 deletions
+2
View File
@@ -46,6 +46,8 @@ public/uploads/*
private/uploads/*
private/keys/*
private/telemetry/*
/.env
seeds/pocket-id/*.db
+5
View File
@@ -25,6 +25,11 @@
"@hookform/resolvers": "^5.4.0",
"@modelcontextprotocol/sdk": "^1.29.0",
"@onboardjs/react": "1.0.0-rc.5",
"@opentelemetry/api": "^1.9.1",
"@opentelemetry/exporter-metrics-otlp-http": "^0.220.0",
"@opentelemetry/resources": "^2.9.0",
"@opentelemetry/sdk-metrics": "^2.9.0",
"@opentelemetry/semantic-conventions": "^1.42.0",
"@radix-ui/react-accordion": "^1.2.12",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-avatar": "^1.1.11",
+198 -53
View File
@@ -16,16 +16,16 @@ importers:
version: 12.33.0
'@better-auth/api-key':
specifier: 1.6.11
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))
'@better-auth/core':
specifier: 1.6.11
version: 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
version: 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/passkey':
specifier: 1.6.11
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))(nanostores@1.3.0)
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))(nanostores@1.3.0)
'@better-auth/sso':
specifier: 1.6.11
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))
version: 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))
'@google-cloud/storage':
specifier: ^7.19.0
version: 7.21.0
@@ -38,6 +38,21 @@ importers:
'@onboardjs/react':
specifier: 1.0.0-rc.5
version: 1.0.0-rc.5(@onboardjs/core@1.0.0-rc.4)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
'@opentelemetry/api':
specifier: ^1.9.1
version: 1.9.1
'@opentelemetry/exporter-metrics-otlp-http':
specifier: ^0.220.0
version: 0.220.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources':
specifier: ^2.9.0
version: 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-metrics':
specifier: ^2.9.0
version: 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/semantic-conventions':
specifier: ^1.42.0
version: 1.42.0
'@radix-ui/react-accordion':
specifier: ^1.2.12
version: 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
@@ -115,7 +130,7 @@ importers:
version: 6.4.24
better-auth:
specifier: 1.6.11
version: 1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
version: 1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
canvas-confetti:
specifier: ^1.9.4
version: 1.9.4
@@ -136,10 +151,10 @@ importers:
version: 16.6.1
drizzle-orm:
specifier: 0.45.2
version: 0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
version: 0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
drizzle-zod:
specifier: 0.8.3
version: 0.8.3(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(zod@4.3.6)
version: 0.8.3(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(zod@4.3.6)
googleapis:
specifier: ^170.1.0
version: 170.1.0
@@ -157,10 +172,10 @@ importers:
version: 12.42.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
next:
specifier: 16.2.3
version: 16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
version: 16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
next-safe-action:
specifier: ^7.10.8
version: 7.10.8(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.3.6)
version: 7.10.8(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.3.6)
next-themes:
specifier: ^0.4.6
version: 0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
@@ -227,7 +242,7 @@ importers:
version: 6.0.2(react@19.2.7)
'@react-email/preview-server':
specifier: 4.3.2
version: 4.3.2(postcss@8.5.10)
version: 4.3.2(@opentelemetry/api@1.9.1)(postcss@8.5.10)
'@react-email/render':
specifier: ^2.0.8
version: 2.0.9(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
@@ -1990,10 +2005,70 @@ packages:
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
'@opentelemetry/api-logs@0.220.0':
resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==}
engines: {node: '>=8.0.0'}
'@opentelemetry/api@1.9.1':
resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==}
engines: {node: '>=8.0.0'}
'@opentelemetry/core@2.9.0':
resolution: {integrity: sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': '>=1.0.0 <1.10.0'
'@opentelemetry/exporter-metrics-otlp-http@0.220.0':
resolution: {integrity: sha512-Yqt3RBw/bRVncaE9qIIhk4WfjbAQqXuP9FgAaU+IKPndnLEp/cUqZlSC324+bpmduRz7DoTjig8Ub0PeILWXUA==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': ^1.3.0
'@opentelemetry/otlp-exporter-base@0.220.0':
resolution: {integrity: sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': ^1.3.0
'@opentelemetry/otlp-transformer@0.220.0':
resolution: {integrity: sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': ^1.3.0
'@opentelemetry/resources@2.9.0':
resolution: {integrity: sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': '>=1.3.0 <1.10.0'
'@opentelemetry/sdk-logs@0.220.0':
resolution: {integrity: sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': '>=1.4.0 <1.10.0'
'@opentelemetry/sdk-metrics@2.9.0':
resolution: {integrity: sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': '>=1.9.0 <1.10.0'
'@opentelemetry/sdk-trace@2.9.0':
resolution: {integrity: sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==}
engines: {node: ^18.19.0 || >=20.6.0}
peerDependencies:
'@opentelemetry/api': '>=1.3.0 <1.10.0'
'@opentelemetry/semantic-conventions@1.41.1':
resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==}
engines: {node: '>=14'}
'@opentelemetry/semantic-conventions@1.42.0':
resolution: {integrity: sha512-icc5xCzndZfhuJMy5oqk5AvloWquR7jtae74qzpkKkhGp8BivK+oCcEXgGnjCdTfp8hA44l+w8gE8yYJbocJJw==}
engines: {node: '>=14'}
'@peculiar/asn1-android@2.8.0':
resolution: {integrity: sha512-skLbS+IOGv1lUgDqtChr8xvtvEr3HMse/JGBaL2r1J1o/n7a8wqOrovMtlRq/UXLhxvmLaONP67hwtshgzwfzA==}
@@ -7966,75 +8041,77 @@ snapshots:
'@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7
'@better-auth/api-key@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))':
'@better-auth/api-key@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
better-auth: 1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
better-auth: 1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
zod: 4.3.6
'@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)':
'@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)':
dependencies:
'@better-auth/utils': 0.4.0
'@better-fetch/fetch': 1.1.21
'@opentelemetry/semantic-conventions': 1.41.1
'@opentelemetry/semantic-conventions': 1.42.0
'@standard-schema/spec': 1.1.0
better-call: 1.3.5(zod@4.3.6)
jose: 6.2.3
kysely: 0.28.17
nanostores: 1.3.0
zod: 4.3.6
optionalDependencies:
'@opentelemetry/api': 1.9.1
'@better-auth/drizzle-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))':
'@better-auth/drizzle-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
optionalDependencies:
drizzle-orm: 0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
'@better-auth/kysely-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(kysely@0.28.17)':
'@better-auth/kysely-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(kysely@0.28.17)':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
optionalDependencies:
kysely: 0.28.17
'@better-auth/memory-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)':
'@better-auth/memory-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
'@better-auth/mongo-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)':
'@better-auth/mongo-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
'@better-auth/passkey@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))(nanostores@1.3.0)':
'@better-auth/passkey@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))(nanostores@1.3.0)':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
'@better-fetch/fetch': 1.1.21
'@simplewebauthn/browser': 13.3.0
'@simplewebauthn/server': 13.3.2
better-auth: 1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
better-auth: 1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
better-call: 1.3.5(zod@4.3.6)
nanostores: 1.3.0
zod: 4.3.6
'@better-auth/prisma-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(prisma@6.7.0(typescript@5.9.3))':
'@better-auth/prisma-adapter@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(prisma@6.7.0(typescript@5.9.3))':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
optionalDependencies:
'@prisma/client': 6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3)
prisma: 6.7.0(typescript@5.9.3)
'@better-auth/sso@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))':
'@better-auth/sso@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(better-call@1.3.5(zod@4.3.6))':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
'@better-fetch/fetch': 1.1.21
better-auth: 1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
better-auth: 1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
better-call: 1.3.5(zod@4.3.6)
fast-xml-parser: 5.9.3
jose: 6.2.3
@@ -8042,9 +8119,9 @@ snapshots:
tldts: 6.1.86
zod: 4.3.6
'@better-auth/telemetry@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)':
'@better-auth/telemetry@1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)':
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/utils': 0.4.0
'@better-fetch/fetch': 1.1.21
@@ -9065,8 +9142,73 @@ snapshots:
react: 19.2.7
react-dom: 19.2.7(react@19.2.7)
'@opentelemetry/api-logs@0.220.0':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/api@1.9.1': {}
'@opentelemetry/core@2.9.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/semantic-conventions': 1.41.1
'@opentelemetry/exporter-metrics-otlp-http@0.220.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/otlp-exporter-base': 0.220.0(@opentelemetry/api@1.9.1)
'@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/otlp-exporter-base@0.220.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.1)
'@opentelemetry/otlp-transformer@0.220.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/api-logs': 0.220.0
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources@2.9.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/semantic-conventions': 1.41.1
'@opentelemetry/sdk-logs@0.220.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/api-logs': 0.220.0
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/semantic-conventions': 1.41.1
'@opentelemetry/sdk-metrics@2.9.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/sdk-trace@2.9.0(@opentelemetry/api@1.9.1)':
dependencies:
'@opentelemetry/api': 1.9.1
'@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.1)
'@opentelemetry/semantic-conventions': 1.41.1
'@opentelemetry/semantic-conventions@1.41.1': {}
'@opentelemetry/semantic-conventions@1.42.0': {}
'@peculiar/asn1-android@2.8.0':
dependencies:
'@peculiar/asn1-schema': 2.8.0
@@ -10191,7 +10333,7 @@ snapshots:
md-to-react-email: 5.0.6(react@19.2.7)
react: 19.2.7
'@react-email/preview-server@4.3.2(postcss@8.5.10)':
'@react-email/preview-server@4.3.2(@opentelemetry/api@1.9.1)(postcss@8.5.10)':
dependencies:
'@babel/core': 7.26.10
'@babel/parser': 7.27.0
@@ -10217,7 +10359,7 @@ snapshots:
json5: 2.2.3
log-symbols: 4.1.0
module-punycode: punycode@2.3.1
next: 15.5.2(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
next: 15.5.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
node-html-parser: 7.0.1
ora: 5.4.1
pretty-bytes: 6.1.1
@@ -11087,15 +11229,15 @@ snapshots:
before-after-hook@4.0.0: {}
better-auth@1.6.11(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
better-auth@1.6.11(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
dependencies:
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/drizzle-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))
'@better-auth/kysely-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(kysely@0.28.17)
'@better-auth/memory-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)
'@better-auth/mongo-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)
'@better-auth/prisma-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(prisma@6.7.0(typescript@5.9.3))
'@better-auth/telemetry': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)
'@better-auth/core': 1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0)
'@better-auth/drizzle-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))
'@better-auth/kysely-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(kysely@0.28.17)
'@better-auth/memory-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)
'@better-auth/mongo-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)
'@better-auth/prisma-adapter': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(prisma@6.7.0(typescript@5.9.3))
'@better-auth/telemetry': 1.6.11(@better-auth/core@1.6.11(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)(@opentelemetry/api@1.9.1)(better-call@1.3.5(zod@4.3.6))(jose@6.2.3)(kysely@0.28.17)(nanostores@1.3.0))(@better-auth/utils@0.4.0)(@better-fetch/fetch@1.1.21)
'@better-auth/utils': 0.4.0
'@better-fetch/fetch': 1.1.21
'@noble/ciphers': 2.2.0
@@ -11109,8 +11251,8 @@ snapshots:
optionalDependencies:
'@prisma/client': 6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3)
drizzle-kit: 0.31.10
drizzle-orm: 0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
next: 16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
next: 16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
pg: 8.22.0
prisma: 6.7.0(typescript@5.9.3)
react: 19.2.7
@@ -11641,17 +11783,18 @@ snapshots:
esbuild: 0.25.12
tsx: 4.22.4
drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)):
drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)):
optionalDependencies:
'@opentelemetry/api': 1.9.1
'@prisma/client': 6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3)
'@types/pg': 8.20.0
kysely: 0.28.17
pg: 8.22.0
prisma: 6.7.0(typescript@5.9.3)
drizzle-zod@0.8.3(drizzle-orm@0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(zod@4.3.6):
drizzle-zod@0.8.3(drizzle-orm@0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3)))(zod@4.3.6):
dependencies:
drizzle-orm: 0.45.2(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
drizzle-orm: 0.45.2(@opentelemetry/api@1.9.1)(@prisma/client@6.7.0(prisma@6.7.0(typescript@5.9.3))(typescript@5.9.3))(@types/pg@8.20.0)(kysely@0.28.17)(pg@8.22.0)(prisma@6.7.0(typescript@5.9.3))
zod: 4.3.6
dunder-proto@1.0.1:
@@ -13362,9 +13505,9 @@ snapshots:
dependencies:
type-fest: 2.19.0
next-safe-action@7.10.8(next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.3.6):
next-safe-action@7.10.8(next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(zod@4.3.6):
dependencies:
next: 16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
next: 16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)
react: 19.2.7
react-dom: 19.2.7(react@19.2.7)
optionalDependencies:
@@ -13375,7 +13518,7 @@ snapshots:
react: 19.2.7
react-dom: 19.2.7(react@19.2.7)
next@15.5.2(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
next@15.5.2(@babel/core@7.26.10)(@opentelemetry/api@1.9.1)(react-dom@19.0.0(react@19.0.0))(react@19.0.0):
dependencies:
'@next/env': 15.5.2
'@swc/helpers': 0.5.15
@@ -13393,12 +13536,13 @@ snapshots:
'@next/swc-linux-x64-musl': 15.5.2
'@next/swc-win32-arm64-msvc': 15.5.2
'@next/swc-win32-x64-msvc': 15.5.2
'@opentelemetry/api': 1.9.1
sharp: 0.34.5
transitivePeerDependencies:
- '@babel/core'
- babel-plugin-macros
next@16.2.3(@babel/core@7.29.7)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
next@16.2.3(@babel/core@7.29.7)(@opentelemetry/api@1.9.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7):
dependencies:
'@next/env': 16.2.3
'@swc/helpers': 0.5.15
@@ -13417,6 +13561,7 @@ snapshots:
'@next/swc-linux-x64-musl': 16.2.3
'@next/swc-win32-arm64-msvc': 16.2.3
'@next/swc-win32-x64-msvc': 16.2.3
'@opentelemetry/api': 1.9.1
sharp: 0.34.5
transitivePeerDependencies:
- '@babel/core'
+7
View File
@@ -122,6 +122,11 @@ export const env = createEnv({
.enum(["true", "false"])
.default("false")
.transform((val) => val === "true"),
TELEMETRY: z
.enum(["true", "false"])
.default("true")
.transform((val) => val === "true"),
},
client: {
NEXT_PUBLIC_PROJECT_VERSION: z.string().optional(),
@@ -204,6 +209,8 @@ export const env = createEnv({
DEMO_ENABLED: process.env.DEMO_ENABLED,
TELEMETRY: process.env.TELEMETRY,
},
});
@@ -0,0 +1,22 @@
"use server";
import { z } from "zod";
import { action } from "@/lib/safe-actions/actions";
import { env } from "@/env.mjs";
import { collectRawTelemetry } from "@/features/telemetry/queries/telemetry.queries";
import { getOrCreateInstance } from "@/features/telemetry/services/instance";
import { buildTelemetryPayload } from "@/features/telemetry/services/anonymize";
export const compileTelemetryAction = action
.schema(z.object({}))
.action(async () => {
const [raw, instance] = await Promise.all([
collectRawTelemetry(),
getOrCreateInstance(),
]);
return buildTelemetryPayload(raw, {
secret: env.PROJECT_SECRET,
version: env.NEXT_PUBLIC_PROJECT_VERSION ?? "unknown",
instanceId: instance.id,
});
});
+11
View File
@@ -0,0 +1,11 @@
export const SERVICE_NAME = "portabase-dashboard";
export const TELEMETRY_METER_NAME = "portabase-telemetry";
export const OTLP_AUTH_TOKEN =
"4625713e72b4ec4eaac8a93716f3a83a3afc7fe17dfb8424c57aa82c459d4a8e";
export function getOtlpEndpoint(): string {
return process.env.NODE_ENV === "production"
? "https://telemetry.portabase.io"
: "http://localhost:4318";
// : "https://sandbox.telemetry.portabase.io";
}
+37
View File
@@ -0,0 +1,37 @@
import cron from "node-cron";
import { logger } from "@/lib/logger";
import { getOrCreateInstance } from "@/features/telemetry/services/instance";
import { runTelemetry } from "@/features/telemetry/run";
import { env } from "@/env.mjs";
const log = logger.child({ module: "telemetry/cron" });
export async function startTelemetryCron(): Promise<void> {
const { schedule, created } = await getOrCreateInstance();
if (created) {
console.warn(
"\n" +
"══════════════════════════════════════════════════════════════════════\n" +
"\n" +
" Portabase sends anonymous, aggregated usage metrics to help us\n" +
" understand how it is used in production. Only counts and enum labels\n" +
" are sent. Never personal data, database contents, names, hosts,\n" +
" credentials or configuration. The instance id is a random UUID,\n" +
" hashed before it ever leaves your server.\n" +
"\n" +
` Details & what we collect: https://portabase.io/privacy\n` +
"\n" +
"══════════════════════════════════════════════════════════════════════" +
"\n",
);
}
cron.schedule(env.NODE_ENV === "production" ? schedule : "* * * * *", async () => {
try {
await runTelemetry();
} catch (err) {
log.error({ job: "cron", name: "telemetryJob", error: err }, "Telemetry Error");
}
});
}
+5
View File
@@ -0,0 +1,5 @@
export { runTelemetry } from "@/features/telemetry/run";
export { startTelemetryCron } from "@/features/telemetry/cron";
export { compileTelemetryAction } from "@/features/telemetry/actions/telemetry.action";
export { getOtlpEndpoint } from "@/features/telemetry/constants";
export type { TelemetryPayload } from "@/features/telemetry/schemas/telemetry.schema";
+43
View File
@@ -0,0 +1,43 @@
import type { Meter } from "@opentelemetry/api";
import { getMeterProvider } from "@/features/telemetry/otel/instrumentation";
import { TELEMETRY_METER_NAME } from "@/features/telemetry/constants";
import type {
DistributionEntry,
TelemetryPayload,
} from "@/features/telemetry/schemas/telemetry.schema";
function recordDistribution(
meter: Meter,
name: string,
attrKey: string,
entries: DistributionEntry[],
): void {
const gauge = meter.createGauge(name);
for (const entry of entries) {
gauge.record(entry.count, { [attrKey]: entry.label });
}
}
export async function exportTelemetry(payload: TelemetryPayload): Promise<void> {
const provider = getMeterProvider(payload.instanceId);
const meter = provider.getMeter(TELEMETRY_METER_NAME);
meter.createGauge("portabase.users.total").record(payload.usersTotal);
meter.createGauge("portabase.organizations.total").record(payload.orgsTotal);
meter.createGauge("portabase.agents.total").record(payload.agentsTotal);
meter.createGauge("portabase.databases.total").record(payload.databasesTotal);
meter
.createGauge("portabase.instance.info")
.record(1, { dashboard_version: payload.dashboardVersion });
meter.createGauge("portabase.encryption.enabled").record(payload.encryptionEnabled ? 1 : 0);
recordDistribution(meter, "portabase.databases.by_type", "db_type", payload.databasesByType);
recordDistribution(meter, "portabase.storage.backends", "backend", payload.storageByBackend);
recordDistribution(meter, "portabase.notification.channels", "channel", payload.notificationsByChannel);
recordDistribution(meter, "portabase.agents.by_version", "agent_version", payload.agentsByVersion);
await provider.forceFlush();
await provider.shutdown();
}
@@ -0,0 +1,25 @@
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
import { resourceFromAttributes } from "@opentelemetry/resources";
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from "@opentelemetry/semantic-conventions";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import { env } from "@/env.mjs";
import { getOtlpEndpoint, OTLP_AUTH_TOKEN, SERVICE_NAME } from "@/features/telemetry/constants";
export function getMeterProvider(instanceId: string): MeterProvider {
const exporter = new OTLPMetricExporter({
url: `${getOtlpEndpoint()}/v1/metrics`,
headers: { Authorization: `Bearer ${OTLP_AUTH_TOKEN}` },
});
const reader = new PeriodicExportingMetricReader({
exporter,
exportIntervalMillis: 24 * 60 * 60 * 1000,
});
return new MeterProvider({
resource: resourceFromAttributes({
[ATTR_SERVICE_NAME]: SERVICE_NAME,
[ATTR_SERVICE_VERSION]: env.NEXT_PUBLIC_PROJECT_VERSION ?? "unknown",
"service.instance.id": instanceId,
}),
readers: [reader],
});
}
@@ -0,0 +1,64 @@
import { count } from "drizzle-orm";
import { db, schemas } from "@/db";
export type RawCount = { key: string | null; count: number };
export type RawTelemetry = {
orgsTotal: number;
usersTotal: number;
agentsTotal: number;
databasesTotal: number;
databasesByType: RawCount[];
storageByBackend: RawCount[];
notificationsByChannel: RawCount[];
agentsByVersion: RawCount[];
encryptionEnabled: boolean;
};
export async function collectRawTelemetry(): Promise<RawTelemetry> {
const [
orgs,
users,
agents,
databases,
databasesByType,
storageByBackend,
notificationsByChannel,
agentsByVersion,
settingRow,
] = await Promise.all([
db.select({ c: count() }).from(schemas.organization),
db.select({ c: count() }).from(schemas.user),
db.select({ c: count() }).from(schemas.agent),
db.select({ c: count() }).from(schemas.database),
db
.select({ key: schemas.database.dbms, count: count() })
.from(schemas.database)
.groupBy(schemas.database.dbms),
db
.select({ key: schemas.storageChannel.provider, count: count() })
.from(schemas.storageChannel)
.groupBy(schemas.storageChannel.provider),
db
.select({ key: schemas.notificationChannel.provider, count: count() })
.from(schemas.notificationChannel)
.groupBy(schemas.notificationChannel.provider),
db
.select({ key: schemas.agent.version, count: count() })
.from(schemas.agent)
.groupBy(schemas.agent.version),
db.select({ encryption: schemas.setting.encryption }).from(schemas.setting).limit(1),
]);
return {
orgsTotal: orgs[0]?.c ?? 0,
usersTotal: users[0]?.c ?? 0,
agentsTotal: agents[0]?.c ?? 0,
databasesTotal: databases[0]?.c ?? 0,
databasesByType,
storageByBackend,
notificationsByChannel,
agentsByVersion,
encryptionEnabled: settingRow[0]?.encryption ?? false,
};
}
+21
View File
@@ -0,0 +1,21 @@
import { logger } from "@/lib/logger";
import { compileTelemetryAction } from "@/features/telemetry/actions/telemetry.action";
import { exportTelemetry } from "@/features/telemetry/otel/export";
const log = logger.child({ module: "telemetry" });
export async function runTelemetry(): Promise<void> {
const result = await compileTelemetryAction({});
const payload = result?.data;
if (!payload) {
log.error(
{ serverError: result?.serverError, validationErrors: result?.validationErrors },
"Telemetry compile failed",
);
return;
}
await exportTelemetry(payload);
log.info({ instanceId: payload.instanceId }, `Telemetry exported (${payload.instanceId})`);
}
@@ -0,0 +1,23 @@
import { z } from "zod";
export const distributionEntrySchema = z.object({
label: z.string(),
count: z.number().int().nonnegative(),
});
export const telemetryPayloadSchema = z.object({
instanceId: z.string(),
dashboardVersion: z.string(),
orgsTotal: z.number().int().nonnegative(),
usersTotal: z.number().int().nonnegative(),
agentsTotal: z.number().int().nonnegative(),
databasesTotal: z.number().int().nonnegative(),
databasesByType: z.array(distributionEntrySchema),
storageByBackend: z.array(distributionEntrySchema),
notificationsByChannel: z.array(distributionEntrySchema),
agentsByVersion: z.array(distributionEntrySchema),
encryptionEnabled: z.boolean(),
});
export type DistributionEntry = z.infer<typeof distributionEntrySchema>;
export type TelemetryPayload = z.infer<typeof telemetryPayloadSchema>;
@@ -0,0 +1,40 @@
import { createHash } from "crypto";
import type { RawTelemetry, RawCount } from "@/features/telemetry/queries/telemetry.queries";
import {
telemetryPayloadSchema,
type DistributionEntry,
type TelemetryPayload,
} from "@/features/telemetry/schemas/telemetry.schema";
export type AnonymizeContext = { secret: string; version: string; instanceId: string };
export function hashInstanceId(instanceId: string, secret: string): string {
return createHash("sha256").update(`${instanceId}${secret}`).digest("hex");
}
function mapDistribution(rows: RawCount[]): DistributionEntry[] {
return rows.map((r) => ({
label: r.key ?? "unknown",
count: r.count,
}));
}
export function buildTelemetryPayload(
raw: RawTelemetry,
ctx: AnonymizeContext,
): TelemetryPayload {
const payload: TelemetryPayload = {
instanceId: hashInstanceId(ctx.instanceId, ctx.secret),
dashboardVersion: ctx.version,
orgsTotal: raw.orgsTotal,
usersTotal: raw.usersTotal,
agentsTotal: raw.agentsTotal,
databasesTotal: raw.databasesTotal,
databasesByType: mapDistribution(raw.databasesByType),
storageByBackend: mapDistribution(raw.storageByBackend),
notificationsByChannel: mapDistribution(raw.notificationsByChannel),
agentsByVersion: mapDistribution(raw.agentsByVersion),
encryptionEnabled: raw.encryptionEnabled,
};
return telemetryPayloadSchema.parse(payload);
}
@@ -0,0 +1,35 @@
import { promises as fs } from "fs";
import path from "path";
import { randomUUID } from "crypto";
import { env } from "@/env.mjs";
export type InstanceData = { id: string; schedule: string; created: boolean };
function randomDailySchedule(): string {
const minute = Math.floor(Math.random() * 60);
const hour = Math.floor(Math.random() * 24);
return `${minute} ${hour} * * *`;
}
export async function getOrCreateInstance(
filePath = path.join(env.PRIVATE_PATH!, "telemetry", "data.json"),
): Promise<InstanceData> {
await fs.mkdir(path.dirname(filePath), { recursive: true });
let data: Partial<InstanceData> = {};
try {
const raw = await fs.readFile(filePath, "utf8");
data = JSON.parse(raw) as Partial<InstanceData>;
} catch {
}
const created = !data.id;
const id = data.id ?? randomUUID();
const schedule = data.schedule ?? randomDailySchedule();
if (data.id !== id || data.schedule !== schedule) {
await fs.writeFile(filePath, JSON.stringify({ id, schedule }, null, 2), { mode: 0o600 });
}
return { id, schedule, created };
}
+5
View File
@@ -1,5 +1,7 @@
import {cleaningHealthcheckLogsJob, cleaningJob, healthcheckAgentAndDatabaseJob, retentionJob} from "@/lib/tasks";
import {logger} from "@/lib/logger";
import { env } from "@/env.mjs";
import { startTelemetryCron } from "@/features/telemetry/cron";
const log = logger.child({module: "init/cron"});
@@ -10,5 +12,8 @@ export async function setupCronJobs() {
cleaningJob.start();
cleaningHealthcheckLogsJob.start();
healthcheckAgentAndDatabaseJob.start();
if (env.TELEMETRY) {
await startTelemetryCron();
}
log.info("==== Cron jobs started ====");
}