Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd537fb571 | ||
|
|
3cbd252980 | ||
|
|
0a99988e6e | ||
|
|
a19d20d973 | ||
|
|
b86eab9e04 | ||
|
|
b36530ff96 | ||
|
|
1019298060 | ||
|
|
99a2ad30ce | ||
|
|
9783a22abf | ||
|
|
68f63b3b90 | ||
|
|
1189d13c14 | ||
|
|
243a784480 | ||
|
|
c89b8c3bab | ||
|
|
b5172219af | ||
|
|
db90f85041 | ||
|
|
db9f90aa91 | ||
|
|
41b19582cc | ||
|
|
766102797b | ||
|
|
773cb1312b | ||
|
|
bb593020d0 | ||
|
|
33ffe62add | ||
|
|
6e1aabb2de | ||
|
|
ab3bdebc57 | ||
|
|
20d00e5ef2 | ||
|
|
e689c1cacb | ||
|
|
37c0737624 | ||
|
|
23bc448088 |
@@ -1,7 +1,7 @@
|
||||
contact_links:
|
||||
- name: 🤗 Get Help
|
||||
url: https://github.com/langfuse/langfuse/discussions/new?category=q-a
|
||||
about: If you can’t get something to work the way you expect, open a question in our discussion forums.
|
||||
- name: 💡 Feature Request
|
||||
url: https://github.com/langfuse/langfuse/discussions/new?category=ideas
|
||||
url: https://github.com/orgs/langfuse/discussions/new?category=ideas
|
||||
about: Suggest any ideas you have using our discussion forums.
|
||||
- name: 🤗 Get Help
|
||||
url: https://github.com/orgs/langfuse/discussions/new?category=support
|
||||
about: If you can’t get something to work the way you expect, open a question in our discussion forums.
|
||||
|
||||
@@ -66,6 +66,11 @@ jobs:
|
||||
matrix:
|
||||
node-version: [18, 20]
|
||||
steps:
|
||||
- name: Set Swap Space
|
||||
uses: pierotofy/set-swap-space@master
|
||||
with:
|
||||
swap-size-gb: 10
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v3
|
||||
|
||||
Generated
+149
-383
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "langfuse-core",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "langfuse-core",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.2",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@anthropic-ai/tokenizer": "^0.0.4",
|
||||
@@ -39,7 +39,7 @@
|
||||
"@radix-ui/react-tooltip": "^1.0.7",
|
||||
"@react-email/components": "^0.0.14",
|
||||
"@react-email/render": "^0.0.12",
|
||||
"@sentry/nextjs": "^7.95.0",
|
||||
"@sentry/nextjs": "^7.99.0",
|
||||
"@sentry/profiling-node": "^1.3.5",
|
||||
"@sentry/types": "^7.88.0",
|
||||
"@t3-oss/env-nextjs": "^0.8.0",
|
||||
@@ -55,7 +55,7 @@
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"cmdk": "^0.2.0",
|
||||
"cmdk": "^0.2.1",
|
||||
"core-js": "^3.35.1",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns": "^3.3.1",
|
||||
@@ -63,11 +63,11 @@
|
||||
"exponential-backoff": "^3.1.1",
|
||||
"js-tiktoken": "^1.0.10",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.316.0",
|
||||
"lucide-react": "^0.321.0",
|
||||
"next": "^14.1.0",
|
||||
"next-auth": "^4.24.5",
|
||||
"next-query-params": "^5.0.0",
|
||||
"nodemailer": "^6.9.8",
|
||||
"nodemailer": "^6.9.9",
|
||||
"posthog-js": "^1.103.1",
|
||||
"posthog-node": "^3.6.1",
|
||||
"react": "18.2.0",
|
||||
@@ -86,23 +86,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jedmao/location": "^3.0.0",
|
||||
"@mermaid-js/mermaid-cli": "^10.6.1",
|
||||
"@playwright/test": "^1.41.1",
|
||||
"@mermaid-js/mermaid-cli": "^10.7.0",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"@release-it/bumper": "^6.0.1",
|
||||
"@testing-library/jest-dom": "^6.2.1",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/jest-dom": "^6.4.1",
|
||||
"@testing-library/react": "^14.2.1",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/eslint": "^8.56.2",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "20.10.5",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react": "^18.2.51",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||
"@typescript-eslint/parser": "^6.19.1",
|
||||
"@typescript-eslint/parser": "^6.20.0",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"dotenv-cli": "^7.3.0",
|
||||
"eslint": "^8.56.0",
|
||||
@@ -2844,9 +2844,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@mermaid-js/mermaid-cli": {
|
||||
"version": "10.6.1",
|
||||
"resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-10.6.1.tgz",
|
||||
"integrity": "sha512-OH2uOXW3/GBaMGagVF7Fzu/9TJrGge+Bu/+Tm8OyIaRBaKa2NN+3SggJOmr5s51oTPaGKu/X1XBDoauvtlXAPg==",
|
||||
"version": "10.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-cli/-/mermaid-cli-10.7.0.tgz",
|
||||
"integrity": "sha512-b1kHdzSStWaxoNdU5KnzXJ/OQzYqFo4mZsHobX44l6gb2s1O6DzD0g801VzxUmcJ+5OWt6piDL1Ug//cQUsrZg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"chalk": "^5.0.1",
|
||||
@@ -3288,12 +3288,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.41.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.1.tgz",
|
||||
"integrity": "sha512-9g8EWTjiQ9yFBXc6HjCWe41msLpxEX0KhmfmPl9RPLJdfzL4F0lg2BdJ91O9azFdl11y1pmpwdjBiSxvqc+btw==",
|
||||
"version": "1.41.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz",
|
||||
"integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"playwright": "1.41.1"
|
||||
"playwright": "1.41.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -4923,57 +4923,57 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/feedback": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.95.0.tgz",
|
||||
"integrity": "sha512-UWNUUg+OrhV58/ChQNY0yLCCYdEI2cIYVwq1riZ+AFU9Z2ZyCxEoSRVLh7c5tnCPLbKAPR+VvlEsSjMqucAKnA==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.99.0.tgz",
|
||||
"integrity": "sha512-exIO1o+bE0MW4z30FxC0cYzJ4ZHSMlDPMHCBDPzU+MWGQc/fb8s58QUrx5Dnm6HTh9G3H+YlroCxIo9u0GSwGQ==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/replay-canvas": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.95.0.tgz",
|
||||
"integrity": "sha512-nK+VYLnhlxLnnEUPMnzN8BSCFXPy2dQ5OVFO+fiTNPlGCbxsq8O9SnkX6E+u1oPLSA/151s2B3VxIasR8bXJAQ==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.99.0.tgz",
|
||||
"integrity": "sha512-PoIkfusToDq0snfl2M6HJx/1KJYtXxYhQplrn11kYadO04SdG0XGXf4h7wBTMEQ7LDEAtQyvsOu4nEQtTO3YjQ==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/replay": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/replay": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry-internal/tracing": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.95.0.tgz",
|
||||
"integrity": "sha512-YKiLPMnEgTsTh7u/W1Zep9HtV1rJqAetqJ4ekaIxyUUB6ppi6V00MacSjb01o++fwlNNDYFxNpJlgQqNPqsCNA==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.99.0.tgz",
|
||||
"integrity": "sha512-z3JQhHjoM1KdM20qrHwRClKJrNLr2CcKtCluq7xevLtXHJWNAQQbafnWD+Aoj85EWXBzKt9yJMv2ltcXJ+at+w==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/browser": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.95.0.tgz",
|
||||
"integrity": "sha512-J+bAryc/7StRZSeaJByLTnEslWu7uXaZ1zERQF17sZbRxvbyaYbAO7cqSUKZ1gK3p9QfrkqzNl7xA8thg4FtHQ==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.99.0.tgz",
|
||||
"integrity": "sha512-bgfoUv3wkwwLgN5YUOe0ibB3y268ZCnamZh6nLFqnY/UBKC1+FXWFdvzVON/XKUm62LF8wlpCybOf08ebNj2yg==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/feedback": "7.95.0",
|
||||
"@sentry-internal/replay-canvas": "7.95.0",
|
||||
"@sentry-internal/tracing": "7.95.0",
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/replay": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry-internal/feedback": "7.99.0",
|
||||
"@sentry-internal/replay-canvas": "7.99.0",
|
||||
"@sentry-internal/tracing": "7.99.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/replay": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -5000,25 +5000,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/core": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.95.0.tgz",
|
||||
"integrity": "sha512-z+ffO6jK/ZUxnRbBGmnj5sOouKZ4mvRY0KJa33kbyqcmeiJKrN81M7Ecj1IJUCamo/6RqX0GCwDDxgUPZZZBwA==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
|
||||
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/integrations": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.95.0.tgz",
|
||||
"integrity": "sha512-5d2RlQr8SHuAZ1gMT5G+R3DjyK//r24b686j18RB8k61qVhylE0SoSpJWmonDwNZnmvmpbLkYvh2kNhlAIKUTA==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-7.99.0.tgz",
|
||||
"integrity": "sha512-q4Nwpc27DTWlR7nDerd1o6KHlT/0usK+3xfBTZ1feVIAHCxt6ohCyZdoQ97+4kQiJJdX47MEmJYsXUlj62yZNg==",
|
||||
"dependencies": {
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0",
|
||||
"localforage": "^1.8.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -5026,18 +5026,18 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/nextjs": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-7.95.0.tgz",
|
||||
"integrity": "sha512-6RinlFxsnZjDSuApFgWnupPNBbqgHW7h/+I02dLWhy7TkTfmfGEiQ8pPENrQlKUvyEGLJv2+Pk7RXi+Xj2DC0g==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/nextjs/-/nextjs-7.99.0.tgz",
|
||||
"integrity": "sha512-8eeEPFJjRBiCp2sFUhDLQFdWFagQ2yBvmALZIOIuoMei69N+clYVSxz84beeztbLal0zvRadJO5LAkBCb6d66Q==",
|
||||
"dependencies": {
|
||||
"@rollup/plugin-commonjs": "24.0.0",
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/integrations": "7.95.0",
|
||||
"@sentry/node": "7.95.0",
|
||||
"@sentry/react": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0",
|
||||
"@sentry/vercel-edge": "7.95.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/integrations": "7.99.0",
|
||||
"@sentry/node": "7.99.0",
|
||||
"@sentry/react": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0",
|
||||
"@sentry/vercel-edge": "7.99.0",
|
||||
"@sentry/webpack-plugin": "1.21.0",
|
||||
"chalk": "3.0.0",
|
||||
"resolve": "1.22.8",
|
||||
@@ -5059,14 +5059,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/node": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.95.0.tgz",
|
||||
"integrity": "sha512-3fbN+4ajPly9rhbuJtuZ+o2FGmka8Y7A3T/ooHuhCGoWegKtn3OzaOIrdwcYoBIy1fO6SuldTi/P72Y7wgIPtw==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/node/-/node-7.99.0.tgz",
|
||||
"integrity": "sha512-34wYtLddnPcQ8qvKq62AfxowaMFw+GMUZGv7fIs9FxeBqqqn6Ckl0gFCTADudIIBQ3rSbmN7sHJIXdyiQv+pcw==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/tracing": "7.95.0",
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry-internal/tracing": "7.99.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -5092,14 +5092,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/react": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.95.0.tgz",
|
||||
"integrity": "sha512-L1WVoRJ14uUBhnpVURVO3G7szuA2hk5pzNWMGjNhE7I+ERdfYjgRS5FMnjcsZsnyNtELe/56jLCBirKqwWZJIQ==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.99.0.tgz",
|
||||
"integrity": "sha512-RtHwgzMHJhzJfSQpVG0SDPQYMTGDX3Q37/YWI59S4ALMbSW4/F6n/eQAvGVYZKbh2UCSqgFuRWaXOYkSZT17wA==",
|
||||
"dependencies": {
|
||||
"@sentry/browser": "7.95.0",
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0",
|
||||
"@sentry/browser": "7.99.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0",
|
||||
"hoist-non-react-statics": "^3.3.2"
|
||||
},
|
||||
"engines": {
|
||||
@@ -5110,47 +5110,47 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/replay": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.95.0.tgz",
|
||||
"integrity": "sha512-WAAEvWCXoNC7hfPI1fNoxODB9UzUYhXtscrWIm89Mn3AAi8haayVNNiUWKVj6+Vpt87C+/sb9UsERwdPWpl/Sw==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.99.0.tgz",
|
||||
"integrity": "sha512-gyN/I2WpQrLAZDT+rScB/0jnFL2knEVBo8U8/OVt8gNP20Pq8T/rDZKO/TG0cBfvULDUbJj2P4CJryn2p/O2rA==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/tracing": "7.95.0",
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry-internal/tracing": "7.99.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/types": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.95.0.tgz",
|
||||
"integrity": "sha512-ouU7NsEcrwmcnXHMNBGmKZEmKMzmgPGoBydZn1gukCI67Ci71fAYpPNrbtmjai6+jtsY21o45rVLqExru2sdfw==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
|
||||
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/utils": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.95.0.tgz",
|
||||
"integrity": "sha512-0zget8AOaQWLIEA9cTx/qiQQYpx2x0UfnaW5xRmQg12QGTSngo/cUm9O04zuHw5gpBBGG0ocMDHxwwr+UCCBiw==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
|
||||
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
|
||||
"dependencies": {
|
||||
"@sentry/types": "7.95.0"
|
||||
"@sentry/types": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@sentry/vercel-edge": {
|
||||
"version": "7.95.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-7.95.0.tgz",
|
||||
"integrity": "sha512-BQ9NIUNe8T1crQIfLB88YQhgWO114Ru9ZxzteuUNWN4+kqNgPNBe25jHLERmZ6pRPLtWdSXIUeIZVxwuKXMUjQ==",
|
||||
"version": "7.99.0",
|
||||
"resolved": "https://registry.npmjs.org/@sentry/vercel-edge/-/vercel-edge-7.99.0.tgz",
|
||||
"integrity": "sha512-9Uw3Iuy8KMlcv71ifnaguwndb1NkHeOAbYcBEeq9W+n0f5ocFZvMlnwszSlVNAL3cK+hlpcBhelXNAO/mBWCfg==",
|
||||
"dependencies": {
|
||||
"@sentry-internal/tracing": "7.95.0",
|
||||
"@sentry/core": "7.95.0",
|
||||
"@sentry/types": "7.95.0",
|
||||
"@sentry/utils": "7.95.0"
|
||||
"@sentry-internal/tracing": "7.99.0",
|
||||
"@sentry/core": "7.99.0",
|
||||
"@sentry/types": "7.99.0",
|
||||
"@sentry/utils": "7.99.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@@ -6091,9 +6091,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@testing-library/jest-dom": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.2.1.tgz",
|
||||
"integrity": "sha512-Nuy/uFFDe9h/2jwoUuMKgoxvgkUv4S9jI9bARj6dGUKJ3euRhg8JFi5sciYbrayoxkadEOZednRT9+vo6LvvxQ==",
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.4.1.tgz",
|
||||
"integrity": "sha512-Z7qMM3J2Zw5H/nC2/5CYx5YcuaD56JmDFKNIozZ89VIo6o6Y9FMhssics4e2madEKYDNEpZz3+glPGz0yWMOag==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@adobe/css-tools": "^4.3.2",
|
||||
@@ -6142,9 +6142,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@testing-library/react": {
|
||||
"version": "14.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.1.2.tgz",
|
||||
"integrity": "sha512-z4p7DVBTPjKM5qDZ0t5ZjzkpSNb+fZy1u6bzO7kk8oeGagpPCAtgh4cx1syrfp7a+QWkM021jGqjJaxJJnXAZg==",
|
||||
"version": "14.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@testing-library/react/-/react-14.2.1.tgz",
|
||||
"integrity": "sha512-sGdjws32ai5TLerhvzThYFbpnF9XtL65Cjf+gB0Dhr29BGqK+mAeN7SURSdu+eqgET4ANcWoC7FQpkaiGvBr+A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
@@ -6463,9 +6463,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/jest": {
|
||||
"version": "29.5.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.11.tgz",
|
||||
"integrity": "sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ==",
|
||||
"version": "29.5.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz",
|
||||
"integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"expect": "^29.0.0",
|
||||
@@ -6534,9 +6534,9 @@
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.2.48",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.48.tgz",
|
||||
"integrity": "sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==",
|
||||
"version": "18.2.51",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.51.tgz",
|
||||
"integrity": "sha512-XeoMaU4CzyjdRr3c4IQQtiH7Rpo18V07rYZUucEZQwOUEtGgTXv7e6igQiQ+xnV6MbMe1qjEmKdgMNnfppnXfg==",
|
||||
"devOptional": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@@ -6643,63 +6643,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz",
|
||||
"integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"@typescript-eslint/visitor-keys": "6.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz",
|
||||
"integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz",
|
||||
"integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "6.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.19.1.tgz",
|
||||
"integrity": "sha512-WEfX22ziAh6pRE9jnbkkLGp/4RhTpffr2ZK5bJ18M8mIfA8A+k97U9ZyaXCEJRlmMHh7R9MJZWXp/r73DzINVQ==",
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.20.0.tgz",
|
||||
"integrity": "sha512-bYerPDF/H5v6V76MdMYhjwmwgMA+jlPVqjSDq2cRqMi8bP5sR3Z+RLOiOMad3nsnmDVmn2gAFCyNgh/dIrfP/w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "6.19.1",
|
||||
"@typescript-eslint/types": "6.19.1",
|
||||
"@typescript-eslint/typescript-estree": "6.19.1",
|
||||
"@typescript-eslint/visitor-keys": "6.19.1",
|
||||
"@typescript-eslint/scope-manager": "6.20.0",
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"@typescript-eslint/typescript-estree": "6.20.0",
|
||||
"@typescript-eslint/visitor-keys": "6.20.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
@@ -6719,13 +6672,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.19.1.tgz",
|
||||
"integrity": "sha512-4CdXYjKf6/6aKNMSly/BP4iCSOpvMmqtDzRtqFyyAae3z5kkqEjKndR5vDHL8rSuMIIWP8u4Mw4VxLyxZW6D5w==",
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz",
|
||||
"integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.19.1",
|
||||
"@typescript-eslint/visitor-keys": "6.19.1"
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"@typescript-eslint/visitor-keys": "6.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
@@ -6762,7 +6715,7 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz",
|
||||
"integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==",
|
||||
@@ -6775,7 +6728,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz",
|
||||
"integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==",
|
||||
@@ -6803,88 +6756,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz",
|
||||
"integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils/node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "6.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.19.1.tgz",
|
||||
"integrity": "sha512-6+bk6FEtBhvfYvpHsDgAL3uo4BfvnTnoge5LrrCj2eJN8g3IJdLTD4B/jK3Q6vo4Ql/Hoip9I8aB6fF+6RfDqg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.19.1.tgz",
|
||||
"integrity": "sha512-aFdAxuhzBFRWhy+H20nYu19+Km+gFfwNO4TEqyszkMcgBDYQjmPJ61erHxuT2ESJXhlhrO7I5EFIlZ+qGR8oVA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.19.1",
|
||||
"@typescript-eslint/visitor-keys": "6.19.1",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "9.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
@@ -6934,65 +6805,7 @@
|
||||
"eslint": "^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.20.0.tgz",
|
||||
"integrity": "sha512-p4rvHQRDTI1tGGMDFQm+GtxP1ZHyAh64WANVoyEcNMpaTFn3ox/3CcgtIlELnRfKzSs/DwYlDccJEtr3O6qBvA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"@typescript-eslint/visitor-keys": "6.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.20.0.tgz",
|
||||
"integrity": "sha512-MM9mfZMAhiN4cOEcUOEx+0HmuaW3WBfukBZPCfwSqFnQy0grXYtngKCqpQN339X3RrwtzspWJrpbrupKYUSBXQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.20.0.tgz",
|
||||
"integrity": "sha512-RnRya9q5m6YYSpBN7IzKu9FmLcYtErkDkc8/dKv81I9QiLLtVBHrjz+Ev/crAqgMNW2FCsoZF4g2QUylMnJz+g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.20.0",
|
||||
"@typescript-eslint/visitor-keys": "6.20.0",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
"minimatch": "9.0.3",
|
||||
"semver": "^7.5.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.20.0",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.20.0.tgz",
|
||||
"integrity": "sha512-E8Cp98kRe4gKHjJD4NExXKz/zOJ1A2hhZc+IMVD6i7w4yjIvh6VyuRI0gRtxAsXtoC35uGMaQ9rjI2zJaXDEAw==",
|
||||
@@ -7009,47 +6822,6 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/brace-expansion": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils/node_modules/minimatch": {
|
||||
"version": "9.0.3",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
|
||||
"integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16 || 14 >=14.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.19.1",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.19.1.tgz",
|
||||
"integrity": "sha512-gkdtIO+xSO/SmI0W68DBg4u1KElmIUo3vXzgHyGPs6cxgB0sa3TlptRAAE0hUY1hM6FcDKEv7aIwiTGm76cXfQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.19.1",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
}
|
||||
},
|
||||
"node_modules/@ungap/structured-clone": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
|
||||
@@ -8273,12 +8045,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cmdk": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-0.2.0.tgz",
|
||||
"integrity": "sha512-JQpKvEOb86SnvMZbYaFKYhvzFntWBeSZdyii0rZPhKJj9uwJBxu4DaVYDrRN7r3mPop56oPhRw+JYWTKs66TYw==",
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-0.2.1.tgz",
|
||||
"integrity": "sha512-U6//9lQ6JvT47+6OF6Gi8BvkxYQ8SCRRSKIJkthIMsFsLZRG0cKvTtuTaefyIKMQb8rvvXy0wGdpTNq/jPtm+g==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "1.0.0",
|
||||
"command-score": "0.1.2"
|
||||
"@radix-ui/react-dialog": "1.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0",
|
||||
@@ -8561,11 +8332,6 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/command-score": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/command-score/-/command-score-0.1.2.tgz",
|
||||
"integrity": "sha512-VtDvQpIJBvBatnONUsPzXYFVKQQAhuf3XTNOAsdBxCNO/QCtUUd8LSgjn0GVarBkCad6aJCZfXgrjYbl/KRr7w=="
|
||||
},
|
||||
"node_modules/commander": {
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
@@ -13678,9 +13444,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lucide-react": {
|
||||
"version": "0.316.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.316.0.tgz",
|
||||
"integrity": "sha512-dTmYX1H4IXsRfVcj/KUxworV6814ApTl7iXaS21AimK2RUEl4j4AfOmqD3VR8phe5V91m4vEJ8tCK4uT1jE5nA==",
|
||||
"version": "0.321.0",
|
||||
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.321.0.tgz",
|
||||
"integrity": "sha512-Fi9VahIna6642U+2nAGSjnXwUBV3WyfFFPQq4yi3w30jtqxDLfSyiYCtCYCYQZ2KWNZc1MDI+rcsa0t+ChdYpw==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.5.1 || ^17.0.0 || ^18.0.0"
|
||||
}
|
||||
@@ -14172,9 +13938,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.9.8",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.8.tgz",
|
||||
"integrity": "sha512-cfrYUk16e67Ks051i4CntM9kshRYei1/o/Gi8K1d+R34OIs21xdFnW7Pt7EucmVKA0LKtqUGNcjMZ7ehjl49mQ==",
|
||||
"version": "6.9.9",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.9.tgz",
|
||||
"integrity": "sha512-dexTll8zqQoVJEZPwQAKzxxtFn0qTnjdQTchoU6Re9BUUGBJiOy3YMn/0ShTW6J5M0dfQ1NeDeRTTl4oIWgQMA==",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
@@ -15033,12 +14799,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.41.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.1.tgz",
|
||||
"integrity": "sha512-gdZAWG97oUnbBdRL3GuBvX3nDDmUOuqzV/D24dytqlKt+eI5KbwusluZRGljx1YoJKZ2NRPaeWiFTeGZO7SosQ==",
|
||||
"version": "1.41.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz",
|
||||
"integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"playwright-core": "1.41.1"
|
||||
"playwright-core": "1.41.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -15051,9 +14817,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.41.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.1.tgz",
|
||||
"integrity": "sha512-/KPO5DzXSMlxSX77wy+HihKGOunh3hqndhqeo/nMxfigiKzogn8kfL0ZBDu0L1RKgan5XHCPmn6zXd2NUJgjhg==",
|
||||
"version": "1.41.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz",
|
||||
"integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
|
||||
+12
-12
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "langfuse-core",
|
||||
"version": "2.0.0",
|
||||
"version": "2.1.2",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"prebuild": "cp generated/openapi-client/openapi.yml public/openapi-client.yml && cp generated/openapi-server/openapi.yml public/openapi-server.yml",
|
||||
@@ -57,7 +57,7 @@
|
||||
"@radix-ui/react-tooltip": "^1.0.7",
|
||||
"@react-email/components": "^0.0.14",
|
||||
"@react-email/render": "^0.0.12",
|
||||
"@sentry/nextjs": "^7.95.0",
|
||||
"@sentry/nextjs": "^7.99.0",
|
||||
"@sentry/profiling-node": "^1.3.5",
|
||||
"@sentry/types": "^7.88.0",
|
||||
"@t3-oss/env-nextjs": "^0.8.0",
|
||||
@@ -73,7 +73,7 @@
|
||||
"bcryptjs": "^2.4.3",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.0",
|
||||
"cmdk": "^0.2.0",
|
||||
"cmdk": "^0.2.1",
|
||||
"core-js": "^3.35.1",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns": "^3.3.1",
|
||||
@@ -81,11 +81,11 @@
|
||||
"exponential-backoff": "^3.1.1",
|
||||
"js-tiktoken": "^1.0.10",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-react": "^0.316.0",
|
||||
"lucide-react": "^0.321.0",
|
||||
"next": "^14.1.0",
|
||||
"next-auth": "^4.24.5",
|
||||
"next-query-params": "^5.0.0",
|
||||
"nodemailer": "^6.9.8",
|
||||
"nodemailer": "^6.9.9",
|
||||
"posthog-js": "^1.103.1",
|
||||
"posthog-node": "^3.6.1",
|
||||
"react": "18.2.0",
|
||||
@@ -104,23 +104,23 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jedmao/location": "^3.0.0",
|
||||
"@mermaid-js/mermaid-cli": "^10.6.1",
|
||||
"@playwright/test": "^1.41.1",
|
||||
"@mermaid-js/mermaid-cli": "^10.7.0",
|
||||
"@playwright/test": "^1.41.2",
|
||||
"@release-it/bumper": "^6.0.1",
|
||||
"@testing-library/jest-dom": "^6.2.1",
|
||||
"@testing-library/react": "^14.1.2",
|
||||
"@testing-library/jest-dom": "^6.4.1",
|
||||
"@testing-library/react": "^14.2.1",
|
||||
"@types/bcryptjs": "^2.4.6",
|
||||
"@types/cors": "^2.8.17",
|
||||
"@types/eslint": "^8.56.2",
|
||||
"@types/jest": "^29.5.11",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/lodash": "^4.14.202",
|
||||
"@types/node": "20.10.5",
|
||||
"@types/nodemailer": "^6.4.14",
|
||||
"@types/react": "^18.2.48",
|
||||
"@types/react": "^18.2.51",
|
||||
"@types/react-dom": "^18.2.18",
|
||||
"@types/uuid": "^9.0.8",
|
||||
"@typescript-eslint/eslint-plugin": "^6.20.0",
|
||||
"@typescript-eslint/parser": "^6.19.1",
|
||||
"@typescript-eslint/parser": "^6.20.0",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"dotenv-cli": "^7.3.0",
|
||||
"eslint": "^8.56.0",
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
DELETE FROM models
|
||||
WHERE id in ('clrp1wopz000808l09nwy32xh', 'clrp1wopz000408l05xcycki1');
|
||||
|
||||
INSERT INTO models (
|
||||
id,
|
||||
project_id,
|
||||
model_name,
|
||||
match_pattern,
|
||||
start_date,
|
||||
input_price,
|
||||
output_price,
|
||||
total_price,
|
||||
unit,
|
||||
tokenizer_id,
|
||||
tokenizer_config
|
||||
)
|
||||
VALUES
|
||||
-- https://openai.com/blog/new-embedding-models-and-api-updates
|
||||
-- https://openai.com/blog/gpt-3-5-turbo-fine-tuning-and-api-updates
|
||||
-- ft model tokens are getting counted like the base model https://github.com/openai/tiktoken/blob/db5bda9fc93b3171db6c4afea329394e6b6d31ca/tiktoken/model.py
|
||||
|
||||
('cls08r8sq000308jq14ae96f0', NULL, 'ft:gpt-3.5-turbo-1106', '(?i)^(ft:)(gpt-3.5-turbo-1106:)(.+)(:)(.*)(:)(.+)$', NULL, 0.000003, 0.000006, NULL, 'TOKENS', 'openai', '{"tokensPerName": 1, "tokenizerModel": "gpt-3.5-turbo-1106", "tokensPerMessage": 3}'),
|
||||
('cls08rp99000408jqepxoakjv', NULL, 'ft:gpt-3.5-turbo-0613', '(?i)^(ft:)(gpt-3.5-turbo-0613:)(.+)(:)(.*)(:)(.+)$', NULL, 0.000012, 0.000016, NULL, 'TOKENS', 'openai', '{"tokensPerName": 1, "tokenizerModel": "gpt-3.5-turbo-0613", "tokensPerMessage": 3}'),
|
||||
('cls08rv9g000508jq5p4z4nlr', NULL, 'ft:davinci-002', '(?i)^(ft:)(davinci-002:)(.+)(:)(.*)(:)(.+)$$', NULL, 0.000012, 0.000012, NULL, 'TOKENS', 'openai', '{"tokenizerModel": "davinci-002"}'),
|
||||
('cls08s2bw000608jq57wj4un2', NULL, 'ft:babbage-002', '(?i)^(ft:)(babbage-002:)(.+)(:)(.*)(:)(.+)$$', NULL, 0.0000016, 0.0000016, NULL, 'TOKENS', 'openai', '{"tokenizerModel": "babbage-002"}'),
|
||||
|
||||
-- https://cloud.google.com/vertex-ai/docs/generative-ai/pricing
|
||||
('cls0k4lqt000008ky1o1s8wd5', NULL, 'gemini-pro', '(?i)^(gemini-pro)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0jni4t000008jk3kyy803r', NULL, 'chat-bison-32k', '(?i)^(chat-bison-32k)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0iv12d000108l251gf3038', NULL, 'chat-bison', '(?i)^(chat-bison)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0jmjt3000108l83ix86w0d', NULL, 'text-bison-32k', '(?i)^(text-bison-32k)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0juygp000308jk2a6x9my2', NULL, 'text-bison', '(?i)^(text-bison)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0jungb000208jk12gm4gk1', NULL, 'text-unicorn', '(?i)^(text-unicorn)(@[a-zA-Z0-9]+)?$', NULL, 0.0000025, 0.0000075, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls1nyj5q000208l33ne901d8', NULL, 'textembedding-gecko', '(?i)^(textembedding-gecko)(@[a-zA-Z0-9]+)?$', NULL, NULL, NULL, 0.0000001, 'CHARACTERS', NULL, NULL),
|
||||
('cls1nyyjp000308l31gxy1bih', NULL, 'textembedding-gecko-multilingual', '(?i)^(textembedding-gecko-multilingual)(@[a-zA-Z0-9]+)?$', NULL, NULL, NULL, 0.0000001, 'CHARACTERS', NULL, NULL),
|
||||
('cls1nzjt3000508l3dnwad3g0', NULL, 'code-gecko', '(?i)^(code-gecko)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls1nzwx4000608l38va7e4tv', NULL, 'code-bison', '(?i)^(code-bison)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls1o053j000708l39f8g4bgs', NULL, 'code-bison-32k', '(?i)^(code-bison-32k)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0j33v1000008joagkc4lql', NULL, 'codechat-bison-32k', '(?i)^(codechat-bison-32k)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL),
|
||||
('cls0jmc9v000008l8ee6r3gsd', NULL, 'codechat-bison', '(?i)^(codechat-bison)(@[a-zA-Z0-9]+)?$', NULL, 0.00000025, 0.0000005, NULL, 'CHARACTERS', NULL, NULL)
|
||||
@@ -353,6 +353,40 @@ describe("/api/public/ingestion API Endpoint", () => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
observationExternalModel: "ft:gpt-3.5-turbo-1106:my-org:custom_suffix:id",
|
||||
observationStartTime: new Date("2022-01-01T10:00:00.000Z"),
|
||||
modelUnit: "TOKENS",
|
||||
expectedInternalModel: "ft:gpt-3.5-turbo-1106",
|
||||
expectedPromptTokens: 0,
|
||||
expectedCompletionTokens: 0,
|
||||
models: [
|
||||
{
|
||||
modelName: "ft:gpt-3.5-turbo-1106",
|
||||
matchPattern: "(?i)^(ft:)(gpt-3.5-turbo-1106:)(.+)(:)(.*)(:)(.+)$",
|
||||
startDate: new Date("2022-01-01T00:00:00.000Z"),
|
||||
unit: "TOKENS",
|
||||
tokenizerId: "openai",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
observationExternalModel: "ft:babbage-002:my-org#2:custom_suffix-2:id",
|
||||
observationStartTime: new Date("2022-01-01T10:00:00.000Z"),
|
||||
modelUnit: "TOKENS",
|
||||
expectedInternalModel: "ft:babbage-002",
|
||||
expectedPromptTokens: 0,
|
||||
expectedCompletionTokens: 0,
|
||||
models: [
|
||||
{
|
||||
modelName: "ft:babbage-002",
|
||||
matchPattern: "(?i)^(ft:)(babbage-002:)(.+)(:)(.*)(:)(.+)$",
|
||||
startDate: new Date("2022-01-01T00:00:00.000Z"),
|
||||
unit: "TOKENS",
|
||||
tokenizerId: "openai",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
observationExternalModel: "GPT-4",
|
||||
observationStartTime: new Date("2021-01-01T00:00:00.000Z"),
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { VERSION } from "@/src/constants/VERSION";
|
||||
import { env } from "@/src/env.mjs";
|
||||
import { cn } from "@/src/utils/tailwind";
|
||||
import { AlertTriangle } from "lucide-react";
|
||||
|
||||
export const LangfuseIcon = ({
|
||||
size = 32,
|
||||
@@ -22,31 +24,54 @@ export const LangfuseLogo = ({
|
||||
className,
|
||||
size = "sm",
|
||||
version = false,
|
||||
showEnvLabel = false,
|
||||
}: {
|
||||
size?: "sm" | "xl";
|
||||
className?: string;
|
||||
version?: boolean;
|
||||
showEnvLabel?: boolean;
|
||||
}) => (
|
||||
<div className={cn("flex items-center", className)}>
|
||||
<LangfuseIcon size={size === "sm" ? 16 : 20} />
|
||||
<span
|
||||
className={cn(
|
||||
"font-mono font-semibold",
|
||||
size === "sm" ? "ml-2 text-sm" : "ml-3 text-xl",
|
||||
)}
|
||||
>
|
||||
Langfuse
|
||||
</span>
|
||||
{version && (
|
||||
<a
|
||||
href="https://github.com/langfuse/langfuse/releases"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
title="View releases on GitHub"
|
||||
className="ml-2 text-xs text-gray-400"
|
||||
<div className={cn("flex gap-4 xl:flex-col xl:items-start", className)}>
|
||||
{/* Environment Labeling for Langfuse Maintainers */}
|
||||
{showEnvLabel && env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION && (
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center gap-2 self-stretch rounded-md px-3 py-1 ring-1 xl:-mx-2",
|
||||
env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION === "STAGING"
|
||||
? "bg-blue-100 text-blue-500 ring-blue-500"
|
||||
: "bg-red-100 text-red-500 ring-red-500",
|
||||
)}
|
||||
>
|
||||
{VERSION}
|
||||
</a>
|
||||
<AlertTriangle size={16} />
|
||||
<span className="whitespace-nowrap">
|
||||
{["EU", "US"].includes(env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION)
|
||||
? `PRODUCTION-${env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION}`
|
||||
: env.NEXT_PUBLIC_LANGFUSE_CLOUD_REGION}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{/* Langfuse Logo */}
|
||||
<div className="flex items-center">
|
||||
<LangfuseIcon size={size === "sm" ? 16 : 20} />
|
||||
<span
|
||||
className={cn(
|
||||
"font-mono font-semibold",
|
||||
size === "sm" ? "ml-2 text-sm" : "ml-3 text-xl",
|
||||
)}
|
||||
>
|
||||
Langfuse
|
||||
</span>
|
||||
{version && (
|
||||
<a
|
||||
href="https://github.com/langfuse/langfuse/releases"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
title="View releases on GitHub"
|
||||
className="ml-2 text-xs text-gray-400"
|
||||
>
|
||||
{VERSION}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -220,7 +220,13 @@ export default function Layout(props: PropsWithChildren) {
|
||||
</Transition.Child>
|
||||
{/* Sidebar component, swap this element with another sidebar if you like */}
|
||||
<div className="flex grow flex-col gap-y-5 overflow-y-auto bg-white px-6 py-4">
|
||||
<LangfuseLogo version size="xl" />
|
||||
<LangfuseLogo
|
||||
version
|
||||
size="xl"
|
||||
showEnvLabel={session.data?.user?.email?.endsWith(
|
||||
"@langfuse.com",
|
||||
)}
|
||||
/>
|
||||
<nav className="flex flex-1 flex-col">
|
||||
<ul role="list" className="flex flex-1 flex-col gap-y-7">
|
||||
<MainNavigation nav={navigation} />
|
||||
@@ -286,7 +292,14 @@ export default function Layout(props: PropsWithChildren) {
|
||||
<div className="hidden xl:fixed xl:inset-y-0 xl:z-50 xl:flex xl:w-72 xl:flex-col">
|
||||
{/* Sidebar component, swap this element with another sidebar if you like */}
|
||||
<div className="flex h-screen grow flex-col gap-y-5 border-r border-gray-200 bg-white pt-7">
|
||||
<LangfuseLogo version size="xl" className="mb-2 px-6" />
|
||||
<LangfuseLogo
|
||||
version
|
||||
size="xl"
|
||||
className="mb-2 px-6"
|
||||
showEnvLabel={session.data?.user?.email?.endsWith(
|
||||
"@langfuse.com",
|
||||
)}
|
||||
/>
|
||||
<nav className="flex h-full flex-1 flex-col overflow-y-auto px-6 pb-3">
|
||||
<ul role="list" className="flex h-full flex-col gap-y-4">
|
||||
<MainNavigation nav={navigation} />
|
||||
@@ -408,7 +421,11 @@ export default function Layout(props: PropsWithChildren) {
|
||||
<span className="sr-only">Open sidebar</span>
|
||||
<Bars3Icon className="h-6 w-6" aria-hidden="true" />
|
||||
</button>
|
||||
<LangfuseLogo version className="flex-1" />
|
||||
<LangfuseLogo
|
||||
version
|
||||
className="flex-1"
|
||||
showEnvLabel={session.data?.user?.email?.endsWith("@langfuse.com")}
|
||||
/>
|
||||
<Menu as="div" className="relative">
|
||||
<Menu.Button className="flex items-center gap-x-4 text-sm font-semibold leading-6 text-gray-900">
|
||||
<span className="sr-only">Open user menu</span>
|
||||
|
||||
@@ -125,6 +125,7 @@ export default function GenerationsTable({ projectId }: GenerationsTableProps) {
|
||||
fileFormat,
|
||||
filter: filterState,
|
||||
searchQuery,
|
||||
orderBy: orderByState,
|
||||
});
|
||||
|
||||
let url: string;
|
||||
|
||||
@@ -24,6 +24,7 @@ import { IOPreview } from "@/src/components/trace/IOPreview";
|
||||
import { formatInterval } from "@/src/utils/dates";
|
||||
import Link from "next/link";
|
||||
import { usdFormatter } from "@/src/utils/numbers";
|
||||
import { calculateDisplayTotalCost } from "@/src/components/trace";
|
||||
|
||||
export const ObservationPreview = (props: {
|
||||
observations: Array<ObservationReturnType>;
|
||||
@@ -41,6 +42,10 @@ export const ObservationPreview = (props: {
|
||||
(o) => o.id === props.currentObservationId,
|
||||
);
|
||||
|
||||
const totalCost = calculateDisplayTotalCost(
|
||||
preloadedObservation ? [preloadedObservation] : [],
|
||||
);
|
||||
|
||||
if (!preloadedObservation) return <div className="flex-1">Not found</div>;
|
||||
return (
|
||||
<Card className="flex-1">
|
||||
@@ -97,11 +102,9 @@ export const ObservationPreview = (props: {
|
||||
{preloadedObservation.model ? (
|
||||
<Badge variant="outline">{preloadedObservation.model}</Badge>
|
||||
) : null}
|
||||
{preloadedObservation.calculatedTotalCost ? (
|
||||
{totalCost ? (
|
||||
<Badge variant="outline">
|
||||
{usdFormatter(
|
||||
preloadedObservation.calculatedTotalCost.toNumber(),
|
||||
)}
|
||||
{usdFormatter(totalCost.toNumber())}
|
||||
</Badge>
|
||||
) : undefined}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import { Toggle } from "@/src/components/ui/toggle";
|
||||
import { Award, ChevronsDownUp, ChevronsUpDown } from "lucide-react";
|
||||
import { ScrollArea } from "@/src/components/ui/scroll-area";
|
||||
import { usdFormatter } from "@/src/utils/numbers";
|
||||
import type Decimal from "decimal.js";
|
||||
import Decimal from "decimal.js";
|
||||
|
||||
export function Trace(props: {
|
||||
observations: Array<ObservationReturnType>;
|
||||
@@ -134,16 +134,8 @@ export function TracePage({ traceId }: { traceId: string }) {
|
||||
const filterOptionTags = traceFilterOptions.data?.tags ?? [];
|
||||
const allTags = filterOptionTags.map((t) => t.value);
|
||||
|
||||
const totalCost: Decimal | undefined = trace.data?.observations.reduce(
|
||||
(prev: Decimal | undefined, curr: ObservationReturnType) => {
|
||||
if (!curr.calculatedTotalCost) return prev;
|
||||
const totalCost = calculateDisplayTotalCost(trace.data?.observations ?? []);
|
||||
|
||||
return prev
|
||||
? prev.plus(curr.calculatedTotalCost)
|
||||
: curr.calculatedTotalCost;
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
if (trace.error?.data?.code === "UNAUTHORIZED") return <NoAccessError />;
|
||||
if (!trace.data) return <div>loading...</div>;
|
||||
return (
|
||||
@@ -232,3 +224,42 @@ export function TracePage({ traceId }: { traceId: string }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const calculateDisplayTotalCost = (
|
||||
observations: ObservationReturnType[],
|
||||
) => {
|
||||
return observations.reduce(
|
||||
(prev: Decimal | undefined, curr: ObservationReturnType) => {
|
||||
// if we don't have any calculated costs, we can't do anything
|
||||
if (
|
||||
!curr.calculatedTotalCost &&
|
||||
!curr.calculatedInputCost &&
|
||||
!curr.calculatedOutputCost
|
||||
)
|
||||
return prev;
|
||||
|
||||
// if we have either input or output cost, but not total cost, we can use that
|
||||
if (
|
||||
!curr.calculatedTotalCost &&
|
||||
(curr.calculatedInputCost || curr.calculatedOutputCost)
|
||||
) {
|
||||
return prev
|
||||
? prev.plus(
|
||||
curr.calculatedInputCost ??
|
||||
new Decimal(0).plus(
|
||||
curr.calculatedOutputCost ?? new Decimal(0),
|
||||
),
|
||||
)
|
||||
: curr.calculatedInputCost ?? curr.calculatedOutputCost ?? undefined;
|
||||
}
|
||||
|
||||
if (!curr.calculatedTotalCost) return prev;
|
||||
|
||||
// if we have total cost, we can use that
|
||||
return prev
|
||||
? prev.plus(curr.calculatedTotalCost)
|
||||
: curr.calculatedTotalCost;
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1 +1 @@
|
||||
export const VERSION = "v2.0.0";
|
||||
export const VERSION = "v2.1.2";
|
||||
|
||||
@@ -88,7 +88,7 @@ export const MetricTable = ({
|
||||
>
|
||||
<DocPopup
|
||||
description="Calculated multiplying the number of tokens with cost per token for each model."
|
||||
href="https://langfuse.com/docs/token-usage"
|
||||
href="https://langfuse.com/docs/model-usage-and-cost"
|
||||
/>
|
||||
</TotalMetric>
|
||||
</DashboardTable>
|
||||
|
||||
@@ -197,6 +197,7 @@ function unicodeToBytesInString(input: string): string {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function unicodeToBytes(input: string): Uint8Array {
|
||||
const encoder = new TextEncoder();
|
||||
return encoder.encode(input);
|
||||
|
||||
@@ -29,12 +29,7 @@ import JsonView from "react18-json-view";
|
||||
|
||||
const formSchema = z.object({
|
||||
modelName: z.string().min(1),
|
||||
exactMatchPattern: z
|
||||
.string()
|
||||
.regex(
|
||||
/^[a-zA-Z0-9_.-]+$/,
|
||||
"Match pattern must be alphanumeric and may contain _.-",
|
||||
), // risk of invalid regex injection that would break the db join,
|
||||
matchPattern: z.string(),
|
||||
startDate: z.date().optional(),
|
||||
inputPrice: z
|
||||
.string()
|
||||
@@ -81,7 +76,7 @@ export const NewModelForm = (props: {
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
modelName: "",
|
||||
exactMatchPattern: "",
|
||||
matchPattern: "",
|
||||
startDate: undefined,
|
||||
inputPrice: "",
|
||||
outputPrice: "",
|
||||
@@ -108,7 +103,7 @@ export const NewModelForm = (props: {
|
||||
.mutateAsync({
|
||||
projectId: props.projectId,
|
||||
modelName: values.modelName,
|
||||
exactMatchPattern: values.exactMatchPattern,
|
||||
matchPattern: values.matchPattern,
|
||||
inputPrice: !!values.inputPrice
|
||||
? parseFloat(values.inputPrice)
|
||||
: undefined,
|
||||
@@ -171,6 +166,7 @@ export const NewModelForm = (props: {
|
||||
onValueChange={(option) => field.onChange(option.value)}
|
||||
value={{ value: field.value, label: field.value }}
|
||||
disabled={false}
|
||||
createLabel="Create a new model name"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
@@ -185,7 +181,7 @@ export const NewModelForm = (props: {
|
||||
<Header level="h3" title="Scope" />
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="exactMatchPattern"
|
||||
name="matchPattern"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Match pattern</FormLabel>
|
||||
@@ -193,8 +189,10 @@ export const NewModelForm = (props: {
|
||||
<Input {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
`model` on generations that should match this model,
|
||||
case-insensitive.
|
||||
Regular expression (Postgres syntax) to match ingested
|
||||
generations (model attribute) to this model definition. For an
|
||||
exact, case-insensitive match to a model name, use the
|
||||
expression: (?i)^modelname$
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
||||
@@ -23,6 +23,7 @@ type AutoCompleteProps = {
|
||||
onValueChange?: (value: AutoCompleteOption) => void;
|
||||
disabled?: boolean;
|
||||
placeholder?: string;
|
||||
createLabel: string;
|
||||
};
|
||||
|
||||
export const AutoComplete = ({
|
||||
@@ -31,6 +32,7 @@ export const AutoComplete = ({
|
||||
value,
|
||||
onValueChange,
|
||||
disabled,
|
||||
createLabel,
|
||||
}: AutoCompleteProps) => {
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
const [isOpen, setOpen] = useState(false);
|
||||
@@ -138,6 +140,7 @@ export const AutoComplete = ({
|
||||
onSelect={() =>
|
||||
handleSelectOption({ value: inputValue, label: inputValue })
|
||||
}
|
||||
createLabel={createLabel}
|
||||
{...{ inputValue, options }}
|
||||
/>
|
||||
</CommandList>
|
||||
@@ -151,11 +154,13 @@ export const AutoComplete = ({
|
||||
const CommandItemCreate = ({
|
||||
inputValue,
|
||||
options,
|
||||
createLabel,
|
||||
onSelect,
|
||||
onMouseDown,
|
||||
}: {
|
||||
inputValue: string;
|
||||
options: AutoCompleteOption[];
|
||||
createLabel: string;
|
||||
onSelect: () => void;
|
||||
onMouseDown: (event: React.MouseEvent<HTMLElement>) => void;
|
||||
}) => {
|
||||
@@ -176,7 +181,7 @@ const CommandItemCreate = ({
|
||||
onMouseDown={onMouseDown}
|
||||
>
|
||||
<div className={cn("m-2 h-4 w-4")} />
|
||||
Create new prompt name: "{inputValue}"
|
||||
{createLabel}: "{inputValue}"
|
||||
</CommandItem>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -191,6 +191,7 @@ export const NewPromptForm = (props: {
|
||||
onValueChange={setNameValue}
|
||||
value={{ value: field.value, label: field.value }}
|
||||
disabled={false}
|
||||
createLabel="Create a new prompt name"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
|
||||
@@ -19,13 +19,15 @@ export default function ModelsPage() {
|
||||
help={{
|
||||
description:
|
||||
"A model represents a LLM model. It is used to calculate tokens and cost.",
|
||||
href: "https://langfuse.com/docs/token-usage",
|
||||
href: "https://langfuse.com/docs/model-usage-and-cost",
|
||||
}}
|
||||
actionButtons={
|
||||
<Button disabled={!hasWriteAccess} asChild>
|
||||
<Link href={`/project/${projectId}/models/new`}>
|
||||
<Link
|
||||
href={hasWriteAccess ? `/project/${projectId}/models/new` : "#"}
|
||||
>
|
||||
{!hasWriteAccess && <Lock size={16} className="mr-2" />}
|
||||
Add model definition{" "}
|
||||
Add model definition
|
||||
</Link>
|
||||
</Button>
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ export default function ModelsPage() {
|
||||
return (
|
||||
<div className="mb-12 md:container">
|
||||
<Header
|
||||
title="New Model"
|
||||
title="New Model Definition"
|
||||
breadcrumb={[
|
||||
{
|
||||
name: "Models",
|
||||
@@ -20,6 +20,11 @@ export default function ModelsPage() {
|
||||
name: "New",
|
||||
},
|
||||
]}
|
||||
help={{
|
||||
description:
|
||||
"Create a project-specific model definition. This will be used by Langfuse to infer model usage (eg tokens) and cost (USD).",
|
||||
href: "https://langfuse.com/docs/model-usage-and-cost",
|
||||
}}
|
||||
/>
|
||||
<NewModelForm
|
||||
projectId={projectId}
|
||||
|
||||
@@ -31,19 +31,19 @@ import {
|
||||
import { orderBy } from "@/src/server/api/interfaces/orderBy";
|
||||
import { orderByToPrismaSql } from "@/src/features/orderBy/server/orderByToPrisma";
|
||||
|
||||
const GenerationFilterOptions = z.object({
|
||||
const GenerationTableOptions = z.object({
|
||||
projectId: z.string(), // Required for protectedProjectProcedure
|
||||
filter: z.array(singleFilter),
|
||||
searchQuery: z.string().nullable(),
|
||||
orderBy: orderBy,
|
||||
});
|
||||
|
||||
const ListInputs = GenerationFilterOptions.extend({
|
||||
orderBy: orderBy,
|
||||
const ListInputs = GenerationTableOptions.extend({
|
||||
...paginationZod,
|
||||
});
|
||||
|
||||
// extend generationfilteroptions with export options
|
||||
const ExportInputs = GenerationFilterOptions.extend({
|
||||
const ExportInputs = GenerationTableOptions.extend({
|
||||
fileFormat: z.enum(exportFileFormats),
|
||||
});
|
||||
|
||||
@@ -51,6 +51,7 @@ export const generationsRouter = createTRPCRouter({
|
||||
all: protectedProjectProcedure
|
||||
.input(ListInputs)
|
||||
.query(async ({ input, ctx }) => {
|
||||
// ATTENTION: When making changes to this query, make sure to also update the export query
|
||||
const searchCondition = input.searchQuery
|
||||
? Prisma.sql`AND (
|
||||
o."id" ILIKE ${`%${input.searchQuery}%`} OR
|
||||
@@ -240,6 +241,7 @@ export const generationsRouter = createTRPCRouter({
|
||||
export: protectedProjectProcedure
|
||||
.input(ExportInputs)
|
||||
.query(async ({ input, ctx }) => {
|
||||
// ATTENTION: When making changes to this query, make sure to also update the all query
|
||||
const searchCondition = input.searchQuery
|
||||
? Prisma.sql`AND (
|
||||
o."id" ILIKE ${`%${input.searchQuery}%`} OR
|
||||
@@ -253,18 +255,45 @@ export const generationsRouter = createTRPCRouter({
|
||||
input.filter,
|
||||
observationsTableCols,
|
||||
);
|
||||
console.log("filters: ", filterCondition);
|
||||
|
||||
const orderByCondition = orderByToPrismaSql(
|
||||
input.orderBy,
|
||||
observationsTableCols,
|
||||
);
|
||||
|
||||
// to improve query performance, add timeseries filter to observation queries as well
|
||||
const startTimeFilter = input.filter.find(
|
||||
(f) => f.column === "start_time" && f.type === "datetime",
|
||||
);
|
||||
const datetimeFilter =
|
||||
startTimeFilter && startTimeFilter.type === "datetime"
|
||||
? datetimeFilterToPrismaSql(
|
||||
"start_time",
|
||||
startTimeFilter.operator,
|
||||
startTimeFilter.value,
|
||||
)
|
||||
: Prisma.empty;
|
||||
|
||||
const generations = await ctx.prisma.$queryRaw<
|
||||
Array<
|
||||
ObservationView & {
|
||||
traceId: string;
|
||||
traceName: string;
|
||||
latency: number | null;
|
||||
}
|
||||
>
|
||||
>(
|
||||
Prisma.sql`
|
||||
-- used for filtering
|
||||
WITH observations_with_latency AS (
|
||||
SELECT
|
||||
o.*,
|
||||
CASE WHEN o.end_time IS NULL THEN NULL ELSE (EXTRACT(EPOCH FROM o."end_time") - EXTRACT(EPOCH FROM o."start_time"))::double precision END AS "latency"
|
||||
FROM observations_view o
|
||||
WHERE o.type = 'GENERATION'
|
||||
AND o.project_id = ${input.projectId}
|
||||
${datetimeFilter}
|
||||
),
|
||||
-- used for filtering
|
||||
scores_avg AS (
|
||||
SELECT
|
||||
trace_id,
|
||||
@@ -293,6 +322,7 @@ export const generationsRouter = createTRPCRouter({
|
||||
o.model,
|
||||
o.start_time as "startTime",
|
||||
o.end_time as "endTime",
|
||||
o.latency,
|
||||
o.input,
|
||||
o.output,
|
||||
o.metadata,
|
||||
@@ -302,6 +332,8 @@ export const generationsRouter = createTRPCRouter({
|
||||
o.prompt_tokens as "promptTokens",
|
||||
o.completion_tokens as "completionTokens",
|
||||
o.total_tokens as "totalTokens",
|
||||
o.level,
|
||||
o.status_message as "statusMessage",
|
||||
o.version,
|
||||
o.model_id as "modelId",
|
||||
o.input_price as "inputPrice",
|
||||
@@ -310,15 +342,14 @@ export const generationsRouter = createTRPCRouter({
|
||||
o.calculated_input_cost as "calculatedInputCost",
|
||||
o.calculated_output_cost as "calculatedOutputCost",
|
||||
o.calculated_total_cost as "calculatedTotalCost"
|
||||
FROM observations_view o
|
||||
FROM observations_with_latency o
|
||||
JOIN traces t ON t.id = o.trace_id
|
||||
LEFT JOIN scores_avg AS s_avg ON s_avg.trace_id = t.id and s_avg.observation_id = o.id
|
||||
WHERE o.type = 'GENERATION'
|
||||
AND o.project_id = ${input.projectId}
|
||||
AND t.project_id = ${input.projectId}
|
||||
WHERE
|
||||
t.project_id = ${input.projectId}
|
||||
${searchCondition}
|
||||
${filterCondition}
|
||||
ORDER BY o.start_time DESC
|
||||
${orderByCondition}
|
||||
`,
|
||||
);
|
||||
|
||||
@@ -445,7 +476,6 @@ export const generationsRouter = createTRPCRouter({
|
||||
Key: fileName,
|
||||
Body: output,
|
||||
ContentType: exportOptions[input.fileFormat].fileType,
|
||||
Expires: new Date(Date.now() + 60 * 60 * 1000), // in 1 hour, file will be deleted
|
||||
}),
|
||||
);
|
||||
const signedUrl = await getSignedUrl(
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
} from "@/src/server/api/trpc";
|
||||
import { paginationZod } from "@/src/utils/zod";
|
||||
import { throwIfNoAccess } from "@/src/features/rbac/utils/checkAccess";
|
||||
import { Prisma } from "@prisma/client";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
const ModelAllOptions = z.object({
|
||||
projectId: z.string(),
|
||||
@@ -39,9 +41,6 @@ export const modelRouter = createTRPCRouter({
|
||||
OR: [{ projectId: input.projectId }, { projectId: null }],
|
||||
},
|
||||
});
|
||||
|
||||
console.log("models", models);
|
||||
|
||||
return {
|
||||
models,
|
||||
totalCount: totalAmount,
|
||||
@@ -86,34 +85,18 @@ export const modelRouter = createTRPCRouter({
|
||||
}),
|
||||
create: protectedProjectProcedure
|
||||
.input(
|
||||
z
|
||||
.object({
|
||||
projectId: z.string(),
|
||||
modelName: z.string(),
|
||||
exactMatchPattern: z
|
||||
.string()
|
||||
.regex(
|
||||
/^[a-zA-Z0-9_.-]+$/,
|
||||
"Match pattern must be alphanumeric and may contain _.-",
|
||||
), // risk of invalid regex injection that would break the db join
|
||||
startDate: z.date().optional(),
|
||||
inputPrice: z.number().positive().optional(),
|
||||
outputPrice: z.number().positive().optional(),
|
||||
totalPrice: z.number().positive().optional(),
|
||||
unit: z.enum(["TOKENS", "CHARACTERS"]),
|
||||
tokenizerId: z.enum(["openai", "claude"]).optional(),
|
||||
tokenizerConfig: z
|
||||
.record(z.union([z.string(), z.number()]))
|
||||
.optional(),
|
||||
})
|
||||
.refine(
|
||||
({ inputPrice, outputPrice, totalPrice }) =>
|
||||
(!!inputPrice && !!outputPrice) || !!totalPrice,
|
||||
{
|
||||
message:
|
||||
"Either inputPrice and outputPrice or totalPrice needs to be set",
|
||||
},
|
||||
),
|
||||
z.object({
|
||||
projectId: z.string(),
|
||||
modelName: z.string(),
|
||||
matchPattern: z.string(),
|
||||
startDate: z.date().optional(),
|
||||
inputPrice: z.number().nonnegative().optional(),
|
||||
outputPrice: z.number().nonnegative().optional(),
|
||||
totalPrice: z.number().nonnegative().optional(),
|
||||
unit: z.enum(["TOKENS", "CHARACTERS"]),
|
||||
tokenizerId: z.enum(["openai", "claude"]).optional(),
|
||||
tokenizerConfig: z.record(z.union([z.string(), z.number()])).optional(),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input, ctx }) => {
|
||||
throwIfNoAccess({
|
||||
@@ -121,11 +104,25 @@ export const modelRouter = createTRPCRouter({
|
||||
projectId: input.projectId,
|
||||
scope: "models:CUD",
|
||||
});
|
||||
|
||||
// Check if regex is valid POSIX regex
|
||||
// Use DB to check, because JS regex is not POSIX compliant
|
||||
try {
|
||||
await ctx.prisma.$queryRaw(
|
||||
Prisma.sql`SELECT 'test_string' ~ ${input.matchPattern}`,
|
||||
);
|
||||
} catch (error) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Invalid regex, needs to be Postgres syntax",
|
||||
});
|
||||
}
|
||||
|
||||
return ctx.prisma.model.create({
|
||||
data: {
|
||||
projectId: input.projectId,
|
||||
modelName: input.modelName,
|
||||
matchPattern: `(?i)^(${input.exactMatchPattern})$`,
|
||||
matchPattern: input.matchPattern,
|
||||
startDate: input.startDate,
|
||||
inputPrice: input.inputPrice,
|
||||
outputPrice: input.outputPrice,
|
||||
|
||||
@@ -208,6 +208,36 @@ export const traceRouter = createTRPCRouter({
|
||||
},
|
||||
});
|
||||
const observations = await ctx.prisma.observationView.findMany({
|
||||
select: {
|
||||
id: true,
|
||||
traceId: true,
|
||||
projectId: true,
|
||||
type: true,
|
||||
startTime: true,
|
||||
endTime: true,
|
||||
name: true,
|
||||
metadata: true,
|
||||
parentObservationId: true,
|
||||
level: true,
|
||||
statusMessage: true,
|
||||
version: true,
|
||||
createdAt: true,
|
||||
model: true,
|
||||
modelParameters: true,
|
||||
promptTokens: true,
|
||||
completionTokens: true,
|
||||
totalTokens: true,
|
||||
unit: true,
|
||||
completionStartTime: true,
|
||||
promptId: true,
|
||||
modelId: true,
|
||||
inputPrice: true,
|
||||
outputPrice: true,
|
||||
totalPrice: true,
|
||||
calculatedInputCost: true,
|
||||
calculatedOutputCost: true,
|
||||
calculatedTotalCost: true,
|
||||
},
|
||||
where: {
|
||||
traceId: {
|
||||
equals: input.traceId,
|
||||
@@ -237,11 +267,7 @@ export const traceRouter = createTRPCRouter({
|
||||
return {
|
||||
...trace,
|
||||
latency: latencyMs !== undefined ? latencyMs / 1000 : undefined,
|
||||
observations: observations.map(
|
||||
({ input: _input, output: _output, ...rest }) => {
|
||||
return { ...rest };
|
||||
},
|
||||
) as ObservationReturnType[],
|
||||
observations: observations as ObservationReturnType[],
|
||||
};
|
||||
}),
|
||||
deleteMany: protectedProjectProcedure
|
||||
|
||||
Reference in New Issue
Block a user